Revert "Merge branch 'master' of https://github.com/mono/mono"
[mono.git] / mono / mini / aot-runtime.c
index d6190013ff8570af5e132bc8011171a756349d7e..abf214f405c291f25243711c73cc36ae3131d02e 100644 (file)
 #define SHARED_EXT ".so"
 #endif
 
+#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))
 
+typedef struct {
+       int method_index;
+       MonoJitInfo *jinfo;
+} JitInfoMap;
+
 typedef struct MonoAotModule {
        char *aot_name;
        /* Pointer to the Global Offset Table */
@@ -98,9 +104,7 @@ typedef struct MonoAotModule {
        guint8 *plt_end;
        guint8 *blob;
        gint32 *code_offsets;
-#ifdef MONOTOUCH
        gpointer *method_addresses;
-#endif
        /* This contains <offset, index> pairs sorted by offset */
        /* This is needed because LLVM emitted methods can be in any order */
        gint32 *sorted_code_offsets;
@@ -132,6 +136,9 @@ typedef struct MonoAotModule {
 
        gpointer *globals;
        MonoDl *sofile;
+
+       JitInfoMap *async_jit_info_table;
+       CRITICAL_SECTION mutex;
 } MonoAotModule;
 
 typedef struct {
@@ -180,6 +187,9 @@ static guint32 n_pagefaults = 0;
 static gsize aot_code_low_addr = (gssize)-1;
 static gsize aot_code_high_addr = 0;
 
+/* Stats */
+static gint32 async_jit_info_size;
+
 static GHashTable *aot_jit_icall_hash;
 
 #ifdef MONOTOUCH
@@ -199,6 +209,18 @@ init_plt (MonoAotModule *info);
 /*                 AOT RUNTIME                       */
 /*****************************************************/
 
+static inline void
+amodule_lock (MonoAotModule *amodule)
+{
+       EnterCriticalSection (&amodule->mutex);
+}
+
+static inline void
+amodule_unlock (MonoAotModule *amodule)
+{
+       LeaveCriticalSection (&amodule->mutex);
+}
+
 /*
  * load_image:
  *
@@ -908,6 +930,12 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod
                                if (!m)
                                        return FALSE;
                                ref->method = mono_marshal_get_synchronized_inner_wrapper (m);
+                       } else if (subtype == WRAPPER_SUBTYPE_ARRAY_ACCESSOR) {
+                               MonoMethod *m = decode_resolve_method_ref (module, p, &p);
+
+                               if (!m)
+                                       return FALSE;
+                               ref->method = mono_marshal_get_array_accessor_wrapper (m);
                        } else if (subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN) {
                                ref->method = mono_marshal_get_gsharedvt_in_wrapper ();
                        } else if (subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
@@ -1042,6 +1070,7 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod
                case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
                case MONO_WRAPPER_DELEGATE_END_INVOKE: {
                        gboolean is_inflated = decode_value (p, &p);
+                       WrapperSubtype subtype;
 
                        if (is_inflated) {
                                MonoClass *klass;
@@ -1079,6 +1108,19 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod
                                if (!target)
                                        return FALSE;
 
+                               if (wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
+                                       WrapperInfo *info;
+
+                                       subtype = decode_value (p, &p);
+                                       info = mono_marshal_get_wrapper_info (target);
+                                       if (info) {
+                                               if (info->subtype != subtype)
+                                                       return FALSE;
+                                       } else {
+                                               if (subtype != WRAPPER_SUBTYPE_NONE)
+                                                       return FALSE;
+                                       }
+                               }
                                if (sig_matches_target (module, target, p, &p))
                                        ref->method = target;
                                else
@@ -1568,7 +1610,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                        sofile = mono_dl_open (aot_name, MONO_DL_LAZY, &err);
 
                        if (!sofile) {
-                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, err);
+                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module '%s' not found: %s\n", aot_name, err);
                                g_free (err);
                        }
                }
@@ -1640,6 +1682,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        /* Sanity check */
        g_assert (info->double_align == align_double);
        g_assert (info->long_align == align_int64);
+       g_assert (info->generic_tramp_num == MONO_TRAMPOLINE_NUM);
 
        blob = info->blob;
 
@@ -1656,6 +1699,8 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        amodule->method_to_code = g_hash_table_new (mono_aligned_addr_hash, NULL);
        amodule->blob = blob;
 
+       InitializeCriticalSection (&amodule->mutex);
+
        /* Read image table */
        {
                guint32 table_len, i;
@@ -1698,9 +1743,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        }
 
        amodule->code_offsets = info->code_offsets;
-#ifdef MONOTOUCH
        amodule->method_addresses = info->method_addresses;
-#endif
        amodule->code = info->methods;
 #ifdef TARGET_ARM
        /* Mask out thumb interop bit */
@@ -1728,21 +1771,27 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        amodule->trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = info->gsharedvt_arg_trampolines;
        amodule->thumb_end = info->thumb_end;
 
-#ifdef MONOTOUCH
        if (info->flags & MONO_AOT_FILE_FLAG_DIRECT_METHOD_ADDRESSES) {
                /* Compute code_offsets from the method addresses */
                amodule->code_offsets = g_malloc0 (amodule->info.nmethods * sizeof (gint32));
                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 = get_arm_bl_target ((guint32*)(amodule->method_addresses + i));
+                       void *addr = NULL;
 
+#ifdef TARGET_ARM
+                       addr = get_arm_bl_target ((guint32*)amodule->method_addresses + i);
+#elif defined(TARGET_X86) || defined(TARGET_AMD64)
+                       addr = mono_arch_get_call_target ((guint8*)amodule->method_addresses + (i * 5) + 5);
+#else
+                       g_assert_not_reached ();
+#endif
+                       g_assert (addr);
                        if (addr == amodule->method_addresses)
                                amodule->code_offsets [i] = 0xffffffff;
                        else
                                amodule->code_offsets [i] = (char*)addr - (char*)amodule->code;
                }
        }
-#endif
 
        if (make_unreadable) {
 #ifndef TARGET_WIN32
@@ -1888,6 +1937,7 @@ mono_aot_init (void)
 #ifndef __native_client__
        mono_install_assembly_load_hook (load_aot_module, NULL);
 #endif
+       mono_counters_register ("Async JIT info size", MONO_COUNTER_INT|MONO_COUNTER_JIT, &async_jit_info_size);
 
        if (g_getenv ("MONO_LASTAOT"))
                mono_last_aot_method = atoi (g_getenv ("MONO_LASTAOT"));
@@ -2033,7 +2083,7 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
        if (!amodule || !amodule->class_name_table)
                return FALSE;
 
-       mono_aot_lock ();
+       amodule_lock (amodule);
 
        *klass = NULL;
 
@@ -2044,7 +2094,7 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
        if (nspace_table) {
                *klass = g_hash_table_lookup (nspace_table, name);
                if (*klass) {
-                       mono_aot_unlock ();
+                       amodule_unlock (amodule);
                        return TRUE;
                }
        }
@@ -2084,19 +2134,19 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
                        name_space2 = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
 
                        if (!strcmp (name, name2) && !strcmp (name_space, name_space2)) {
-                               mono_aot_unlock ();
+                               amodule_unlock (amodule);
                                *klass = mono_class_get (image, token);
 
                                /* Add to cache */
                                if (*klass) {
-                                       mono_aot_lock ();
+                                       amodule_lock (amodule);
                                        nspace_table = g_hash_table_lookup (amodule->name_cache, name_space);
                                        if (!nspace_table) {
                                                nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
                                                g_hash_table_insert (amodule->name_cache, (char*)name_space2, nspace_table);
                                        }
                                        g_hash_table_insert (nspace_table, (char*)name2, *klass);
-                                       mono_aot_unlock ();
+                                       amodule_unlock (amodule);
                                }
                                return TRUE;
                        }
@@ -2109,7 +2159,7 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
                }
        }
 
-       mono_aot_unlock ();
+       amodule_unlock (amodule);
        
        return TRUE;
 }
@@ -2236,11 +2286,11 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
         * allocate a new JI.
         */
        jinfo = 
-               mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * (ei_len + nested_len)) + extra_size);
+               mono_domain_alloc0_lock_free (domain, MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * (ei_len + nested_len)) + extra_size);
 
        jinfo->code_size = code_len;
        jinfo->used_regs = mono_cache_unwind_info (info.unw_info, info.unw_info_len);
-       jinfo->method = method;
+       jinfo->d.method = method;
        jinfo->code_start = code;
        jinfo->domain_neutral = 0;
        /* This signals that used_regs points to a normal cached unwind info */
@@ -2300,15 +2350,30 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
        return jinfo;
 }
 
+static gpointer
+alloc0_jit_info_data (MonoDomain *domain, int size, gboolean async_context)
+{
+       gpointer res;
+
+       if (async_context) {
+               res = mono_domain_alloc0_lock_free (domain, size);
+               InterlockedExchangeAdd (&async_jit_info_size, size);
+       } else {
+               res = mono_domain_alloc0 (domain, size);
+       }
+       return res;
+}
+
 /*
  * LOCKING: Acquires the domain lock.
+ * In async context, this is async safe.
  */
 static MonoJitInfo*
 decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, 
                                                         MonoMethod *method, guint8* ex_info, guint8 *addr,
                                                         guint8 *code, guint32 code_len)
 {
-       int i, buf_len, num_clauses;
+       int i, buf_len, num_clauses, len;
        MonoJitInfo *jinfo;
        guint used_int_regs, flags;
        gboolean has_generic_jit_info, has_dwarf_unwind_info, has_clauses, has_seq_points, has_try_block_holes, has_arch_eh_jit_info;
@@ -2316,8 +2381,10 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
        guint8 *p;
        int generic_info_size, try_holes_info_size, num_holes, arch_eh_jit_info_size;
        int this_reg = 0, this_offset = 0;
+       gboolean async;
 
        /* Load the method info from the AOT file */
+       async = mono_thread_info_is_async_context ();
 
        p = ex_info;
        flags = decode_value (p, &p);
@@ -2364,6 +2431,9 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
                MonoJitExceptionInfo *clauses;
                GSList **nesting;
 
+               // FIXME: async
+               g_assert (!async);
+
                /*
                 * Part of the info is encoded by the AOT compiler, the rest is in the .eh_frame
                 * section.
@@ -2396,8 +2466,8 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
                        g_slist_free (nesting [i]);
                g_free (nesting);
        } else {
-               jinfo = 
-                       mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * num_clauses) + generic_info_size + try_holes_info_size + arch_eh_jit_info_size);
+               len = MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * num_clauses) + generic_info_size + try_holes_info_size + arch_eh_jit_info_size;
+               jinfo = alloc0_jit_info_data (domain, len, async);
                jinfo->num_clauses = num_clauses;
 
                for (i = 0; i < jinfo->num_clauses; ++i) {
@@ -2410,8 +2480,14 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
                        if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
                                ei->data.filter = code + decode_value (p, &p);
                        else {
-                               if (decode_value (p, &p))
-                                       ei->data.catch_class = decode_klass_ref (amodule, p, &p);
+                               int len = decode_value (p, &p);
+
+                               if (len > 0) {
+                                       if (async)
+                                               p += len;
+                                       else
+                                               ei->data.catch_class = decode_klass_ref (amodule, p, &p);
+                               }
                        }
 
                        ei->try_start = code + decode_value (p, &p);
@@ -2421,14 +2497,49 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
 
                jinfo->code_size = code_len;
                jinfo->used_regs = used_int_regs;
-               jinfo->method = method;
+               jinfo->d.method = method;
                jinfo->code_start = code;
                jinfo->domain_neutral = 0;
                jinfo->from_aot = 1;
        }
 
+       if (has_try_block_holes) {
+               MonoTryBlockHoleTableJitInfo *table;
+
+               jinfo->has_try_block_holes = 1;
+
+               table = mono_jit_info_get_try_block_hole_table_info (jinfo);
+               g_assert (table);
+
+               table->num_holes = (guint16)num_holes;
+               for (i = 0; i < num_holes; ++i) {
+                       MonoTryBlockHoleJitInfo *hole = &table->holes [i];
+                       hole->clause = decode_value (p, &p);
+                       hole->length = decode_value (p, &p);
+                       hole->offset = decode_value (p, &p);
+               }
+       }
+
+       if (has_arch_eh_jit_info) {
+               MonoArchEHJitInfo *eh_info;
+
+               jinfo->has_arch_eh_info = 1;
+
+               eh_info = mono_jit_info_get_arch_eh_info (jinfo);
+               eh_info->stack_size = decode_value (p, &p);
+       }
+
+       if (async) {
+               /* The rest is not needed in async mode */
+               jinfo->async = TRUE;
+               jinfo->d.aot_info = amodule;
+               // FIXME: Cache
+               return jinfo;
+       }
+
        if (has_generic_jit_info) {
                MonoGenericJitInfo *gi;
+               int len;
 
                jinfo->has_generic_jit_info = 1;
 
@@ -2437,7 +2548,7 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
 
                gi->nlocs = decode_value (p, &p);
                if (gi->nlocs) {
-                       gi->locations = mono_domain_alloc0 (domain, gi->nlocs * sizeof (MonoDwarfLocListEntry));
+                       gi->locations = alloc0_jit_info_data (domain, gi->nlocs * sizeof (MonoDwarfLocListEntry), async);
                        for (i = 0; i < gi->nlocs; ++i) {
                                MonoDwarfLocListEntry *entry = &gi->locations [i];
 
@@ -2461,7 +2572,11 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
                        }
                }
 
-               jinfo->method = decode_resolve_method_ref (amodule, p, &p);
+               len = decode_value (p, &p);
+               if (async)
+                       p += len;
+               else
+                       jinfo->d.method = decode_resolve_method_ref (amodule, p, &p);
 
                gi->generic_sharing_context = g_new0 (MonoGenericSharingContext, 1);
                if (decode_value (p, &p)) {
@@ -2471,46 +2586,20 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
 
                        n = decode_value (p, &p);
                        if (n) {
-                               gsctx->var_is_vt = g_new0 (gboolean, 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 = g_new0 (gboolean, 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);
                        }
                }
        }
 
-       if (has_try_block_holes) {
-               MonoTryBlockHoleTableJitInfo *table;
-
-               jinfo->has_try_block_holes = 1;
-
-               table = mono_jit_info_get_try_block_hole_table_info (jinfo);
-               g_assert (table);
-
-               table->num_holes = (guint16)num_holes;
-               for (i = 0; i < num_holes; ++i) {
-                       MonoTryBlockHoleJitInfo *hole = &table->holes [i];
-                       hole->clause = decode_value (p, &p);
-                       hole->length = decode_value (p, &p);
-                       hole->offset = decode_value (p, &p);
-               }
-       }
-
-       if (has_arch_eh_jit_info) {
-               MonoArchEHJitInfo *eh_info;
-
-               jinfo->has_arch_eh_info = 1;
-
-               eh_info = mono_jit_info_get_arch_eh_info (jinfo);
-               eh_info->stack_size = decode_value (p, &p);
-       }
-
-       if (has_seq_points) {
+       if (method && has_seq_points) {
                MonoSeqPointInfo *seq_points;
                int il_offset, native_offset, last_il_offset, last_native_offset, j;
 
@@ -2527,6 +2616,7 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
                        sp->il_offset = il_offset;
                        sp->native_offset = native_offset;
                        
+                       sp->flags = decode_value (p, &p);
                        sp->next_len = decode_value (p, &p);
                        sp->next = g_new (int, sp->next_len);
                        for (j = 0; j < sp->next_len; ++j)
@@ -2543,7 +2633,8 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
 
        /* Load debug info */
        buf_len = decode_value (p, &p);
-       mono_debug_add_aot_method (domain, method, code, p, buf_len);
+       if (!async)
+               mono_debug_add_aot_method (domain, method, code, p, buf_len);
        p += buf_len;
 
        if (has_gc_map) {
@@ -2555,7 +2646,7 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
                p += map_size;
        }
 
-       if (amodule != jinfo->method->klass->image->aot_module) {
+       if (amodule != jinfo->d.method->klass->image->aot_module) {
                mono_aot_lock ();
                if (!ji_to_amodule)
                        ji_to_amodule = g_hash_table_new (NULL, NULL);
@@ -2574,10 +2665,14 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
 guint8*
 mono_aot_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
 {
-       MonoAotModule *amodule = ji->method->klass->image->aot_module;
+       MonoAotModule *amodule;
        guint8 *p;
        guint8 *code = ji->code_start;
 
+       if (ji->async)
+               amodule = ji->d.aot_info;
+       else
+               amodule = jinfo_get_method (ji)->klass->image->aot_module;
        g_assert (amodule);
        g_assert (ji->from_aot);
 
@@ -2656,6 +2751,13 @@ msort_code_offsets (gint32 *array, int len)
        g_free (scratch);
 }
 
+/*
+ * mono_aot_find_jit_info:
+ *
+ *   In async context, the resulting MonoJitInfo will not have its method field set, and it will not be added
+ * to the jit info tables.
+ * FIXME: Large sizes in the lock free allocator
+ */
 MonoJitInfo *
 mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
 {
@@ -2663,13 +2765,14 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
        int method_index, table_len;
        guint32 token;
        MonoAotModule *amodule = image->aot_module;
-       MonoMethod *method;
+       MonoMethod *method = NULL;
        MonoJitInfo *jinfo;
        guint8 *code, *ex_info, *p;
        guint32 *table;
        int nmethods = amodule->info.nmethods;
        gint32 *code_offsets;
        int offsets_len, i;
+       gboolean async;
 
        if (!amodule)
                return NULL;
@@ -2678,10 +2781,13 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
                /* FIXME: */
                return NULL;
 
+       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) {
+               // FIXME: async
                code_offsets = g_new0 (gint32, nmethods * 2);
                offsets_len = 0;
                for (i = 0; i < nmethods; ++i) {
@@ -2736,6 +2842,20 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
                g_assert (offset < code_offsets [((pos + 1) * 2)]);
        method_index = code_offsets [(pos * 2) + 1];
 
+       /* In async mode, jinfo is not added to the normal jit info table, so have to cache it ourselves */
+       if (async) {
+               JitInfoMap *table = amodule->async_jit_info_table;
+               int len;
+
+               if (table) {
+                       len = table [0].method_index;
+                       for (i = 1; i < len; ++i) {
+                               if (table [i].method_index == method_index)
+                                       return table [i].jinfo;
+                       }
+               }
+       }
+
        code = &amodule->code [amodule->code_offsets [method_index]];
        ex_info = &amodule->blob [mono_aot_get_offset (amodule->ex_info_offsets, method_index)];
 
@@ -2747,54 +2867,55 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
        g_assert ((guint8*)code <= (guint8*)addr && (guint8*)addr < (guint8*)code + code_len);
 
        /* Might be a wrapper/extra method */
-       if (amodule->extra_methods) {
-               mono_aot_lock ();
-               method = g_hash_table_lookup (amodule->extra_methods, GUINT_TO_POINTER (method_index));
-               mono_aot_unlock ();
-       } else {
-               method = NULL;
-       }
-
-       if (!method) {
-               if (method_index >= image->tables [MONO_TABLE_METHOD].rows) {
-                       /* 
-                        * This is hit for extra methods which are called directly, so they are
-                        * not in amodule->extra_methods.
-                        */
-                       table_len = amodule->extra_method_info_offsets [0];
-                       table = amodule->extra_method_info_offsets + 1;
-                       left = 0;
-                       right = table_len;
-                       pos = 0;
-
-                       /* Binary search */
-                       while (TRUE) {
-                               pos = ((left + right) / 2);
+       if (!async) {
+               if (amodule->extra_methods) {
+                       amodule_lock (amodule);
+                       method = g_hash_table_lookup (amodule->extra_methods, GUINT_TO_POINTER (method_index));
+                       amodule_unlock (amodule);
+               } else {
+                       method = NULL;
+               }
 
-                               g_assert (pos < table_len);
+               if (!method) {
+                       if (method_index >= image->tables [MONO_TABLE_METHOD].rows) {
+                               /*
+                                * This is hit for extra methods which are called directly, so they are
+                                * not in amodule->extra_methods.
+                                */
+                               table_len = amodule->extra_method_info_offsets [0];
+                               table = amodule->extra_method_info_offsets + 1;
+                               left = 0;
+                               right = table_len;
+                               pos = 0;
+
+                               /* Binary search */
+                               while (TRUE) {
+                                       pos = ((left + right) / 2);
+
+                                       g_assert (pos < table_len);
+
+                                       if (table [pos * 2] < method_index)
+                                               left = pos + 1;
+                                       else if (table [pos * 2] > method_index)
+                                               right = pos;
+                                       else
+                                               break;
+                               }
 
-                               if (table [pos * 2] < method_index)
-                                       left = pos + 1;
-                               else if (table [pos * 2] > method_index)
-                                       right = pos;
-                               else
-                                       break;
+                               p = amodule->blob + table [(pos * 2) + 1];
+                               method = decode_resolve_method_ref (amodule, p, &p);
+                               if (!method)
+                                       /* Happens when a random address is passed in which matches a not-yey called wrapper encoded using its name */
+                                       return NULL;
+                       } else {
+                               token = mono_metadata_make_token (MONO_TABLE_METHOD, method_index + 1);
+                               method = mono_get_method (image, token, NULL);
                        }
-
-                       p = amodule->blob + table [(pos * 2) + 1];
-                       method = decode_resolve_method_ref (amodule, p, &p);
-                       if (!method)
-                               /* Happens when a random address is passed in which matches a not-yey called wrapper encoded using its name */
-                               return NULL;
-               } else {
-                       token = mono_metadata_make_token (MONO_TABLE_METHOD, method_index + 1);
-                       method = mono_get_method (image, token, NULL);
                }
+               /* FIXME: */
+               g_assert (method);
        }
 
-       /* FIXME: */
-       g_assert (method);
-
        //printf ("F: %s\n", mono_method_full_name (method, TRUE));
        
        jinfo = decode_exception_debug_info (amodule, domain, method, ex_info, addr, code, code_len);
@@ -2803,7 +2924,35 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
        g_assert ((guint8*)addr < (guint8*)jinfo->code_start + jinfo->code_size);
 
        /* Add it to the normal JitInfo tables */
-       mono_jit_info_table_add (domain, jinfo);
+       if (async) {
+               JitInfoMap *old_table, *new_table;
+               int len;
+
+               /*
+                * Use a simple inmutable table with linear search to cache async jit info entries.
+                * This assumes that the number of entries is small.
+                */
+               while (TRUE) {
+                       /* Copy the table, adding a new entry at the end */
+                       old_table = amodule->async_jit_info_table;
+                       if (old_table)
+                               len = old_table[0].method_index;
+                       else
+                               len = 1;
+                       new_table = alloc0_jit_info_data (domain, (len + 1) * sizeof (JitInfoMap), async);
+                       if (old_table)
+                               memcpy (new_table, old_table, len * sizeof (JitInfoMap));
+                       new_table [0].method_index = len + 1;
+                       new_table [len].method_index = method_index;
+                       new_table [len].jinfo = jinfo;
+                       /* Publish it */
+                       mono_memory_barrier ();
+                       if (InterlockedCompareExchangePointer ((gpointer)&amodule->async_jit_info_table, new_table, old_table) == old_table)
+                               break;
+               }
+       } else {
+               mono_jit_info_table_add (domain, jinfo);
+       }
        
        return jinfo;
 }
@@ -2820,7 +2969,8 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin
        case MONO_PATCH_INFO_METHOD:
        case MONO_PATCH_INFO_METHOD_JUMP:
        case MONO_PATCH_INFO_ICALL_ADDR:
-       case MONO_PATCH_INFO_METHOD_RGCTX: {
+       case MONO_PATCH_INFO_METHOD_RGCTX:
+       case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
                MethodRef ref;
                gboolean res;
 
@@ -2860,16 +3010,22 @@ 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)
                        goto cleanup;
                break;
-       case MONO_PATCH_INFO_CLASS_INIT:
        case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
-               ji->data.klass = decode_klass_ref (aot_module, p, &p);
-               if (!ji->data.klass)
+               ji->data.del_tramp = mono_mempool_alloc0 (mp, sizeof (MonoClassMethodPair));
+               ji->data.del_tramp->klass = decode_klass_ref (aot_module, p, &p);
+               if (!ji->data.del_tramp->klass)
                        goto cleanup;
+               if (decode_value (p, &p)) {
+                       ji->data.del_tramp->method = decode_resolve_method_ref (aot_module, p, &p);
+                       if (!ji->data.del_tramp->method)
+                               goto cleanup;
+               }
                break;
        case MONO_PATCH_INFO_IMAGE:
                ji->data.image = load_image (aot_module, decode_value (p, &p), TRUE);
@@ -2992,7 +3148,7 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin
                ji->data.target = GINT_TO_POINTER (decode_value (p, &p));
                break;
        case MONO_PATCH_INFO_GSHAREDVT_CALL: {
-               MonoJumpInfoGSharedVtCall *info = g_new0 (MonoJumpInfoGSharedVtCall, 1);
+               MonoJumpInfoGSharedVtCall *info = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoGSharedVtCall));
                info->sig = decode_signature (aot_module, p, &p);
                g_assert (info->sig);
                info->method = decode_resolve_method_ref (aot_module, p, &p);
@@ -3002,15 +3158,16 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin
                break;
        }
        case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
-               MonoGSharedVtMethodInfo *info = g_new0 (MonoGSharedVtMethodInfo, 1);
-               int i, nentries;
+               MonoGSharedVtMethodInfo *info = mono_mempool_alloc0 (mp, sizeof (MonoGSharedVtMethodInfo));
+               int i;
                
                info->method = decode_resolve_method_ref (aot_module, p, &p);
                g_assert (info->method);
-               nentries = decode_value (p, &p);
-               info->entries = g_ptr_array_new ();
-               for (i = 0; i < nentries; ++i) {
-                       MonoRuntimeGenericContextInfoTemplate *template = g_new0 (MonoRuntimeGenericContextInfoTemplate, 1);
+               info->num_entries = decode_value (p, &p);
+               info->count_entries = info->num_entries;
+               info->entries = mono_mempool_alloc0 (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
+               for (i = 0; i < info->num_entries; ++i) {
+                       MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
 
                        template->info_type = decode_value (p, &p);
                        switch (mini_rgctx_info_type_to_patch_info_type (template->info_type)) {
@@ -3030,8 +3187,6 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin
                                g_assert_not_reached ();
                                break;
                        }
-
-                       g_ptr_array_add (info->entries, template);
                }
                ji->data.target = info;
                break;
@@ -3171,10 +3326,17 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
                code = &amodule->code [amodule->code_offsets [method_index] + 1];
        }
 
-       mono_aot_lock ();
-       if (!amodule->methods_loaded)
-               amodule->methods_loaded = g_new0 (guint32, amodule->info.nmethods / 32 + 1);
-       mono_aot_unlock ();
+       if (!amodule->methods_loaded) {
+               amodule_lock (amodule);
+               if (!amodule->methods_loaded) {
+                       guint32 *loaded;
+
+                       loaded = g_new0 (guint32, amodule->info.nmethods / 32 + 1);
+                       mono_memory_barrier ();
+                       amodule->methods_loaded = loaded;
+               }
+               amodule_unlock (amodule);
+       }
 
        if ((amodule->methods_loaded [method_index / 32] >> (method_index % 32)) & 0x1)
                return code;
@@ -3271,7 +3433,7 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
                g_free (full_name);
        }
 
-       mono_aot_lock ();
+       amodule_lock (amodule);
 
        InterlockedIncrement (&mono_jit_stats.methods_aot);
 
@@ -3282,7 +3444,7 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
        if (method && method->wrapper_type)
                g_hash_table_insert (amodule->method_to_code, method, code);
 
-       mono_aot_unlock ();
+       amodule_unlock (amodule);
 
        if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION) {
                MonoJitInfo *jinfo;
@@ -3347,17 +3509,17 @@ find_extra_method_in_amodule (MonoAotModule *amodule, MonoMethod *method)
                p = amodule->blob + key;
                orig_p = p;
 
-               mono_aot_lock ();
+               amodule_lock (amodule);
                if (!amodule->method_ref_to_method)
                        amodule->method_ref_to_method = g_hash_table_new (NULL, NULL);
                m = g_hash_table_lookup (amodule->method_ref_to_method, p);
-               mono_aot_unlock ();
+               amodule_unlock (amodule);
                if (!m) {
                        m = decode_resolve_method_ref_with_target (amodule, method, p, &p);
                        if (m) {
-                               mono_aot_lock ();
+                               amodule_lock (amodule);
                                g_hash_table_insert (amodule->method_ref_to_method, orig_p, m);
-                               mono_aot_unlock ();
+                               amodule_unlock (amodule);
                        }
                }
                if (m == method) {
@@ -3496,9 +3658,9 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
                method_index = mono_metadata_token_index (method->token) - 1;
        } else if (method->is_inflated || !method->token) {
                /* This hash table is used to avoid the slower search in the extra_method_table in the AOT image */
-               mono_aot_lock ();
+               amodule_lock (amodule);
                code = g_hash_table_lookup (amodule->method_to_code, method);
-               mono_aot_unlock ();
+               amodule_unlock (amodule);
                if (code)
                        return code;
 
@@ -3512,15 +3674,8 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
                        MonoMethod *m = mono_aot_get_array_helper_from_wrapper (method);
 
                        code = mono_aot_get_method (domain, m);
-                       if (code) {
-                               if (mono_method_needs_static_rgctx_invoke (m, FALSE)) {
-                                       code = mono_create_static_rgctx_trampoline (m, mono_create_ftnptr (domain, code));
-                                       /* The call above returns an ftnptr */
-                                       code = mono_get_addr_from_ftnptr (code);
-                               }
-
+                       if (code)
                                return code;
-                       }
                }
 
                /*
@@ -3614,7 +3769,7 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
                                char *full_name;
 
                                full_name = mono_method_full_name (method, TRUE);
-                               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", full_name);
+                               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.", full_name);
                                g_free (full_name);
                        }
                        return NULL;
@@ -3624,11 +3779,11 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
                        return NULL;
 
                /* Needed by find_jit_info */
-               mono_aot_lock ();
+               amodule_lock (amodule);
                if (!amodule->extra_methods)
                        amodule->extra_methods = g_hash_table_new (NULL, NULL);
                g_hash_table_insert (amodule->extra_methods, GUINT_TO_POINTER (method_index), method);
-               mono_aot_unlock ();
+               amodule_unlock (amodule);
        } else {
                /* Common case */
                method_index = mono_metadata_token_index (method->token) - 1;
@@ -3827,7 +3982,7 @@ mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code
  *
  *   Initialize the PLT table of the AOT module. Called lazily when the first AOT
  * method in the module is loaded to avoid committing memory by writing to it.
- * LOCKING: Assumes the AOT lock is held.
+ * LOCKING: Assumes the AMODULE lock is held.
  */
 static void
 init_plt (MonoAotModule *amodule)
@@ -4147,14 +4302,16 @@ get_new_trampoline_from_page (int tramp_type)
        vm_address_t addr, taddr;
        kern_return_t ret;
        vm_prot_t prot, max_prot;
-       int psize;
+       int psize, specific_trampoline_size;
        unsigned char *code;
 
+       specific_trampoline_size = 2 * sizeof (gpointer);
+
        mono_aot_page_lock ();
        page = trampoline_pages [tramp_type];
        if (page && page->trampolines < page->trampolines_end) {
                code = page->trampolines;
-               page->trampolines += 8;
+               page->trampolines += specific_trampoline_size;
                mono_aot_page_unlock ();
                return code;
        }
@@ -4167,6 +4324,8 @@ get_new_trampoline_from_page (int tramp_type)
        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)
@@ -4210,7 +4369,7 @@ get_new_trampoline_from_page (int tramp_type)
                /* some other thread already allocated, so use that to avoid wasting memory */
                if (page && page->trampolines < page->trampolines_end) {
                        code = page->trampolines;
-                       page->trampolines += 8;
+                       page->trampolines += specific_trampoline_size;
                        mono_aot_page_unlock ();
                        vm_deallocate (mach_task_self (), addr, psize);
                        vm_deallocate (mach_task_self (), taddr, psize);
@@ -4322,7 +4481,7 @@ get_numerous_trampoline (MonoAotTrampoline tramp_type, int n_got_slots, MonoAotM
        *out_amodule = amodule;
 
 #ifdef MONOTOUCH
-#define        MONOTOUCH_TRAMPOLINES_ERROR ". See http://docs.xamarin.com/ios/troubleshooting for instruction on how to fix this condition"
+#define        MONOTOUCH_TRAMPOLINES_ERROR ". See http://docs.xamarin.com/ios/troubleshooting for instructions on how to fix this condition."
 #else
 #define        MONOTOUCH_TRAMPOLINES_ERROR ""
 #endif