Merge remote branch 'upstream/master'
[mono.git] / mono / mini / aot-runtime.c
index 597a76aa7848b557f45e33fa6d896bd8c467061c..115384028f003b2d2bca9677e26e655fb197ce92 100644 (file)
@@ -964,6 +964,65 @@ find_symbol (MonoDl *module, gpointer *globals, const char *name, gpointer *valu
        }
 }
 
+static gboolean
+check_usable (MonoAssembly *assembly, MonoAotFileInfo *info, char **out_msg)
+{
+       char *build_info;
+       char *msg = NULL;
+       gboolean usable = TRUE;
+       gboolean full_aot;
+       guint8 *blob;
+
+       if (strcmp (assembly->image->guid, info->assembly_guid)) {
+               msg = g_strdup_printf ("doesn't match assembly");
+               usable = FALSE;
+       }
+
+       build_info = mono_get_runtime_build_info ();
+       if (strlen (info->runtime_version) > 0 && strcmp (info->runtime_version, build_info)) {
+               msg = g_strdup_printf ("compiled against runtime version '%s' while this runtime has version '%s'", info->runtime_version, build_info);
+               usable = FALSE;
+       }
+       g_free (build_info);
+
+       full_aot = info->flags & MONO_AOT_FILE_FLAG_FULL_AOT;
+
+       if (mono_aot_only && !full_aot) {
+               msg = g_strdup_printf ("not compiled with --aot=full");
+               usable = FALSE;
+       }
+       if (!mono_aot_only && full_aot) {
+               msg = g_strdup_printf ("compiled with --aot=full");
+               usable = FALSE;
+       }
+#ifdef TARGET_ARM
+       /* mono_arch_find_imt_method () requires this */
+       if ((info->flags & MONO_AOT_FILE_FLAG_WITH_LLVM) && !mono_use_llvm) {
+               msg = g_strdup_printf ("compiled against LLVM");
+               usable = FALSE;
+       }
+#endif
+       if (mini_get_debug_options ()->mdb_optimizations && !(info->flags & MONO_AOT_FILE_FLAG_DEBUG) && !full_aot) {
+               msg = g_strdup_printf ("not compiled for debugging");
+               usable = FALSE;
+       }
+
+       blob = info->blob;
+
+       if (info->gc_name_index != -1) {
+               char *gc_name = (char*)&blob [info->gc_name_index];
+               const char *current_gc_name = mono_gc_get_gc_name ();
+
+               if (strcmp (current_gc_name, gc_name) != 0) {
+                       msg = g_strdup_printf ("compiled against GC %s, while the current runtime uses GC %s.\n", gc_name, current_gc_name);
+                       usable = FALSE;
+               }
+       }
+
+       *out_msg = msg;
+       return usable;
+}
+
 static void
 load_aot_module (MonoAssembly *assembly, gpointer user_data)
 {
@@ -971,15 +1030,13 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        MonoAotModule *amodule;
        MonoDl *sofile;
        gboolean usable = TRUE;
-       char *saved_guid = NULL;
-       char *aot_version = NULL;
-       char *runtime_version, *build_info;
-       char *opt_flags = NULL;
+       char *version_symbol = NULL;
+       char *msg = NULL;
        gpointer *globals;
-       gboolean full_aot = FALSE;
-       MonoAotFileInfo *file_info = NULL;
-       int i;
+       MonoAotFileInfo *info = NULL;
+       int i, version;
        guint8 *blob;
+       gboolean do_load_image = TRUE;
 
        if (mono_compile_aot)
                return;
@@ -1034,74 +1091,32 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                return;
        }
 
-       find_symbol (sofile, globals, "mono_assembly_guid", (gpointer *) &saved_guid);
-       find_symbol (sofile, globals, "mono_aot_version", (gpointer *) &aot_version);
-       find_symbol (sofile, globals, "mono_aot_opt_flags", (gpointer *)&opt_flags);
-       find_symbol (sofile, globals, "mono_runtime_version", (gpointer *)&runtime_version);
+       find_symbol (sofile, globals, "mono_aot_version", (gpointer *) &version_symbol);
+       find_symbol (sofile, globals, "mono_aot_file_info", (gpointer*)&info);
 
-       if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
-               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
-               usable = FALSE;
-       }
-       else {
-               if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
-                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
-                       usable = FALSE;
-               }
-       }
-
-       build_info = mono_get_runtime_build_info ();
-       if (!runtime_version || ((strlen (runtime_version) > 0 && strcmp (runtime_version, build_info)))) {
-               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is compiled against runtime version '%s' while this runtime has version '%s'.\n", aot_name, runtime_version, build_info);
-               usable = FALSE;
-       }
-       g_free (build_info);
-
-       find_symbol (sofile, globals, "mono_aot_file_info", (gpointer*)&file_info);
-       g_assert (file_info);
-
-       full_aot = ((MonoAotFileInfo*)file_info)->flags & MONO_AOT_FILE_FLAG_FULL_AOT;
-
-       if (mono_aot_only && !full_aot) {
-               fprintf (stderr, "Can't use AOT image '%s' in aot-only mode because it is not compiled with --aot=full.\n", aot_name);
-               exit (1);
-       }
-       if (!mono_aot_only && full_aot) {
-               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is compiled with --aot=full.\n", aot_name);
-               usable = FALSE;
-       }
-
-       /* This is no longer needed, LLVM and non-LLVM runtimes should be compatible.
-       if ((((MonoAotFileInfo*)file_info)->flags & MONO_AOT_FILE_FLAG_WITH_LLVM) && !mono_use_llvm) {
-               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is compiled with LLVM.\n", aot_name);
-               usable = FALSE;
+       if (version_symbol) {
+               /* Old file format */
+               version = atoi (version_symbol);
+       } else {
+               g_assert (info);
+               version = info->version;
        }
-       */
 
-       if (mini_get_debug_options ()->mdb_optimizations && !(file_info->flags & MONO_AOT_FILE_FLAG_DEBUG) && !full_aot) {
-               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is not compiled for debugging.\n", aot_name);
+       if (version != MONO_AOT_FILE_VERSION) {
+               msg = g_strdup_printf ("wrong file format version (expected %d got %d)", MONO_AOT_FILE_VERSION, version);
                usable = FALSE;
-       }
-
-       find_symbol (sofile, globals, "blob", (gpointer*)&blob);
-
-       if (usable && ((MonoAotFileInfo*)file_info)->gc_name_index != -1) {
-               char *gc_name = (char*)&blob [((MonoAotFileInfo*)file_info)->gc_name_index];
-               const char *current_gc_name = mono_gc_get_gc_name ();
-
-               if (strcmp (current_gc_name, gc_name) != 0) {
-                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is compiled against GC %s, while the current runtime uses GC %s.\n", aot_name, gc_name, current_gc_name);
-                       usable = FALSE;
-               }
+       } else {
+               usable = check_usable (assembly, info, &msg);
        }
 
        if (!usable) {
                if (mono_aot_only) {
-                       fprintf (stderr, "Failed to load AOT module '%s' while running in aot-only mode.\n", aot_name);
+                       fprintf (stderr, "Failed to load AOT module '%s' while running in aot-only mode: %s.\n", aot_name, msg);
                        exit (1);
                } else {
-                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is unusable.\n", aot_name);
+                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is unusable: %s.\n", aot_name, msg);
                }
+               g_free (msg);
                g_free (aot_name);
                if (sofile)
                        mono_dl_close (sofile);
@@ -1109,11 +1124,13 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                return;
        }
 
+       blob = info->blob;
+
        amodule = g_new0 (MonoAotModule, 1);
        amodule->aot_name = aot_name;
        amodule->assembly = assembly;
 
-       memcpy (&amodule->info, file_info, sizeof (*file_info));
+       memcpy (&amodule->info, info, sizeof (*info));
 
        amodule->got = amodule->info.got;
        amodule->got [0] = assembly->image;
@@ -1127,7 +1144,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                guint32 table_len, i;
                char *table = NULL;
 
-               find_symbol (sofile, globals, "mono_image_table", (gpointer *)&table);
+               table = info->image_table;
                g_assert (table);
 
                table_len = *(guint32*)table;
@@ -1163,34 +1180,30 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                }
        }
 
-       /* Read method and method_info tables */
-       find_symbol (sofile, globals, "code_offsets", (gpointer*)&amodule->code_offsets);
-       amodule->code = amodule->info.methods;
+       amodule->code_offsets = info->code_offsets;
+       amodule->code = info->methods;
 #ifdef TARGET_ARM
        /* Mask out thumb interop bit */
        amodule->code = (void*)((mgreg_t)amodule->code & ~1);
 #endif
-       find_symbol (sofile, globals, "methods_end", (gpointer*)&amodule->code_end);
-       find_symbol (sofile, globals, "method_info_offsets", (gpointer*)&amodule->method_info_offsets);
-       find_symbol (sofile, globals, "ex_info_offsets", (gpointer*)&amodule->ex_info_offsets);
-       find_symbol (sofile, globals, "class_info_offsets", (gpointer*)&amodule->class_info_offsets);
-       find_symbol (sofile, globals, "class_name_table", (gpointer *)&amodule->class_name_table);
-       find_symbol (sofile, globals, "extra_method_table", (gpointer *)&amodule->extra_method_table);
-       find_symbol (sofile, globals, "extra_method_info_offsets", (gpointer *)&amodule->extra_method_info_offsets);
-       find_symbol (sofile, globals, "got_info_offsets", (gpointer*)&amodule->got_info_offsets);
-       find_symbol (sofile, globals, "specific_trampolines", (gpointer*)&(amodule->trampolines [MONO_AOT_TRAMP_SPECIFIC]));
-       find_symbol (sofile, globals, "static_rgctx_trampolines", (gpointer*)&(amodule->trampolines [MONO_AOT_TRAMP_STATIC_RGCTX]));
-       find_symbol (sofile, globals, "imt_thunks", (gpointer*)&(amodule->trampolines [MONO_AOT_TRAMP_IMT_THUNK]));
-       find_symbol (sofile, globals, "unwind_info", (gpointer)&amodule->unwind_info);
-       find_symbol (sofile, globals, "mem_end", (gpointer*)&amodule->mem_end);
-       find_symbol (sofile, globals, "thumb_end", (gpointer*)&amodule->thumb_end);
-
+       amodule->code_end = info->methods_end;
+       amodule->method_info_offsets = info->method_info_offsets;
+       amodule->ex_info_offsets = info->ex_info_offsets;
+       amodule->class_info_offsets = info->class_info_offsets;
+       amodule->class_name_table = info->class_name_table;
+       amodule->extra_method_table = info->extra_method_table;
+       amodule->extra_method_info_offsets = info->extra_method_info_offsets;
+       amodule->got_info_offsets = info->got_info_offsets;
+       amodule->unwind_info = info->unwind_info;
+       amodule->mem_end = info->mem_end;
        amodule->mem_begin = amodule->code;
-
-       find_symbol (sofile, globals, "plt", (gpointer*)&amodule->plt);
-       find_symbol (sofile, globals, "plt_end", (gpointer*)&amodule->plt_end);
-
-       amodule->mono_eh_frame = amodule->info.mono_eh_frame;
+       amodule->plt = info->plt;
+       amodule->plt_end = info->plt_end;
+       amodule->mono_eh_frame = info->mono_eh_frame;
+       amodule->trampolines [MONO_AOT_TRAMP_SPECIFIC] = info->specific_trampolines;
+       amodule->trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = info->static_rgctx_trampolines;
+       amodule->trampolines [MONO_AOT_TRAMP_IMT_THUNK] = info->imt_thunks;
+       amodule->thumb_end = info->thumb_end;
 
        if (make_unreadable) {
 #ifndef TARGET_WIN32
@@ -1250,8 +1263,20 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
         * non-lazily, since we can't handle out-of-date errors later.
         * The cached class info also depends on the exact assemblies.
         */
-       for (i = 0; i < amodule->image_table_len; ++i)
-               load_image (amodule, i, FALSE);
+#if defined(__native_client__)
+       /* TODO: Don't 'load_image' on mscorlib due to a */
+       /* recursive loading problem.  This should be    */
+       /* removed if mscorlib is loaded from disk.      */
+       if (strncmp(assembly->aname.name, "mscorlib", 8)) {
+               do_load_image = TRUE;
+       } else {
+               do_load_image = FALSE;
+       }
+#endif
+       if (do_load_image) {
+               for (i = 0; i < amodule->image_table_len; ++i)
+                       load_image (amodule, i, FALSE);
+       }
 
        if (amodule->out_of_date) {
                mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Module %s is unusable because a dependency is out-of-date.\n", assembly->image->name);
@@ -2049,7 +2074,6 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
 
        /* Compute a sorted table mapping code offsets to method indexes. */
        if (!amodule->sorted_code_offsets) {
-
                code_offsets = g_new0 (gint32, nmethods * 2);
                offsets_len = 0;
                for (i = 0; i < nmethods; ++i) {
@@ -3164,53 +3188,7 @@ mono_aot_get_plt_entry (guint8 *code)
 
 #ifdef TARGET_ARM
        if (amodule->thumb_end && code < amodule->thumb_end) {
-               int s, j1, j2, imm10, imm11, i1, i2, imm32;
-               guint8 *bl, *base;
-               guint16 t1, t2;
-
-               /*
-                * This is code generated by LLVM:
-                * bl <plt entry stub>
-                * ...
-                * <plt entry stub>:
-                * bx pc
-                * nop
-                * <real plt entry>
-                */
-
-               /* code should be right after a BL */
-               code = (guint8*)((mgreg_t)code & ~1);
-               base = (guint8*)((mgreg_t)code & ~3);
-               bl = code - 4;
-               t1 = ((guint16*)bl) [0];
-               t2 = ((guint16*)bl) [1];
-
-               g_assert ((t1 >> 11) == 0b11110);
-
-               s = (t1 >> 10) & 0x1;
-               imm10 = (t1 >> 0) & 0x3ff;
-               j1 = (t2 >> 13) & 0x1;
-               j2 = (t2 >> 11) & 0x1;
-               imm11 = t2 & 0x7ff;
-
-               i1 = (s ^ j1) ? 0 : 1;
-               i2 = (s ^ j2) ? 0 : 1;
-
-               imm32 = (imm11 << 1) | (imm10 << 12) | (i2 << 22) | (i1 << 23);
-               // FIXME:
-               g_assert (s == 0);
-
-               target = code + imm32;
-
-               /* target now points to the thumb->arm stub */
-               /* bx pc */
-               g_assert (((guint16*)target) [0] == 0x4778);
-               /* nop */
-               g_assert (((guint16*)target) [1] == 0x46c0);
-
-               target += 4;
-
-               return target;
+               return mono_arm_get_thumb_plt_entry (code);
        }
 #endif