2009-05-11 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-compiler.c
index ac61601b8b53031b477aa0807b34375065f6cfb8..2f231bb48780579f7b1b6dfa4b66b69c9efbe87c 100644 (file)
 
 #include <errno.h>
 #include <sys/stat.h>
-#include <limits.h>    /* for PAGESIZE */
-#ifndef PAGESIZE
-#define PAGESIZE 4096
-#endif
 
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/class.h>
 #include <mono/metadata/monitor.h>
 #include <mono/metadata/mempool-internals.h>
 #include <mono/metadata/mono-endian.h>
+#include <mono/metadata/threads-types.h>
 #include <mono/utils/mono-logger.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-time.h>
+#include <mono/utils/mono-mmap.h>
 
 #include "mini.h"
 #include "image-writer.h"
 #include "dwarfwriter.h"
 
-#ifndef DISABLE_AOT
+#if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
 
 #define TV_DECLARE(name) gint64 name
 #define TV_GETTIME(tv) tv = mono_100ns_ticks ()
@@ -99,13 +97,15 @@ typedef struct MonoAotOptions {
        gboolean static_link;
        gboolean asm_only;
        gboolean asm_writer;
+       gboolean nodebug;
        int nthreads;
+       int ntrampolines;
        gboolean print_skipped_methods;
 } MonoAotOptions;
 
 typedef struct MonoAotStats {
        int ccount, mcount, lmfcount, abscount, gcount, ocount, genericcount;
-       int code_size, info_size, ex_info_size, got_size, class_info_size, got_info_size, got_info_offsets_size;
+       int code_size, info_size, ex_info_size, unwind_info_size, got_size, class_info_size, got_info_size, got_info_offsets_size;
        int methods_without_got_slots, direct_calls, all_calls;
        int got_slots;
        int got_slot_types [MONO_PATCH_INFO_NONE];
@@ -130,13 +130,16 @@ typedef struct MonoAotCompile {
        GPtrArray *globals;
        GList *method_order;
        guint32 *plt_got_info_offsets;
-       /* Number of trampolines emitted into the AOT file */
-       guint32 num_aot_trampolines;
        guint32 got_offset, plt_offset, plt_got_offset_base;
        /* Number of GOT entries reserved for trampolines */
        guint32 num_trampoline_got_entries;
-       guint32 trampoline_got_offset_base;
+       guint32 num_specific_trampolines;
        guint32 specific_trampoline_size;
+       guint32 specific_trampoline_got_offset_base;
+       /* Same for static rgctx trampolines */
+       guint32 num_static_rgctx_trampolines;
+       guint32 static_rgctx_trampoline_size;
+       guint32 static_rgctx_trampoline_got_offset_base;
        MonoAotOptions aot_opts;
        guint32 nmethods;
        guint32 opts;
@@ -151,6 +154,9 @@ typedef struct MonoAotCompile {
        FILE *fp;
        char *tmpfname;
        GSList *cie_program;
+       GHashTable *unwind_info_offsets;
+       GPtrArray *unwind_ops;
+       guint32 unwind_info_offset;
 } MonoAotCompile;
 
 #define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
@@ -174,7 +180,7 @@ static const gint16 opidx [] = {
 #undef PATCH_INFO
 };
 
-static const char*
+static G_GNUC_UNUSED const char*
 get_patch_name (int info)
 {
        return (const char*)&opstr + opidx [info];
@@ -196,9 +202,6 @@ get_patch_name (int info)
 
 #endif
 
-static void
-emit_global (MonoAotCompile *acfg, const char *name, gboolean func);
-
 /* Wrappers around the image writer functions */
 
 static inline void
@@ -411,7 +414,7 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 
 /* ARCHITECTURE SPECIFIC CODE */
 
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM)
 #define EMIT_DWARF_INFO 1
 #endif
 
@@ -424,12 +427,12 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 static void
 arch_emit_direct_call (MonoAotCompile *acfg, const char *target, int *call_size)
 {
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
        /* Need to make sure this is exactly 5 bytes long */
        emit_byte (acfg, '\xe8');
        emit_symbol_diff (acfg, target, ".", -4);
        *call_size = 5;
-#elif defined(__arm__)
+#elif defined(TARGET_ARM)
        if (acfg->use_bin_writer) {
                guint8 buf [4];
                guint8 *code;
@@ -449,6 +452,24 @@ arch_emit_direct_call (MonoAotCompile *acfg, const char *target, int *call_size)
 #endif
 }
 
+#ifdef MONO_ARCH_AOT_SUPPORTED
+/*
+ * arch_emit_got_offset:
+ *
+ *   The memory pointed to by CODE should hold native code for computing the GOT
+ * address. Emit this code while patching it with the offset between code and
+ * the GOT. CODE_SIZE is set to the number of bytes emitted.
+ */
+static void
+arch_emit_got_offset (MonoAotCompile *acfg, guint8 *code, int *code_size)
+{
+       guint32 offset = mono_arch_get_patch_offset (code);
+       emit_bytes (acfg, code, offset);
+       emit_symbol_diff (acfg, "got", ".", offset);
+
+       *code_size = offset + 4;
+}
+
 /*
  * arch_emit_got_access:
  *
@@ -463,11 +484,11 @@ arch_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *cod
        emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
 
        /* Emit the offset */
-#ifdef __x86_64__
+#ifdef TARGET_AMD64
        emit_symbol_diff (acfg, "got", ".", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
-#elif defined(__i386__)
+#elif defined(TARGET_X86)
        emit_int32 (acfg, (unsigned int) ((got_slot * sizeof (gpointer))));
-#elif defined(__arm__)
+#elif defined(TARGET_ARM)
        emit_symbol_diff (acfg, "got", ".", (unsigned int) ((got_slot * sizeof (gpointer))) - 12);
 #else
        g_assert_not_reached ();
@@ -476,6 +497,8 @@ arch_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *cod
        *code_size = mono_arch_get_patch_offset (code) + 4;
 }
 
+#endif
+
 /*
  * arch_emit_plt_entry:
  *
@@ -484,7 +507,7 @@ arch_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *cod
 static void
 arch_emit_plt_entry (MonoAotCompile *acfg, int index)
 {
-#if defined(__i386__)
+#if defined(TARGET_X86)
                if (index == 0) {
                        /* It is filled up during loading by the AOT loader. */
                        emit_zero_bytes (acfg, 16);
@@ -494,7 +517,7 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                        emit_symbol_diff (acfg, "plt", ".", -4);
                        emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
                }
-#elif defined(__x86_64__)
+#elif defined(TARGET_AMD64)
                /*
                 * We can't emit jumps because they are 32 bits only so they can't be patched.
                 * So we make indirect calls through GOT entries which are patched by the AOT 
@@ -507,7 +530,7 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                emit_symbol_diff (acfg, "got", ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) -4);
                /* Used by mono_aot_get_plt_info_offset */
                emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
-#elif defined(__arm__)
+#elif defined(TARGET_ARM)
                guint8 buf [256];
                guint8 *code;
 
@@ -566,7 +589,7 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
         *   loading the argument from there.
         * - all the trampolines should be of the same length.
         */
-#if defined(__x86_64__)
+#if defined(TARGET_AMD64)
        /* This should be exactly 16 bytes long */
        *tramp_size = 16;
        /* call *<offset>(%rip) */
@@ -577,7 +600,7 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
        /* This should be relative to the start of the trampoline */
        emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4 + 19);
        emit_zero_bytes (acfg, 5);
-#elif defined(__arm__)
+#elif defined(TARGET_ARM)
        guint8 buf [128];
        guint8 *code;
 
@@ -612,7 +635,7 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
 static void
 arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGenericSharingContext *gsctx, const char *call_target)
 {
-#if defined(__x86_64__)
+#if defined(TARGET_AMD64)
        guint8 buf [32];
        guint8 *code;
        int this_reg;
@@ -625,7 +648,7 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGeneri
        /* jump <method> */
        emit_byte (acfg, '\xe9');
        emit_symbol_diff (acfg, call_target, ".", -4);
-#elif defined(__arm__)
+#elif defined(TARGET_ARM)
        guint8 buf [128];
        guint8 *code;
        int this_pos = 0;
@@ -639,15 +662,75 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGeneri
 
        emit_bytes (acfg, buf, code - buf);
        /* jump to method */
-       if (acfg->use_bin_writer)
-               g_assert_not_reached ();
-       else
+       if (acfg->use_bin_writer) {
+               guint8 buf [4];
+               guint8 *code;
+
+               code = buf;
+               ARM_B (code, 0);
+
+               img_writer_emit_reloc (acfg->w, R_ARM_JUMP24, call_target, -8);
+               emit_bytes (acfg, buf, 4);
+       } else {
                fprintf (acfg->fp, "\n\tb %s\n", call_target);
+       }
 #else
        g_assert_not_reached ();
 #endif
 }
 
+/*
+ * arch_emit_static_rgctx_trampoline:
+ *
+ *   Emit code for a static rgctx trampoline. OFFSET is the offset of the first of
+ * two GOT slots which contain the rgctx argument, and the method to jump to.
+ * TRAMP_SIZE is set to the size of the emitted trampoline.
+ * These kinds of trampolines cannot be enumerated statically, since there could
+ * be one trampoline per method instantiation, so we emit the same code for all
+ * trampolines, and parameterize them using two GOT slots.
+ */
+static void
+arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+#if defined(TARGET_AMD64)
+       /* This should be exactly 13 bytes long */
+       *tramp_size = 13;
+
+       /* mov <OFFSET>(%rip), %r10 */
+       emit_byte (acfg, '\x4d');
+       emit_byte (acfg, '\x8b');
+       emit_byte (acfg, '\x15');
+       emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4);
+
+       /* jmp *<offset>(%rip) */
+       emit_byte (acfg, '\xff');
+       emit_byte (acfg, '\x25');
+       emit_symbol_diff (acfg, "got", ".", ((offset + 1) * sizeof (gpointer)) - 4);
+#elif defined(TARGET_ARM)
+       guint8 buf [128];
+       guint8 *code;
+
+       /* This should be exactly 24 bytes long */
+       *tramp_size = 24;
+       code = buf;
+       /* Load rgctx value */
+       ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 8);
+       ARM_LDR_REG_REG (code, MONO_ARCH_RGCTX_REG, ARMREG_PC, ARMREG_R1);
+       /* Load branch addr + branch */
+       ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 4);
+       ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_R1);
+
+       g_assert (code - buf == 16);
+
+       /* Emit it */
+       emit_bytes (acfg, buf, code - buf);
+       emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4 + 8);
+       emit_symbol_diff (acfg, "got", ".", ((offset + 1) * sizeof (gpointer)) - 4 + 4);
+#else
+       g_assert_not_reached ();
+#endif
+}      
+
 /*
  * arch_get_cie_program:
  *
@@ -656,7 +739,7 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGeneri
 static GSList*
 arch_get_cie_program (void)
 {
-#ifdef __x86_64__
+#ifdef TARGET_AMD64
        GSList *l = NULL;
 
        mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, AMD64_RSP, 8);
@@ -798,20 +881,20 @@ encode_klass_ref (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, guint8 **
                encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, p, &p);
                encode_value (get_image_index (acfg, klass->image), p, &p);
        } else if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR)) {
-               MonoGenericParam *param = klass->byval_arg.data.generic_param;
+               MonoGenericContainer *container = mono_type_get_generic_param_owner (&klass->byval_arg);
+               g_assert (container);
 
                /* Marker */
                encode_value (MONO_TOKEN_TYPE_SPEC, p, &p);
                encode_value (klass->byval_arg.type, p, &p);
 
-               encode_value (param->num, p, &p);
+               encode_value (mono_type_get_generic_param_num (&klass->byval_arg), p, &p);
                
-               g_assert (param->owner);
-               encode_value (param->owner->is_method, p, &p);
-               if (param->owner->is_method)
-                       encode_method_ref (acfg, param->owner->owner.method, p, &p);
+               encode_value (container->is_method, p, &p);
+               if (container->is_method)
+                       encode_method_ref (acfg, container->owner.method, p, &p);
                else
-                       encode_klass_ref (acfg, param->owner->owner.klass, p, &p);
+                       encode_klass_ref (acfg, container->owner.klass, p, &p);
        } else {
                /* Array class */
                g_assert (klass->rank > 0);
@@ -965,11 +1048,13 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                                g_assert_not_reached ();
                        break;
                case MONO_WRAPPER_STATIC_RGCTX_INVOKE:
-               case MONO_WRAPPER_SYNCHRONIZED: {
+               case MONO_WRAPPER_SYNCHRONIZED:
+               case MONO_WRAPPER_MANAGED_TO_NATIVE: {
                        MonoMethod *m;
 
                        m = mono_marshal_method_from_wrapper (method);
                        g_assert (m);
+                       g_assert (m != method);
                        encode_method_ref (acfg, m, p, &p);
                        break;
                }
@@ -1098,41 +1183,6 @@ is_plt_patch (MonoJumpInfo *patch_info)
        }
 }
 
-static gboolean 
-is_got_patch (MonoJumpInfoType patch_type)
-{
-       return TRUE;
-}
-
-/*
- * is_shared_got_patch:
- *
- *   Return whenever PATCH_INFO refers to a patch which needs a shared GOT
- * entry.
- * Keep it in sync with the version in aot-runtime.c.
- */
-static inline gboolean
-is_shared_got_patch (MonoJumpInfo *patch_info)
-{
-       switch (patch_info->type) {
-       case MONO_PATCH_INFO_VTABLE:
-       case MONO_PATCH_INFO_CLASS:
-       case MONO_PATCH_INFO_IID:
-       case MONO_PATCH_INFO_ADJUSTED_IID:
-       case MONO_PATCH_INFO_FIELD:
-       case MONO_PATCH_INFO_SFLDA:
-       case MONO_PATCH_INFO_DECLSEC:
-       case MONO_PATCH_INFO_LDTOKEN:
-       case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
-       case MONO_PATCH_INFO_RVA:
-       case MONO_PATCH_INFO_METHODCONST:
-       case MONO_PATCH_INFO_IMAGE:
-               return TRUE;
-       default:
-               return FALSE;
-       }
-}
-
 static int
 get_plt_offset (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
 {
@@ -1285,7 +1335,7 @@ get_runtime_invoke_sig (MonoMethodSignature *sig)
 
        mb = mono_mb_new (mono_defaults.object_class, "FOO", MONO_WRAPPER_NONE);
        m = mono_mb_create_method (mb, sig, 16);
-       return mono_marshal_get_runtime_invoke (m);
+       return mono_marshal_get_runtime_invoke (m, FALSE);
 }
 
 static void
@@ -1360,6 +1410,9 @@ add_wrappers (MonoAotCompile *acfg)
        csig->params [1] = &mono_defaults.boolean_class->byval_arg;
        add_method (acfg, get_runtime_invoke_sig (csig));
 
+       /* runtime-invoke used by finalizers */
+       add_method (acfg, mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE));
+
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
                MonoMethod *method;
                guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
@@ -1387,7 +1440,7 @@ add_wrappers (MonoAotCompile *acfg)
                }
 
                if (!skip)
-                       add_method (acfg, mono_marshal_get_runtime_invoke (method));
+                       add_method (acfg, mono_marshal_get_runtime_invoke (method, FALSE));
        }
 
        if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
@@ -1436,8 +1489,7 @@ add_wrappers (MonoAotCompile *acfg)
 
                sig = mono_method_signature (method);
 
-               if (sig->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
-                       !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+               if (sig->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class)) {
                        m = mono_marshal_get_remoting_invoke_with_check (method);
 
                        add_method (acfg, m);
@@ -1475,23 +1527,6 @@ add_wrappers (MonoAotCompile *acfg)
                        add_method (acfg, mono_marshal_get_synchronized_wrapper (method));
        }
 
-#if 0
-       /* static rgctx wrappers */
-       /* FIXME: Each wrapper belongs to a given instantiation of a generic method */
-       for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
-               token = MONO_TOKEN_METHOD_DEF | (i + 1);
-               method = mono_get_method (acfg->image, token, NULL);
-
-               if (((method->flags & METHOD_ATTRIBUTE_STATIC) ||
-                        (method->is_inflated && mono_method_get_context (method)->method_inst)) &&
-                       mono_class_generic_sharing_enabled (method->klass) &&
-                       mono_method_is_generic_sharable_impl (method, FALSE)) {
-                       m = mono_marshal_get_static_rgctx_invoke (method);
-                       add_method (acfg, m);
-               }
-       }
-#endif
-
        /* pinvoke wrappers */
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
                MonoMethod *method;
@@ -1592,6 +1627,46 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
                 */
                add_extra_method (acfg, method);
        }
+
+       /* 
+        * For ICollection<T>, where T is a vtype, add instances of the helper methods
+        * in Array, since a T[] could be cast to ICollection<T>.
+        */
+       if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") &&
+               (!strcmp(klass->name, "ICollection`1") || !strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IList`1") || !strcmp (klass->name, "IEnumerator`1")) &&
+               MONO_TYPE_ISSTRUCT (klass->generic_class->context.class_inst->type_argv [0])) {
+               MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+               MonoClass *array_class = mono_bounded_array_class_get (tclass, 1, FALSE);
+               gpointer iter;
+               char *name_prefix;
+
+               if (!strcmp (klass->name, "IEnumerator`1"))
+                       name_prefix = g_strdup_printf ("%s.%s", klass->name_space, "IEnumerable`1");
+               else
+                       name_prefix = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
+
+               /* Add the T[]/InternalEnumerator class */
+               if (!strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IEnumerator`1")) {
+                       MonoClass *nclass;
+
+                       iter = NULL;
+                       while ((nclass = mono_class_get_nested_types (array_class->parent, &iter))) {
+                               if (!strcmp (nclass->name, "InternalEnumerator`1"))
+                                       break;
+                       }
+                       g_assert (nclass);
+                       nclass = mono_class_inflate_generic_class (nclass, mono_generic_class_get_context (klass->generic_class));
+                       add_generic_class (acfg, nclass);
+               }
+
+               iter = NULL;
+               while ((method = mono_class_get_methods (array_class, &iter))) {
+                       if (strstr (method->name, name_prefix))
+                               add_extra_method (acfg, method);
+               }
+
+               g_free (name_prefix);
+       }
 }
 
 /*
@@ -1605,6 +1680,8 @@ add_generic_instances (MonoAotCompile *acfg)
        int i;
        guint32 token;
        MonoMethod *method;
+       MonoMethodHeader *header;
+       MonoMethodSignature *sig;
        MonoGenericContext *context;
 
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHODSPEC].rows; ++i) {
@@ -1637,6 +1714,29 @@ add_generic_instances (MonoAotCompile *acfg)
 
                add_generic_class (acfg, klass);
        }
+
+       /* Add types of args/locals */
+       for (i = 0; i < acfg->methods->len; ++i) {
+               int j;
+
+               method = g_ptr_array_index (acfg->methods, i);
+
+               sig = mono_method_signature (method);
+
+               if (sig) {
+                       for (j = 0; j < sig->param_count; ++j)
+                               if (sig->params [j]->type == MONO_TYPE_GENERICINST)
+                                       add_generic_class (acfg, mono_class_from_mono_type (sig->params [j]));
+               }
+
+               header = mono_method_get_header (method);
+
+               if (header) {
+                       for (j = 0; j < header->num_locals; ++j)
+                               if (header->locals [j]->type == MONO_TYPE_GENERICINST)
+                                       add_generic_class (acfg, mono_class_from_mono_type (header->locals [j]));
+               }
+       }
 }
 
 /*
@@ -1688,18 +1788,14 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                        case MONO_PATCH_INFO_NONE:
                                break;
                        case MONO_PATCH_INFO_GOT_OFFSET: {
-                               guint32 offset = mono_arch_get_patch_offset (code + i);
-                               emit_bytes (acfg, code + i, offset);
-                               emit_symbol_diff (acfg, "got", ".", offset);
-
-                               i += offset + 4 - 1;
+                               int code_size;
+                               arch_emit_got_offset (acfg, code + i, &code_size);
+                               i += code_size - 1;
                                skip = TRUE;
                                break;
                        }
                        default: {
-                               if (!is_got_patch (patch_info->type))
-                                       break;
-
                                /*
                                 * If this patch is a call, try emitting a direct call instead of
                                 * through a PLT entry. This is possible if the called method is in
@@ -1801,7 +1897,7 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
        emit_alignment (acfg, func_alignment);
        emit_label (acfg, symbol);
 
-       if (acfg->aot_opts.write_symbols && acfg->use_bin_writer) {
+       if (acfg->aot_opts.write_symbols && !acfg->aot_opts.nodebug && acfg->use_bin_writer) {
                char *full_name;
                /* Emit a local symbol into the symbol table */
                full_name = mono_method_full_name (method, TRUE);
@@ -1949,7 +2045,7 @@ static void
 encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, int first_got_offset, guint8 *buf, guint8 **endbuf)
 {
        guint8 *p = buf;
-       guint32 last_offset, j, pindex;
+       guint32 pindex;
        MonoJumpInfo *patch_info;
 
        encode_value (n_patches, p, &p);
@@ -1957,32 +2053,15 @@ encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, int
        if (n_patches)
                encode_value (first_got_offset, p, &p);
 
-       /* First encode the type+position table */
-       last_offset = 0;
-       j = 0;
        for (pindex = 0; pindex < patches->len; ++pindex) {
-               guint32 offset;
                patch_info = g_ptr_array_index (patches, pindex);
-               
+
                if (patch_info->type == MONO_PATCH_INFO_NONE)
                        /* Nothing to do */
                        continue;
 
-               j ++;
-               //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
-               offset = patch_info->ip.i - last_offset;
-               last_offset = patch_info->ip.i;
-
-               /* Only the type is needed */
-               *p = patch_info->type;
-               p++;
-       }
-
-       /* Then encode the other info */
-       for (pindex = 0; pindex < patches->len; ++pindex) {
-               patch_info = g_ptr_array_index (patches, pindex);
-
-               if (is_shared_got_patch (patch_info)) {
+               encode_value (patch_info->type, p, &p);
+               if (mono_aot_is_shared_got_patch (patch_info)) {
                        guint32 offset = get_got_offset (acfg, patch_info);
                        encode_value (offset, p, &p);
                } else {
@@ -2091,6 +2170,39 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        g_free (buf);
 }
 
+static guint32
+get_unwind_info_offset (MonoAotCompile *acfg, guint8 *encoded, guint32 encoded_len)
+{
+       guint32 cache_index;
+       guint32 offset;
+
+       /* Reuse the unwind module to canonize and store unwind info entries */
+       cache_index = mono_cache_unwind_info (encoded, encoded_len);
+
+       /* Use +/- 1 to distinguish 0s from missing entries */
+       offset = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->unwind_info_offsets, GUINT_TO_POINTER (cache_index + 1)));
+       if (offset)
+               return offset - 1;
+       else {
+               guint8 buf [16];
+               guint8 *p;
+
+               /* 
+                * It would be easier to use assembler symbols, but the caller needs an
+                * offset now.
+                */
+               offset = acfg->unwind_info_offset;
+               g_hash_table_insert (acfg->unwind_info_offsets, GUINT_TO_POINTER (cache_index + 1), GUINT_TO_POINTER (offset + 1));
+               g_ptr_array_add (acfg->unwind_ops, GUINT_TO_POINTER (cache_index));
+
+               p = buf;
+               encode_value (encoded_len, p, &p);
+
+               acfg->unwind_info_offset += encoded_len + (p - buf);
+               return offset;
+       }
+}
+
 static void
 emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
 {
@@ -2114,7 +2226,12 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        /* Make the labels local */
        sprintf (symbol, ".Le_%x_p", method_index);
 
-       mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
+       if (!acfg->aot_opts.nodebug) {
+               mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
+       } else {
+               debug_info = NULL;
+               debug_info_size = 0;
+       }
 
        buf_size = header->num_clauses * 256 + debug_info_size + 1024;
        p = buf = g_malloc (buf_size);
@@ -2137,9 +2254,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                 * section cannot be accessed using the dl interface.
                 */
                encoded = mono_unwind_ops_encode (cfg->unwind_ops, &encoded_len);
-               encode_value (encoded_len, p, &p);
-               memcpy (p, encoded, encoded_len);
-               p += encoded_len;
+               encode_value (get_unwind_info_offset (acfg, encoded, encoded_len), p, &p);
                g_free (encoded);
        } else {
                encode_value (jinfo->used_regs, p, &p);
@@ -2290,9 +2405,9 @@ emit_plt (MonoAotCompile *acfg)
 
        emit_section_change (acfg, ".text", 0);
        emit_global (acfg, symbol, TRUE);
-#ifdef __i386__
+#ifdef TARGET_X86
        /* This section will be made read-write by the AOT loader */
-       emit_alignment (acfg, PAGESIZE);
+       emit_alignment (acfg, mono_pagesize ());
 #else
        emit_alignment (acfg, 16);
 #endif
@@ -2316,7 +2431,7 @@ emit_plt (MonoAotCompile *acfg)
 }
 
 static G_GNUC_UNUSED void
-emit_named_code (MonoAotCompile *acfg, const char *name, guint8 *code, 
+emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code, 
                                 guint32 code_size, int got_offset, MonoJumpInfo *ji, GSList *unwind_ops)
 {
        char symbol [256];
@@ -2373,7 +2488,8 @@ emit_named_code (MonoAotCompile *acfg, const char *name, guint8 *code,
                sprintf (symbol, "%s", name);
                sprintf (symbol2, ".Lnamed_%s", name);
 
-               mono_dwarf_writer_emit_trampoline (acfg->dwarf, symbol, symbol2, NULL, NULL, code_size, unwind_ops);
+               if (acfg->dwarf)
+                       mono_dwarf_writer_emit_trampoline (acfg->dwarf, symbol, symbol2, NULL, NULL, code_size, unwind_ops);
        }
 }
 
@@ -2391,7 +2507,7 @@ static void
 emit_trampolines (MonoAotCompile *acfg)
 {
        char symbol [256];
-       int i, offset;
+       int i, tramp_got_offset;
 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
        int tramp_type;
        guint32 code_size;
@@ -2422,100 +2538,142 @@ emit_trampolines (MonoAotCompile *acfg)
 
                        sprintf (symbol, "generic_trampoline_%d", tramp_type);
 
-                       emit_named_code (acfg, symbol, code, code_size, acfg->got_offset, ji, unwind_ops);
+                       emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, unwind_ops);
                }
 
                code = mono_arch_get_nullified_class_init_trampoline (&code_size);
-               emit_named_code (acfg, "nullified_class_init_trampoline", code, code_size, acfg->got_offset, NULL, NULL);
-#if defined(__x86_64__) && defined(MONO_ARCH_MONITOR_OBJECT_REG)
+               emit_trampoline (acfg, "nullified_class_init_trampoline", code, code_size, acfg->got_offset, NULL, NULL);
+#if defined(TARGET_AMD64) && defined(MONO_ARCH_MONITOR_OBJECT_REG)
                code = mono_arch_create_monitor_enter_trampoline_full (&code_size, &ji, TRUE);
-               emit_named_code (acfg, "monitor_enter_trampoline", code, code_size, acfg->got_offset, ji, NULL);
+               emit_trampoline (acfg, "monitor_enter_trampoline", code, code_size, acfg->got_offset, ji, NULL);
                code = mono_arch_create_monitor_exit_trampoline_full (&code_size, &ji, TRUE);
-               emit_named_code (acfg, "monitor_exit_trampoline", code, code_size, acfg->got_offset, ji, NULL);
+               emit_trampoline (acfg, "monitor_exit_trampoline", code, code_size, acfg->got_offset, ji, NULL);
 #endif
 
                code = mono_arch_create_generic_class_init_trampoline_full (&code_size, &ji, TRUE);
-               emit_named_code (acfg, "generic_class_init_trampoline", code, code_size, acfg->got_offset, ji, NULL);
+               emit_trampoline (acfg, "generic_class_init_trampoline", code, code_size, acfg->got_offset, ji, NULL);
 
                /* Emit the exception related code pieces */
                code = mono_arch_get_restore_context_full (&code_size, &ji, TRUE);
-               emit_named_code (acfg, "restore_context", code, code_size, acfg->got_offset, ji, NULL);
+               emit_trampoline (acfg, "restore_context", code, code_size, acfg->got_offset, ji, NULL);
                code = mono_arch_get_call_filter_full (&code_size, &ji, TRUE);
-               emit_named_code (acfg, "call_filter", code, code_size, acfg->got_offset, ji, NULL);
+               emit_trampoline (acfg, "call_filter", code, code_size, acfg->got_offset, ji, NULL);
                code = mono_arch_get_throw_exception_full (&code_size, &ji, TRUE);
-               emit_named_code (acfg, "throw_exception", code, code_size, acfg->got_offset, ji, NULL);
+               emit_trampoline (acfg, "throw_exception", code, code_size, acfg->got_offset, ji, NULL);
                code = mono_arch_get_rethrow_exception_full (&code_size, &ji, TRUE);
-               emit_named_code (acfg, "rethrow_exception", code, code_size, acfg->got_offset, ji, NULL);
+               emit_trampoline (acfg, "rethrow_exception", code, code_size, acfg->got_offset, ji, NULL);
                code = mono_arch_get_throw_exception_by_name_full (&code_size, &ji, TRUE);
-               emit_named_code (acfg, "throw_exception_by_name", code, code_size, acfg->got_offset, ji, NULL);
+               emit_trampoline (acfg, "throw_exception_by_name", code, code_size, acfg->got_offset, ji, NULL);
                code = mono_arch_get_throw_corlib_exception_full (&code_size, &ji, TRUE);
-               emit_named_code (acfg, "throw_corlib_exception", code, code_size, acfg->got_offset, ji, NULL);
+               emit_trampoline (acfg, "throw_corlib_exception", code, code_size, acfg->got_offset, ji, NULL);
 
-#if defined(__x86_64__)
+#if defined(TARGET_AMD64)
                code = mono_arch_get_throw_pending_exception_full (&code_size, &ji, TRUE);
-               emit_named_code (acfg, "throw_pending_exception", code, code_size, acfg->got_offset, ji, NULL);
+               emit_trampoline (acfg, "throw_pending_exception", code, code_size, acfg->got_offset, ji, NULL);
 #endif
 
-#if defined(__x86_64__) || defined(__arm__)
+#if defined(TARGET_AMD64) || defined(TARGET_ARM)
                for (i = 0; i < 128; ++i) {
                        int offset;
 
                        offset = MONO_RGCTX_SLOT_MAKE_RGCTX (i);
                        code = mono_arch_create_rgctx_lazy_fetch_trampoline_full (offset, &code_size, &ji, TRUE);
                        sprintf (symbol, "rgctx_fetch_trampoline_%u", offset);
-                       emit_named_code (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL);
+                       emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL);
 
                        offset = MONO_RGCTX_SLOT_MAKE_MRGCTX (i);
                        code = mono_arch_create_rgctx_lazy_fetch_trampoline_full (offset, &code_size, &ji, TRUE);
                        sprintf (symbol, "rgctx_fetch_trampoline_%u", offset);
-                       emit_named_code (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL);
+                       emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL);
                }
 #endif
+
+#if defined(TARGET_AMD64) || defined(TARGET_ARM)
+               {
+                       GSList *l;
+
+                       /* delegate_invoke_impl trampolines */
+                       l = mono_arch_get_delegate_invoke_impls ();
+                       while (l) {
+                               MonoAotTrampInfo *info = l->data;
+
+                               emit_trampoline (acfg, info->name, info->code, info->code_size, acfg->got_offset, NULL, NULL);
+                               l = l->next;
+                       }
+               }
 #endif
 
+#endif /* #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES */
+
                /*
                 * FIXME: Maybe we should use more specific trampolines (i.e. one class init for
                 * each class).
                 */
 
                /* Reserve some entries at the end of the GOT for our use */
-               acfg->num_trampoline_got_entries = acfg->num_aot_trampolines * 2;
+               acfg->num_trampoline_got_entries = (acfg->num_specific_trampolines * 2) + (acfg->num_static_rgctx_trampolines * 2);
 
-               sprintf (symbol, "trampolines");
+               sprintf (symbol, "specific_trampolines");
 
                emit_section_change (acfg, ".text", 0);
                emit_global (acfg, symbol, TRUE);
                emit_alignment (acfg, 16);
                emit_label (acfg, symbol);
 
-               for (i = 0; i < acfg->num_aot_trampolines; ++i) {
-                       int tramp_size = 0;
+               tramp_got_offset = acfg->got_offset;
+
+               acfg->specific_trampoline_got_offset_base = tramp_got_offset;
 
-                       offset = acfg->got_offset + (i * 2);
+               for (i = 0; i < acfg->num_specific_trampolines; ++i) {
+                       int tramp_size = 0;
 
-                       arch_emit_specific_trampoline (acfg, offset, &tramp_size);
+                       arch_emit_specific_trampoline (acfg, tramp_got_offset, &tramp_size);
                        if (!acfg->specific_trampoline_size) {
                                g_assert (tramp_size);
                                acfg->specific_trampoline_size = tramp_size;
                        }
+
+                       tramp_got_offset += 2;
+               }
+
+               sprintf (symbol, "static_rgctx_trampolines");
+
+               emit_section_change (acfg, ".text", 0);
+               emit_global (acfg, symbol, TRUE);
+               emit_alignment (acfg, 16);
+               emit_label (acfg, symbol);
+
+               acfg->static_rgctx_trampoline_got_offset_base = tramp_got_offset;
+
+               for (i = 0; i < acfg->num_static_rgctx_trampolines; ++i) {
+                       int tramp_size = 0;
+
+                       arch_emit_static_rgctx_trampoline (acfg, tramp_got_offset, &tramp_size);
+                       if (!acfg->static_rgctx_trampoline_size) {
+                               g_assert (tramp_size);
+                               acfg->static_rgctx_trampoline_size = tramp_size;
+                       }
+
+                       tramp_got_offset += 2;
                }
        }
 
        /* Unbox trampolines */
-
-       for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
-               MonoMethod *method;
-               guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
+       for (i = 0; i < acfg->methods->len; ++i) {
+               MonoMethod *method = g_ptr_array_index (acfg->methods, i);
                MonoCompile *cfg;
                char call_target [256];
 
-               method = mono_get_method (acfg->image, token, NULL);
-
                cfg = g_hash_table_lookup (acfg->method_to_cfg, method);
                if (!cfg || !cfg->orig_method->klass->valuetype || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL))
                        continue;
 
-               sprintf (symbol, "unbox_trampoline_%d", i);
+               if (!method->wrapper_type && !method->is_inflated) {
+                       g_assert (method->token);
+                       sprintf (symbol, "ut_%d", mono_metadata_token_index (method->token) - 1);
+               } else {
+                       sprintf (symbol, "ut_e_%d", get_method_index (acfg, method));
+               }
 
                emit_section_change (acfg, ".text", 0);
                emit_global (acfg, symbol, TRUE);
@@ -2526,8 +2684,6 @@ emit_trampolines (MonoAotCompile *acfg)
                arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
        }
 
-       acfg->trampoline_got_offset_base = acfg->got_offset;
-
        acfg->got_offset += acfg->num_trampoline_got_entries;
 }
 
@@ -2561,15 +2717,6 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->bind_to_runtime_version = TRUE;
                } else if (str_begins_with (arg, "full")) {
                        opts->full_aot = TRUE;
-                       /*
-                        * The no-dlsym option is only useful on the iphone, and even there,
-                        * do to other limitations of the dynamic linker, it doesn't seem to
-                        * work. So disable it for now so we don't have to support it.
-                        */
-                       /*
-               } else if (str_begins_with (arg, "no-dlsym")) {
-                       opts->no_dlsym = TRUE;
-                       */
                } else if (str_begins_with (arg, "threads=")) {
                        opts->nthreads = atoi (arg + strlen ("threads="));
                } else if (str_begins_with (arg, "static")) {
@@ -2579,6 +2726,10 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->asm_only = TRUE;
                } else if (str_begins_with (arg, "asmwriter")) {
                        opts->asm_writer = TRUE;
+               } else if (str_begins_with (arg, "nodebug")) {
+                       opts->nodebug = TRUE;
+               } else if (str_begins_with (arg, "ntrampolines=")) {
+                       opts->ntrampolines = atoi (arg + strlen ("ntrampolines="));
                } else {
                        fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
                        exit (1);
@@ -3057,7 +3208,7 @@ alloc_got_slots (MonoAotCompile *acfg)
                        MonoCompile *cfg = acfg->cfgs [i];
 
                        for (ji = cfg->patch_info; ji; ji = ji->next) {
-                               if (is_shared_got_patch (ji))
+                               if (mono_aot_is_shared_got_patch (ji))
                                        get_shared_got_offset (acfg, ji);
                        }
                }
@@ -3155,6 +3306,29 @@ emit_info (MonoAotCompile *acfg)
        emit_line (acfg);
 }
 
+#endif /* #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) */
+
+/*
+ * mono_aot_str_hash:
+ *
+ * Hash function for strings which we use to hash strings for things which are
+ * saved in the AOT image, since g_str_hash () can change.
+ */
+guint
+mono_aot_str_hash (gconstpointer v1)
+{
+       /* Same as g_str_hash () in glib */
+       char *p = (char *) v1;
+       guint hash = *p;
+
+       while (*p++) {
+               if (*p)
+                       hash = (hash << 5) - hash + *p;
+       }
+
+       return hash;
+} 
+
 /*
  * mono_aot_method_hash:
  *
@@ -3166,17 +3340,96 @@ mono_aot_method_hash (MonoMethod *method)
        guint32 hash;
 
        if (method->wrapper_type) {
-               hash = g_str_hash (method->name);
+               hash = mono_aot_str_hash (method->name);
        } else {
                char *full_name = mono_method_full_name (method, TRUE);
                // FIXME: Improve this (changing this requires bumping MONO_AOT_FILE_VERSION)
-               hash = g_str_hash (full_name);
+               hash = mono_aot_str_hash (full_name);
                g_free (full_name);
        }
 
        return hash;
 }
+
+/*
+ * mono_aot_wrapper_name:
+ *
+ *   Return a string which uniqely identifies the given wrapper method.
+ */
+char*
+mono_aot_wrapper_name (MonoMethod *method)
+{
+       char *name, *tmpsig, *klass_desc;
+
+       tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
+
+       switch (method->wrapper_type) {
+       case MONO_WRAPPER_RUNTIME_INVOKE:
+       case MONO_WRAPPER_DELEGATE_INVOKE:
+       case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
+       case MONO_WRAPPER_DELEGATE_END_INVOKE:
+               /* This is a hack to work around the fact that runtime invoke wrappers get assigned to some random class */
+               name = g_strdup_printf ("%s (%s)", method->name, tmpsig);
+               break;
+       default:
+               klass_desc = mono_type_full_name (&method->klass->byval_arg);
+
+               name = g_strdup_printf ("%s:%s (%s)", klass_desc, method->name, tmpsig);
+               break;
+       }
+
+       g_free (tmpsig);
+
+       return name;
+}
+
+/*
+ * mono_aot_tramp_info_create:
+ *
+ *   Create a MonoAotTrampInfo structure from the arguments.
+ */
+MonoAotTrampInfo*
+mono_aot_tramp_info_create (char *name, guint8 *code, guint32 code_size)
+{
+       MonoAotTrampInfo *info = g_new0 (MonoAotTrampInfo, 1);
+
+       info->name = name;
+       info->code = code;
+       info->code_size = code_size;
+
+       return info;
+}
+
+/*
+ * mono_is_shared_got_patch:
+ *
+ *   Return whenever PATCH_INFO refers to a patch which needs a shared GOT
+ * entry.
+ */
+gboolean
+mono_aot_is_shared_got_patch (MonoJumpInfo *patch_info)
+{
+       switch (patch_info->type) {
+       case MONO_PATCH_INFO_VTABLE:
+       case MONO_PATCH_INFO_CLASS:
+       case MONO_PATCH_INFO_IID:
+       case MONO_PATCH_INFO_ADJUSTED_IID:
+       case MONO_PATCH_INFO_FIELD:
+       case MONO_PATCH_INFO_SFLDA:
+       case MONO_PATCH_INFO_DECLSEC:
+       case MONO_PATCH_INFO_LDTOKEN:
+       case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+       case MONO_PATCH_INFO_RVA:
+       case MONO_PATCH_INFO_METHODCONST:
+       case MONO_PATCH_INFO_IMAGE:
+               return TRUE;
+       default:
+               return FALSE;
+       }
+}
+
+#if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
+
 typedef struct HashEntry {
     guint32 key, value, index;
        struct HashEntry *next;
@@ -3213,6 +3466,7 @@ emit_extra_methods (MonoAotCompile *acfg)
        for (i = 0; i < acfg->extra_methods->len; ++i) {
                MonoMethod *method = g_ptr_array_index (acfg->extra_methods, i);
                MonoCompile *cfg = g_hash_table_lookup (acfg->method_to_cfg, method);
+               char *name;
 
                if (!cfg)
                        continue;
@@ -3220,31 +3474,27 @@ emit_extra_methods (MonoAotCompile *acfg)
                nmethods ++;
                info_offsets [i] = p - buf;
 
+               name = NULL;
                if (method->wrapper_type) {
-                       char *name;
-
-                       // FIXME: Optimize disk usage
-                       if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
-                               char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
-                               name = g_strdup_printf ("(wrapper runtime-invoke):%s (%s)", method->name, tmpsig);
-                               g_free (tmpsig);
-                       } else if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
-                               char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
-                               name = g_strdup_printf ("(wrapper delegate-invoke):%s (%s)", method->name, tmpsig);
-                               g_free (tmpsig);
-                       } else if (method->wrapper_type == MONO_WRAPPER_DELEGATE_BEGIN_INVOKE) {
-                               char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
-                               name = g_strdup_printf ("(wrapper delegate-begin-invoke):%s (%s)", method->name, tmpsig);
-                               g_free (tmpsig);
-                       } else if (method->wrapper_type == MONO_WRAPPER_DELEGATE_END_INVOKE) {
-                               char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
-                               name = g_strdup_printf ("(wrapper delegate-end-invoke):%s (%s)", method->name, tmpsig);
-                               g_free (tmpsig);
-                       } else {
-                               name = mono_method_full_name (cfg->orig_method, TRUE);
+                       /* 
+                        * We encode some wrappers using their name, since encoding them
+                        * directly would be difficult. This also avoids creating the wrapper
+                        * methods at runtime, since they are not needed anyway.
+                        */
+                       switch (method->wrapper_type) {
+                       case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
+                       case MONO_WRAPPER_SYNCHRONIZED:
+                               /* encode_method_ref () can handle these */
+                               break;
+                       default:
+                               name = mono_aot_wrapper_name (method);
+                               break;
                        }
+               }
 
+               if (name) {
                        encode_value (1, p, &p);
+                       encode_value (method->wrapper_type, p, &p);
                        strcpy ((char*)p, name);
                        p += strlen (name ) + 1;
                        g_free (name);
@@ -3449,10 +3699,46 @@ emit_exception_info (MonoAotCompile *acfg)
 }
 
 static void
-emit_class_info (MonoAotCompile *acfg)
+emit_unwind_info (MonoAotCompile *acfg)
 {
        int i;
-       char symbol [256];
+       char symbol [128];
+
+       /* 
+        * The unwind info contains a lot of duplicates so we emit each unique
+        * entry once, and only store the offset from the start of the table in the
+        * exception info.
+        */
+
+       sprintf (symbol, "unwind_info");
+       emit_section_change (acfg, ".text", 1);
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+       emit_global (acfg, symbol, FALSE);
+
+       for (i = 0; i < acfg->unwind_ops->len; ++i) {
+               guint32 index = GPOINTER_TO_UINT (g_ptr_array_index (acfg->unwind_ops, i));
+               guint8 *unwind_info;
+               guint32 unwind_info_len;
+               guint8 buf [16];
+               guint8 *p;
+
+               unwind_info = mono_get_cached_unwind_info (index, &unwind_info_len);
+
+               p = buf;
+               encode_value (unwind_info_len, p, &p);
+               emit_bytes (acfg, buf, p - buf);
+               emit_bytes (acfg, unwind_info, unwind_info_len);
+
+               acfg->stats.unwind_info_size += (p - buf) + unwind_info_len;
+       }
+}
+
+static void
+emit_class_info (MonoAotCompile *acfg)
+{
+       int i;
+       char symbol [256];
 
        sprintf (symbol, "class_info");
        emit_section_change (acfg, ".text", 1);
@@ -3503,7 +3789,7 @@ emit_class_name_table (MonoAotCompile *acfg)
                token = MONO_TOKEN_TYPE_DEF | (i + 1);
                klass = mono_class_get (acfg->image, token);
                full_name = mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME);
-               hash = g_str_hash (full_name) % table_size;
+               hash = mono_aot_str_hash (full_name) % table_size;
                g_free (full_name);
 
                /* FIXME: Allocate from the mempool */
@@ -3675,6 +3961,13 @@ emit_got (MonoAotCompile *acfg)
        emit_label (acfg, symbol);
        if (acfg->got_offset > 0)
                emit_zero_bytes (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
+
+       sprintf (symbol, "mono_aot_got_addr");
+       emit_section_change (acfg, ".data", 0);
+       emit_global (acfg, symbol, FALSE);
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+       emit_pointer (acfg, "got");
 }
 
 static void
@@ -3701,20 +3994,16 @@ emit_globals (MonoAotCompile *acfg)
                emit_string_symbol (acfg, "mono_runtime_version", "");
        }
 
-       /*
-        * Some platforms like the iphone have no working dlsym (). To work around this,
-        * we create an ELF ctor function which will be invoked by dlopen, and which
-        * will call a function in the AOT loader to register the symbols used by the
-        * image.
+       /* 
         * When static linking, we emit a global which will point to the symbol table.
         */
-       if (acfg->aot_opts.no_dlsym) {
+       if (acfg->aot_opts.static_link) {
                int i;
                char symbol [256];
+               char *p;
 
-               if (acfg->aot_opts.static_link)
-                       /* Emit a string holding the assembly name */
-                       emit_string_symbol (acfg, "mono_aot_assembly_name", acfg->image->assembly->aname.name);
+               /* Emit a string holding the assembly name */
+               emit_string_symbol (acfg, "mono_aot_assembly_name", acfg->image->assembly->aname.name);
 
                /* Emit the names */
                for (i = 0; i < acfg->globals->len; ++i) {
@@ -3743,101 +4032,45 @@ emit_globals (MonoAotCompile *acfg)
                        emit_pointer (acfg, symbol);
                }
                /* Null terminate the table */
-               emit_pointer (acfg, NULL);
-               emit_pointer (acfg, NULL);
+               emit_int32 (acfg, 0);
+               emit_int32 (acfg, 0);
 
-#if 0
-               if (acfg->aot_opts.static_link) {
-                       char *p;
-
-                       /* 
-                        * Emit a global symbol which can be passed by an embedding app to
-                        * mono_aot_register_module ().
-                        */
+               /* 
+                * Emit a global symbol which can be passed by an embedding app to
+                * mono_aot_register_module ().
+                */
 #if defined(__MACH__)
-                       sprintf (symbol, "_mono_aot_module_%s_info", acfg->image->assembly->aname.name);
+               sprintf (symbol, "_mono_aot_module_%s_info", acfg->image->assembly->aname.name);
 #else
-                       sprintf (symbol, "mono_aot_module_%s_info", acfg->image->assembly->aname.name);
+               sprintf (symbol, "mono_aot_module_%s_info", acfg->image->assembly->aname.name);
 #endif
 
-                       /* Get rid of characters which cannot occur in symbols */
-                       p = symbol;
-                       for (p = symbol; *p; ++p) {
-                               if (!(isalnum (*p) || *p == '_'))
-                                       *p = '_';
-                       }
-                       acfg->static_linking_symbol = g_strdup (symbol);
-                       emit_global_inner (acfg, symbol, FALSE);
-                       emit_alignment (acfg, 8);
-                       emit_label (acfg, symbol);
-                       emit_pointer (acfg, "globals");
-               } else {
-                       sprintf (symbol, "init_%s", acfg->image->assembly->aname.name);
-                       emit_section_change (acfg, ".text", 1);
-                       emit_alignment (acfg, 8);
-                       emit_label (acfg, symbol);
-                       if (acfg->use_bin_writer)
-                               g_assert_not_reached ();
-#ifdef __x86_64__
-                       fprintf (acfg->fp, "leaq globals(%%rip), %%rdi\n");
-                       fprintf (acfg->fp, "call mono_aot_register_globals@PLT\n");
-                       fprintf (acfg->fp, "ret\n");
-                       fprintf (acfg->fp, ".section .ctors,\"aw\",@progbits\n");
-                       emit_alignment (acfg, 8);
-                       emit_pointer (acfg, symbol);
-#elif defined(__arm__) && defined(__MACH__)
-                               
-                       fprintf (acfg->fp, ".text\n");
-                       fprintf (acfg->fp, ".align   3\n");
-               
-                       fprintf (acfg->fp, "ldr r0, .L5\n");
-                       fprintf (acfg->fp, ".LPIC0:\n");
-                       fprintf (acfg->fp, "add r0, pc, r0\n");
-                       fprintf (acfg->fp, "ldr r0, [r0]\n");
-                       fprintf (acfg->fp, "b   _mono_aot_register_globals@PLT\n");
-                       fprintf (acfg->fp, ".align 2\n");
-
-                       fprintf (acfg->fp, ".L5:\n");
-                       fprintf (acfg->fp, ".long       globals_ptr-(.LPIC0+8)\n");
-                       
-                       fprintf (acfg->fp, ".data\n");
-                       fprintf (acfg->fp, ".align      2\n");
-                       fprintf (acfg->fp, "globals_ptr:\n");
-                       fprintf (acfg->fp, ".long       globals\n");
-                       
-                       fprintf (acfg->fp, ".mod_init_func\n");
-                       fprintf (acfg->fp, ".align      2\n");
-                       fprintf (acfg->fp, ".long       %s@target1\n", symbol);
-
-#elif defined(__arm__)
-                       /* 
-                        * Taken from gcc generated code for:
-                        * static int i;
-                        * void foo () { bar (&i); }
-                        * gcc --shared -fPIC -O2
-                        */
-                       fprintf (acfg->fp, "ldr r3, .L5\n");
-                       fprintf (acfg->fp, "ldr r0, .L5+4\n");
-                       fprintf (acfg->fp, ".LPIC0:\n");
-                       fprintf (acfg->fp, "add r3, pc, r3\n");
-                       fprintf (acfg->fp, "add r0, r3, r0\n");
-                       fprintf (acfg->fp, "b   mono_aot_register_globals(PLT)\n");
-
-                       fprintf (acfg->fp, ".L5:\n");
-                       fprintf (acfg->fp, ".word       _GLOBAL_OFFSET_TABLE_-(.LPIC0+8)\n");
-                       fprintf (acfg->fp, ".word       globals(GOTOFF)\n");
-
-                       fprintf (acfg->fp, ".section    .init_array,\"aw\",%%init_array\n");
-                       fprintf (acfg->fp, ".align      2\n");
-                       fprintf (acfg->fp, ".word       %s(target1)\n", symbol);
-#else
-                       g_assert_not_reached ();
-#endif
+               /* Get rid of characters which cannot occur in symbols */
+               p = symbol;
+               for (p = symbol; *p; ++p) {
+                       if (!(isalnum (*p) || *p == '_'))
+                               *p = '_';
                }
-#endif
+               acfg->static_linking_symbol = g_strdup (symbol);
+               emit_global_inner (acfg, symbol, FALSE);
+               emit_alignment (acfg, 8);
+               emit_label (acfg, symbol);
+               emit_pointer (acfg, "globals");
        }
 }
 
+static void
+emit_mem_end (MonoAotCompile *acfg)
+{
+       char symbol [128];
+
+       sprintf (symbol, "mem_end");
+       emit_section_change (acfg, ".text", 1);
+       emit_global (acfg, symbol, FALSE);
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+}
+
 /*
  * Emit a structure containing all the information not stored elsewhere.
  */
@@ -3854,18 +4087,16 @@ emit_file_info (MonoAotCompile *acfg)
 
        /* The data emitted here must match MonoAotFileInfo in aot-runtime.c. */
        emit_int32 (acfg, acfg->plt_got_offset_base);
-       emit_int32 (acfg, acfg->trampoline_got_offset_base);
-       emit_int32 (acfg, acfg->num_aot_trampolines);
        emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
        emit_int32 (acfg, acfg->plt_offset);
+       emit_int32 (acfg, acfg->num_specific_trampolines);
        emit_int32 (acfg, acfg->specific_trampoline_size);
-       emit_pointer (acfg, "got");
+       emit_int32 (acfg, acfg->specific_trampoline_got_offset_base);
+       emit_int32 (acfg, acfg->num_static_rgctx_trampolines);
+       emit_int32 (acfg, acfg->static_rgctx_trampoline_size);
+       emit_int32 (acfg, acfg->static_rgctx_trampoline_got_offset_base);
 }
 
-/*****************************************/
-/*   Emitting DWARF debug information    */
-/*****************************************/
-
 static void
 emit_dwarf_info (MonoAotCompile *acfg)
 {
@@ -3888,13 +4119,113 @@ emit_dwarf_info (MonoAotCompile *acfg)
 #endif
 }
 
+static void
+collect_methods (MonoAotCompile *acfg)
+{
+       int i;
+       MonoImage *image = acfg->image;
+
+       /* Collect methods */
+       for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
+               MonoMethod *method;
+               guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
+
+               method = mono_get_method (acfg->image, token, NULL);
+
+               if (!method) {
+                       printf ("Failed to load method 0x%x from '%s'.\n", token, image->name);
+                       exit (1);
+               }
+                       
+               /* Load all methods eagerly to skip the slower lazy loading code */
+               mono_class_setup_methods (method->klass);
+
+               if (acfg->aot_opts.full_aot && method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
+                       /* Compile the wrapper instead */
+                       /* We do this here instead of add_wrappers () because it is easy to do it here */
+                       MonoMethod *wrapper = mono_marshal_get_native_wrapper (method, check_for_pending_exc, TRUE);
+                       method = wrapper;
+               }
+
+               /* Since we add the normal methods first, their index will be equal to their zero based token index */
+               add_method_with_index (acfg, method, i);
+               acfg->method_index ++;
+       }
+
+       add_generic_instances (acfg);
+
+       if (acfg->aot_opts.full_aot)
+               add_wrappers (acfg);
+}
+
+static void
+compile_methods (MonoAotCompile *acfg)
+{
+       int i, methods_len;
+
+       if (acfg->aot_opts.nthreads > 0) {
+               GPtrArray *frag;
+               int len, j;
+               GPtrArray *threads;
+               HANDLE handle;
+               gpointer *user_data;
+               MonoMethod **methods;
+
+               methods_len = acfg->methods->len;
+
+               len = acfg->methods->len / acfg->aot_opts.nthreads;
+               g_assert (len > 0);
+               /* 
+                * Partition the list of methods into fragments, and hand it to threads to
+                * process.
+                */
+               threads = g_ptr_array_new ();
+               /* Make a copy since acfg->methods is modified by compile_method () */
+               methods = g_new0 (MonoMethod*, methods_len);
+               //memcpy (methods, g_ptr_array_index (acfg->methods, 0), sizeof (MonoMethod*) * methods_len);
+               for (i = 0; i < methods_len; ++i)
+                       methods [i] = g_ptr_array_index (acfg->methods, i);
+               i = 0;
+               while (i < methods_len) {
+                       frag = g_ptr_array_new ();
+                       for (j = 0; j < len; ++j) {
+                               if (i < methods_len) {
+                                       g_ptr_array_add (frag, methods [i]);
+                                       i ++;
+                               }
+                       }
+
+                       user_data = g_new0 (gpointer, 3);
+                       user_data [0] = mono_domain_get ();
+                       user_data [1] = acfg;
+                       user_data [2] = frag;
+                       
+                       handle = mono_create_thread (NULL, 0, (gpointer)compile_thread_main, user_data, 0, NULL);
+                       g_ptr_array_add (threads, handle);
+               }
+               g_free (methods);
+
+               for (i = 0; i < threads->len; ++i) {
+                       WaitForSingleObjectEx (g_ptr_array_index (threads, i), INFINITE, FALSE);
+               }
+       } else {
+               methods_len = 0;
+       }
+
+       /* Compile methods added by compile_method () or all methods if nthreads == 0 */
+       for (i = methods_len; i < acfg->methods->len; ++i) {
+               /* This can new methods to acfg->methods */
+               compile_method (acfg, g_ptr_array_index (acfg->methods, i));
+       }
+}
+
 static int
 compile_asm (MonoAotCompile *acfg)
 {
        char *command, *objfile;
        char *outfile_name, *tmp_outfile_name;
 
-#if defined(__x86_64__)
+#if defined(TARGET_AMD64)
 #define AS_OPTIONS "--64"
 #elif defined(sparc) && SIZEOF_VOID_P == 8
 #define AS_OPTIONS "-xarch=v9"
@@ -3942,20 +4273,13 @@ compile_asm (MonoAotCompile *acfg)
        tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
 
 #if defined(sparc)
-       command = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, acfg->tmpfname);
+       command = g_strdup_printf ("ld -shared -G -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
 #elif defined(__ppc__) && defined(__MACH__)
-       command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, acfg->tmpfname);
+       command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
 #elif defined(PLATFORM_WIN32)
-       command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", outfile_name, acfg->tmpfname);
+       command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
 #else
-       if (acfg->aot_opts.no_dlsym) {
-               /* 
-                * Need to link using gcc so our ctor function gets called.
-                */
-               command = g_strdup_printf ("gcc -shared -o %s %s.o", outfile_name, acfg->tmpfname);
-       } else {
-               command = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, acfg->tmpfname);
-       }
+       command = g_strdup_printf ("ld -shared -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
 #endif
        printf ("Executing the native linker: %s\n", command);
        if (system (command) != 0) {
@@ -3973,6 +4297,22 @@ compile_asm (MonoAotCompile *acfg)
        system (com);
        g_free (com);*/
 
+#if defined(TARGET_ARM) && !defined(__MACH__)
+       /* 
+        * gas generates 'mapping symbols' each time code and data is mixed, which 
+        * happens a lot in emit_and_reloc_code (), so we need to get rid of them.
+        */
+       command = g_strdup_printf ("strip --strip-symbol=\\$a --strip-symbol=\\$d %s", tmp_outfile_name);
+       printf ("Stripping the binary: %s\n", command);
+       if (system (command) != 0) {
+               g_free (tmp_outfile_name);
+               g_free (outfile_name);
+               g_free (command);
+               g_free (objfile);
+               return 1;
+       }
+#endif
+
        rename (tmp_outfile_name, outfile_name);
 
        g_free (tmp_outfile_name);
@@ -3987,6 +4327,35 @@ compile_asm (MonoAotCompile *acfg)
        return 0;
 }
 
+static MonoAotCompile*
+acfg_create (MonoAssembly *ass, guint32 opts)
+{
+       MonoImage *image = ass->image;
+       MonoAotCompile *acfg;
+
+       acfg = g_new0 (MonoAotCompile, 1);
+       acfg->methods = g_ptr_array_new ();
+       acfg->method_indexes = g_hash_table_new (NULL, NULL);
+       acfg->plt_offset_to_patch = g_hash_table_new (NULL, NULL);
+       acfg->patch_to_plt_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
+       acfg->patch_to_shared_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
+       acfg->shared_patches = g_ptr_array_new ();
+       acfg->method_to_cfg = g_hash_table_new (NULL, NULL);
+       acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, g_free);
+       acfg->image_hash = g_hash_table_new (NULL, NULL);
+       acfg->image_table = g_ptr_array_new ();
+       acfg->globals = g_ptr_array_new ();
+       acfg->image = image;
+       acfg->opts = opts;
+       acfg->mempool = mono_mempool_new ();
+       acfg->extra_methods = g_ptr_array_new ();
+       acfg->unwind_info_offsets = g_hash_table_new (NULL, NULL);
+       acfg->unwind_ops = g_ptr_array_new ();
+       InitializeCriticalSection (&acfg->mutex);
+
+       return acfg;
+}
+
 static void
 acfg_free (MonoAotCompile *acfg)
 {
@@ -4002,6 +4371,7 @@ acfg_free (MonoAotCompile *acfg)
        g_ptr_array_free (acfg->shared_patches, TRUE);
        g_ptr_array_free (acfg->image_table, TRUE);
        g_ptr_array_free (acfg->globals, TRUE);
+       g_ptr_array_free (acfg->unwind_ops, TRUE);
        g_hash_table_destroy (acfg->method_indexes);
        g_hash_table_destroy (acfg->plt_offset_to_patch);
        g_hash_table_destroy (acfg->patch_to_plt_offset);
@@ -4009,6 +4379,7 @@ acfg_free (MonoAotCompile *acfg)
        g_hash_table_destroy (acfg->method_to_cfg);
        g_hash_table_destroy (acfg->token_info_hash);
        g_hash_table_destroy (acfg->image_hash);
+       g_hash_table_destroy (acfg->unwind_info_offsets);
        mono_mempool_destroy (acfg->mempool);
        g_free (acfg);
 }
@@ -4017,8 +4388,7 @@ int
 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 {
        MonoImage *image = ass->image;
-       char symbol [256];
-       int i, res, methods_len;
+       int res;
        MonoAotCompile *acfg;
        char *outfile_name, *tmp_outfile_name;
        TV_DECLARE (atv);
@@ -4026,37 +4396,16 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
 
-       acfg = g_new0 (MonoAotCompile, 1);
-       acfg->methods = g_ptr_array_new ();
-       acfg->method_indexes = g_hash_table_new (NULL, NULL);
-       acfg->plt_offset_to_patch = g_hash_table_new (NULL, NULL);
-       acfg->patch_to_plt_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
-       acfg->patch_to_shared_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
-       acfg->shared_patches = g_ptr_array_new ();
-       acfg->method_to_cfg = g_hash_table_new (NULL, NULL);
-       acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, g_free);
-       acfg->image_hash = g_hash_table_new (NULL, NULL);
-       acfg->image_table = g_ptr_array_new ();
-       acfg->globals = g_ptr_array_new ();
-       acfg->image = image;
-       acfg->opts = opts;
-       acfg->mempool = mono_mempool_new ();
-       acfg->extra_methods = g_ptr_array_new ();
-       InitializeCriticalSection (&acfg->mutex);
+       acfg = acfg_create (ass, opts);
 
        memset (&acfg->aot_opts, 0, sizeof (acfg->aot_opts));
        acfg->aot_opts.write_symbols = TRUE;
+       acfg->aot_opts.ntrampolines = 10240;
 
        mono_aot_parse_options (aot_options, &acfg->aot_opts);
 
        //acfg->aot_opts.print_skipped_methods = TRUE;
 
-#ifdef __arm__
-       if (acfg->aot_opts.full_aot)
-               /* arch_emit_unbox_trampoline () etc only works with the asm writer */
-               acfg->aot_opts.asm_writer = TRUE;
-#endif
-
 #ifndef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
        if (acfg->aot_opts.full_aot) {
                printf ("--aot=full is not supported on this platform.\n");
@@ -4064,6 +4413,9 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        }
 #endif
 
+       if (acfg->aot_opts.static_link)
+               acfg->aot_opts.asm_writer = TRUE;
+
        if (!acfg->aot_opts.asm_only && !acfg->aot_opts.asm_writer && bin_writer_supported ()) {
                if (acfg->aot_opts.outfile)
                        outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
@@ -4092,52 +4444,23 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
                acfg->w = img_writer_create (acfg->fp, FALSE);
                
-               /* hush compiler warnings about these being possibly uninitialized */
                tmp_outfile_name = NULL;
                outfile_name = NULL;
        }
 
        load_profile_files (acfg);
 
-       img_writer_emit_start (acfg->w);
-
-       acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL);
+       if (!acfg->aot_opts.nodebug)
+               acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL);
 
-       acfg->num_aot_trampolines = acfg->aot_opts.full_aot ? 10240 : 0;
+       acfg->num_specific_trampolines = acfg->aot_opts.full_aot ? acfg->aot_opts.ntrampolines : 0;
+#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
+       acfg->num_static_rgctx_trampolines = acfg->aot_opts.full_aot ? 1024 : 0;
+#endif
 
        acfg->method_index = 1;
 
-       /* Collect methods */
-       for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
-               MonoMethod *method;
-               guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
-
-               method = mono_get_method (acfg->image, token, NULL);
-
-               if (!method) {
-                       printf ("Failed to load method 0x%x from '%s'.\n", token, image->name);
-                       exit (1);
-               }
-                       
-               /* Load all methods eagerly to skip the slower lazy loading code */
-               mono_class_setup_methods (method->klass);
-
-               if (acfg->aot_opts.full_aot && method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
-                       /* Compile the wrapper instead */
-                       /* We do this here instead of add_wrappers () because it is easy to do it here */
-                       MonoMethod *wrapper = mono_marshal_get_native_wrapper (method, check_for_pending_exc, TRUE);
-                       method = wrapper;
-               }
-
-               /* Since we add the normal methods first, their index will be equal to their zero based token index */
-               add_method_with_index (acfg, method, i);
-               acfg->method_index ++;
-       }
-
-       add_generic_instances (acfg);
-
-       if (acfg->aot_opts.full_aot)
-               add_wrappers (acfg);
+       collect_methods (acfg);
 
        acfg->cfgs_size = acfg->methods->len + 32;
        acfg->cfgs = g_new0 (MonoCompile*, acfg->cfgs_size);
@@ -4145,74 +4468,23 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        /* PLT offset 0 is reserved for the PLT trampoline */
        acfg->plt_offset = 1;
 
-       /* Compile methods */
        TV_GETTIME (atv);
 
-       if (acfg->aot_opts.nthreads > 0) {
-               GPtrArray *frag;
-               int len, j;
-               GPtrArray *threads;
-               HANDLE handle;
-               gpointer *user_data;
-               MonoMethod **methods;
-
-               methods_len = acfg->methods->len;
-
-               len = acfg->methods->len / acfg->aot_opts.nthreads;
-               g_assert (len > 0);
-               /* 
-                * Partition the list of methods into fragments, and hand it to threads to
-                * process.
-                */
-               threads = g_ptr_array_new ();
-               /* Make a copy since acfg->methods is modified by compile_method () */
-               methods = g_new0 (MonoMethod*, methods_len);
-               //memcpy (methods, g_ptr_array_index (acfg->methods, 0), sizeof (MonoMethod*) * methods_len);
-               for (i = 0; i < methods_len; ++i)
-                       methods [i] = g_ptr_array_index (acfg->methods, i);
-               i = 0;
-               while (i < methods_len) {
-                       frag = g_ptr_array_new ();
-                       for (j = 0; j < len; ++j) {
-                               if (i < methods_len) {
-                                       g_ptr_array_add (frag, methods [i]);
-                                       i ++;
-                               }
-                       }
-
-                       user_data = g_new0 (gpointer, 3);
-                       user_data [0] = mono_domain_get ();
-                       user_data [1] = acfg;
-                       user_data [2] = frag;
-                       
-                       handle = CreateThread (NULL, 0, (gpointer)compile_thread_main, user_data, 0, NULL);
-                       g_ptr_array_add (threads, handle);
-               }
-               g_free (methods);
-
-               for (i = 0; i < threads->len; ++i) {
-                       WaitForSingleObjectEx (g_ptr_array_index (threads, i), INFINITE, FALSE);
-               }
-       } else {
-               methods_len = 0;
-       }
-
-       /* Compile methods added by compile_method () or all methods if nthreads == 0 */
-       for (i = methods_len; i < acfg->methods->len; ++i) {
-               /* This can new methods to acfg->methods */
-               compile_method (acfg, g_ptr_array_index (acfg->methods, i));
-       }
+       compile_methods (acfg);
 
        TV_GETTIME (btv);
+
        acfg->stats.jit_time = TV_ELAPSED (atv, btv);
 
        TV_GETTIME (atv);
 
-       mono_dwarf_writer_emit_base_info (acfg->dwarf, arch_get_cie_program ());
-
        alloc_got_slots (acfg);
 
+       img_writer_emit_start (acfg->w);
+
+       if (acfg->dwarf)
+               mono_dwarf_writer_emit_base_info (acfg->dwarf, arch_get_cie_program ());
+
        emit_code (acfg);
 
        emit_info (acfg);
@@ -4229,6 +4501,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        emit_exception_info (acfg);
 
+       emit_unwind_info (acfg);
+
        emit_class_info (acfg);
 
        emit_plt (acfg);
@@ -4241,19 +4515,16 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        emit_globals (acfg);
 
-       emit_dwarf_info (acfg);
+       if (acfg->dwarf)
+               emit_dwarf_info (acfg);
 
-       sprintf (symbol, "mem_end");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
+       emit_mem_end (acfg);
 
        TV_GETTIME (btv);
 
        acfg->stats.gen_time = TV_ELAPSED (atv, btv);
 
-       printf ("Code: %d Info: %d Ex Info: %d Class Info: %d PLT: %d GOT Info: %d GOT Info Offsets: %d GOT: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_info_size, acfg->stats.class_info_size, acfg->plt_offset, acfg->stats.got_info_size, acfg->stats.got_info_offsets_size, (int)(acfg->got_offset * sizeof (gpointer)));
+       printf ("Code: %d Info: %d Ex Info: %d Unwind Info: %d Class Info: %d PLT: %d GOT Info: %d GOT Info Offsets: %d GOT: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_info_size, acfg->stats.unwind_info_size, acfg->stats.class_info_size, acfg->plt_offset, acfg->stats.got_info_size, acfg->stats.got_info_offsets_size, (int)(acfg->got_offset * sizeof (gpointer)));
 
        TV_GETTIME (atv);
        res = img_writer_emit_writeout (acfg->w);
@@ -4284,12 +4555,15 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
        printf ("Methods without GOT slots: %d (%d%%)\n", acfg->stats.methods_without_got_slots, acfg->stats.mcount ? (acfg->stats.methods_without_got_slots * 100) / acfg->stats.mcount : 100);
        printf ("Direct calls: %d (%d%%)\n", acfg->stats.direct_calls, acfg->stats.all_calls ? (acfg->stats.direct_calls * 100) / acfg->stats.all_calls : 100);
-       printf ("JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000);
 
+       /*
        printf ("GOT slot distribution:\n");
        for (i = 0; i < MONO_PATCH_INFO_NONE; ++i)
                if (acfg->stats.got_slot_types [i])
                        printf ("\t%s: %d\n", get_patch_name (i), acfg->stats.got_slot_types [i]);
+       */
+
+       printf ("JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000);
 
        acfg_free (acfg);
        
@@ -4322,20 +4596,14 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 */
 
 static MonoDwarfWriter *xdebug_writer;
-static CRITICAL_SECTION xdebug_mutex;
 static FILE *xdebug_fp;
 
-#define mono_xdebug_lock(acfg) EnterCriticalSection (&xdebug_mutex)
-#define mono_xdebug_unlock(acfg) LeaveCriticalSection (&xdebug_mutex)
-
 void
 mono_xdebug_init (void)
 {
        FILE *il_file;
        MonoImageWriter *w;
 
-       InitializeCriticalSection (&xdebug_mutex);
-
        unlink ("xdb.s");
        xdebug_fp = fopen ("xdb.s", "w");
 
@@ -4360,6 +4628,7 @@ mono_xdebug_init (void)
  *
  *   Emit debugging info for METHOD into an assembly file which can be assembled
  * and loaded into gdb to provide debugging info for JITted code.
+ * LOCKING: Acquires the loader lock.
  */
 void
 mono_save_xdebug_info (MonoCompile *cfg)
@@ -4367,16 +4636,17 @@ mono_save_xdebug_info (MonoCompile *cfg)
        if (!xdebug_writer)
                return;
 
-       mono_xdebug_lock ();
+       mono_loader_lock ();
        mono_dwarf_writer_emit_method (xdebug_writer, cfg, cfg->jit_info->method, NULL, NULL, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ()));
        fflush (xdebug_fp);
-       mono_xdebug_unlock ();
+       mono_loader_unlock ();
 }
 
 /*
  * mono_save_trampoline_xdebug_info:
  *
  *   Same as mono_save_xdebug_info, but for trampolines.
+ * LOCKING: Acquires the loader lock.
  */
 void
 mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32 code_size, GSList *unwind_info)
@@ -4384,10 +4654,10 @@ mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32
        if (!xdebug_writer)
                return;
 
-       mono_xdebug_lock ();
+       mono_loader_lock ();
        mono_dwarf_writer_emit_trampoline (xdebug_writer, tramp_name, NULL, NULL, code, code_size, unwind_info);
        fflush (xdebug_fp);
-       mono_xdebug_unlock ();
+       mono_loader_unlock ();
 }
 
 #else