X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mono%2Fmini%2Faot-runtime.c;h=868b4fa6fbb9b77ac259fa5449a9d1f01301e181;hb=85988f4de7356eff9a6da00764d73ce48da07448;hp=4fa4c6dcef8f374c99d25dfc85f6830411d5d184;hpb=bd471cb710a60b5c594758291428dbe4160f264f;p=mono.git diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index 4fa4c6dcef8..868b4fa6fbb 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -68,6 +68,9 @@ #define ENABLE_AOT_CACHE #endif +/* Number of got entries shared between the JIT and LLVM GOT */ +#define N_COMMON_GOT_ENTRIES 4 + #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1))) #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1)) @@ -82,6 +85,7 @@ typedef struct MonoAotModule { /* Pointer to the Global Offset Table */ gpointer *got; gpointer *llvm_got; + gpointer shared_got [N_COMMON_GOT_ENTRIES]; GHashTable *name_cache; GHashTable *extra_methods; /* Maps methods to their code */ @@ -97,8 +101,6 @@ typedef struct MonoAotModule { gboolean plt_inited; guint8 *mem_begin; guint8 *mem_end; - /* Points to either the start of JIT compiler or LLVM compiled code */ - guint8 *code; guint8 *jit_code_start; guint8 *jit_code_end; guint8 *llvm_code_start; @@ -106,12 +108,14 @@ typedef struct MonoAotModule { guint8 *plt; guint8 *plt_end; guint8 *blob; - gint32 *code_offsets; - gpointer *method_addresses; - /* This contains pairs sorted by offset */ - /* This is needed because LLVM emitted methods can be in any order */ - gint32 *sorted_code_offsets; - gint32 sorted_code_offsets_len; + /* Maps method indexes to their code */ + gpointer *methods; + /* Sorted array of method addresses */ + gpointer *sorted_methods; + /* Method indexes for each method in sorted_methods */ + int *sorted_method_indexes; + /* The length of the two tables above */ + int sorted_methods_len; guint32 *method_info_offsets; guint32 *ex_info_offsets; guint32 *class_info_offsets; @@ -123,7 +127,6 @@ typedef struct MonoAotModule { guint32 *unbox_trampolines_end; guint32 *unbox_trampoline_addresses; guint8 *unwind_info; - guint8 *thumb_end; /* Points to the mono EH data created by LLVM */ guint8 *mono_eh_frame; @@ -201,12 +204,17 @@ static GHashTable *aot_jit_icall_hash; #define mono_aot_page_unlock() mono_mutex_unlock (&aot_page_mutex) static mono_mutex_t aot_page_mutex; +static MonoAotModule *mscorlib_aot_module; + static void init_plt (MonoAotModule *info); static void compute_llvm_code_range (MonoAotModule *amodule, guint8 **code_start, guint8 **code_end); +static gboolean +init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass **klass); + /*****************************************************/ /* AOT RUNTIME */ /*****************************************************/ @@ -468,7 +476,7 @@ decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf) int type = decode_value (p, &p); int num = decode_value (p, &p); gboolean has_container = decode_value (p, &p); - MonoTypeEnum gshared_constraint = 0; + MonoType *gshared_constraint = NULL; char *par_name = NULL; if (has_container) { @@ -492,9 +500,15 @@ decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf) container = class_def->generic_container; } } else { - gshared_constraint = decode_value (p, &p); - if (gshared_constraint) { - int len = decode_value (p, &p); + gboolean has_gshared_constraint = decode_value (p, &p); + if (has_gshared_constraint) { + int len; + + gshared_constraint = decode_type (module, p, &p); + if (!gshared_constraint) + return NULL; + + len = decode_value (p, &p); if (len) { par_name = mono_image_alloc (module->assembly->image, len + 1); memcpy (par_name, p, len); @@ -508,7 +522,7 @@ decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf) t->type = type; if (container) { t->data.generic_param = mono_generic_container_get_param (container, num); - g_assert (gshared_constraint == 0); + g_assert (gshared_constraint == NULL); } else { /* Anonymous */ MonoGenericParam *par = (MonoGenericParam*)mono_image_alloc0 (module->assembly->image, sizeof (MonoGenericParamFull)); @@ -832,7 +846,10 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod if (!m) return FALSE; mono_class_init (m->klass); - ref->method = mono_marshal_get_remoting_invoke_with_check (m); + if (mono_aot_only) + ref->method = m; + else + ref->method = mono_marshal_get_remoting_invoke_with_check (m); break; } case MONO_WRAPPER_PROXY_ISINST: { @@ -871,7 +888,7 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod case MONO_WRAPPER_ALLOC: { int atype = decode_value (p, &p); - ref->method = mono_gc_get_managed_allocator_by_type (atype); + ref->method = mono_gc_get_managed_allocator_by_type (atype, !!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS)); if (!ref->method) { fprintf (stderr, "Error: No managed allocator, but we need one for AOT.\nAre you using non-standard GC options?\n"); exit (1); @@ -1734,6 +1751,21 @@ get_call_table_entry (void *table, int index) #endif } +static void +init_gots (MonoAotModule *amodule) +{ + int i; + + if (amodule->got) { + for (i = 0; i < N_COMMON_GOT_ENTRIES; ++i) + amodule->got [i] = amodule->shared_got [i]; + } + if (amodule->llvm_got) { + for (i = 0; i < N_COMMON_GOT_ENTRIES; ++i) + amodule->llvm_got [i] = amodule->shared_got [i]; + } +} + static void load_aot_module (MonoAssembly *assembly, gpointer user_data) { @@ -1763,9 +1795,6 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) if (image_is_dynamic (assembly->image) || assembly->ref_only) return; - if (mono_security_cas_enabled ()) - return; - mono_aot_lock (); if (static_aot_modules) info = g_hash_table_lookup (static_aot_modules, assembly->aname.name); @@ -1880,7 +1909,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) memcpy (&amodule->info, info, sizeof (*info)); - amodule->got = amodule->info.got; + amodule->got = amodule->info.jit_got; amodule->llvm_got = amodule->info.llvm_got; amodule->globals = globals; amodule->sofile = sofile; @@ -1930,12 +1959,6 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) } } - amodule->method_addresses = info->method_addresses; - amodule->code = info->methods; -#ifdef TARGET_ARM - /* Mask out thumb interop bit */ - amodule->code = (void*)((mgreg_t)amodule->code & ~1); -#endif amodule->jit_code_start = info->jit_code_start; amodule->jit_code_end = info->jit_code_end; amodule->method_info_offsets = info->method_info_offsets; @@ -1948,8 +1971,8 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) amodule->unbox_trampolines_end = info->unbox_trampolines_end; amodule->unbox_trampoline_addresses = info->unbox_trampoline_addresses; amodule->unwind_info = info->unwind_info; + amodule->mem_begin = amodule->jit_code_start; amodule->mem_end = info->mem_end; - amodule->mem_begin = amodule->code; amodule->plt = info->plt; amodule->plt_end = info->plt_end; amodule->mono_eh_frame = info->mono_eh_frame; @@ -1957,20 +1980,26 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) amodule->trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = info->static_rgctx_trampolines; amodule->trampolines [MONO_AOT_TRAMP_IMT_THUNK] = info->imt_thunks; amodule->trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = info->gsharedvt_arg_trampolines; - amodule->thumb_end = info->thumb_end; - /* Compute code_offsets from the method addresses */ - amodule->code_offsets = g_malloc0 (amodule->info.nmethods * sizeof (gint32)); + if (!strcmp (assembly->aname.name, "mscorlib")) + mscorlib_aot_module = amodule; + + /* Compute method addresses */ + amodule->methods = g_malloc0 (amodule->info.nmethods * sizeof (gpointer)); for (i = 0; i < amodule->info.nmethods; ++i) { - /* method_addresses () contains a table of branches, since the ios linker can update those correctly */ - void *addr; + void *addr = NULL; - addr = get_call_table_entry (amodule->method_addresses, i); - g_assert (addr); - if (addr == amodule->method_addresses) - amodule->code_offsets [i] = 0xffffffff; + /* method_addresses () contains a table of branches, since the ios linker can update those correctly */ + if (!addr && amodule->info.method_addresses) { + addr = get_call_table_entry (amodule->info.method_addresses, i); + g_assert (addr); + if (addr == amodule->info.method_addresses) + addr = NULL; + } + if (addr == NULL) + amodule->methods [i] = GINT_TO_POINTER (-1); else - amodule->code_offsets [i] = (char*)addr - (char*)amodule->code; + amodule->methods [i] = addr; } if (make_unreadable) { @@ -1980,6 +2009,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) int err, len; addr = amodule->mem_begin; + g_assert (addr); len = amodule->mem_end - amodule->mem_begin; /* Round down in both directions to avoid modifying data which is not ours */ @@ -1998,8 +2028,10 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) mono_aot_lock (); - aot_code_low_addr = MIN (aot_code_low_addr, (gsize)amodule->jit_code_start); - aot_code_high_addr = MAX (aot_code_high_addr, (gsize)amodule->jit_code_end); + if (amodule->jit_code_start) { + aot_code_low_addr = MIN (aot_code_low_addr, (gsize)amodule->jit_code_start); + aot_code_high_addr = MAX (aot_code_high_addr, (gsize)amodule->jit_code_end); + } if (amodule->llvm_code_start) { aot_code_low_addr = MIN (aot_code_low_addr, (gsize)amodule->llvm_code_start); aot_code_high_addr = MAX (aot_code_high_addr, (gsize)amodule->llvm_code_end); @@ -2008,13 +2040,14 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) g_hash_table_insert (aot_modules, assembly, amodule); mono_aot_unlock (); - mono_jit_info_add_aot_module (assembly->image, amodule->jit_code_start, amodule->jit_code_end); + if (amodule->jit_code_start) + mono_jit_info_add_aot_module (assembly->image, amodule->jit_code_start, amodule->jit_code_end); if (amodule->llvm_code_start) mono_jit_info_add_aot_module (assembly->image, amodule->llvm_code_start, amodule->llvm_code_end); assembly->image->aot_module = amodule; - amodule->got [0] = assembly->image; + amodule->shared_got [0] = assembly->image; if (mono_aot_only) { char *code; @@ -2025,9 +2058,9 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) /* The second got slot contains the mscorlib got addr */ MonoAotModule *mscorlib_amodule = mono_defaults.corlib->aot_module; - amodule->got [1] = mscorlib_amodule->got; + amodule->shared_got [1] = mscorlib_amodule->got; } else { - amodule->got [1] = amodule->got; + amodule->shared_got [1] = amodule->got; } } @@ -2036,19 +2069,14 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) memset (&ji, 0, sizeof (ji)); ji.type = MONO_PATCH_INFO_GC_CARD_TABLE_ADDR; - amodule->got [2] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE); + amodule->shared_got [2] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE); memset (&ji, 0, sizeof (ji)); ji.type = MONO_PATCH_INFO_GC_NURSERY_START; - amodule->got [3] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE); + amodule->shared_got [3] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE); } - if (amodule->llvm_got) { - amodule->llvm_got [0] = amodule->got [0]; - amodule->llvm_got [1] = amodule->got [1]; - amodule->llvm_got [2] = amodule->got [2]; - amodule->llvm_got [3] = amodule->got [3]; - } + init_gots (amodule); /* * Since we store methoddef and classdef tokens when referring to methods/classes in @@ -2396,16 +2424,34 @@ compute_llvm_code_range (MonoAotModule *amodule, guint8 **code_start, guint8 **c if (fde_count > 1) { /* mono_aot_personality () */ g_assert (table [0] == -1); - *code_start = amodule->code + amodule->code_offsets [table [2]]; - *code_end = amodule->code + amodule->code_offsets [table [(fde_count - 1) * 2]] + table [fde_count * 2]; + *code_start = amodule->methods [table [2]]; + *code_end = (guint8*)amodule->methods [table [(fde_count - 1) * 2]] + table [fde_count * 2]; } else { *code_start = NULL; *code_end = NULL; } } +static gboolean +is_llvm_code (MonoAotModule *amodule, guint8 *code) +{ + if ((guint8*)code >= amodule->llvm_code_start && (guint8*)code < amodule->llvm_code_end) + return TRUE; + else + return FALSE; +} + +static gboolean +is_thumb_code (MonoAotModule *amodule, guint8 *code) +{ + if (is_llvm_code (amodule, code) && (amodule->info.flags & MONO_AOT_FILE_FLAG_LLVM_THUMB)) + return TRUE; + else + return FALSE; +} + /* - * decode_mono_eh_frame: + * decode_llvm_mono_eh_frame: * * Decode the EH information emitted by our modified LLVM compiler and construct a * MonoJitInfo structure from it. @@ -2419,11 +2465,11 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, GSList **nesting, int *this_reg, int *this_offset) { - guint8 *p; + guint8 *p, *code1, *code2; guint8 *fde, *cie, *code_start, *code_end; int version, fde_count; gint32 *table; - int i, j, pos, left, right, offset, offset1, offset2, code_len; + int i, pos, left, right, code_len; MonoJitExceptionInfo *ei; guint32 fde_len, ei_len, nested_len, nindex; gpointer *type_info; @@ -2452,7 +2498,6 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, cie = p + ((fde_count + 1) * 8); /* Binary search in the table to find the entry for code */ - offset = code - amodule->code; left = 0; right = fde_count; while (TRUE) { @@ -2460,35 +2505,35 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, /* The table contains method index/fde offset pairs */ g_assert (table [(pos * 2)] != -1); - offset1 = amodule->code_offsets [table [(pos * 2)]]; + code1 = amodule->methods [table [(pos * 2)]]; if (pos + 1 == fde_count) { - offset2 = amodule->llvm_code_end - amodule->llvm_code_start; + code2 = amodule->llvm_code_end; } else { g_assert (table [(pos + 1) * 2] != -1); - offset2 = amodule->code_offsets [table [(pos + 1) * 2]]; + code2 = amodule->methods [table [(pos + 1) * 2]]; } - if (offset < offset1) + if (code < code1) right = pos; - else if (offset >= offset2) + else if (code >= code2) left = pos + 1; else break; } - code_start = amodule->code + amodule->code_offsets [table [(pos * 2)]]; + code_start = amodule->methods [table [(pos * 2)]]; if (pos + 1 == fde_count) { /* The +1 entry in the table contains the length of the last method */ int len = table [(pos + 1) * 2]; code_end = code_start + len; } else { - code_end = amodule->code + amodule->code_offsets [table [(pos + 1) * 2]]; + code_end = amodule->methods [table [(pos + 1) * 2]]; } code_len = code_end - code_start; g_assert (code >= code_start && code < code_end); - if (amodule->thumb_end && (guint8*)code_start < amodule->thumb_end) + if (is_thumb_code (amodule, code_start)) /* Clear thumb flag */ code_start = (guint8*)(((mgreg_t)code_start) & ~1); @@ -2510,16 +2555,8 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, gint32 cindex1 = read32 (type_info [i]); GSList *l; - for (l = nesting [cindex1]; l; l = l->next) { - gint32 nesting_cindex = GPOINTER_TO_INT (l->data); - - for (j = 0; j < ei_len; ++j) { - gint32 cindex2 = read32 (type_info [j]); - - if (cindex2 == nesting_cindex) - nested_len ++; - } - } + for (l = nesting [cindex1]; l; l = l->next) + nested_len ++; } /* @@ -2554,9 +2591,12 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, jei->handler_start = ei [i].handler_start; jei->clause_index = clause_index; - /* Make sure we transition to thumb when a handler starts */ - if (amodule->thumb_end && (guint8*)jei->handler_start < amodule->thumb_end) + if (is_thumb_code (amodule, jei->try_start)) { + jei->try_start = (void*)((mgreg_t)jei->try_start & ~1); + jei->try_end = (void*)((mgreg_t)jei->try_end & ~1); + /* Make sure we transition to thumb when a handler starts */ jei->handler_start = (void*)((mgreg_t)jei->handler_start + 1); + } } /* See exception_cb () in mini-llvm.c as to why this is needed */ @@ -2567,19 +2607,16 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, for (l = nesting [cindex1]; l; l = l->next) { gint32 nesting_cindex = GPOINTER_TO_INT (l->data); + MonoJitExceptionInfo *nesting_ei; + MonoJitExceptionInfo *nesting_clause = &clauses [nesting_cindex]; - for (j = 0; j < ei_len; ++j) { - gint32 cindex2 = read32 (type_info [j]); + nesting_ei = &jinfo->clauses [nindex]; + nindex ++; - if (cindex2 == nesting_cindex) { - memcpy (&jinfo->clauses [nindex], &jinfo->clauses [j], sizeof (MonoJitExceptionInfo)); - jinfo->clauses [nindex].try_start = jinfo->clauses [i].try_start; - jinfo->clauses [nindex].try_end = jinfo->clauses [i].try_end; - jinfo->clauses [nindex].handler_start = jinfo->clauses [i].handler_start; - jinfo->clauses [nindex].exvar_offset = jinfo->clauses [i].exvar_offset; - nindex ++; - } - } + memcpy (nesting_ei, &jinfo->clauses [i], sizeof (MonoJitExceptionInfo)); + nesting_ei->flags = nesting_clause->flags; + nesting_ei->data.catch_class = nesting_clause->data.catch_class; + nesting_ei->clause_index = nesting_cindex; } } g_assert (nindex == ei_len + nested_len); @@ -2711,7 +2748,13 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, ei->flags = decode_value (p, &p); +#ifdef MONO_CONTEXT_SET_LLVM_EXC_REG + /* Not used for catch clauses */ + if (ei->flags != MONO_EXCEPTION_CLAUSE_NONE) + ei->exvar_offset = decode_value (p, &p); +#else ei->exvar_offset = decode_value (p, &p); +#endif if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) ei->data.filter = code + decode_value (p, &p); @@ -2816,28 +2859,16 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, gi->generic_sharing_context = g_new0 (MonoGenericSharingContext, 1); if (decode_value (p, &p)) { /* gsharedvt */ - int i, n; MonoGenericSharingContext *gsctx = gi->generic_sharing_context; - n = decode_value (p, &p); - if (n) { - gsctx->var_is_vt = alloc0_jit_info_data (domain, sizeof (gboolean) * n, async); - for (i = 0; i < n; ++i) - gsctx->var_is_vt [i] = decode_value (p, &p); - } - n = decode_value (p, &p); - if (n) { - gsctx->mvar_is_vt = alloc0_jit_info_data (domain, sizeof (gboolean) * n, async); - for (i = 0; i < n; ++i) - gsctx->mvar_is_vt [i] = decode_value (p, &p); - } + gsctx->is_gsharedvt = TRUE; } } if (method && has_seq_points) { MonoSeqPointInfo *seq_points; - p += seq_point_info_read (&seq_points, p, FALSE); + p += mono_seq_point_info_read (&seq_points, p, FALSE); mono_domain_lock (domain); g_hash_table_insert (domain_jit_info (domain)->seq_points, method, seq_points); @@ -2911,14 +2942,8 @@ mono_aot_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len) return p; } -static G_GNUC_UNUSED int -compare_ints (const void *a, const void *b) -{ - return *(gint32*)a - *(gint32*)b; -} - static void -msort_code_offsets_internal (gint32 *array, int lo, int hi, gint32 *scratch) +msort_method_addresses_internal (gpointer *array, int *indexes, int lo, int hi, gpointer *scratch, int *scratch_indexes) { int mid = (lo + hi) / 2; int i, t_lo, t_hi; @@ -2928,47 +2953,50 @@ msort_code_offsets_internal (gint32 *array, int lo, int hi, gint32 *scratch) if (hi - lo < 32) { for (i = lo; i < hi; ++i) - if (array [(i * 2)] > array [(i * 2) + 2]) + if (array [i] > array [i + 1]) break; if (i == hi) /* Already sorted */ return; } - msort_code_offsets_internal (array, lo, mid, scratch); - msort_code_offsets_internal (array, mid + 1, hi, scratch); + msort_method_addresses_internal (array, indexes, lo, mid, scratch, scratch_indexes); + msort_method_addresses_internal (array, indexes, mid + 1, hi, scratch, scratch_indexes); - if (array [mid * 2] < array [(mid + 1) * 2]) + if (array [mid] < array [mid + 1]) return; /* Merge */ t_lo = lo; t_hi = mid + 1; for (i = lo; i <= hi; i ++) { - if (t_lo <= mid && ((t_hi > hi) || array [t_lo * 2] < array [t_hi * 2])) { - scratch [(i * 2)] = array [t_lo * 2]; - scratch [(i * 2) + 1] = array [(t_lo *2) + 1]; + if (t_lo <= mid && ((t_hi > hi) || array [t_lo] < array [t_hi])) { + scratch [i] = array [t_lo]; + scratch_indexes [i] = indexes [t_lo]; t_lo ++; } else { - scratch [(i * 2)] = array [t_hi * 2]; - scratch [(i * 2) + 1] = array [(t_hi *2) + 1]; + scratch [i] = array [t_hi]; + scratch_indexes [i] = indexes [t_hi]; t_hi ++; } } for (i = lo; i <= hi; ++i) { - array [(i * 2)] = scratch [i * 2]; - array [(i * 2) + 1] = scratch [(i * 2) + 1]; + array [i] = scratch [i]; + indexes [i] = scratch_indexes [i]; } } static void -msort_code_offsets (gint32 *array, int len) +msort_method_addresses (gpointer *array, int *indexes, int len) { - gint32 *scratch; + gpointer *scratch; + int *scratch_indexes; - scratch = g_new (gint32, len * 2); - msort_code_offsets_internal (array, 0, len - 1, scratch); + scratch = g_new (gpointer, len); + scratch_indexes = g_new (int, len); + msort_method_addresses_internal (array, indexes, 0, len - 1, scratch, scratch_indexes); g_free (scratch); + g_free (scratch_indexes); } /* @@ -2981,7 +3009,7 @@ msort_code_offsets (gint32 *array, int len) MonoJitInfo * mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) { - int pos, left, right, offset, offset1, offset2, code_len; + int pos, left, right, code_len; int method_index, table_len; guint32 token; MonoAotModule *amodule = image->aot_module; @@ -2990,8 +3018,9 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) guint8 *code, *ex_info, *p; guint32 *table; int nmethods; - gint32 *code_offsets; - int offsets_len, i; + gpointer *methods; + guint8 *code1, *code2; + int methods_len, i; gboolean async; if (!amodule) @@ -3008,65 +3037,65 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) async = mono_thread_info_is_async_context (); - offset = (guint8*)addr - amodule->code; - - /* Compute a sorted table mapping code offsets to method indexes. */ - if (!amodule->sorted_code_offsets) { + /* Compute a sorted table mapping code to method indexes. */ + if (!amodule->sorted_methods) { // FIXME: async - code_offsets = g_new0 (gint32, nmethods * 2); - offsets_len = 0; + gpointer *methods = g_new0 (gpointer, nmethods); + int *method_indexes = g_new0 (int, nmethods); + int methods_len = 0; + for (i = 0; i < nmethods; ++i) { /* Skip the -1 entries to speed up sorting */ - if (amodule->code_offsets [i] == 0xffffffff) + if (amodule->methods [i] == GINT_TO_POINTER (-1)) continue; - code_offsets [(offsets_len * 2)] = amodule->code_offsets [i]; - code_offsets [(offsets_len *2) + 1] = i; - offsets_len ++; + methods [methods_len] = amodule->methods [i]; + method_indexes [methods_len] = i; + methods_len ++; } /* Use a merge sort as this is mostly sorted */ - msort_code_offsets (code_offsets, offsets_len); - //qsort (code_offsets, offsets_len, sizeof (gint32) * 2, compare_ints); - for (i = 0; i < offsets_len -1; ++i) - g_assert (code_offsets [(i * 2)] <= code_offsets [(i + 1) * 2]); - - amodule->sorted_code_offsets_len = offsets_len; - mono_memory_barrier (); - if (InterlockedCompareExchangePointer ((gpointer*)&amodule->sorted_code_offsets, code_offsets, NULL) != NULL) + msort_method_addresses (methods, method_indexes, methods_len); + for (i = 0; i < methods_len -1; ++i) + g_assert (methods [i] <= methods [i + 1]); + amodule->sorted_methods_len = methods_len; + if (InterlockedCompareExchangePointer ((gpointer*)&amodule->sorted_methods, methods, NULL) != NULL) + /* Somebody got in before us */ + g_free (methods); + if (InterlockedCompareExchangePointer ((gpointer*)&amodule->sorted_method_indexes, method_indexes, NULL) != NULL) /* Somebody got in before us */ - g_free (code_offsets); + g_free (method_indexes); } - code_offsets = amodule->sorted_code_offsets; - offsets_len = amodule->sorted_code_offsets_len; - - /* Binary search in the sorted_code_offsets table */ + /* Binary search in the sorted_methods table */ + methods = amodule->sorted_methods; + methods_len = amodule->sorted_methods_len; + code = addr; left = 0; - right = offsets_len; + right = methods_len; while (TRUE) { pos = (left + right) / 2; - offset1 = code_offsets [(pos * 2)]; - if (pos + 1 == offsets_len) { - if (amodule->code + offset1 >= amodule->jit_code_start && amodule->code + offset1 < amodule->jit_code_end) - offset2 = amodule->jit_code_end - amodule->code; + code1 = methods [pos]; + if (pos + 1 == methods_len) { + if (code1 >= amodule->jit_code_start && code1 < amodule->jit_code_end) + code2 = amodule->jit_code_end; else - offset2 = amodule->llvm_code_end - amodule->code; + code2 = amodule->llvm_code_end; } else { - offset2 = code_offsets [(pos + 1) * 2]; + code2 = methods [pos + 1]; } - if (offset < offset1) + if (code < code1) right = pos; - else if (offset >= offset2) + else if (code >= code2) left = pos + 1; else break; } - g_assert (offset >= code_offsets [(pos * 2)]); - if (pos + 1 < offsets_len) - g_assert (offset < code_offsets [((pos + 1) * 2)]); - method_index = code_offsets [(pos * 2) + 1]; + g_assert (addr >= methods [pos]); + if (pos + 1 < methods_len) + g_assert (addr < methods [pos + 1]); + method_index = amodule->sorted_method_indexes [pos]; /* In async mode, jinfo is not added to the normal jit info table, so have to cache it ourselves */ if (async) { @@ -3082,16 +3111,16 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) } } - code = &amodule->code [amodule->code_offsets [method_index]]; + code = amodule->methods [method_index]; ex_info = &amodule->blob [mono_aot_get_offset (amodule->ex_info_offsets, method_index)]; - if (pos == offsets_len - 1) { + if (pos == methods_len - 1) { if (code >= amodule->jit_code_start && code < amodule->jit_code_end) code_len = amodule->jit_code_end - code; else code_len = amodule->llvm_code_end - code; } else { - code_len = code_offsets [(pos + 1) * 2] - code_offsets [pos * 2]; + code_len = (guint8*)methods [pos + 1] - (guint8*)methods [pos]; } g_assert ((guint8*)code <= (guint8*)addr && (guint8*)addr < (guint8*)code + code_len); @@ -3240,7 +3269,6 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin case MONO_PATCH_INFO_CLASS: case MONO_PATCH_INFO_IID: case MONO_PATCH_INFO_ADJUSTED_IID: - case MONO_PATCH_INFO_CLASS_INIT: /* Shared */ ji->data.klass = decode_klass_ref (aot_module, p, &p); if (!ji->data.klass) @@ -3331,7 +3359,6 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin ji->data.offset = decode_value (p, &p); break; case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG: - case MONO_PATCH_INFO_GENERIC_CLASS_INIT: case MONO_PATCH_INFO_MONITOR_ENTER: case MONO_PATCH_INFO_MONITOR_ENTER_V4: case MONO_PATCH_INFO_MONITOR_EXIT: @@ -3448,6 +3475,8 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin ji->data.target = info; break; } + case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG: + break; default: g_warning ("unhandled type %d", ji->type); g_assert_not_reached (); @@ -3553,12 +3582,9 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM { MonoClass *klass; gboolean from_plt = method == NULL; - MonoMemPool *mp; - int i, pindex, n_patches, used_strings; - gboolean keep_patches = TRUE; - guint8 *p; MonoJitInfo *jinfo = NULL; - guint8 *code, *info; + guint8 *code = NULL, *info; + gboolean res; if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE) { if (mono_aot_only) @@ -3567,27 +3593,29 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM return NULL; } - if ((domain != mono_get_root_domain ()) && (!(amodule->info.opts & MONO_OPT_SHARED))) + if (domain != mono_get_root_domain ()) /* Non shared AOT code can't be used in other appdomains */ return NULL; if (amodule->out_of_date) return NULL; - if (amodule->code_offsets [method_index] == 0xffffffff) { - if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) { - char *full_name; + if (!code) { + if (amodule->methods [method_index] == GINT_TO_POINTER (-1)) { + if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) { + char *full_name; - if (!method) - method = mono_get_method (image, token, NULL); - full_name = mono_method_full_name (method, TRUE); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: NOT FOUND: %s.", full_name); - g_free (full_name); + if (!method) + method = mono_get_method (image, token, NULL); + full_name = mono_method_full_name (method, TRUE); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: NOT FOUND: %s.", full_name); + g_free (full_name); + } + return NULL; } - return NULL; } - code = &amodule->code [amodule->code_offsets [method_index]]; + code = amodule->methods [method_index]; info = &amodule->blob [mono_aot_get_offset (amodule->method_info_offsets, method_index)]; @@ -3622,85 +3650,9 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM } } - p = info; - - if (method) { - klass = method->klass; - decode_klass_ref (amodule, p, &p); - } else { - klass = decode_klass_ref (amodule, p, &p); - } - - if (amodule->info.opts & MONO_OPT_SHARED) - used_strings = decode_value (p, &p); - else - used_strings = 0; - - for (i = 0; i < used_strings; i++) { - guint token = decode_value (p, &p); - mono_ldstr (mono_get_root_domain (), image, mono_metadata_token_index (token)); - } - - if (amodule->info.opts & MONO_OPT_SHARED) - keep_patches = FALSE; - - n_patches = decode_value (p, &p); - - keep_patches = FALSE; - - if (n_patches) { - MonoJumpInfo *patches; - guint32 *got_slots; - gboolean llvm; - gpointer *got; - - if (keep_patches) - mp = domain->mp; - else - mp = mono_mempool_new (); - - if ((gpointer)code >= amodule->info.jit_code_start && (gpointer)code <= amodule->info.jit_code_end) { - llvm = FALSE; - got = amodule->got; - } else { - llvm = TRUE; - got = amodule->llvm_got; - g_assert (got); - } - - patches = load_patch_info (amodule, mp, n_patches, llvm, &got_slots, p, &p); - if (patches == NULL) - goto cleanup; - - for (pindex = 0; pindex < n_patches; ++pindex) { - MonoJumpInfo *ji = &patches [pindex]; - gpointer addr; - - /* - * For SFLDA, we need to call resolve_patch_target () since the GOT slot could have - * been initialized by load_method () for a static cctor before the cctor has - * finished executing (#23242). - */ - if (!got [got_slots [pindex]] || ji->type == MONO_PATCH_INFO_SFLDA) { - addr = mono_resolve_patch_target (method, domain, code, ji, TRUE); - if (ji->type == MONO_PATCH_INFO_METHOD_JUMP) - addr = mono_create_ftnptr (domain, addr); - mono_memory_barrier (); - got [got_slots [pindex]] = addr; - if (ji->type == MONO_PATCH_INFO_METHOD_JUMP) - register_jump_target_got_slot (domain, ji->data.method, &(got [got_slots [pindex]])); - } - ji->type = MONO_PATCH_INFO_NONE; - } - - g_free (got_slots); - - if (!keep_patches) - mono_mempool_destroy (mp); - } - - if (mini_get_debug_options ()->load_aot_jit_info_eagerly) - jinfo = mono_aot_find_jit_info (domain, amodule->assembly->image, code); + res = init_method (amodule, method_index, method, &klass); + if (!res) + goto cleanup; if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) { char *full_name; @@ -3734,7 +3686,7 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM MonoJitInfo *jinfo; if (!method) { - method = mono_get_method (image, token, NULL); + method = mono_get_method (amodule->assembly->image, token, NULL); g_assert (method); } mono_profiler_method_jit (method); @@ -3749,11 +3701,6 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM return code; cleanup: - /* FIXME: The space in domain->mp is wasted */ - if (amodule->info.opts & MONO_OPT_SHARED) - /* No need to cache patches */ - mono_mempool_destroy (mp); - if (jinfo) g_free (jinfo); @@ -3761,7 +3708,7 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM } static guint32 -find_aot_method_in_amodule (MonoAotModule *amodule, MonoMethod *method) +find_aot_method_in_amodule (MonoAotModule *amodule, MonoMethod *method, guint32 hash_full) { guint32 table_size, entry_size, hash; guint32 *table, *entry; @@ -3772,11 +3719,10 @@ find_aot_method_in_amodule (MonoAotModule *amodule, MonoMethod *method) return 0xffffff; table_size = amodule->extra_method_table [0]; + hash = hash_full % table_size; table = amodule->extra_method_table + 1; entry_size = 3; - hash = mono_aot_method_hash (method) % table_size; - entry = &table [hash * entry_size]; if (entry [0] == 0) @@ -3857,10 +3803,11 @@ find_aot_method (MonoMethod *method, MonoAotModule **out_amodule) guint32 index; GPtrArray *modules; int i; + guint32 hash = mono_aot_method_hash (method); /* Try the method's module first */ *out_amodule = method->klass->image->aot_module; - index = find_aot_method_in_amodule (method->klass->image->aot_module, method); + index = find_aot_method_in_amodule (method->klass->image->aot_module, method, hash); if (index != 0xffffff) return index; @@ -3882,7 +3829,7 @@ find_aot_method (MonoMethod *method, MonoAotModule **out_amodule) MonoAotModule *amodule = g_ptr_array_index (modules, i); if (amodule != method->klass->image->aot_module) - index = find_aot_method_in_amodule (amodule, method); + index = find_aot_method_in_amodule (amodule, method, hash); if (index != 0xffffff) { *out_amodule = amodule; break; @@ -3901,6 +3848,89 @@ mono_aot_find_method_index (MonoMethod *method) return find_aot_method (method, &out_amodule); } +static gboolean +init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass **klass) +{ + MonoDomain *domain = mono_domain_get (); + MonoMemPool *mp; + int pindex, n_patches; + guint8 *p; + MonoJitInfo *jinfo = NULL; + guint8 *code, *info; + + code = amodule->methods [method_index]; + info = &amodule->blob [mono_aot_get_offset (amodule->method_info_offsets, method_index)]; + + p = info; + + if (method) { + *klass = method->klass; + decode_klass_ref (amodule, p, &p); + } else { + *klass = decode_klass_ref (amodule, p, &p); + } + + n_patches = decode_value (p, &p); + + if (n_patches) { + MonoJumpInfo *patches; + guint32 *got_slots; + gboolean llvm; + gpointer *got; + + mp = mono_mempool_new (); + + if ((gpointer)code >= amodule->info.jit_code_start && (gpointer)code <= amodule->info.jit_code_end) { + llvm = FALSE; + got = amodule->got; + } else { + llvm = TRUE; + got = amodule->llvm_got; + g_assert (got); + } + + patches = load_patch_info (amodule, mp, n_patches, llvm, &got_slots, p, &p); + if (patches == NULL) + goto cleanup; + + for (pindex = 0; pindex < n_patches; ++pindex) { + MonoJumpInfo *ji = &patches [pindex]; + gpointer addr; + + /* + * For SFLDA, we need to call resolve_patch_target () since the GOT slot could have + * been initialized by load_method () for a static cctor before the cctor has + * finished executing (#23242). + */ + if (!got [got_slots [pindex]] || ji->type == MONO_PATCH_INFO_SFLDA) { + addr = mono_resolve_patch_target (method, domain, code, ji, TRUE); + if (ji->type == MONO_PATCH_INFO_METHOD_JUMP) + addr = mono_create_ftnptr (domain, addr); + mono_memory_barrier (); + got [got_slots [pindex]] = addr; + if (ji->type == MONO_PATCH_INFO_METHOD_JUMP) + register_jump_target_got_slot (domain, ji->data.method, &(got [got_slots [pindex]])); + } + ji->type = MONO_PATCH_INFO_NONE; + } + + g_free (got_slots); + + mono_mempool_destroy (mp); + } + + if (mini_get_debug_options ()->load_aot_jit_info_eagerly) + jinfo = mono_aot_find_jit_info (domain, amodule->assembly->image, code); + + return TRUE; + + cleanup: + if (jinfo) + g_free (jinfo); + + return FALSE; +} + /* * mono_aot_get_method: * @@ -3949,7 +3979,7 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method) /* Find method index */ method_index = 0xffffff; - if (method->is_inflated && !method->wrapper_type && mono_method_is_generic_sharable_full (method, FALSE, FALSE, FALSE)) { + if (method->is_inflated && !method->wrapper_type && mono_method_is_generic_sharable_full (method, TRUE, FALSE, FALSE)) { /* * For generic methods, we store the fully shared instance in place of the * original method. @@ -4260,7 +4290,7 @@ mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code * patches, so have to translate between the two. * FIXME: Clean this up, but how ? */ - if (ji.type == MONO_PATCH_INFO_ABS || ji.type == MONO_PATCH_INFO_INTERNAL_METHOD || ji.type == MONO_PATCH_INFO_CLASS_INIT || ji.type == MONO_PATCH_INFO_ICALL_ADDR || ji.type == MONO_PATCH_INFO_JIT_ICALL_ADDR || ji.type == MONO_PATCH_INFO_RGCTX_FETCH) { + if (ji.type == MONO_PATCH_INFO_ABS || ji.type == MONO_PATCH_INFO_INTERNAL_METHOD || ji.type == MONO_PATCH_INFO_ICALL_ADDR || ji.type == MONO_PATCH_INFO_JIT_ICALL_ADDR || ji.type == MONO_PATCH_INFO_RGCTX_FETCH) { /* These should already have a function descriptor */ #ifdef PPC_USES_FUNCTION_DESCRIPTOR /* Our function descriptors have a 0 environment, gcc created ones don't */ @@ -4334,10 +4364,8 @@ mono_aot_get_plt_entry (guint8 *code) return NULL; #ifdef TARGET_ARM - if (amodule->thumb_end) { - if (code >= amodule->llvm_code_start && code < amodule->llvm_code_end) - return mono_arm_get_thumb_plt_entry (code); - } + if (is_thumb_code (amodule, code)) + return mono_arm_get_thumb_plt_entry (code); #endif #ifdef MONO_ARCH_AOT_SUPPORTED @@ -4530,9 +4558,6 @@ load_function_full (MonoAotModule *amodule, const char *name, MonoTrampInfo **ou } else if (!strcmp (ji->data.name, "specific_trampoline_monitor_exit")) { target = mono_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_EXIT, mono_get_root_domain (), NULL); target = mono_create_ftnptr_malloc (target); - } else if (!strcmp (ji->data.name, "specific_trampoline_generic_class_init")) { - target = mono_create_specific_trampoline (NULL, MONO_TRAMPOLINE_GENERIC_CLASS_INIT, mono_get_root_domain (), NULL); - target = mono_create_ftnptr_malloc (target); } else if (!strcmp (ji->data.name, "mono_thread_get_and_clear_pending_exception")) { target = mono_thread_get_and_clear_pending_exception; } else if (!strcmp (ji->data.name, "debugger_agent_single_step_from_context")) { @@ -4574,6 +4599,21 @@ load_function (MonoAotModule *amodule, const char *name) return load_function_full (amodule, name, NULL); } +static MonoAotModule* +get_mscorlib_aot_module (void) +{ + MonoImage *image; + MonoAotModule *amodule; + + image = mono_defaults.corlib; + if (image) + amodule = image->aot_module; + else + amodule = mscorlib_aot_module; + g_assert (amodule); + return amodule; +} + /* * Return the trampoline identified by NAME from the mscorlib AOT file. * On ppc64, this returns a function descriptor. @@ -4581,14 +4621,7 @@ load_function (MonoAotModule *amodule, const char *name) gpointer mono_aot_get_trampoline_full (const char *name, MonoTrampInfo **out_tinfo) { - MonoImage *image; - MonoAotModule *amodule; - - image = mono_defaults.corlib; - g_assert (image); - - amodule = image->aot_module; - g_assert (amodule); + MonoAotModule *amodule = get_mscorlib_aot_module (); return mono_create_ftnptr_malloc (load_function_full (amodule, name, out_tinfo)); } @@ -4629,16 +4662,15 @@ get_new_trampoline_from_page (int tramp_type) return code; } mono_aot_page_unlock (); - psize = mono_pagesize (); /* the trampoline template page is in the mscorlib module */ image = mono_defaults.corlib; g_assert (image); + psize = MONO_AOT_TRAMP_PAGE_SIZE; + amodule = image->aot_module; g_assert (amodule); - g_assert (amodule->info.tramp_page_size == psize); - if (tramp_type == MONO_AOT_TRAMP_SPECIFIC) tpage = load_function (amodule, "specific_trampolines_page"); else if (tramp_type == MONO_AOT_TRAMP_STATIC_RGCTX) @@ -4720,7 +4752,7 @@ get_new_specific_trampoline_from_page (gpointer tramp, gpointer arg) code = get_new_trampoline_from_page (MONO_AOT_TRAMP_SPECIFIC); - data = (gpointer*)((char*)code - mono_pagesize ()); + data = (gpointer*)((char*)code - MONO_AOT_TRAMP_PAGE_SIZE); data [0] = arg; data [1] = tramp; /*g_warning ("new trampoline at %p for data %p, tramp %p (stored at %p)", code, arg, tramp, data);*/ @@ -4736,7 +4768,7 @@ get_new_rgctx_trampoline_from_page (gpointer tramp, gpointer arg) code = get_new_trampoline_from_page (MONO_AOT_TRAMP_STATIC_RGCTX); - data = (gpointer*)((char*)code - mono_pagesize ()); + data = (gpointer*)((char*)code - MONO_AOT_TRAMP_PAGE_SIZE); data [0] = arg; data [1] = tramp; /*g_warning ("new rgctx trampoline at %p for data %p, tramp %p (stored at %p)", code, arg, tramp, data);*/ @@ -4752,7 +4784,7 @@ get_new_imt_trampoline_from_page (gpointer arg) code = get_new_trampoline_from_page (MONO_AOT_TRAMP_IMT_THUNK); - data = (gpointer*)((char*)code - mono_pagesize ()); + data = (gpointer*)((char*)code - MONO_AOT_TRAMP_PAGE_SIZE); data [0] = arg; /*g_warning ("new imt trampoline at %p for data %p, (stored at %p)", code, arg, data);*/ return code; @@ -4767,7 +4799,7 @@ get_new_gsharedvt_arg_trampoline_from_page (gpointer tramp, gpointer arg) code = get_new_trampoline_from_page (MONO_AOT_TRAMP_GSHAREDVT_ARG); - data = (gpointer*)((char*)code - mono_pagesize ()); + data = (gpointer*)((char*)code - MONO_AOT_TRAMP_PAGE_SIZE); data [0] = arg; data [1] = tramp; /*g_warning ("new rgctx trampoline at %p for data %p, tramp %p (stored at %p)", code, arg, tramp, data);*/ @@ -4778,21 +4810,17 @@ get_new_gsharedvt_arg_trampoline_from_page (gpointer tramp, gpointer arg) static gpointer get_numerous_trampoline (MonoAotTrampoline tramp_type, int n_got_slots, MonoAotModule **out_amodule, guint32 *got_offset, guint32 *out_tramp_size) { - MonoAotModule *amodule; - int index, tramp_size; MonoImage *image; + MonoAotModule *amodule = get_mscorlib_aot_module (); + int index, tramp_size; /* 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); *out_amodule = amodule; + mono_aot_lock (); + #ifdef MONOTOUCH #define MONOTOUCH_TRAMPOLINES_ERROR ". See http://docs.xamarin.com/ios/troubleshooting for instructions on how to fix this condition." #else @@ -4800,7 +4828,7 @@ get_numerous_trampoline (MonoAotTrampoline tramp_type, int n_got_slots, MonoAotM #endif if (amodule->trampoline_index [tramp_type] == amodule->info.num_trampolines [tramp_type]) { g_error ("Ran out of trampolines of type %d in '%s' (%d)%s\n", - tramp_type, image->name, amodule->info.num_trampolines [tramp_type], MONOTOUCH_TRAMPOLINES_ERROR); + tramp_type, image ? image->name : "mscorlib", amodule->info.num_trampolines [tramp_type], MONOTOUCH_TRAMPOLINES_ERROR); } index = amodule->trampoline_index [tramp_type] ++; @@ -4900,7 +4928,11 @@ mono_aot_get_unbox_trampoline (MonoMethod *method) if (method->is_inflated && !mono_method_is_generic_sharable_full (method, FALSE, FALSE, FALSE)) { method_index = find_aot_method (method, &amodule); - if (method_index == 0xffffff && mono_method_is_generic_sharable_full (method, FALSE, FALSE, TRUE)) { + if (method_index == 0xffffff && mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE)) { + MonoMethod *shared = mini_get_shared_method_full (method, FALSE, FALSE); + method_index = find_aot_method (shared, &amodule); + } + if (method_index == 0xffffff && mono_method_is_generic_sharable_full (method, FALSE, TRUE, TRUE)) { MonoMethod *shared = mini_get_shared_method_full (method, TRUE, TRUE); method_index = find_aot_method (shared, &amodule); }