Mon Jan 19 17:44:50 CET 2004 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / aot.c
index 9bf96eaad2b8209089c02a6c841c785438143049..a24419d440eff910468080f669dca3d5c3212713 100644 (file)
@@ -30,6 +30,7 @@
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/assembly.h>
+#include <mono/metadata/marshal.h>
 #include <mono/os/gc_wrapper.h>
 
 #include "mini.h"
@@ -70,6 +71,15 @@ static CRITICAL_SECTION aot_mutex;
 
 static guint32 mono_aot_verbose = 0;
 
+/*
+ * Disabling this will make a copy of the loaded code and use the copy instead 
+ * of the original. This will place the caller and the callee close to each 
+ * other in memory, possibly improving cache behavior. Since the original
+ * code is in copy-on-write memory, this will not increase the memory usage
+ * of the runtime.
+ */
+static gboolean use_loaded_code = FALSE;
+
 /* For debugging */
 static gint32 mono_last_aot_method = -1;
 
@@ -160,9 +170,11 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                        if (!info->image_table [i]) {
                                if (mono_aot_verbose > 0)
                                        printf ("AOT module %s is out of date.\n", aot_name);
-                               g_free (info->methods);
+                               mono_g_hash_table_destroy (info->methods);
                                g_free (info->image_table);
+#ifndef HAVE_BOEHM_GC
                                g_free (info);
+#endif
                                g_free (aot_name);
                                g_module_close (assembly->aot_module);
                                assembly->aot_module = NULL;
@@ -238,6 +250,9 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
        if (!method->token)
                return NULL;
 
+       if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
+               return NULL;
+
        if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
                (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
                (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
@@ -273,11 +288,11 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                        memcpy (code, minfo->info->code_start, minfo->info->code_size);
 
                        if (mono_aot_verbose > 1)
-                               printf ("REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + code_len);
+                               printf ("REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + minfo->info->code_size);
 
                        /* Do this outside the lock to avoid deadlocks */
                        LeaveCriticalSection (&aot_mutex);
-                       mono_arch_patch_code (method, domain, code, minfo->patch_info);
+                       mono_arch_patch_code (method, domain, code, minfo->patch_info, TRUE);
                        EnterCriticalSection (&aot_mutex);
 
                        /* Relocate jinfo */
@@ -321,18 +336,12 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
        if (!g_module_symbol (module, info_label, (gpointer *)&info))
                return NULL;
 
-       {
-               static int count = 0;
-
-               count ++;
-
-               if (mono_last_aot_method != -1) {
-                       if (count > mono_last_aot_method)
+       if (mono_last_aot_method != -1) {
+               if (mono_jit_stats.methods_aot > mono_last_aot_method)
                                return NULL;
-                       else
-                               if (count == mono_last_aot_method)
-                                       printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
-               }
+               else
+                       if (mono_jit_stats.methods_aot == mono_last_aot_method)
+                               printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
        }
 
 #ifdef HAVE_BOEHM_GC
@@ -348,18 +357,12 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
        used_int_regs = GPOINTER_TO_UINT (*((gpointer **)info));
        info++;
 
-       /* 
-        * Enabling this will place the caller and the callee close to each other
-        * in memory, possibly improving cache behavior.
-        */
-/*
-       {
+       if (!use_loaded_code) {
                guint8 *code2;
                code2 = mono_mempool_alloc (domain->code_mp, code_len);
                memcpy (code2, code, code_len);
                code = code2;
        }
-*/
 
        if (mono_aot_verbose > 1)
                printf ("FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info);
@@ -412,7 +415,7 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                gpointer *table;
                int pages;
                int i, err;
-               guint32 last_offset;
+               guint32 last_offset, buf_len;
 
                if (aot_module->opts & MONO_OPT_SHARED)
                        mp = mono_mempool_new ();
@@ -454,6 +457,7 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                                mono_class_init (ji->data.klass);
                                break;
                        case MONO_PATCH_INFO_VTABLE:
+                       case MONO_PATCH_INFO_CLASS_INIT:
                                ji->data.klass = decode_class_info (aot_module, data);
                                g_assert (ji->data.klass);
                                mono_class_init (ji->data.klass);
@@ -463,7 +467,8 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                                g_assert (ji->data.image);
                                break;
                        case MONO_PATCH_INFO_METHOD:
-                       case MONO_PATCH_INFO_METHODCONST: {
+                       case MONO_PATCH_INFO_METHODCONST:
+                       case MONO_PATCH_INFO_METHOD_JUMP: {
                                guint32 image_index, token;
 
                                image_index = (guint32)data >> 24;
@@ -476,6 +481,24 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
 
                                break;
                        }
+                       case MONO_PATCH_INFO_WRAPPER: {
+                               guint32 image_index, token;
+                               guint32 wrapper_type;
+
+                               wrapper_type = (guint32)data[0];
+                               image_index = (guint32)data[1] >> 24;
+                               token = MONO_TOKEN_METHOD_DEF | ((guint32)data[1] & 0xffffff);
+
+                               image = aot_module->image_table [image_index];
+                               ji->data.method = mono_get_method (image, token, NULL);
+                               g_assert (ji->data.method);
+                               mono_class_init (ji->data.method->klass);
+
+                               g_assert (wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
+                               ji->type = MONO_PATCH_INFO_METHOD;
+                               ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
+                               break;
+                       }
                        case MONO_PATCH_INFO_FIELD:
                        case MONO_PATCH_INFO_SFLDA: {
                                MonoClass *klass = decode_class_info (aot_module, data [1]);
@@ -503,7 +526,8 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                        case MONO_PATCH_INFO_LDSTR:
                        case MONO_PATCH_INFO_LDTOKEN:
                        case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
-                               ji->data.target = *data;
+                               image = aot_module->image_table [(int)data [0]];
+                               ji->data.token = mono_jump_info_token_new (mp, image, (int)data [1]);
                                break;
                        case MONO_PATCH_INFO_EXC_NAME:
                                ji->data.klass = decode_class_info (aot_module, data);
@@ -524,22 +548,29 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                        patch_info = ji;
                }
 
-#ifndef PLATFORM_WIN32
+               info = (gpointer)((guint8*)info + 4);
+               buf_len = *(guint32*)info;
+               info = (gpointer)((guint8*)info + 4);
+               mono_debug_add_aot_method (domain, method, code, (guint8*)info, buf_len);
+
+               if (use_loaded_code) {
                /* disable write protection */
-               page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
-               pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
-               err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
-               g_assert (err == 0);
+#ifndef PLATFORM_WIN32
+                       page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
+                       pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
+                       err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
+                       g_assert (err == 0);
 #else
-               {
-                       DWORD oldp;
-                       g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
-               }
+                       {
+                               DWORD oldp;
+                               g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
+                       }
 #endif
+               }
 
                /* Do this outside the lock to avoid deadlocks */
                LeaveCriticalSection (&aot_mutex);
-               mono_arch_patch_code (method, domain, code, patch_info);
+               mono_arch_patch_code (method, domain, code, patch_info, TRUE);
                EnterCriticalSection (&aot_mutex);
 
                if (aot_module->opts & MONO_OPT_SHARED)
@@ -794,7 +825,8 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        break;
                }
                case MONO_PATCH_INFO_METHODCONST:
-               case MONO_PATCH_INFO_METHOD: {
+               case MONO_PATCH_INFO_METHOD:
+               case MONO_PATCH_INFO_METHOD_JUMP: {
                        /*
                         * The majority of patches are for methods, so we emit
                         * them inline instead of defining a label for them to
@@ -810,6 +842,24 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        j++;
                        break;
                }
+               case MONO_PATCH_INFO_WRAPPER: {
+                       MonoMethod *m;
+                       guint32 image_index;
+                       guint32 token;
+
+                       m = mono_marshal_method_from_wrapper (patch_info->data.method);
+                       image_index = get_image_index (acfg, m->klass->image);
+                       token = m->token;
+                       g_assert (image_index < 256);
+                       g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
+
+                       fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
+                       fprintf (tmpfp, "%s_p_%d:\n", mname, j);
+                       fprintf (tmpfp, "\t.long %d\n", patch_info->data.method->wrapper_type);
+                       fprintf (tmpfp, "\t.long %d\n", (image_index << 24) + (mono_metadata_token_index (token)));
+                       j++;
+                       break;
+               }
                case MONO_PATCH_INFO_FIELD:
                        patch_info->data.name = cond_emit_field_label (acfg, patch_info);
                        j++;
@@ -854,6 +904,7 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        j++;
                        break;
                case MONO_PATCH_INFO_VTABLE:
+               case MONO_PATCH_INFO_CLASS_INIT:
                        patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
                        j++;
                        break;
@@ -866,7 +917,8 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
                        fprintf (tmpfp, "\t.align 8\n");
                        fprintf (tmpfp, "%s_p_%d:\n", mname, j);
-                       fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token);
+                       fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.token->image));
+                       fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token->token);
                        j++;
                        break;
                default:
@@ -949,12 +1001,14 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        switch (patch_info->type) {
                        case MONO_PATCH_INFO_METHODCONST:
                        case MONO_PATCH_INFO_METHOD:
+                       case MONO_PATCH_INFO_METHOD_JUMP:
                        case MONO_PATCH_INFO_CLASS:
                        case MONO_PATCH_INFO_IID:
                        case MONO_PATCH_INFO_FIELD:
                        case MONO_PATCH_INFO_INTERNAL_METHOD:
                        case MONO_PATCH_INFO_IMAGE:
                        case MONO_PATCH_INFO_VTABLE:
+                       case MONO_PATCH_INFO_CLASS_INIT:
                        case MONO_PATCH_INFO_SFLDA:
                        case MONO_PATCH_INFO_EXC_NAME:
                                fprintf (tmpfp, "\t.long %s\n", patch_info->data.name);
@@ -967,6 +1021,7 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        case MONO_PATCH_INFO_LDSTR:
                        case MONO_PATCH_INFO_LDTOKEN:
                        case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+                       case MONO_PATCH_INFO_WRAPPER:
                                fprintf (tmpfp, "\t.long %s_p_%d\n", mname, j);
                                j++;
                                break;
@@ -987,6 +1042,21 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
        /* NULL terminated array */
        fprintf (tmpfp, "\t.long 0\n");
 
+       {
+               guint8 *buf;
+               guint32 buf_len;
+
+               mono_debug_serialize_debug_info (cfg, &buf, &buf_len);
+
+               fprintf (tmpfp, "\t.long %d\n", buf_len);
+
+               for (i = 0; i < buf_len; ++i)
+                       fprintf (tmpfp, ".byte %d\n", (unsigned int) buf [i]);
+
+               if (buf_len > 0)
+                       g_free (buf);
+       }
+
        /* fixme: save the rest of the required infos */
 
        g_free (mname);
@@ -1007,7 +1077,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
        MonoAotCompile *acfg;
        gboolean *emitted;
 
-       printf ("Mono AOT compiler - compiling assembly %s\n", image->name);
+       printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
 
        i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
        tmpfp = fdopen (i, "w+");
@@ -1060,7 +1130,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
                //printf ("START:           %s\n", mono_method_full_name (method, TRUE));
                //mono_compile_method (method);
 
-               cfg = mini_method_compile (method, opts, mono_root_domain, 0);
+               cfg = mini_method_compile (method, opts, mono_root_domain, FALSE, 0);
                g_assert (cfg);
 
                if (cfg->disable_aot) {
@@ -1084,6 +1154,13 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
                        continue;
                }
 
+               /* remoting-invoke-with-check wrappers are very common */
+               for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
+                       if ((patch_info->type == MONO_PATCH_INFO_METHOD) &&
+                               ((patch_info->data.method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)))
+                               patch_info->type = MONO_PATCH_INFO_WRAPPER;
+               }
+
                skip = FALSE;
                for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                        if ((patch_info->type == MONO_PATCH_INFO_METHOD ||
@@ -1184,11 +1261,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
        system (com);
        g_free (com);*/
 
-       printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, (ccount*100)/mcount);
-       printf ("%d methods contain absolute addresses (%d%%)\n", abscount, (abscount*100)/mcount);
-       printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, (wrappercount*100)/mcount);
-       printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, (lmfcount*100)/mcount);
-       printf ("%d methods have other problems (%d%%)\n", ocount, (ocount*100)/mcount);
+       printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, mcount ? (ccount*100)/mcount : 100);
+       printf ("%d methods contain absolute addresses (%d%%)\n", abscount, mcount ? (abscount*100)/mcount : 100);
+       printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, mcount ? (wrappercount*100)/mcount : 100);
+       printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, mcount ? (lmfcount*100)/mcount : 100);
+       printf ("%d methods have other problems (%d%%)\n", ocount, mcount ? (ocount*100)/mcount : 100);
        unlink (tmpfname);
 
        return 0;