X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Faot-runtime.c;h=d14c6b1f921dfe17464e578572b05c51a78b2fbd;hb=4323fbeaebf249f016dfdd6dc9b3b52a515f87c4;hp=cd81d225c7f1982736f5fe60fd54543f0758cdac;hpb=bfa6b049dfd69288521a94d6db88be219219bd78;p=mono.git diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index cd81d225c7f..d14c6b1f921 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -10,7 +10,9 @@ #include "config.h" #include +#ifdef HAVE_UNISTD_H #include +#endif #include #include #ifndef PLATFORM_WIN32 @@ -44,16 +46,18 @@ #include #include #include +#include #include #include "mono/utils/mono-compiler.h" #include "mini.h" +#include "version.h" #ifndef DISABLE_AOT #ifdef PLATFORM_WIN32 #define SHARED_EXT ".dll" -#elif defined(__ppc__) && defined(__MACH__) +#elif (defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__)) || defined(__MACH__) #define SHARED_EXT ".dylib" #else #define SHARED_EXT ".so" @@ -70,8 +74,14 @@ typedef struct MonoAotModule { gpointer *got; guint32 got_size; GHashTable *name_cache; + GHashTable *wrappers; + /* Maps wrapper names to their method index */ + GHashTable *wrappers_by_name; + /* Maps wrapper methods to their code */ + GHashTable *wrappers_to_code; MonoAssemblyName *image_names; char **image_guids; + MonoAssembly *assembly; MonoImage **image_table; guint32 image_table_len; gboolean out_of_date; @@ -98,6 +108,11 @@ typedef struct MonoAotModule { guint32 *class_info_offsets; guint32 *methods_loaded; guint16 *class_name_table; + guint8 *wrapper_info; + guint8 *trampolines; + guint32 num_trampolines, first_trampoline_got_offset, trampoline_index; + gpointer *globals; + MonoDl *sofile; } MonoAotModule; static GHashTable *aot_modules; @@ -105,6 +120,12 @@ static GHashTable *aot_modules; #define mono_aot_unlock() LeaveCriticalSection (&aot_mutex) static CRITICAL_SECTION aot_mutex; +/* + * Maps assembly names to the mono_aot_module__info symbols in the + * AOT modules registered by mono_aot_register_module (). + */ +static GHashTable *static_aot_modules; + /* * 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 @@ -137,22 +158,24 @@ static guint32 name_table_accesses = 0; static gsize aot_code_low_addr = (gssize)-1; static gsize aot_code_high_addr = 0; +/* Used to communicate with mono_aot_register_globals () */ +static guint32 globals_tls_id = -1; + static gpointer -mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info); +mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info, int method_index); static void init_plt (MonoAotModule *info); +static MonoJumpInfo* +load_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, int n_patches, + guint32 got_index, guint32 **got_slots, + guint8 *buf, guint8 **endbuf); + static inline gboolean is_got_patch (MonoJumpInfoType patch_type) { -#ifdef __x86_64__ return TRUE; -#elif defined(__i386__) - return TRUE; -#else - return FALSE; -#endif } /*****************************************************/ @@ -174,6 +197,7 @@ load_image (MonoAotModule *module, int index) assembly = mono_assembly_load (&module->image_names [index], NULL, &status); if (!assembly) { + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is unusable because dependency %s is not found.\n", module->aot_name, module->image_names [index].name); module->out_of_date = TRUE; return NULL; } @@ -219,81 +243,343 @@ decode_value (guint8 *ptr, guint8 **rptr) return len; } +static MonoMethod* +decode_method_ref_2 (MonoAotModule *module, guint8 *buf, guint8 **endbuf); + +static MonoClass* +decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf); + +static MonoGenericInst* +decode_generic_inst (MonoAotModule *module, guint8 *buf, guint8 **endbuf) +{ + int type_argc, i; + MonoType **type_argv; + MonoGenericInst *inst; + guint8 *p = buf; + + type_argc = decode_value (p, &p); + type_argv = g_new0 (MonoType*, type_argc); + + for (i = 0; i < type_argc; ++i) { + MonoClass *pclass = decode_klass_ref (module, p, &p); + if (!pclass) { + g_free (type_argv); + return NULL; + } + type_argv [i] = &pclass->byval_arg; + } + + inst = mono_metadata_get_generic_inst (type_argc, type_argv); + g_free (type_argv); + + *endbuf = p; + + return inst; +} + static MonoClass* -decode_klass_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf) +decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf) { MonoImage *image; - MonoClass *klass; - guint32 token, rank, image_index; + MonoClass *klass, *eklass; + guint32 token, rank; + guint8 *p = buf; - token = decode_value (buf, &buf); + token = decode_value (p, &p); if (token == 0) { - *endbuf = buf; + *endbuf = p; return NULL; } - image_index = decode_value (buf, &buf); - image = load_image (module, image_index); - if (!image) - return NULL; - if (mono_metadata_token_code (token) == 0) { + if (mono_metadata_token_table (token) == 0) { + image = load_image (module, decode_value (p, &p)); + if (!image) + return NULL; klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + token); - } else { - token = MONO_TOKEN_TYPE_DEF + decode_value (buf, &buf); - rank = decode_value (buf, &buf); - if (token == MONO_TOKEN_TYPE_DEF) { - /* [][] */ - token = MONO_TOKEN_TYPE_DEF + decode_value (buf, &buf); - klass = mono_class_get (image, token); - g_assert (klass); - klass = mono_array_class_get (klass, rank); + } else if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) { + if (token == MONO_TOKEN_TYPE_SPEC) { + MonoTypeEnum type = decode_value (p, &p); + + if (type == MONO_TYPE_GENERICINST) { + MonoClass *gclass; + MonoGenericContext ctx; + MonoType *type; + + gclass = decode_klass_ref (module, p, &p); + g_assert (gclass->generic_container); + + memset (&ctx, 0, sizeof (ctx)); + ctx.class_inst = decode_generic_inst (module, p, &p); + if (!ctx.class_inst) + return NULL; + type = mono_class_inflate_generic_type (&gclass->byval_arg, &ctx); + klass = mono_class_from_mono_type (type); + mono_metadata_free_type (type); + } else if ((type == MONO_TYPE_VAR) || (type == MONO_TYPE_MVAR)) { + MonoType *t; + gboolean is_method; + MonoGenericContainer *container; + + // FIXME: Maybe use types directly to avoid + // the overhead of creating MonoClass-es + + // FIXME: Memory management + t = g_new0 (MonoType, 1); + t->type = type; + t->data.generic_param = g_new0 (MonoGenericParam, 1); + t->data.generic_param->num = decode_value (p, &p); + t->data.generic_param->name = "T"; + + is_method = decode_value (p, &p); + if (is_method) { + MonoMethod *method_def = decode_method_ref_2 (module, p, &p); + + if (!method_def) { + g_free (t->data.generic_param); + g_free (t); + return NULL; + } - rank = decode_value (buf, &buf); - klass = mono_array_class_get (klass, rank); + container = mono_method_get_generic_container (method_def); + } else { + MonoClass *class_def = decode_klass_ref (module, p, &p); + + if (!class_def) { + g_free (t->data.generic_param); + g_free (t); + return NULL; + } + + container = class_def->generic_container; + } + + g_assert (container); + t->data.generic_param->owner = container; + + klass = mono_class_from_mono_type (t); + } else { + g_assert_not_reached (); + } } else { + image = load_image (module, decode_value (p, &p)); + if (!image) + return NULL; klass = mono_class_get (image, token); - g_assert (klass); - klass = mono_array_class_get (klass, rank); } + } else if (token == MONO_TOKEN_TYPE_DEF) { + /* Array */ + image = load_image (module, decode_value (p, &p)); + if (!image) + return NULL; + rank = decode_value (p, &p); + eklass = decode_klass_ref (module, p, &p); + klass = mono_array_class_get (eklass, rank); + } else { + g_assert_not_reached (); } g_assert (klass); mono_class_init (klass); - *endbuf = buf; + *endbuf = p; return klass; } static MonoClassField* decode_field_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf) { - MonoClass *klass = decode_klass_info (module, buf, &buf); + MonoClass *klass = decode_klass_ref (module, buf, &buf); guint32 token; + guint8 *p = buf; if (!klass) return NULL; - token = MONO_TOKEN_FIELD_DEF + decode_value (buf, &buf); + token = MONO_TOKEN_FIELD_DEF + decode_value (p, &p); - *endbuf = buf; + *endbuf = p; return mono_class_get_field (klass, token); } +/* + * decode_method_ref: + * + * Decode a method reference, and return its image and token. This avoids loading + * metadata for the method if the caller does not need it. If the method has no token, + * then it is loaded from metadata and METHOD is set to the method instance. + */ static inline MonoImage* -decode_method_ref (MonoAotModule *module, guint32 *token, guint8 *buf, guint8 **endbuf) +decode_method_ref (MonoAotModule *module, guint32 *token, MonoMethod **method, guint8 *buf, guint8 **endbuf) { guint32 image_index, value; MonoImage *image; + guint8 *p = buf; - value = decode_value (buf, &buf); - *endbuf = buf; + if (method) + *method = NULL; + + value = decode_value (p, &p); image_index = value >> 24; - *token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff); - image = load_image (module, image_index); + if (image_index == 253) { + /* Wrapper */ + guint32 wrapper_type; + + wrapper_type = decode_value (p, &p); + + /* Doesn't matter */ + image = mono_defaults.corlib; + + switch (wrapper_type) { + case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: { + MonoMethod *m = decode_method_ref_2 (module, p, &p); + + if (!m) + return NULL; + mono_class_init (m->klass); + *method = mono_marshal_get_remoting_invoke_with_check (m); + break; + } + case MONO_WRAPPER_PROXY_ISINST: { + MonoClass *klass = decode_klass_ref (module, p, &p); + if (!klass) + return NULL; + *method = mono_marshal_get_proxy_cancast (klass); + break; + } + case MONO_WRAPPER_LDFLD: + case MONO_WRAPPER_LDFLDA: + case MONO_WRAPPER_STFLD: + case MONO_WRAPPER_ISINST: { + MonoClass *klass = decode_klass_ref (module, p, &p); + if (!klass) + return NULL; + if (wrapper_type == MONO_WRAPPER_LDFLD) + *method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg); + else if (wrapper_type == MONO_WRAPPER_LDFLDA) + *method = mono_marshal_get_ldflda_wrapper (&klass->byval_arg); + else if (wrapper_type == MONO_WRAPPER_STFLD) + *method = mono_marshal_get_stfld_wrapper (&klass->byval_arg); + else if (wrapper_type == MONO_WRAPPER_ISINST) + *method = mono_marshal_get_isinst (klass); + else + g_assert_not_reached (); + break; + } + case MONO_WRAPPER_LDFLD_REMOTE: + *method = mono_marshal_get_ldfld_remote_wrapper (NULL); + break; + case MONO_WRAPPER_STFLD_REMOTE: + *method = mono_marshal_get_stfld_remote_wrapper (NULL); + break; + case MONO_WRAPPER_ALLOC: { + int atype = decode_value (p, &p); + + *method = mono_gc_get_managed_allocator_by_type (atype); + break; + } + case MONO_WRAPPER_STELEMREF: + *method = mono_marshal_get_stelemref (); + break; + case MONO_WRAPPER_STATIC_RGCTX_INVOKE: { + MonoMethod *m = decode_method_ref_2 (module, p, &p); + + if (!m) + return NULL; + *method = mono_marshal_get_static_rgctx_invoke (m); + break; + } + default: + g_assert_not_reached (); + } + } else if (image_index == 255) { + /* Methodspec */ + image_index = decode_value (p, &p); + *token = decode_value (p, &p); + + image = load_image (module, image_index); + if (!image) + return NULL; + } else if (image_index == 254) { + /* Method on generic instance */ + MonoClass *klass; + MonoGenericContext ctx; + gboolean has_class_inst, has_method_inst; + + /* + * These methods do not have a token which resolves them, so we + * resolve them immediately. + */ + klass = decode_klass_ref (module, p, &p); + if (!klass) + return NULL; + + image_index = decode_value (p, &p); + *token = decode_value (p, &p); + + image = load_image (module, image_index); + if (!image) + return NULL; + + *method = mono_get_method_full (image, *token, NULL, NULL); + if (!(*method)) + return NULL; + + memset (&ctx, 0, sizeof (ctx)); + + if (FALSE && klass->generic_class) { + ctx.class_inst = klass->generic_class->context.class_inst; + ctx.method_inst = NULL; + + *method = mono_class_inflate_generic_method_full (*method, klass, &ctx); + } + + memset (&ctx, 0, sizeof (ctx)); + + // FIXME: Memory management + has_class_inst = decode_value (p, &p); + if (has_class_inst) { + ctx.class_inst = decode_generic_inst (module, p, &p); + if (!ctx.class_inst) + return NULL; + } + has_method_inst = decode_value (p, &p); + if (has_method_inst) { + ctx.method_inst = decode_generic_inst (module, p, &p); + if (!ctx.method_inst) + return NULL; + } + + *method = mono_class_inflate_generic_method_full (*method, klass, &ctx); + } else { + *token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff); + + image = load_image (module, image_index); + if (!image) + return NULL; + } + + *endbuf = p; + + return image; +} + +/* + * decode_method_ref_2: + * + * Similar to decode_method_ref, but resolve and return the method itself. + */ +static MonoMethod* +decode_method_ref_2 (MonoAotModule *module, guint8 *buf, guint8 **endbuf) +{ + MonoMethod *method; + guint32 token; + MonoImage *image = decode_method_ref (module, &token, &method, buf, endbuf); + + if (method) + return method; if (!image) return NULL; - else - return image; + return mono_get_method (image, token, NULL); } G_GNUC_UNUSED @@ -304,6 +590,9 @@ make_writable (guint8* addr, guint32 len) guint8 *page_start; int pages, err; + if (mono_aot_only) + g_error ("Attempt to make AOT memory writable while running in aot-only mode.\n"); + page_start = (guint8 *) (((gssize) (addr)) & ~ (PAGESIZE - 1)); pages = (addr + len - page_start + PAGESIZE - 1) / PAGESIZE; err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC); @@ -414,7 +703,7 @@ load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name) res = g_spawn_command_line_sync (cmd, &out, &err, &exit_status, NULL); -#if !defined(PLATFORM_WIN32) && !defined(__ppc__) && !defined(__powerpc__) +#if !defined(PLATFORM_WIN32) && !defined(__ppc__) && !defined(__ppc64__) && !defined(__powerpc__) if (res) { if (!WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) == 0)) mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed: %s.", err); @@ -442,17 +731,40 @@ load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name) return module; } +static void +find_symbol (MonoDl *module, gpointer *globals, const char *name, gpointer *value) +{ + if (globals) { + int i = 0; + + *value = NULL; + for (i = 0; globals [i]; i+= 2) { + if (strcmp (globals [i], name) == 0) { + *value = globals [i + 1]; + break; + } + } + } else { + mono_dl_symbol (module, name, value); + } +} + static void load_aot_module (MonoAssembly *assembly, gpointer user_data) { char *aot_name; - MonoAotModule *info; + MonoAotModule *amodule; + MonoDl *sofile; gboolean usable = TRUE; char *saved_guid = NULL; char *aot_version = NULL; + char *runtime_version; char *opt_flags = NULL; + gpointer *globals; + gboolean full_aot = FALSE; gpointer *plt_jump_table_addr = NULL; guint32 *plt_jump_table_size = NULL; + guint32 *trampolines_info = NULL; gpointer *got_addr = NULL; gpointer *got = NULL; guint32 *got_size_ptr = NULL; @@ -461,35 +773,68 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) if (mono_compile_aot) return; - if (assembly->aot_module) + if (assembly->image->aot_module) /* * Already loaded. This can happen because the assembly loading code might invoke * the assembly load hooks multiple times for the same assembly. */ return; - if (use_aot_cache) - assembly->aot_module = load_aot_module_from_cache (assembly, &aot_name); - else { - char *err; - aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT); + if (assembly->image->dynamic) + return; - assembly->aot_module = mono_dl_open (aot_name, MONO_DL_LAZY, &err); + mono_aot_lock (); + if (static_aot_modules) + globals = g_hash_table_lookup (static_aot_modules, assembly->aname.name); + else + globals = NULL; + mono_aot_unlock (); - if (!assembly->aot_module) { - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, err); - g_free (err); + if (globals) { + /* Statically linked AOT module */ + sofile = NULL; + aot_name = g_strdup_printf ("%s", assembly->aname.name); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "Found statically linked AOT module '%s'.\n", aot_name); + } else { + TlsSetValue (globals_tls_id, NULL); + + if (use_aot_cache) + sofile = load_aot_module_from_cache (assembly, &aot_name); + else { + char *err; + aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT); + + sofile = mono_dl_open (aot_name, MONO_DL_LAZY, &err); + + if (!sofile) { + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, err); + g_free (err); + } } + + /* + * If the image was compiled in no-dlsym mode, it contains no global symbols, + * instead it contains an ELF ctor function which is called by dlopen () which + * in turn calls mono_aot_register_globals () to register a table which contains + * the name and address of the globals. + */ + globals = TlsGetValue (globals_tls_id); + TlsSetValue (globals_tls_id, NULL); } - if (!assembly->aot_module) { + if (!sofile && !globals) { + if (mono_aot_only) { + fprintf (stderr, "Failed to load AOT module '%s' in aot-only mode.\n", aot_name); + exit (1); + } g_free (aot_name); return; } - mono_dl_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid); - mono_dl_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version); - mono_dl_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags); + 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); 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); @@ -502,48 +847,79 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) } } + if (!runtime_version || ((strlen (runtime_version) > 0 && strcmp (runtime_version, FULL_VERSION)))) { + 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, FULL_VERSION); + usable = FALSE; + } + + { + char *full_aot_str; + + find_symbol (sofile, globals, "mono_aot_full_aot", (gpointer *)&full_aot_str); + + if (full_aot_str && !strcmp (full_aot_str, "TRUE")) + full_aot = TRUE; + } + + 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; + } + if (!usable) { + if (mono_aot_only) { + fprintf (stderr, "Failed to load AOT module '%s' while running in aot-only mode.\n", aot_name); + exit (1); + } g_free (aot_name); - mono_dl_close (assembly->aot_module); - assembly->aot_module = NULL; + if (sofile) + mono_dl_close (sofile); + assembly->image->aot_module = NULL; return; } - mono_dl_symbol (assembly->aot_module, "got_addr", (gpointer *)&got_addr); + find_symbol (sofile, globals, "got_addr", (gpointer *)&got_addr); g_assert (got_addr); got = (gpointer*)*got_addr; g_assert (got); - mono_dl_symbol (assembly->aot_module, "got_size", (gpointer *)&got_size_ptr); + find_symbol (sofile, globals, "got_size", (gpointer *)&got_size_ptr); g_assert (got_size_ptr); - info = g_new0 (MonoAotModule, 1); - info->aot_name = aot_name; - info->got = got; - info->got_size = *got_size_ptr; - info->got [0] = assembly->image; + amodule = g_new0 (MonoAotModule, 1); + amodule->aot_name = aot_name; + amodule->assembly = assembly; + amodule->got = got; + amodule->got_size = *got_size_ptr; + amodule->got [0] = assembly->image; + amodule->globals = globals; + amodule->sofile = sofile; - sscanf (opt_flags, "%d", &info->opts); + sscanf (opt_flags, "%d", &amodule->opts); /* Read image table */ { guint32 table_len, i; char *table = NULL; - mono_dl_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table); + find_symbol (sofile, globals, "mono_image_table", (gpointer *)&table); g_assert (table); table_len = *(guint32*)table; table += sizeof (guint32); - info->image_table = g_new0 (MonoImage*, table_len); - info->image_names = g_new0 (MonoAssemblyName, table_len); - info->image_guids = g_new0 (char*, table_len); - info->image_table_len = table_len; + amodule->image_table = g_new0 (MonoImage*, table_len); + amodule->image_names = g_new0 (MonoAssemblyName, table_len); + amodule->image_guids = g_new0 (char*, table_len); + amodule->image_table_len = table_len; for (i = 0; i < table_len; ++i) { - MonoAssemblyName *aname = &(info->image_names [i]); + MonoAssemblyName *aname = &(amodule->image_names [i]); aname->name = g_strdup (table); table += strlen (table) + 1; - info->image_guids [i] = g_strdup (table); + amodule->image_guids [i] = g_strdup (table); table += strlen (table) + 1; if (table [0] != 0) aname->culture = g_strdup (table); @@ -566,36 +942,44 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) } /* Read method and method_info tables */ - mono_dl_symbol (assembly->aot_module, "method_offsets", (gpointer*)&info->code_offsets); - mono_dl_symbol (assembly->aot_module, "methods", (gpointer*)&info->code); - mono_dl_symbol (assembly->aot_module, "methods_end", (gpointer*)&info->code_end); - mono_dl_symbol (assembly->aot_module, "method_info_offsets", (gpointer*)&info->method_info_offsets); - mono_dl_symbol (assembly->aot_module, "method_info", (gpointer*)&info->method_info); - mono_dl_symbol (assembly->aot_module, "ex_info_offsets", (gpointer*)&info->ex_info_offsets); - mono_dl_symbol (assembly->aot_module, "ex_info", (gpointer*)&info->ex_info); - mono_dl_symbol (assembly->aot_module, "method_order", (gpointer*)&info->method_order); - mono_dl_symbol (assembly->aot_module, "method_order_end", (gpointer*)&info->method_order_end); - mono_dl_symbol (assembly->aot_module, "class_info", (gpointer*)&info->class_info); - mono_dl_symbol (assembly->aot_module, "class_info_offsets", (gpointer*)&info->class_info_offsets); - mono_dl_symbol (assembly->aot_module, "class_name_table", (gpointer *)&info->class_name_table); - mono_dl_symbol (assembly->aot_module, "got_info", (gpointer*)&info->got_info); - mono_dl_symbol (assembly->aot_module, "got_info_offsets", (gpointer*)&info->got_info_offsets); - mono_dl_symbol (assembly->aot_module, "mem_end", (gpointer*)&info->mem_end); - - info->mem_begin = info->code; - - mono_dl_symbol (assembly->aot_module, "plt", (gpointer*)&info->plt); - mono_dl_symbol (assembly->aot_module, "plt_end", (gpointer*)&info->plt_end); - mono_dl_symbol (assembly->aot_module, "plt_info", (gpointer*)&info->plt_info); - - mono_dl_symbol (assembly->aot_module, "plt_jump_table_addr", (gpointer *)&plt_jump_table_addr); + find_symbol (sofile, globals, "method_offsets", (gpointer*)&amodule->code_offsets); + find_symbol (sofile, globals, "methods", (gpointer*)&amodule->code); + 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, "method_info", (gpointer*)&amodule->method_info); + find_symbol (sofile, globals, "ex_info_offsets", (gpointer*)&amodule->ex_info_offsets); + find_symbol (sofile, globals, "ex_info", (gpointer*)&amodule->ex_info); + find_symbol (sofile, globals, "method_order", (gpointer*)&amodule->method_order); + find_symbol (sofile, globals, "method_order_end", (gpointer*)&amodule->method_order_end); + find_symbol (sofile, globals, "class_info", (gpointer*)&amodule->class_info); + 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, "got_info", (gpointer*)&amodule->got_info); + find_symbol (sofile, globals, "got_info_offsets", (gpointer*)&amodule->got_info_offsets); + find_symbol (sofile, globals, "wrapper_info", (gpointer*)&amodule->wrapper_info); + find_symbol (sofile, globals, "trampolines", (gpointer*)&amodule->trampolines); + find_symbol (sofile, globals, "mem_end", (gpointer*)&amodule->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); + find_symbol (sofile, globals, "plt_info", (gpointer*)&amodule->plt_info); + + find_symbol (sofile, globals, "plt_jump_table_addr", (gpointer *)&plt_jump_table_addr); g_assert (plt_jump_table_addr); - info->plt_jump_table = (guint8*)*plt_jump_table_addr; - g_assert (info->plt_jump_table); + amodule->plt_jump_table = (guint8*)*plt_jump_table_addr; + g_assert (amodule->plt_jump_table); - mono_dl_symbol (assembly->aot_module, "plt_jump_table_size", (gpointer *)&plt_jump_table_size); + find_symbol (sofile, globals, "plt_jump_table_size", (gpointer *)&plt_jump_table_size); g_assert (plt_jump_table_size); - info->plt_jump_table_size = *plt_jump_table_size; + amodule->plt_jump_table_size = *plt_jump_table_size; + + find_symbol (sofile, globals, "trampolines_info", (gpointer *)&trampolines_info); + if (trampolines_info) { + amodule->num_trampolines = trampolines_info [0]; + amodule->first_trampoline_got_offset = trampolines_info [1]; + } if (make_unreadable) { #ifndef PLATFORM_WIN32 @@ -603,8 +987,8 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) guint8 *page_start; int pages, err, len; - addr = info->mem_begin; - len = info->mem_end - info->mem_begin; + addr = amodule->mem_begin; + len = amodule->mem_end - amodule->mem_begin; /* Round down in both directions to avoid modifying data which is not ours */ page_start = (guint8 *) (((gssize) (addr)) & ~ (PAGESIZE - 1)) + PAGESIZE; @@ -616,13 +1000,15 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) mono_aot_lock (); - aot_code_low_addr = MIN (aot_code_low_addr, (gsize)info->code); - aot_code_high_addr = MAX (aot_code_high_addr, (gsize)info->code_end); + aot_code_low_addr = MIN (aot_code_low_addr, (gsize)amodule->code); + aot_code_high_addr = MAX (aot_code_high_addr, (gsize)amodule->code_end); - g_hash_table_insert (aot_modules, assembly, info); + g_hash_table_insert (aot_modules, assembly, amodule); mono_aot_unlock (); - mono_jit_info_add_aot_module (assembly->image, info->code, info->code_end); + mono_jit_info_add_aot_module (assembly->image, amodule->code, amodule->code_end); + + assembly->image->aot_module = amodule; /* * Since we store methoddef and classdef tokens when referring to methods/classes in @@ -630,20 +1016,71 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) * MS calls this 'hard binding'. This means we have to load all referenced assemblies * non-lazily, since we can't handle out-of-date errors later. */ - for (i = 0; i < info->image_table_len; ++i) - load_image (info, i); + for (i = 0; i < amodule->image_table_len; ++i) + load_image (amodule, i); - if (info->out_of_date) + 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); + if (mono_aot_only) { + fprintf (stderr, "Failed to load AOT module '%s' while running in aot-only mode because a dependency cannot be found or it is out of date.\n", aot_name); + exit (1); + } + } else mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name); } +/* + * mono_aot_register_globals: + * + * This is called by the ctor function in AOT images compiled with the + * 'no-dlsym' option. + */ +void +mono_aot_register_globals (gpointer *globals) +{ + TlsSetValue (globals_tls_id, globals); +} + +/* + * mono_aot_register_module: + * + * This should be called by embedding code to register AOT modules statically linked + * into the executable. AOT_INFO should be the value of the + * 'mono_aot_module__info' global symbol from the AOT module. + */ +void +mono_aot_register_module (gpointer *aot_info) +{ + gpointer *globals; + char *aname; + + globals = aot_info; + g_assert (globals); + + /* Determine the assembly name */ + find_symbol (NULL, globals, "mono_aot_assembly_name", (gpointer*)&aname); + g_assert (aname); + + /* This could be called before startup */ + if (aot_modules) + mono_aot_lock (); + + if (!static_aot_modules) + static_aot_modules = g_hash_table_new (g_str_hash, g_str_equal); + + g_hash_table_insert (static_aot_modules, aname, globals); + + if (aot_modules) + mono_aot_unlock (); +} + void mono_aot_init (void) { InitializeCriticalSection (&aot_mutex); aot_modules = g_hash_table_new (NULL, NULL); + globals_tls_id = TlsAlloc (); mono_install_assembly_load_hook (load_aot_module, NULL); @@ -659,6 +1096,9 @@ decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, guin guint32 flags; info->vtable_size = decode_value (buf, &buf); + if (info->vtable_size == -1) + /* Generic type */ + return FALSE; flags = decode_value (buf, &buf); info->ghcimpl = (flags >> 0) & 0x1; info->has_finalize = (flags >> 1) & 0x1; @@ -670,12 +1110,12 @@ decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, guin info->no_special_static_fields = (flags >> 7) & 0x1; if (info->has_cctor) { - MonoImage *cctor_image = decode_method_ref (module, &info->cctor_token, buf, &buf); + MonoImage *cctor_image = decode_method_ref (module, &info->cctor_token, NULL, buf, &buf); if (!cctor_image) return FALSE; } if (info->has_finalize) { - info->finalize_image = decode_method_ref (module, &info->finalize_token, buf, &buf); + info->finalize_image = decode_method_ref (module, &info->finalize_token, NULL, buf, &buf); if (!info->finalize_image) return FALSE; } @@ -690,102 +1130,53 @@ decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, guin return TRUE; } -gboolean -mono_aot_init_vtable (MonoVTable *vtable) +gpointer +mono_aot_get_method_from_vt_slot (MonoDomain *domain, MonoVTable *vtable, int slot) { int i; - MonoAotModule *aot_module; MonoClass *klass = vtable->klass; + MonoAotModule *aot_module = klass->image->aot_module; guint8 *info, *p; MonoCachedClassInfo class_info; gboolean err; + guint32 token; + MonoImage *image; - if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !klass->image->assembly->aot_module) - return FALSE; - - mono_aot_lock (); - - aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly); - if (!aot_module) { - mono_aot_unlock (); - return FALSE; - } + if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !aot_module) + return NULL; info = &aot_module->class_info [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]]; p = info; err = decode_cached_class_info (aot_module, &class_info, p, &p); - if (!err) { - mono_aot_unlock (); - return FALSE; - } - - //printf ("VT0: %s.%s %d\n", klass->name_space, klass->name, vtable_size); - for (i = 0; i < class_info.vtable_size; ++i) { - guint32 image_index, token, value; - MonoImage *image; -#ifndef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN - MonoMethod *m; -#endif - - vtable->vtable [i] = 0; - - value = decode_value (p, &p); - if (!value) - continue; - - image_index = value >> 24; - token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff); - - image = load_image (aot_module, image_index); - if (!image) { - mono_aot_unlock (); - return FALSE; - } - -#ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN - vtable->vtable [i] = mono_create_jit_trampoline_from_token (image, token); -#else - m = mono_get_method (image, token, NULL); - g_assert (m); + if (!err) + return NULL; - //printf ("M: %d %p %s\n", i, &(vtable->vtable [i]), mono_method_full_name (m, TRUE)); - vtable->vtable [i] = mono_create_jit_trampoline (m); -#endif - } + for (i = 0; i < slot; ++i) + decode_method_ref (aot_module, &token, NULL, p, &p); - mono_aot_unlock (); + image = decode_method_ref (aot_module, &token, NULL, p, &p); + if (!image) + return NULL; - return TRUE; + return mono_aot_get_method_from_token (domain, image, token); } gboolean mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res) { - MonoAotModule *aot_module; + MonoAotModule *aot_module = klass->image->aot_module; guint8 *p; gboolean err; - if (klass->rank || !klass->image->assembly->aot_module) + if (klass->rank || !aot_module) return FALSE; - mono_aot_lock (); - - aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly); - if (!aot_module) { - mono_aot_unlock (); - return FALSE; - } - p = (guint8*)&aot_module->class_info [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]]; err = decode_cached_class_info (aot_module, res, p, &p); - if (!err) { - mono_aot_unlock (); + if (!err) return FALSE; - } - - mono_aot_unlock (); return TRUE; } @@ -803,7 +1194,7 @@ mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res) gboolean mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const char *name, MonoClass **klass) { - MonoAotModule *aot_module; + MonoAotModule *aot_module = image->aot_module; guint16 *table, *entry; guint16 table_size; guint32 hash; @@ -814,17 +1205,11 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch guint32 cols [MONO_TYPEDEF_SIZE]; GHashTable *nspace_table; - if (!aot_modules) + if (!aot_module || !aot_module->class_name_table) return FALSE; mono_aot_lock (); - aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, image->assembly); - if (!aot_module || !aot_module->class_name_table) { - mono_aot_unlock (); - return FALSE; - } - *klass = NULL; /* First look in the cache */ @@ -911,8 +1296,10 @@ decode_exception_debug_info (MonoAotModule *aot_module, MonoDomain *domain, int i, buf_len; MonoJitInfo *jinfo; guint code_len, used_int_regs; + gboolean has_generic_jit_info; guint8 *p; MonoMethodHeader *header; + int generic_info_size; header = mono_method_get_header (method); @@ -921,11 +1308,16 @@ decode_exception_debug_info (MonoAotModule *aot_module, MonoDomain *domain, p = ex_info; code_len = decode_value (p, &p); used_int_regs = decode_value (p, &p); + has_generic_jit_info = decode_value (p, &p); + if (has_generic_jit_info) + generic_info_size = sizeof (MonoGenericJitInfo); + else + generic_info_size = 0; /* Exception table */ - if (header->num_clauses) { + if (header && header->num_clauses) { jinfo = - mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo) + (sizeof (MonoJitExceptionInfo) * header->num_clauses)); + mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo) + (sizeof (MonoJitExceptionInfo) * header->num_clauses) + generic_info_size); jinfo->num_clauses = header->num_clauses; for (i = 0; i < header->num_clauses; ++i) { @@ -946,7 +1338,7 @@ decode_exception_debug_info (MonoAotModule *aot_module, MonoDomain *domain, } } else - jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo)); + jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo) + generic_info_size); jinfo->code_size = code_len; jinfo->used_regs = used_int_regs; @@ -954,6 +1346,24 @@ decode_exception_debug_info (MonoAotModule *aot_module, MonoDomain *domain, jinfo->code_start = code; jinfo->domain_neutral = 0; + if (has_generic_jit_info) { + MonoGenericJitInfo *gi; + + jinfo->has_generic_jit_info = 1; + + gi = mono_jit_info_get_generic_jit_info (jinfo); + g_assert (gi); + + gi->has_this = decode_value (p, &p); + gi->this_reg = decode_value (p, &p); + gi->this_offset = decode_value (p, &p); + + /* This currently contains no data */ + gi->generic_sharing_context = g_new0 (MonoGenericSharingContext, 1); + + jinfo->method = decode_method_ref_2 (aot_module, p, &p); + } + /* Load debug info */ buf_len = decode_value (p, &p); mono_debug_add_aot_method (domain, method, code, p, buf_len); @@ -964,22 +1374,18 @@ decode_exception_debug_info (MonoAotModule *aot_module, MonoDomain *domain, MonoJitInfo * mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) { - MonoAssembly *ass = image->assembly; - MonoDl *module = ass->aot_module; int pos, left, right, offset, offset1, offset2, last_offset, new_offset, page_index, method_index, table_len; guint32 token; - MonoAotModule *aot_module; + MonoAotModule *aot_module = image->aot_module; MonoMethod *method; MonoJitInfo *jinfo; guint8 *code, *ex_info; guint32 *table, *ptr; gboolean found; - if (!module) + if (!aot_module) return NULL; - aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass); - if (domain != mono_get_root_domain ()) /* FIXME: */ return NULL; @@ -1062,8 +1468,19 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) method_index = table [pos]; - token = mono_metadata_make_token (MONO_TABLE_METHOD, method_index + 1); - method = mono_get_method (image, token, NULL); + /* Might be a wrapper */ + if (aot_module->wrappers) { + mono_aot_lock (); + method = g_hash_table_lookup (aot_module->wrappers, GUINT_TO_POINTER (method_index)); + mono_aot_unlock (); + } else { + method = NULL; + } + + if (!method) { + token = mono_metadata_make_token (MONO_TABLE_METHOD, method_index + 1); + method = mono_get_method (image, token, NULL); + } /* FIXME: */ g_assert (method); @@ -1084,8 +1501,30 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) return jinfo; } +/* Keep it in sync with the version in aot-compiler.c */ +static inline gboolean +is_shared_got_patch (MonoJumpInfo *patch_info) +{ + switch (patch_info->type) { + case MONO_PATCH_INFO_VTABLE: + case MONO_PATCH_INFO_CLASS: + case MONO_PATCH_INFO_IID: + case MONO_PATCH_INFO_ADJUSTED_IID: + case MONO_PATCH_INFO_FIELD: + case MONO_PATCH_INFO_SFLDA: + case MONO_PATCH_INFO_DECLSEC: + case MONO_PATCH_INFO_LDTOKEN: + case MONO_PATCH_INFO_TYPE_FROM_HANDLE: + case MONO_PATCH_INFO_RVA: + case MONO_PATCH_INFO_METHODCONST: + return TRUE; + default: + return FALSE; + } +} + static gboolean -decode_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guint8 *buf, guint8 **endbuf, guint32 *got_offset) +decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guint8 *buf, guint8 **endbuf) { guint8 *p = buf; gpointer *table; @@ -1094,25 +1533,26 @@ decode_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, switch (ji->type) { case MONO_PATCH_INFO_METHOD: - case MONO_PATCH_INFO_METHODCONST: - case MONO_PATCH_INFO_METHOD_JUMP: { - guint32 image_index, token, value; - - value = decode_value (p, &p); - image_index = value >> 24; - token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff); + case MONO_PATCH_INFO_METHOD_JUMP: + case MONO_PATCH_INFO_ICALL_ADDR: + case MONO_PATCH_INFO_METHOD_RGCTX: { + guint32 token; + MonoMethod *method; - image = load_image (aot_module, image_index); + image = decode_method_ref (aot_module, &token, &method, p, &p); if (!image) goto cleanup; #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN - if (ji->type == MONO_PATCH_INFO_METHOD) { + if (!method && !mono_aot_only && (ji->type == MONO_PATCH_INFO_METHOD) && (mono_metadata_token_table (token) == MONO_TABLE_METHOD)) { ji->data.target = mono_create_jit_trampoline_from_token (image, token); ji->type = MONO_PATCH_INFO_ABS; } else { - ji->data.method = mono_get_method (image, token, NULL); + if (method) + ji->data.method = method; + else + ji->data.method = mono_get_method (image, token, NULL); g_assert (ji->data.method); mono_class_init (ji->data.method->klass); } @@ -1124,98 +1564,32 @@ decode_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, break; } - case MONO_PATCH_INFO_WRAPPER: { - guint32 wrapper_type; - - wrapper_type = decode_value (p, &p); - - switch (wrapper_type) { - case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: { - guint32 image_index, token, value; - - value = decode_value (p, &p); - image_index = value >> 24; - token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff); - - image = load_image (aot_module, image_index); - if (!image) - goto cleanup; - ji->data.method = mono_get_method (image, token, NULL); - g_assert (ji->data.method); - mono_class_init (ji->data.method->klass); - - ji->type = MONO_PATCH_INFO_METHOD; - ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method); - break; - } - case MONO_WRAPPER_PROXY_ISINST: { - MonoClass *klass = decode_klass_info (aot_module, p, &p); - if (!klass) - goto cleanup; - ji->type = MONO_PATCH_INFO_METHOD; - ji->data.method = mono_marshal_get_proxy_cancast (klass); - break; - } - case MONO_WRAPPER_LDFLD: - case MONO_WRAPPER_LDFLDA: - case MONO_WRAPPER_STFLD: - case MONO_WRAPPER_LDFLD_REMOTE: - case MONO_WRAPPER_STFLD_REMOTE: - case MONO_WRAPPER_ISINST: { - MonoClass *klass = decode_klass_info (aot_module, p, &p); - if (!klass) - goto cleanup; - ji->type = MONO_PATCH_INFO_METHOD; - if (wrapper_type == MONO_WRAPPER_LDFLD) - ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg); - else if (wrapper_type == MONO_WRAPPER_LDFLDA) - ji->data.method = mono_marshal_get_ldflda_wrapper (&klass->byval_arg); - else if (wrapper_type == MONO_WRAPPER_STFLD) - ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg); - else if (wrapper_type == MONO_WRAPPER_LDFLD_REMOTE) - ji->data.method = mono_marshal_get_ldfld_remote_wrapper (klass); - else if (wrapper_type == MONO_WRAPPER_STFLD_REMOTE) - ji->data.method = mono_marshal_get_stfld_remote_wrapper (klass); - else if (wrapper_type == MONO_WRAPPER_ISINST) - ji->data.method = mono_marshal_get_isinst (klass); - else - g_assert_not_reached (); - break; - } - case MONO_WRAPPER_STELEMREF: - ji->type = MONO_PATCH_INFO_METHOD; - ji->data.method = mono_marshal_get_stelemref (); - break; - default: - g_assert_not_reached (); - } - break; - } - case MONO_PATCH_INFO_INTERNAL_METHOD: { + case MONO_PATCH_INFO_INTERNAL_METHOD: + case MONO_PATCH_INFO_JIT_ICALL_ADDR: { guint32 len = decode_value (p, &p); ji->data.name = (char*)p; p += len + 1; break; } + case MONO_PATCH_INFO_METHODCONST: + /* Shared */ + ji->data.method = decode_method_ref_2 (aot_module, p, &p); + if (!ji->data.method) + goto cleanup; + break; case MONO_PATCH_INFO_VTABLE: case MONO_PATCH_INFO_CLASS: case MONO_PATCH_INFO_IID: case MONO_PATCH_INFO_ADJUSTED_IID: - *got_offset = decode_value (p, &p); - - if (aot_module->got [*got_offset]) { - /* Already loaded */ - //printf ("HIT!\n"); - } else { - guint8 *tmp = aot_module->got_info + aot_module->got_info_offsets [*got_offset]; - ji->data.klass = decode_klass_info (aot_module, tmp, &tmp); - if (!ji->data.klass) - goto cleanup; - } + /* Shared */ + ji->data.klass = decode_klass_ref (aot_module, p, &p); + if (!ji->data.klass) + goto cleanup; break; case MONO_PATCH_INFO_CLASS_INIT: - ji->data.klass = decode_klass_info (aot_module, p, &p); + case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: + ji->data.klass = decode_klass_ref (aot_module, p, &p); if (!ji->data.klass) goto cleanup; break; @@ -1226,17 +1600,10 @@ decode_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, break; case MONO_PATCH_INFO_FIELD: case MONO_PATCH_INFO_SFLDA: - *got_offset = decode_value (p, &p); - - if (aot_module->got [*got_offset]) { - /* Already loaded */ - //printf ("HIT2!\n"); - } else { - guint8 *tmp = aot_module->got_info + aot_module->got_info_offsets [*got_offset]; - ji->data.field = decode_field_info (aot_module, tmp, &tmp); - if (!ji->data.field) - goto cleanup; - } + /* Shared */ + ji->data.field = decode_field_info (aot_module, p, &p); + if (!ji->data.field) + goto cleanup; break; case MONO_PATCH_INFO_SWITCH: ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable)); @@ -1274,20 +1641,14 @@ decode_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, case MONO_PATCH_INFO_DECLSEC: case MONO_PATCH_INFO_LDTOKEN: case MONO_PATCH_INFO_TYPE_FROM_HANDLE: - *got_offset = decode_value (p, &p); - - if (aot_module->got [*got_offset]) { - /* Already loaded */ - } else { - guint8 *tmp = aot_module->got_info + aot_module->got_info_offsets [*got_offset]; - image = load_image (aot_module, decode_value (tmp, &tmp)); - if (!image) - goto cleanup; - ji->data.token = mono_jump_info_token_new (mp, image, decode_value (tmp, &tmp)); - } + /* Shared */ + image = load_image (aot_module, decode_value (p, &p)); + if (!image) + goto cleanup; + ji->data.token = mono_jump_info_token_new (mp, image, decode_value (p, &p)); break; case MONO_PATCH_INFO_EXC_NAME: - ji->data.klass = decode_klass_info (aot_module, p, &p); + ji->data.klass = decode_klass_ref (aot_module, p, &p); if (!ji->data.klass) goto cleanup; ji->data.name = ji->data.klass->name; @@ -1295,6 +1656,26 @@ decode_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, case MONO_PATCH_INFO_METHOD_REL: ji->data.offset = decode_value (p, &p); break; + case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG: + case MONO_PATCH_INFO_GENERIC_CLASS_INIT: + break; + case MONO_PATCH_INFO_RGCTX_FETCH: { + gboolean res; + MonoJumpInfoRgctxEntry *entry; + + entry = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry)); + entry->method = decode_method_ref_2 (aot_module, p, &p); + entry->in_mrgctx = decode_value (p, &p); + entry->info_type = decode_value (p, &p); + entry->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo)); + entry->data->type = decode_value (p, &p); + + res = decode_patch (aot_module, mp, entry->data, p, &p); + if (!res) + goto cleanup; + ji->data.rgctx_entry = entry; + break; + } default: g_warning ("unhandled type %d", ji->type); g_assert_not_reached (); @@ -1308,6 +1689,36 @@ decode_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, return FALSE; } +static gboolean +decode_got_entry (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guint8 *buf, guint8 **endbuf, guint32 *got_offset) +{ + guint8 *p = buf; + guint8 *shared_p; + gboolean res; + + if (is_shared_got_patch (ji)) { + *got_offset = decode_value (p, &p); + + if (aot_module->got [*got_offset]) { + /* Already loaded */ + //printf ("HIT!\n"); + } else { + shared_p = aot_module->got_info + aot_module->got_info_offsets [*got_offset]; + + res = decode_patch (aot_module, mp, ji, shared_p, &shared_p); + if (!res) + return FALSE; + } + } else { + res = decode_patch (aot_module, mp, ji, p, &p); + if (!res) + return FALSE; + } + + *endbuf = p; + return TRUE; +} + static MonoJumpInfo* load_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, int n_patches, guint32 got_index, guint32 **got_slots, @@ -1343,7 +1754,7 @@ load_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, int n_patches, for (pindex = 0; pindex < n_patches; ++pindex) { MonoJumpInfo *ji = &patches [pindex]; - if (!decode_patch_info (aot_module, mp, ji, p, &p, (*got_slots) + pindex)) + if (!decode_got_entry (aot_module, mp, ji, p, &p, (*got_slots) + pindex)) goto cleanup; if ((*got_slots) [pindex] == 0xffffffff) @@ -1359,21 +1770,37 @@ load_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, int n_patches, return NULL; } - -static gpointer -mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) + +static void +register_jump_target_got_slot (MonoDomain *domain, MonoMethod *method, gpointer *got_slot) +{ + /* + * Jump addresses cannot be patched by the trampoline code since it + * does not have access to the caller's address. Instead, we collect + * the addresses of the GOT slots pointing to a method, and patch + * them after the method has been compiled. + */ + MonoJitDomainInfo *info = jit_domain_info (domain); + GSList *list; + + mono_domain_lock (domain); + if (!info->jump_target_got_slot_hash) + info->jump_target_got_slot_hash = g_hash_table_new (NULL, NULL); + list = g_hash_table_lookup (info->jump_target_got_slot_hash, method); + list = g_slist_prepend (list, got_slot); + g_hash_table_insert (info->jump_target_got_slot_hash, method, list); + mono_domain_unlock (domain); +} + +gpointer +mono_aot_get_method (MonoDomain *domain, MonoMethod *method) { MonoClass *klass = method->klass; - MonoAssembly *ass = klass->image->assembly; - MonoDl *module = ass->aot_module; guint32 method_index = mono_metadata_token_index (method->token) - 1; guint8 *code, *info; - MonoAotModule *aot_module; - - if (!module) - return NULL; + MonoAotModule *aot_module = klass->image->aot_module; - if (!method->token) + if (!aot_module) return NULL; if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE) @@ -1384,8 +1811,6 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) return NULL; - - aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass); g_assert (klass->inited); @@ -1396,6 +1821,73 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) if (aot_module->out_of_date) return NULL; + if (method->is_inflated) { + if (!mono_method_is_generic_sharable_impl (method, FALSE)) + return NULL; + method = mono_method_get_declaring_generic_method (method); + } + + if (!method->token) { + char *full_name; + char *p; + + if (!method->wrapper_type || !aot_module->wrapper_info) + return NULL; + + mono_aot_lock (); + + /* Avoid doing a hash table lookup using strings if possible */ + if (!aot_module->wrappers_to_code) + aot_module->wrappers_to_code = g_hash_table_new (mono_aligned_addr_hash, NULL); + code = g_hash_table_lookup (aot_module->wrappers_to_code, method); + if (code) { + mono_aot_unlock (); + return code; + } + + /* Try to find the wrapper among the wrapper info */ + /* FIXME: This is a hack to work around the fact that runtime invoke wrappers get assigned to some random class */ + if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) { + char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE); + full_name = g_strdup_printf ("(wrapper runtime-invoke):%s (%s)", method->name, tmpsig); + g_free (tmpsig); + } else { + full_name = mono_method_full_name (method, TRUE); + } + + /* Create a hash table to avoid repeated linear searches */ + if (!aot_module->wrappers_by_name) { + aot_module->wrappers_by_name = g_hash_table_new (g_str_hash, g_str_equal); + p = (char*)aot_module->wrapper_info; + while (*p) { + char *end; + + end = p + strlen (p) + 1; + end = ALIGN_PTR_TO (end, 4); + method_index = *(guint32*)end; + end += 4; + /* The + 1 is used to distinguish a 0 index from a not-found one */ + g_hash_table_insert (aot_module->wrappers_by_name, p, GUINT_TO_POINTER (method_index + 1)); + p = end; + } + } + method_index = GPOINTER_TO_UINT (g_hash_table_lookup (aot_module->wrappers_by_name, full_name)); + mono_aot_unlock (); + + g_free (full_name); + if (!method_index) + return NULL; + + method_index --; + + /* Needed by find_jit_info */ + mono_aot_lock (); + if (!aot_module->wrappers) + aot_module->wrappers = g_hash_table_new (NULL, NULL); + g_hash_table_insert (aot_module->wrappers, GUINT_TO_POINTER (method_index), method); + mono_aot_unlock (); + } + if (aot_module->code_offsets [method_index] == 0xffffffff) { if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) { char *full_name = mono_method_full_name (method, TRUE); @@ -1408,8 +1900,10 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) code = &aot_module->code [aot_module->code_offsets [method_index]]; info = &aot_module->method_info [aot_module->method_info_offsets [method_index]]; + mono_aot_lock (); if (!aot_module->methods_loaded) aot_module->methods_loaded = g_new0 (guint32, klass->image->tables [MONO_TABLE_METHOD].rows + 1); + mono_aot_unlock (); if ((aot_module->methods_loaded [method_index / 32] >> (method_index % 32)) & 0x1) return code; @@ -1422,23 +1916,22 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name); } - return mono_aot_load_method (domain, aot_module, method, code, info); + return mono_aot_load_method (domain, aot_module, method, code, info, method_index); } static gpointer -mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info) +mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info, int method_index) { MonoClass *klass = method->klass; MonoJumpInfo *patch_info = NULL; MonoMemPool *mp; int i, pindex, got_index = 0, n_patches, used_strings; gboolean non_got_patches, keep_patches = TRUE; - guint32 method_index = mono_metadata_token_index (method->token) - 1; guint8 *p, *ex_info; MonoJitInfo *jinfo = NULL; p = info; - decode_klass_info (aot_module, p, &p); + decode_klass_ref (aot_module, p, &p); if (!use_loaded_code) { guint8 *code2; @@ -1448,7 +1941,9 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code); } + mono_domain_lock (domain); code2 = mono_code_manager_reserve (domain->code_mp, jinfo->code_size); + mono_domain_unlock (domain); memcpy (code2, code, jinfo->code_size); mono_arch_flush_icache (code2, jinfo->code_size); code = code2; @@ -1486,15 +1981,16 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod if (patches == NULL) goto cleanup; - /* Do this outside the lock to avoid deadlocks */ - mono_aot_unlock (); non_got_patches = FALSE; for (pindex = 0; pindex < n_patches; ++pindex) { MonoJumpInfo *ji = &patches [pindex]; if (is_got_patch (ji->type)) { - if (!aot_module->got [got_slots [pindex]]) + if (!aot_module->got [got_slots [pindex]]) { aot_module->got [got_slots [pindex]] = mono_resolve_patch_target (method, domain, code, ji, TRUE); + if (ji->type == MONO_PATCH_INFO_METHOD_JUMP) + register_jump_target_got_slot (domain, ji->data.method, &(aot_module->got [got_slots [pindex]])); + } ji->type = MONO_PATCH_INFO_NONE; } else @@ -1510,7 +2006,6 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod make_writable (code, jinfo->code_size); mono_arch_patch_code (method, domain, code, patch_info, TRUE); } - mono_aot_lock (); g_free (got_slots); @@ -1518,13 +2013,15 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod mono_mempool_destroy (mp); } + mono_aot_lock (); + mono_jit_stats.methods_aot++; if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) { char *full_name = mono_method_full_name (method, TRUE); if (!jinfo) { - ex_info = &aot_module->ex_info [aot_module->ex_info_offsets [mono_metadata_token_index (method->token) - 1]]; + ex_info = &aot_module->ex_info [aot_module->ex_info_offsets [method_index]]; jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code); } @@ -1536,6 +2033,11 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod init_plt (aot_module); + if (method->wrapper_type) + g_hash_table_insert (aot_module->wrappers_to_code, method, code); + + mono_aot_unlock (); + return code; cleanup: @@ -1550,41 +2052,28 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod return NULL; } +/** + * Same as mono_aot_get_method, but we try to avoid loading any metadata from the + * method. + */ gpointer -mono_aot_get_method (MonoDomain *domain, MonoMethod *method) -{ - gpointer code; - - mono_aot_lock (); - code = mono_aot_get_method_inner (domain, method); - mono_aot_unlock (); - - return code; -} - -static gpointer -mono_aot_get_method_from_token_inner (MonoDomain *domain, MonoImage *image, guint32 token, MonoClass **klass) +mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token) { - MonoAssembly *ass = image->assembly; MonoMemPool *mp; int i, method_index, pindex, got_index, n_patches, used_strings; gboolean keep_patches = TRUE; guint8 *p; - MonoDl *module = ass->aot_module; guint8 *code = NULL; guint8 *info; - MonoAotModule *aot_module; - - *klass = NULL; + MonoAotModule *aot_module = image->aot_module; + MonoClass *klass; - if (!module) + if (!aot_module) return NULL; if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE) return NULL; - aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass); - if (domain != mono_get_root_domain ()) return NULL; @@ -1599,8 +2088,10 @@ mono_aot_get_method_from_token_inner (MonoDomain *domain, MonoImage *image, guin code = &aot_module->code [aot_module->code_offsets [method_index]]; info = &aot_module->method_info [aot_module->method_info_offsets [method_index]]; + mono_aot_lock (); if (!aot_module->methods_loaded) aot_module->methods_loaded = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 1); + mono_aot_unlock (); if ((aot_module->methods_loaded [method_index / 32] >> (method_index % 32)) & 0x1) return code; @@ -1616,7 +2107,7 @@ mono_aot_get_method_from_token_inner (MonoDomain *domain, MonoImage *image, guin } p = info; - *klass = decode_klass_info (aot_module, p, &p); + klass = decode_klass_ref (aot_module, p, &p); if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) { MonoMethod *method = mono_get_method (image, token, NULL); @@ -1657,21 +2148,19 @@ mono_aot_get_method_from_token_inner (MonoDomain *domain, MonoImage *image, guin if (patches == NULL) goto cleanup; - /* Do this outside the lock to avoid deadlocks */ - mono_aot_unlock (); - for (pindex = 0; pindex < n_patches; ++pindex) { MonoJumpInfo *ji = &patches [pindex]; if (is_got_patch (ji->type)) { - if (!aot_module->got [got_slots [pindex]]) + if (!aot_module->got [got_slots [pindex]]) { aot_module->got [got_slots [pindex]] = mono_resolve_patch_target (NULL, domain, code, ji, TRUE); + if (ji->type == MONO_PATCH_INFO_METHOD_JUMP) + register_jump_target_got_slot (domain, ji->data.method, &(aot_module->got [got_slots [pindex]])); + } ji->type = MONO_PATCH_INFO_NONE; } } - mono_aot_lock (); - g_free (got_slots); if (!keep_patches) @@ -1680,10 +2169,17 @@ mono_aot_get_method_from_token_inner (MonoDomain *domain, MonoImage *image, guin mono_jit_stats.methods_aot++; + mono_aot_lock (); + aot_module->methods_loaded [method_index / 32] |= 1 << (method_index % 32); init_plt (aot_module); + mono_aot_unlock (); + + if (klass) + mono_runtime_class_init (mono_class_vtable (domain, klass)); + return code; cleanup: @@ -1695,29 +2191,6 @@ mono_aot_get_method_from_token_inner (MonoDomain *domain, MonoImage *image, guin return NULL; } -/** - * Same as mono_aot_get_method, but we try to avoid loading any metadata from the - * method. - */ -gpointer -mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token) -{ - gpointer res; - MonoClass *klass; - - mono_aot_lock (); - res = mono_aot_get_method_from_token_inner (domain, image, token, &klass); - mono_aot_unlock (); - - if (!res) - return NULL; - - if (klass) - mono_runtime_class_init (mono_class_vtable (domain, klass)); - - return res; -} - typedef struct { guint8 *addr; gboolean res; @@ -1888,7 +2361,7 @@ mono_aot_handle_pagefault (void *ptr) } /* - * aot_dyn_resolve: + * mono_aot_plt_resolve: * * This function is called by the entries in the PLT to resolve the actual method that * needs to be called. It returns a trampoline to the method and patches the PLT entry. @@ -1896,11 +2369,12 @@ mono_aot_handle_pagefault (void *ptr) gpointer mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code) { -#ifdef MONO_ARCH_HAVE_PIC_AOT +#ifdef MONO_ARCH_AOT_SUPPORTED guint8 *p, *target, *plt_entry; MonoJumpInfo ji; MonoAotModule *module = (MonoAotModule*)aot_module; gboolean res; + MonoMemPool *mp; //printf ("DYN: %p %d\n", aot_module, plt_info_offset); @@ -1908,12 +2382,15 @@ mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code ji.type = decode_value (p, &p); - res = decode_patch_info (module, NULL, &ji, p, &p, NULL); + mp = mono_mempool_new_size (512); + res = decode_patch (module, mp, &ji, p, &p); // FIXME: Error handling (how ?) g_assert (res); target = mono_resolve_patch_target (NULL, mono_domain_get (), NULL, &ji, TRUE); + mono_mempool_destroy (mp); + /* Patch the PLT entry with target which might be the actual method not a trampoline */ plt_entry = mono_aot_get_plt_entry (code); g_assert (plt_entry); @@ -1936,11 +2413,12 @@ mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code static void init_plt (MonoAotModule *info) { -#ifdef MONO_ARCH_HAVE_PIC_AOT +#ifdef MONO_ARCH_AOT_SUPPORTED #ifdef __i386__ guint8 *buf = info->plt; -#endif -#if defined(__x86_64__) +#elif defined(__x86_64__) + int i, n_entries; +#elif defined(__arm__) int i, n_entries; #endif gpointer tramp; @@ -1948,13 +2426,13 @@ init_plt (MonoAotModule *info) if (info->plt_inited) return; - tramp = mono_arch_create_specific_trampoline (info, MONO_TRAMPOLINE_AOT_PLT, mono_get_root_domain (), NULL); + tramp = mono_create_specific_trampoline (info, MONO_TRAMPOLINE_AOT_PLT, mono_get_root_domain (), NULL); #ifdef __i386__ /* Initialize the first PLT entry */ make_writable (info->plt, info->plt_end - info->plt); x86_jump_code (buf, tramp); -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(__arm__) /* * Initialize the entries in the plt_jump_table to point to the default targets. */ @@ -1963,8 +2441,8 @@ init_plt (MonoAotModule *info) /* The first entry points to the AOT trampoline */ ((gpointer*)info->plt_jump_table)[0] = tramp; for (i = 1; i < n_entries; ++i) - /* Each PLT entry is 16 bytes long, the default entry begins at offset 6 */ - ((gpointer*)info->plt_jump_table)[i] = info->plt + (i * 16) + 6; + /* All the default entries point to the first entry */ + ((gpointer*)info->plt_jump_table)[i] = info->plt; #else g_assert_not_reached (); #endif @@ -1982,6 +2460,9 @@ guint8* mono_aot_get_plt_entry (guint8 *code) { MonoAotModule *aot_module = find_aot_module (code); +#if defined(__arm__) + guint32 ins; +#endif if (!aot_module) return NULL; @@ -1994,11 +2475,251 @@ mono_aot_get_plt_entry (guint8 *code) if ((target >= (guint8*)(aot_module->plt)) && (target < (guint8*)(aot_module->plt_end))) return target; } +#elif defined(__arm__) + ins = ((guint32*)(gpointer)code) [-1]; + + /* Should be a 'bl' */ + if ((((ins >> 25) & 0x7) == 0x5) && (((ins >> 24) & 0x1) == 0x1)) { + gint32 disp = ((gint32)ins) & 0xffffff; + guint8 *target = code - 4 + 8 + (disp * 4); + + if ((target >= (guint8*)(aot_module->plt)) && (target < (guint8*)(aot_module->plt_end))) + return target; + } +#else + g_assert_not_reached (); #endif return NULL; } +/* + * mono_aot_get_plt_info_offset: + * + * Return the PLT info offset belonging to the plt entry called by CODE. + */ +guint32 +mono_aot_get_plt_info_offset (gssize *regs, guint8 *code) +{ + guint8 *plt_entry = mono_aot_get_plt_entry (code); + + g_assert (plt_entry); + + /* The offset is embedded inside the code after the plt entry */ +#if defined(__i386__) + return *(guint32*)(plt_entry + 5); +#elif defined(__x86_64__) + return *(guint32*)(plt_entry + 6); +#elif defined(__arm__) + /* The offset is stored as the 5th word of the plt entry */ + return ((guint32*)plt_entry) [4]; +#else + g_assert_not_reached (); + return 0; +#endif +} + +static gpointer +load_named_code (MonoAotModule *amodule, const char *name) +{ + char *symbol; + guint8 *p; + int n_patches, got_index, pindex; + MonoMemPool *mp; + gpointer code; + + /* Load the code */ + + symbol = g_strdup_printf ("%s", name); + find_symbol (amodule->sofile, amodule->globals, symbol, (gpointer *)&code); + g_free (symbol); + if (!code) + g_error ("Symbol '%s' not found in AOT file '%s'.\n", name, amodule->aot_name); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND function '%s' in AOT file '%s'.\n", name, amodule->aot_name); + + /* Load info */ + + symbol = g_strdup_printf ("%s_p", name); + find_symbol (amodule->sofile, amodule->globals, symbol, (gpointer *)&p); + g_free (symbol); + if (!p) + /* Nothing to patch */ + return code; + + /* Similar to mono_aot_load_method () */ + + n_patches = decode_value (p, &p); + + if (n_patches) { + MonoJumpInfo *patches; + guint32 *got_slots; + + mp = mono_mempool_new (); + + got_index = decode_value (p, &p); + + patches = load_patch_info (amodule, mp, n_patches, got_index, &got_slots, p, &p); + g_assert (patches); + + for (pindex = 0; pindex < n_patches; ++pindex) { + MonoJumpInfo *ji = &patches [pindex]; + gpointer target; + + /* + * When this code is executed, the runtime may not yet initalized, so + * resolve the patch info by hand. + */ + if (ji->type == MONO_PATCH_INFO_JIT_ICALL_ADDR) { + if (!strcmp (ji->data.name, "mono_get_lmf_addr")) { + target = mono_get_lmf_addr; + } else if (!strcmp (ji->data.name, "mono_thread_force_interruption_checkpoint")) { + target = mono_thread_force_interruption_checkpoint; + } else if (!strcmp (ji->data.name, "mono_exception_from_token")) { + target = mono_exception_from_token; + } else if (!strcmp (ji->data.name, "mono_throw_exception")) { + target = mono_get_throw_exception (); +#ifdef __x86_64__ + } else if (!strcmp (ji->data.name, "mono_amd64_throw_exception")) { + target = mono_amd64_throw_exception; +#endif +#ifdef __arm__ + } else if (!strcmp (ji->data.name, "mono_arm_throw_exception")) { + target = mono_arm_throw_exception; +#endif + } else if (strstr (ji->data.name, "trampoline_func_") == ji->data.name) { + int tramp_type2 = atoi (ji->data.name + strlen ("trampoline_func_")); + target = (gpointer)mono_get_trampoline_func (tramp_type2); + } else if (strstr (ji->data.name, "specific_trampoline_lazy_fetch_") == ji->data.name) { + guint32 slot = atoi (ji->data.name + strlen ("specific_trampoline_lazy_fetch_")); + target = mono_create_specific_trampoline (GUINT_TO_POINTER (slot), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL); + } else { + fprintf (stderr, "Unknown relocation '%s'\n", ji->data.name); + g_assert_not_reached (); + target = NULL; + } + } else { + /* Hopefully the code doesn't have patches which need method or + * domain to be set. + */ + target = mono_resolve_patch_target (NULL, NULL, code, ji, FALSE); + } + + amodule->got [got_slots [pindex]] = target; + } + + g_free (got_slots); + + mono_mempool_destroy (mp); + } + + return code; +} + +/* + * Return the piece of code identified by NAME from the mscorlib AOT file. + */ +gpointer +mono_aot_get_named_code (const char *name) +{ + MonoImage *image; + MonoAotModule *amodule; + + image = mono_defaults.corlib; + g_assert (image); + + amodule = image->aot_module; + g_assert (amodule); + + return load_named_code (amodule, name); +} + +/* + * Return a specific trampoline from the AOT file. + */ +gpointer +mono_aot_create_specific_trampoline (MonoImage *image, gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len) +{ + MonoAotModule *amodule; + int index, tramp_size; + guint8 *code, *tramp; + static gpointer generic_trampolines [MONO_TRAMPOLINE_NUM]; + + /* Currently, we keep all trampolines in the mscorlib AOT image */ + image = mono_defaults.corlib; + g_assert (image); + + mono_aot_lock (); + + amodule = image->aot_module; + g_assert (amodule); + + if (amodule->trampoline_index == amodule->num_trampolines) + g_error ("Ran out of trampolines in '%s' (%d)\n", image->name, amodule->num_trampolines); + + index = amodule->trampoline_index ++; + + mono_aot_unlock (); + + if (!generic_trampolines [tramp_type]) { + char *symbol; + + symbol = g_strdup_printf ("generic_trampoline_%d", tramp_type); + generic_trampolines [tramp_type] = mono_aot_get_named_code (symbol); + g_free (symbol); + } + + tramp = generic_trampolines [tramp_type]; + g_assert (tramp); + + amodule->got [amodule->first_trampoline_got_offset + (index *2)] = tramp; + amodule->got [amodule->first_trampoline_got_offset + (index *2) + 1] = arg1; + +#ifdef __x86_64__ + tramp_size = 16; +#elif defined(__arm__) + tramp_size = 28; +#else + tramp_size = -1; + g_assert_not_reached (); +#endif + + code = amodule->trampolines + (index * tramp_size); + if (code_len) + *code_len = tramp_size; + + return code; +} + +gpointer +mono_aot_get_unbox_trampoline (MonoMethod *method) +{ + guint32 method_index = mono_metadata_token_index (method->token) - 1; + MonoAotModule *amodule; + char *symbol; + gpointer code; + + amodule = method->klass->image->aot_module; + g_assert (amodule); + + symbol = g_strdup_printf ("unbox_trampoline_%d", method_index); + code = load_named_code (amodule, symbol); + g_free (symbol); + return code; +} + +gpointer +mono_aot_get_lazy_fetch_trampoline (guint32 slot) +{ + char *symbol; + gpointer code; + + symbol = g_strdup_printf ("rgctx_fetch_trampoline_%u", slot); + code = load_named_code (mono_defaults.corlib->aot_module, symbol); + g_free (symbol); + return code; +} + /* * mono_aot_get_n_pagefaults: * @@ -2018,7 +2739,7 @@ mono_aot_init (void) { } -MonoJitInfo* +gpointer mono_aot_get_method (MonoDomain *domain, MonoMethod *method) { return NULL; @@ -2030,12 +2751,6 @@ mono_aot_is_got_entry (guint8 *code, guint8 *addr) return FALSE; } -gboolean -mono_aot_init_vtable (MonoVTable *vtable) -{ - return FALSE; -} - gboolean mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res) { @@ -2088,4 +2803,37 @@ mono_aot_get_plt_entry (guint8 *code) return NULL; } +gpointer +mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code) +{ + return NULL; +} + +gpointer +mono_aot_get_method_from_vt_slot (MonoDomain *domain, MonoVTable *vtable, int slot) +{ + return NULL; +} + +gpointer +mono_aot_create_specific_trampolines (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_aot_get_named_code (char *name) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_aot_get_unbox_trampoline (MonoMethod *method) +{ + g_assert_not_reached (); + return NULL; +} + #endif