Merge pull request #1954 from kumpera/fix_aot_compilation
[mono.git] / mono / mini / aot-runtime.c
index 4fa4c6dcef8f374c99d25dfc85f6830411d5d184..868b4fa6fbb9b77ac259fa5449a9d1f01301e181 100644 (file)
@@ -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 <offset, index> 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);
                }