Add an 'mtriple' aot option to set the target triple used by the AOT compiler in...
[mono.git] / mono / mini / aot-compiler.c
index c98e8d611e881864a6417dea558345d59e9f0344..ce86f494b773f37e3ed605b4a0718da146b46a54 100644 (file)
@@ -57,7 +57,7 @@
 #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-logger-internal.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-time.h>
 #include <mono/utils/mono-mmap.h>
 
 #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
 
+#if defined(__linux__) || defined(__native_client_codegen__)
+#define RODATA_SECT ".rodata"
+#else
+#define RODATA_SECT ".text"
+#endif
+
 #define TV_DECLARE(name) gint64 name
 #define TV_GETTIME(tv) tv = mono_100ns_ticks ()
 #define TV_ELAPSED(start,end) (((end) - (start)) / 10)
@@ -76,6 +82,8 @@
 #define SHARED_EXT ".dll"
 #elif defined(__ppc__) && defined(__MACH__)
 #define SHARED_EXT ".dylib"
+#elif defined(__APPLE__) && defined(TARGET_X86) && !defined(__native_client_codegen__)
+#define SHARED_EXT ".dylib"
 #else
 #define SHARED_EXT ".so"
 #endif
@@ -100,10 +108,12 @@ typedef struct MonoAotOptions {
        int nthreads;
        int ntrampolines;
        int nrgctx_trampolines;
+       int nimt_trampolines;
        gboolean print_skipped_methods;
        gboolean stats;
        char *tool_prefix;
        gboolean autoreg;
+       char *mtriple;
 } MonoAotOptions;
 
 typedef struct MonoAotStats {
@@ -122,8 +132,8 @@ typedef struct MonoAotCompile {
        GHashTable *method_depth;
        MonoCompile **cfgs;
        int cfgs_size;
-       GHashTable *patch_to_plt_offset;
-       GHashTable *plt_offset_to_patch;
+       GHashTable *patch_to_plt_entry;
+       GHashTable *plt_offset_to_entry;
        GHashTable *patch_to_got_offset;
        GHashTable **patch_to_got_offset_by_type;
        GPtrArray *got_patches;
@@ -161,16 +171,27 @@ typedef struct MonoAotCompile {
        GHashTable *unwind_info_offsets;
        GPtrArray *unwind_ops;
        guint32 unwind_info_offset;
+       char *got_symbol_base;
        char *got_symbol;
        char *plt_symbol;
        GHashTable *method_label_hash;
        const char *temp_prefix;
+       const char *llvm_label_prefix;
        guint32 label_generator;
        gboolean llvm;
        MonoAotFileFlags flags;
        MonoDynamicStream blob;
+       MonoClass **typespec_classes;
+       GString *llc_args;
+       GString *as_args;
 } MonoAotCompile;
 
+typedef struct {
+       int plt_offset;
+       char *symbol;
+       MonoJumpInfo *ji;
+} MonoPltEntry;
+
 #define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
 #define mono_acfg_unlock(acfg) LeaveCriticalSection (&((acfg)->mutex))
 
@@ -315,6 +336,14 @@ emit_byte (MonoAotCompile *acfg, guint8 val)
        img_writer_emit_byte (acfg->w, val); 
 }
 
+#ifdef __native_client_codegen__
+static inline void
+emit_nacl_call_alignment (MonoAotCompile *acfg)
+{
+       img_writer_emit_nacl_call_alignment (acfg->w);
+}
+#endif
+
 static G_GNUC_UNUSED void
 emit_global_inner (MonoAotCompile *acfg, const char *name, gboolean func)
 {
@@ -341,7 +370,7 @@ emit_symbol_size (MonoAotCompile *acfg, const char *name, const char *end_label)
 static void
 emit_string_symbol (MonoAotCompile *acfg, const char *name, const char *value)
 {
-       img_writer_emit_section_change (acfg->w, ".text", 1);
+       img_writer_emit_section_change (acfg->w, RODATA_SECT, 1);
        emit_global (acfg, name, FALSE);
        img_writer_emit_label (acfg->w, name);
        img_writer_emit_string (acfg->w, value);
@@ -445,6 +474,10 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #else
 #define AOT_FUNC_ALIGNMENT 16
 #endif
+#if defined(TARGET_X86) && defined(__native_client_codegen__)
+#undef AOT_FUNC_ALIGNMENT
+#define AOT_FUNC_ALIGNMENT 32
+#endif
  
 #if defined(TARGET_POWERPC64) && !defined(__mono_ilp32__)
 #define PPC_LD_OP "ld"
@@ -454,6 +487,34 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #define PPC_LDX_OP "lwzx"
 #endif
 
+static void
+arch_process_target_triple (MonoAotCompile *acfg)
+{
+       char *mtriple = acfg->aot_opts.mtriple;
+
+       if (!mtriple)
+               return;
+
+       acfg->llc_args = g_string_new ("");
+       acfg->as_args = g_string_new ("");
+
+#ifdef TARGET_ARM
+       if (strstr (acfg->aot_opts.mtriple, "darwin")) {
+               g_string_append (acfg->llc_args, "-mattr=+v6");
+               acfg->llvm_label_prefix = "_";
+       } else {
+#ifdef ARM_FPU_VFP
+               g_string_append (acfg->llc_args, " -mattr=+vfp2,+d16");
+               g_string_append (acfg->as_args, " -mfpu=vfp3");
+#else
+               g_string_append (acfg->llc_args, " -soft-float");
+#endif
+       }
+
+       mono_arch_set_target (mtriple);
+#endif
+}
+
 /*
  * arch_emit_direct_call:
  *
@@ -522,6 +583,11 @@ arch_emit_direct_call (MonoAotCompile *acfg, const char *target, int *call_size)
  * one.
  */
 
+/*
+ * X86 design:
+ * - similar to the PPC32 design, we reserve EBX to hold the GOT pointer.
+ */
+
 #ifdef MONO_ARCH_AOT_SUPPORTED
 /*
  * arch_emit_got_offset:
@@ -615,15 +681,28 @@ static void
 arch_emit_plt_entry (MonoAotCompile *acfg, int index)
 {
 #if defined(TARGET_X86)
-               if (index == 0) {
-                       /* It is filled up during loading by the AOT loader. */
-                       emit_zero_bytes (acfg, 16);
-               } else {
-                       /* Need to make sure this is 9 bytes long */
-                       emit_byte (acfg, '\xe9');
-                       emit_symbol_diff (acfg, acfg->plt_symbol, ".", -4);
-                       emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
-               }
+               guint32 offset = (acfg->plt_got_offset_base + index) * sizeof (gpointer);
+
+#ifdef __native_client_codegen__
+               const guint8 kSizeOfNaClJmp = 11;
+               guint8 bytes[kSizeOfNaClJmp];
+               guint8 *pbytes = &bytes[0];
+               
+               x86_jump_membase32 (pbytes, X86_EBX, offset);
+               emit_bytes (acfg, bytes, kSizeOfNaClJmp);
+               /* four bytes of data, used by mono_arch_patch_plt_entry              */
+               /* For Native Client, make this work with data embedded in push.      */
+               emit_byte (acfg, 0x68);  /* hide data in a push */
+               emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+               emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
+#else
+               /* jmp *<offset>(%ebx) */
+               emit_byte (acfg, 0xff);
+               emit_byte (acfg, 0xa3);
+               emit_int32 (acfg, offset);
+               /* Used by mono_aot_get_plt_info_offset */
+               emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+#endif  /* __native_client_codegen__ */
 #elif defined(TARGET_AMD64)
                /*
                 * We can't emit jumps because they are 32 bits only so they can't be patched.
@@ -787,6 +866,40 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
 #else
        *tramp_size = 9 * 4;
 #endif
+#elif defined(TARGET_X86)
+       guint8 buf [128];
+       guint8 *code;
+
+       /* Similar to the PPC code above */
+
+       /* FIXME: Could this clobber the register needed by get_vcall_slot () ? */
+
+       /* We clobber ECX, since EAX is used as MONO_ARCH_MONITOR_OBJECT_REG */
+#ifdef MONO_ARCH_MONITOR_OBJECT_REG
+       g_assert (MONO_ARCH_MONITOR_OBJECT_REG != X86_ECX);
+#endif
+
+       code = buf;
+       /* Load mscorlib got address */
+       x86_mov_reg_membase (code, X86_ECX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
+       /* Push trampoline argument */
+       x86_push_membase (code, X86_ECX, (offset + 1) * sizeof (gpointer));
+       /* Load generic trampoline address */
+       x86_mov_reg_membase (code, X86_ECX, X86_ECX, offset * sizeof (gpointer), 4);
+       /* Branch to generic trampoline */
+       x86_jump_reg (code, X86_ECX);
+
+#ifdef __native_client_codegen__
+       {
+               /* emit nops to next 32 byte alignment */
+               int a = (~kNaClAlignmentMask) & ((code - buf) + kNaClAlignment - 1);
+               while (code < (buf + a)) x86_nop(code);
+       }
+#endif
+       emit_bytes (acfg, buf, code - buf);
+
+       *tramp_size = NACL_SIZE(17, kNaClAlignment);
+       g_assert (code - buf == *tramp_size);
 #else
        g_assert_not_reached ();
 #endif
@@ -799,32 +912,42 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
  * CALL_TARGET is the symbol pointing to the native code of METHOD.
  */
 static void
-arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGenericSharingContext *gsctx, const char *call_target)
+arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, const char *call_target)
 {
 #if defined(TARGET_AMD64)
        guint8 buf [32];
        guint8 *code;
        int this_reg;
 
-       this_reg = mono_arch_get_this_arg_reg (mono_method_signature (method), gsctx, NULL);
+       this_reg = mono_arch_get_this_arg_reg (NULL);
        code = buf;
        amd64_alu_reg_imm (code, X86_ADD, this_reg, sizeof (MonoObject));
 
        emit_bytes (acfg, buf, code - buf);
+       /* jump <method> */
+       emit_byte (acfg, '\xe9');
+       emit_symbol_diff (acfg, call_target, ".", -4);
+#elif defined(TARGET_X86)
+       guint8 buf [32];
+       guint8 *code;
+       int this_pos = 4;
+
+       code = buf;
+
+       x86_alu_membase_imm (code, X86_ADD, X86_ESP, this_pos, sizeof (MonoObject));
+
+       emit_bytes (acfg, buf, code - buf);
+
        /* jump <method> */
        emit_byte (acfg, '\xe9');
        emit_symbol_diff (acfg, call_target, ".", -4);
 #elif defined(TARGET_ARM)
        guint8 buf [128];
        guint8 *code;
-       int this_pos = 0;
 
        code = buf;
 
-       if (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret))
-               this_pos = 1;
-
-       ARM_ADD_REG_IMM8 (code, this_pos, this_pos, sizeof (MonoObject));
+       ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, sizeof (MonoObject));
 
        emit_bytes (acfg, buf, code - buf);
        /* jump to method */
@@ -843,9 +966,6 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGeneri
 #elif defined(TARGET_POWERPC)
        int this_pos = 3;
 
-       if (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret))
-               this_pos = 4;
-
        g_assert (!acfg->use_bin_writer);
 
        fprintf (acfg->fp, "\n\taddi %d, %d, %d\n", this_pos, this_pos, (int)sizeof (MonoObject));
@@ -942,6 +1062,34 @@ arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_
        *tramp_size = 9 * 4;
 #endif
 
+#elif defined(TARGET_X86)
+       guint8 buf [128];
+       guint8 *code;
+
+       /* Similar to the PPC code above */
+
+       g_assert (MONO_ARCH_RGCTX_REG != X86_ECX);
+
+       code = buf;
+       /* Load mscorlib got address */
+       x86_mov_reg_membase (code, X86_ECX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
+       /* Load arg */
+       x86_mov_reg_membase (code, MONO_ARCH_RGCTX_REG, X86_ECX, offset * sizeof (gpointer), 4);
+       /* Branch to the target address */
+       x86_jump_membase (code, X86_ECX, (offset + 1) * sizeof (gpointer));
+
+#ifdef __native_client_codegen__
+       {
+               /* emit nops to next 32 byte alignment */
+               int a = (~kNaClAlignmentMask) & ((code - buf) + kNaClAlignment - 1);
+               while (code < (buf + a)) x86_nop(code);
+       }
+#endif
+
+       emit_bytes (acfg, buf, code - buf);
+
+       *tramp_size = NACL_SIZE (15, kNaClAlignment);
+       g_assert (code - buf == *tramp_size);
 #else
        g_assert_not_reached ();
 #endif
@@ -970,41 +1118,107 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
        /* FIXME: Optimize this, i.e. use binary search etc. */
        /* Maybe move the body into a separate function (slower, but much smaller) */
 
-       /* R10 is a free register */
+       /* R11 is a free register */
 
        labels [0] = code;
-       amd64_alu_membase_imm (code, X86_CMP, AMD64_R10, 0, 0);
+       amd64_alu_membase_imm (code, X86_CMP, AMD64_R11, 0, 0);
        labels [1] = code;
        amd64_branch8 (code, X86_CC_Z, FALSE, 0);
 
        /* Check key */
-       amd64_alu_membase_reg (code, X86_CMP, AMD64_R10, 0, MONO_ARCH_IMT_REG);
+       amd64_alu_membase_reg (code, X86_CMP, AMD64_R11, 0, MONO_ARCH_IMT_REG);
        labels [2] = code;
        amd64_branch8 (code, X86_CC_Z, FALSE, 0);
 
        /* Loop footer */
-       amd64_alu_reg_imm (code, X86_ADD, AMD64_R10, 2 * sizeof (gpointer));
+       amd64_alu_reg_imm (code, X86_ADD, AMD64_R11, 2 * sizeof (gpointer));
        amd64_jump_code (code, labels [0]);
 
        /* Match */
        mono_amd64_patch (labels [2], code);
-       amd64_mov_reg_membase (code, AMD64_R10, AMD64_R10, sizeof (gpointer), 8);
-       amd64_jump_membase (code, AMD64_R10, 0);
+       amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, sizeof (gpointer), 8);
+       amd64_jump_membase (code, AMD64_R11, 0);
 
        /* No match */
        /* FIXME: */
        mono_amd64_patch (labels [1], code);
        x86_breakpoint (code);
 
-       /* mov <OFFSET>(%rip), %r10 */
+       amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 12345678, 8);
+
+       /* mov <OFFSET>(%rip), %r11 */
        emit_byte (acfg, '\x4d');
        emit_byte (acfg, '\x8b');
-       emit_byte (acfg, '\x15');
+       emit_byte (acfg, '\x1d');
        emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
 
        emit_bytes (acfg, buf, code - buf);
        
        *tramp_size = code - buf + 7;
+#elif defined(TARGET_X86)
+       guint8 *buf, *code;
+#ifdef __native_client_codegen__
+       guint8 *buf_alloc;
+#endif
+       guint8 *labels [3];
+
+#ifdef __native_client_codegen__
+       buf_alloc = g_malloc (256 + kNaClAlignment);
+       code = buf = ((guint)buf_alloc + kNaClAlignment) & ~kNaClAlignmentMask;
+#else
+       code = buf = g_malloc (256);
+#endif
+
+       /* Allocate a temporary stack slot */
+       x86_push_reg (code, X86_EAX);
+       /* Save EAX */
+       x86_push_reg (code, X86_EAX);
+
+       /* Load mscorlib got address */
+       x86_mov_reg_membase (code, X86_EAX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
+       /* Load arg */
+       x86_mov_reg_membase (code, X86_EAX, X86_EAX, offset * sizeof (gpointer), 4);
+
+       labels [0] = code;
+       x86_alu_membase_imm (code, X86_CMP, X86_EAX, 0, 0);
+       labels [1] = code;
+       x86_branch8 (code, X86_CC_Z, FALSE, 0);
+
+       /* Check key */
+       x86_alu_membase_reg (code, X86_CMP, X86_EAX, 0, MONO_ARCH_IMT_REG);
+       labels [2] = code;
+       x86_branch8 (code, X86_CC_Z, FALSE, 0);
+
+       /* Loop footer */
+       x86_alu_reg_imm (code, X86_ADD, X86_EAX, 2 * sizeof (gpointer));
+       x86_jump_code (code, labels [0]);
+
+       /* Match */
+       mono_x86_patch (labels [2], code);
+       x86_mov_reg_membase (code, X86_EAX, X86_EAX, sizeof (gpointer), 4);
+       x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0, 4);
+       /* Save the target address to the temporary stack location */
+       x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
+       /* Restore EAX */
+       x86_pop_reg (code, X86_EAX);
+       /* Jump to the target address */
+       x86_ret (code);
+
+       /* No match */
+       /* FIXME: */
+       mono_x86_patch (labels [1], code);
+       x86_breakpoint (code);
+
+#ifdef __native_client_codegen__
+       {
+               /* emit nops to next 32 byte alignment */
+               int a = (~kNaClAlignmentMask) & ((code - buf) + kNaClAlignment - 1);
+               while (code < (buf + a)) x86_nop(code);
+       }
+#endif
+       emit_bytes (acfg, buf, code - buf);
+       
+       *tramp_size = code - buf;
 #elif defined(TARGET_ARM)
        guint8 buf [128];
        guint8 *code, *code2, *labels [16];
@@ -1118,7 +1332,7 @@ arch_emit_autoreg (MonoAotCompile *acfg, char *symbol)
        img_writer_emit_unset_mode (acfg->w);
 
        fprintf (acfg->fp,
-#ifdef _MSC_VER  
+#if defined(_MSC_VER) || defined(MONO_CROSS_COMPILE) 
                         ".section      .ctors,\"aw\",@progbits\n"
                         ".align 2\n"
                         ".globl        %s\n"
@@ -1130,6 +1344,7 @@ arch_emit_autoreg (MonoAotCompile *acfg, char *symbol)
                         ".size %s,.-%s\n"
                         ".section .text\n"
                         ".type .%s,@function\n"
+                        ".align 2\n"
                         ".%s:\n", symbol, symbol, symbol, symbol, symbol, symbol, symbol, symbol);
 #else
                         ".section      .ctors,\"aw\",@progbits\n"
@@ -1143,6 +1358,7 @@ arch_emit_autoreg (MonoAotCompile *acfg, char *symbol)
                         ".size %1$s,.-%1$s\n"
                         ".section .text\n"
                         ".type .%1$s,@function\n"
+                        ".align 2\n"
                         ".%1$s:\n", symbol);
 #endif
 
@@ -1164,7 +1380,7 @@ arch_emit_autoreg (MonoAotCompile *acfg, char *symbol)
                         "mr 1,11\n"
                         "blr\n"
                         );
-#ifdef _MSC_VER
+#if defined(_MSC_VER) || defined(MONO_CROSS_COMPILE) 
                fprintf (acfg->fp,
                         ".size .%s,.-.%s\n", symbol, symbol);
 #else
@@ -1175,32 +1391,6 @@ arch_emit_autoreg (MonoAotCompile *acfg, char *symbol)
 #endif
 }
 
-/*
- * arch_get_cie_program:
- *
- *   Get the unwind bytecode for the DWARF CIE.
- */
-static GSList*
-arch_get_cie_program (void)
-{
-#ifdef TARGET_AMD64
-       GSList *l = NULL;
-
-       mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, AMD64_RSP, 8);
-       mono_add_unwind_op_offset (l, (guint8*)NULL, (guint8*)NULL, AMD64_RIP, -8);
-
-       return l;
-#elif defined(TARGET_POWERPC)
-       GSList *l = NULL;
-
-       mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
-
-       return l;
-#else
-       return NULL;
-#endif
-}
-
 /* END OF ARCH SPECIFIC CODE */
 
 static guint32
@@ -1262,6 +1452,7 @@ stream_init (MonoDynamicStream *sh)
        sh->data = g_malloc (4096);
 
        /* So offsets are > 0 */
+       sh->data [0] = 0;
        sh->index ++;
 }
 
@@ -1300,7 +1491,7 @@ add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
  * blob where the data was stored.
  */
 static guint32
-add_to_blob (MonoAotCompile *acfg, guint8 *data, guint32 data_len)
+add_to_blob (MonoAotCompile *acfg, const guint8 *data, guint32 data_len)
 {
        if (acfg->blob.alloc_size == 0)
                stream_init (&acfg->blob);
@@ -1391,16 +1582,21 @@ static guint32
 find_typespec_for_class (MonoAotCompile *acfg, MonoClass *klass)
 {
        int i;
-       MonoClass *k = NULL;
+       int len = acfg->image->tables [MONO_TABLE_TYPESPEC].rows;
 
        /* FIXME: Search referenced images as well */
-       for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) {
-               k = mono_class_get_full (acfg->image, MONO_TOKEN_TYPE_SPEC | (i + 1), NULL);
-               if (k == klass)
+       if (!acfg->typespec_classes) {
+               acfg->typespec_classes = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoClass*) * len);
+               for (i = 0; i < len; ++i) {
+                       acfg->typespec_classes [i] = mono_class_get_full (acfg->image, MONO_TOKEN_TYPE_SPEC | (i + 1), NULL);
+               }
+       }
+       for (i = 0; i < len; ++i) {
+               if (acfg->typespec_classes [i] == klass)
                        break;
        }
 
-       if (i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows)
+       if (i < len)
                return MONO_TOKEN_TYPE_SPEC | (i + 1);
        else
                return 0;
@@ -1597,7 +1793,7 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                case MONO_WRAPPER_LDFLDA:
                case MONO_WRAPPER_STFLD:
                case MONO_WRAPPER_ISINST: {
-                       MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (method);
+                       MonoClass *proxy_class = mono_marshal_get_wrapper_info (method);
                        encode_klass_ref (acfg, proxy_class, p, &p);
                        break;
                }
@@ -1605,13 +1801,22 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                case MONO_WRAPPER_STFLD_REMOTE:
                        break;
                case MONO_WRAPPER_ALLOC: {
-                       int alloc_type = mono_gc_get_managed_allocator_type (method);
-                       g_assert (alloc_type != -1);
-                       encode_value (alloc_type, p, &p);
+                       AllocatorWrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+                       /* The GC name is saved once in MonoAotFileInfo */
+                       g_assert (info->alloc_type != -1);
+                       encode_value (info->alloc_type, p, &p);
                        break;
                }
-               case MONO_WRAPPER_STELEMREF:
+               case MONO_WRAPPER_WRITE_BARRIER:
                        break;
+               case MONO_WRAPPER_STELEMREF: {
+                       MonoClass *klass = mono_marshal_get_wrapper_info (method);
+
+                       /* Make sure this is the 'normal' stelemref wrapper, not the virtual one */
+                       g_assert (!klass);
+                       break;
+               }
                case MONO_WRAPPER_UNKNOWN:
                        if (strcmp (method->name, "FastMonitorEnter") == 0)
                                encode_value (MONO_AOT_WRAPPER_MONO_ENTER, p, &p);
@@ -1631,6 +1836,18 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                        encode_method_ref (acfg, m, p, &p);
                        break;
                }
+               case MONO_WRAPPER_MANAGED_TO_MANAGED:
+                       if (!strcmp (method->name, "ElementAddr")) {
+                               ElementAddrWrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+                               g_assert (info);
+                               encode_value (MONO_AOT_WRAPPER_ELEMENT_ADDR, p, &p);
+                               encode_value (info->rank, p, &p);
+                               encode_value (info->elem_size, p, &p);
+                       } else {
+                               g_assert_not_reached ();
+                       }
+                       break;
                default:
                        g_assert_not_reached ();
                }
@@ -1731,6 +1948,26 @@ compare_patches (gconstpointer a, gconstpointer b)
                return 0;
 }
 
+static G_GNUC_UNUSED char*
+patch_to_string (MonoJumpInfo *patch_info)
+{
+       GString *str;
+
+       str = g_string_new ("");
+
+       g_string_append_printf (str, "%s(", get_patch_name (patch_info->type));
+
+       switch (patch_info->type) {
+       case MONO_PATCH_INFO_VTABLE:
+               mono_type_get_desc (str, &patch_info->data.klass->byval_arg, TRUE);
+               break;
+       default:
+               break;
+       }
+       g_string_append_printf (str, ")");
+       return g_string_free (str, FALSE);
+}
+
 /*
  * is_plt_patch:
  *
@@ -1757,36 +1994,67 @@ is_plt_patch (MonoJumpInfo *patch_info)
        }
 }
 
-static int
-get_plt_offset (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
+/*
+ * get_plt_symbol:
+ *
+ *   Return the symbol identifying the plt entry PLT_OFFSET.
+ */
+static char*
+get_plt_symbol (MonoAotCompile *acfg, int plt_offset, MonoJumpInfo *patch_info)
+{
+#ifdef __MACH__
+       /* 
+        * The Apple linker reorganizes object files, so it doesn't like branches to local
+        * labels, since those have no relocations.
+        */
+       return g_strdup_printf ("%sp_%d", acfg->llvm_label_prefix, plt_offset);
+#else
+       return g_strdup_printf ("%s%sp_%d", acfg->llvm_label_prefix, acfg->temp_prefix, plt_offset);
+#endif
+}
+
+/*
+ * get_plt_entry:
+ *
+ *   Return a PLT entry which belongs to the method identified by PATCH_INFO.
+ */
+static MonoPltEntry*
+get_plt_entry (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
 {
-       int res = -1;
+       MonoPltEntry *res;
 
-       if (is_plt_patch (patch_info)) {
-               int idx = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_plt_offset, patch_info));
+       if (!is_plt_patch (patch_info))
+               return NULL;
 
-               // FIXME: This breaks the calculation of final_got_size         
-               if (!acfg->llvm && patch_info->type == MONO_PATCH_INFO_METHOD && (patch_info->data.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)) {
-                       /* 
-                        * Allocate a separate PLT slot for each such patch, since some plt
-                        * entries will refer to the method itself, and some will refer to the
-                        * wrapper.
-                        */
-                       idx = 0;
-               }
+       res = g_hash_table_lookup (acfg->patch_to_plt_entry, patch_info);
 
-               if (idx) {
-                       res = idx;
-               } else {
-                       MonoJumpInfo *new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
+       // FIXME: This breaks the calculation of final_got_size         
+       if (!acfg->llvm && patch_info->type == MONO_PATCH_INFO_METHOD && (patch_info->data.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)) {
+               /* 
+                * Allocate a separate PLT slot for each such patch, since some plt
+                * entries will refer to the method itself, and some will refer to the
+                * wrapper.
+                */
+               res = NULL;
+       }
 
-                       g_assert (!acfg->final_got_size);
+       if (!res) {
+               MonoJumpInfo *new_ji;
 
-                       res = acfg->plt_offset;
-                       g_hash_table_insert (acfg->plt_offset_to_patch, GUINT_TO_POINTER (res), new_ji);
-                       g_hash_table_insert (acfg->patch_to_plt_offset, new_ji, GUINT_TO_POINTER (res));
-                       acfg->plt_offset ++;
-               }
+               g_assert (!acfg->final_got_size);
+
+               new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
+
+               res = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoPltEntry));
+               res->plt_offset = acfg->plt_offset;
+               res->ji = new_ji;
+               res->symbol = get_plt_symbol (acfg, res->plt_offset, patch_info);
+
+               g_hash_table_insert (acfg->patch_to_plt_entry, new_ji, res);
+
+               g_hash_table_insert (acfg->plt_offset_to_entry, GUINT_TO_POINTER (res->plt_offset), res);
+
+               acfg->plt_offset ++;
        }
 
        return res;
@@ -1807,11 +2075,12 @@ get_got_offset (MonoAotCompile *acfg, MonoJumpInfo *ji)
        if (got_offset)
                return got_offset - 1;
 
-       g_assert (!acfg->final_got_size);
-
        got_offset = acfg->got_offset;
        acfg->got_offset ++;
 
+       if (acfg->final_got_size)
+               g_assert (got_offset < acfg->final_got_size);
+
        acfg->stats.got_slots ++;
        acfg->stats.got_slot_types [ji->type] ++;
 
@@ -1950,7 +2219,7 @@ can_marshal_struct (MonoClass *klass)
                case MONO_TYPE_STRING:
                        break;
                case MONO_TYPE_VALUETYPE:
-                       if (!can_marshal_struct (mono_class_from_mono_type (field->type)))
+                       if (!mono_class_from_mono_type (field->type)->enumtype && !can_marshal_struct (mono_class_from_mono_type (field->type)))
                                can_marshal = FALSE;
                        break;
                default:
@@ -2003,6 +2272,8 @@ add_wrappers (MonoAotCompile *acfg)
 
                /* Skip methods which can not be handled by get_runtime_invoke () */
                sig = mono_method_signature (method);
+               if (!sig)
+                       continue;
                if ((sig->ret->type == MONO_TYPE_PTR) ||
                        (sig->ret->type == MONO_TYPE_TYPEDBYREF))
                        skip = TRUE;
@@ -2015,8 +2286,14 @@ add_wrappers (MonoAotCompile *acfg)
 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
                if (!method->klass->contextbound) {
                        MonoDynCallInfo *info = mono_arch_dyn_call_prepare (sig);
+                       gboolean has_nullable = FALSE;
+
+                       for (j = 0; j < sig->param_count; j++) {
+                               if (sig->params [j]->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (sig->params [j])))
+                                       has_nullable = TRUE;
+                       }
 
-                       if (info) {
+                       if (info && !has_nullable) {
                                /* Supported by the dynamic runtime-invoke wrapper */
                                skip = TRUE;
                                g_free (info);
@@ -2133,6 +2410,17 @@ add_wrappers (MonoAotCompile *acfg)
                if (method)
                        add_method (acfg, method);
 #endif
+
+               /* Stelemref wrappers */
+               /* There is only a constant number of these, iterating over all types should handle them all */
+               for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
+                       MonoClass *klass;
+               
+                       token = MONO_TOKEN_TYPE_DEF | (i + 1);
+                       klass = mono_class_get (acfg->image, token);
+                       if (klass)
+                               add_method (acfg, mono_marshal_get_virtual_stelemref (mono_array_class_get (klass, 1)));
+               }
        }
 
        /* 
@@ -2201,6 +2489,69 @@ add_wrappers (MonoAotCompile *acfg)
                        add_method (acfg, mono_marshal_get_native_wrapper (method, TRUE, TRUE));
                }
        }
+       /* native-to-managed wrappers */
+       for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+               MonoMethod *method;
+               guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
+               MonoCustomAttrInfo *cattr;
+               int j;
+
+               method = mono_get_method (acfg->image, token, NULL);
+
+               /* 
+                * Only generate native-to-managed wrappers for methods which have an
+                * attribute named MonoPInvokeCallbackAttribute. We search for the attribute by
+                * name to avoid defining a new assembly to contain it.
+                */
+               cattr = mono_custom_attrs_from_method (method);
+
+               if (cattr) {
+                       for (j = 0; j < cattr->num_attrs; ++j)
+                               if (cattr->attrs [j].ctor && !strcmp (cattr->attrs [j].ctor->klass->name, "MonoPInvokeCallbackAttribute"))
+                                       break;
+                       if (j < cattr->num_attrs) {
+                               MonoCustomAttrEntry *e = &cattr->attrs [j];
+                               MonoMethodSignature *sig = mono_method_signature (e->ctor);
+                               const char *p = (const char*)e->data;
+                               int slen;
+                               char *n;
+                               MonoType *t;
+                               MonoClass *klass;
+
+                               g_assert (method->flags & METHOD_ATTRIBUTE_STATIC);
+
+                               g_assert (sig->param_count == 1);
+                               g_assert (sig->params [0]->type == MONO_TYPE_CLASS && !strcmp (mono_class_from_mono_type (sig->params [0])->name, "Type"));
+
+                               /* 
+                                * Decode the cattr manually since we can't create objects
+                                * during aot compilation.
+                                */
+                                       
+                               /* Skip prolog */
+                               p += 2;
+
+                               /* From load_cattr_value () in reflection.c */
+                               slen = mono_metadata_decode_value (p, &p);
+                               n = g_memdup (p, slen + 1);
+                               n [slen] = 0;
+                               t = mono_reflection_type_from_name (n, acfg->image);
+                               g_assert (t);
+                               g_free (n);
+
+                               klass = mono_class_from_mono_type (t);
+                               g_assert (klass->parent == mono_defaults.multicastdelegate_class);
+
+                               add_method (acfg, mono_marshal_get_managed_wrapper (method, klass, 0));
+                       }
+               }
+
+               if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
+                       (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
+                       add_method (acfg, mono_marshal_get_native_wrapper (method, TRUE, TRUE));
+               }
+       }
 
        /* StructureToPtr/PtrToStructure wrappers */
        for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
@@ -2255,13 +2606,25 @@ method_has_type_vars (MonoMethod *method)
        return FALSE;
 }
 
+static void add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth);
+
+static void
+add_generic_class (MonoAotCompile *acfg, MonoClass *klass, gboolean force)
+{
+       /* This might lead to a huge code blowup so only do it if neccesary */
+       if (!acfg->aot_opts.full_aot && !force)
+               return;
+
+       add_generic_class_with_depth (acfg, klass, 0);
+}
+
 /*
  * add_generic_class:
  *
  *   Add all methods of a generic class.
  */
 static void
-add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
+add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth)
 {
        MonoMethod *method;
        gpointer iter;
@@ -2279,7 +2642,7 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
 
        iter = NULL;
        while ((method = mono_class_get_methods (klass, &iter))) {
-               if (mono_method_is_generic_sharable_impl (method, FALSE))
+               if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
                        /* Already added */
                        continue;
 
@@ -2291,7 +2654,7 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
                 * FIXME: Instances which are referenced by these methods are not added,
                 * for example Array.Resize<int> for List<int>.Add ().
                 */
-               add_extra_method (acfg, method);
+               add_extra_method_with_depth (acfg, method, depth);
        }
 
        if (klass->delegate) {
@@ -2329,14 +2692,14 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
                        }
                        g_assert (nclass);
                        nclass = mono_class_inflate_generic_class (nclass, mono_generic_class_get_context (klass->generic_class));
-                       add_generic_class (acfg, nclass);
+                       add_generic_class (acfg, nclass, FALSE);
                }
 
                iter = NULL;
                while ((method = mono_class_get_methods (array_class, &iter))) {
                        if (strstr (method->name, name_prefix)) {
                                MonoMethod *m = mono_aot_get_array_helper_from_wrapper (method);
-                               add_extra_method (acfg, m);
+                               add_extra_method_with_depth (acfg, m, depth);
                        }
                }
 
@@ -2360,13 +2723,34 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
                if (mono_class_is_assignable_from (mono_class_inflate_generic_class (icomparable, &ctx), tclass)) {
                        gcomparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "GenericComparer`1");
                        g_assert (gcomparer);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (gcomparer, &ctx));
+                       add_generic_class (acfg, mono_class_inflate_generic_class (gcomparer, &ctx), FALSE);
+               }
+       }
+
+       /* Add an instance of GenericEqualityComparer<T> which is created dynamically by EqualityComparer<T> */
+       if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "EqualityComparer`1")) {
+               MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+               MonoClass *iface, *gcomparer;
+               MonoGenericContext ctx;
+               MonoType *args [16];
+
+               memset (&ctx, 0, sizeof (ctx));
+
+               iface = mono_class_from_name (mono_defaults.corlib, "System", "IEquatable`1");
+               g_assert (iface);
+               args [0] = &tclass->byval_arg;
+               ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+
+               if (mono_class_is_assignable_from (mono_class_inflate_generic_class (iface, &ctx), tclass)) {
+                       gcomparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "GenericEqualityComparer`1");
+                       g_assert (gcomparer);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (gcomparer, &ctx), FALSE);
                }
        }
 }
 
 static void
-add_instances_of (MonoAotCompile *acfg, MonoClass *klass, MonoType **insts, int ninsts)
+add_instances_of (MonoAotCompile *acfg, MonoClass *klass, MonoType **insts, int ninsts, gboolean force)
 {
        int i;
        MonoGenericContext ctx;
@@ -2377,7 +2761,7 @@ add_instances_of (MonoAotCompile *acfg, MonoClass *klass, MonoType **insts, int
        for (i = 0; i < ninsts; ++i) {
                args [0] = insts [i];
                ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-               add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+               add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx), force);
        }
 }
 
@@ -2400,23 +2784,106 @@ add_generic_instances (MonoAotCompile *acfg)
                token = MONO_TOKEN_METHOD_SPEC | (i + 1);
                method = mono_get_method (acfg->image, token, NULL);
 
-               context = mono_method_get_context (method);
-               if (context && ((context->class_inst && context->class_inst->is_open) ||
-                                               (context->method_inst && context->method_inst->is_open)))
+               if (!method)
                        continue;
 
                if (method->klass->image != acfg->image)
                        continue;
 
-               if (mono_method_is_generic_sharable_impl (method, FALSE))
-                       /* Already added */
-                       continue;
-
-               add_extra_method (acfg, method);
-       }
+               context = mono_method_get_context (method);
 
-       for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) {
-               MonoClass *klass;
+               if (context && ((context->class_inst && context->class_inst->is_open)))
+                       continue;
+
+               /*
+                * For open methods, create an instantiation which can be passed to the JIT.
+                * FIXME: Handle class_inst as well.
+                */
+               if (context && context->method_inst && context->method_inst->is_open) {
+                       MonoGenericContext shared_context;
+                       MonoGenericInst *inst;
+                       MonoType **type_argv;
+                       int i;
+                       MonoMethod *declaring_method;
+                       gboolean supported = TRUE;
+
+                       /* Check that the context doesn't contain open constructed types */
+                       if (context->class_inst) {
+                               inst = context->class_inst;
+                               for (i = 0; i < inst->type_argc; ++i) {
+                                       if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                               continue;
+                                       if (mono_class_is_open_constructed_type (inst->type_argv [i]))
+                                               supported = FALSE;
+                               }
+                       }
+                       if (context->method_inst) {
+                               inst = context->method_inst;
+                               for (i = 0; i < inst->type_argc; ++i) {
+                                       if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                               continue;
+                                       if (mono_class_is_open_constructed_type (inst->type_argv [i]))
+                                               supported = FALSE;
+                               }
+                       }
+
+                       if (!supported)
+                               continue;
+
+                       memset (&shared_context, 0, sizeof (MonoGenericContext));
+
+                       inst = context->class_inst;
+                       if (inst) {
+                               type_argv = g_new0 (MonoType*, inst->type_argc);
+                               for (i = 0; i < inst->type_argc; ++i) {
+                                       if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                               type_argv [i] = &mono_defaults.object_class->byval_arg;
+                                       else
+                                               type_argv [i] = inst->type_argv [i];
+                               }
+                               
+                               shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+                               g_free (type_argv);
+                       }
+
+                       inst = context->method_inst;
+                       if (inst) {
+                               type_argv = g_new0 (MonoType*, inst->type_argc);
+                               for (i = 0; i < inst->type_argc; ++i) {
+                                       if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                               type_argv [i] = &mono_defaults.object_class->byval_arg;
+                                       else
+                                               type_argv [i] = inst->type_argv [i];
+                               }
+
+                               shared_context.method_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+                               g_free (type_argv);
+                       }
+
+                       if (method->is_generic || method->klass->generic_container)
+                               declaring_method = method;
+                       else
+                               declaring_method = mono_method_get_declaring_generic_method (method);
+
+                       method = mono_class_inflate_generic_method (declaring_method, &shared_context);
+               }
+
+               /* 
+                * If the method is fully sharable, it was already added in place of its
+                * generic definition.
+                */
+               if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
+                       continue;
+
+               /*
+                * FIXME: Partially shared methods are not shared here, so we end up with
+                * many identical methods.
+                */
+               add_extra_method (acfg, method);
+       }
+
+       for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) {
+               MonoClass *klass;
 
                token = MONO_TOKEN_TYPE_SPEC | (i + 1);
 
@@ -2424,7 +2891,7 @@ add_generic_instances (MonoAotCompile *acfg)
                if (!klass || klass->rank)
                        continue;
 
-               add_generic_class (acfg, klass);
+               add_generic_class (acfg, klass, FALSE);
        }
 
        /* Add types of args/locals */
@@ -2438,7 +2905,7 @@ add_generic_instances (MonoAotCompile *acfg)
                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]));
+                                       add_generic_class (acfg, mono_class_from_mono_type (sig->params [j]), FALSE);
                }
 
                header = mono_method_get_header (method);
@@ -2446,7 +2913,7 @@ add_generic_instances (MonoAotCompile *acfg)
                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]));
+                                       add_generic_class (acfg, mono_class_from_mono_type (header->locals [j]), FALSE);
                }
        }
 
@@ -2471,22 +2938,22 @@ add_generic_instances (MonoAotCompile *acfg)
                /* Add GenericComparer<T> instances for primitive types for Enum.ToString () */
                klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericComparer`1");
                if (klass)
-                       add_instances_of (acfg, klass, insts, ninsts);
+                       add_instances_of (acfg, klass, insts, ninsts, TRUE);
                klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericEqualityComparer`1");
                if (klass)
-                       add_instances_of (acfg, klass, insts, ninsts);
+                       add_instances_of (acfg, klass, insts, ninsts, TRUE);
 
                /* Add instances of the array generic interfaces for primitive types */
                /* This will add instances of the InternalArray_ helper methods in Array too */
                klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "ICollection`1");
                if (klass)
-                       add_instances_of (acfg, klass, insts, ninsts);
+                       add_instances_of (acfg, klass, insts, ninsts, TRUE);
                klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "IList`1");
                if (klass)
-                       add_instances_of (acfg, klass, insts, ninsts);
+                       add_instances_of (acfg, klass, insts, ninsts, TRUE);
                klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "IEnumerable`1");
                if (klass)
-                       add_instances_of (acfg, klass, insts, ninsts);
+                       add_instances_of (acfg, klass, insts, ninsts, TRUE);
 
                /* 
                 * Add a managed-to-native wrapper of Array.GetGenericValueImpl<object>, which is
@@ -2607,7 +3074,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                                MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
                                                //printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE));
                                                direct_call = TRUE;
-                                               sprintf (direct_call_target, "%sm_%x", acfg->temp_prefix, get_method_index (acfg, callee_cfg->orig_method));
+                                               sprintf (direct_call_target, "%s", callee_cfg->asm_symbol);
                                                patch_info->type = MONO_PATCH_INFO_NONE;
                                                acfg->stats.direct_calls ++;
                                        }
@@ -2616,11 +3083,11 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                }
 
                                if (!got_only && !direct_call) {
-                                       int plt_offset = get_plt_offset (acfg, patch_info);
-                                       if (plt_offset != -1) {
+                                       MonoPltEntry *plt_entry = get_plt_entry (acfg, patch_info);
+                                       if (plt_entry) {
                                                /* This patch has a PLT entry, so we must emit a call to the PLT entry */
                                                direct_call = TRUE;
-                                               sprintf (direct_call_target, "%sp_%d", acfg->temp_prefix, plt_offset);
+                                               sprintf (direct_call_target, "%s", plt_entry->symbol);
                
                                                /* Nullify the patch */
                                                patch_info->type = MONO_PATCH_INFO_NONE;
@@ -2733,32 +3200,12 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
 
        method = cfg->orig_method;
        code = cfg->native_code;
-       header = mono_method_get_header (method);
+       header = cfg->header;
 
        method_index = get_method_index (acfg, method);
 
-       /* Emit unbox trampoline */
-       if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
-               char call_target [256];
-
-               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);
-               emit_label (acfg, symbol);
-
-               sprintf (call_target, "%sm_%x", acfg->temp_prefix, method_index);
-
-               arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
-       }
-
        /* Make the labels local */
-       sprintf (symbol, "%sm_%x", acfg->temp_prefix, method_index);
+       sprintf (symbol, "%s", cfg->asm_symbol);
 
        emit_section_change (acfg, ".text", 0);
        emit_alignment (acfg, func_alignment);
@@ -2815,6 +3262,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
                break;
        case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
+       case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
                break;
        case MONO_PATCH_INFO_METHOD_REL:
                encode_value ((gint)patch_info->data.offset, p, &p);
@@ -3016,6 +3464,12 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
                        continue;
                }
 
+               if (patch_info->type == MONO_PATCH_INFO_GC_CARD_TABLE_ADDR) {
+                       /* Stored in a GOT slot initialized at module load time */
+                       patch_info->type = MONO_PATCH_INFO_NONE;
+                       continue;
+               }
+
                if (is_plt_patch (patch_info)) {
                        /* Calls are made through the PLT */
                        patch_info->type = MONO_PATCH_INFO_NONE;
@@ -3083,11 +3537,11 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        MonoJitInfo *jinfo = cfg->jit_info;
        guint32 flags;
        gboolean use_unwind_ops = FALSE;
-       GPtrArray *seq_points;
+       MonoSeqPointInfo *seq_points;
 
        method = cfg->orig_method;
        code = cfg->native_code;
-       header = mono_method_get_header (method);
+       header = cfg->header;
 
        method_index = get_method_index (acfg, method);
 
@@ -3098,16 +3552,16 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                debug_info_size = 0;
        }
 
-       buf_size = header->num_clauses * 256 + debug_info_size + 1024 + (cfg->seq_points ? (cfg->seq_points->len * 16) : 0);
+       seq_points = cfg->seq_point_info;
+
+       buf_size = header->num_clauses * 256 + debug_info_size + 1024 + (seq_points ? (seq_points->len * 64) : 0);
        p = buf = g_malloc (buf_size);
 
 #ifdef MONO_ARCH_HAVE_XP_UNWIND
        use_unwind_ops = cfg->unwind_ops != NULL;
 #endif
 
-       seq_points = cfg->seq_points;
-
-       flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0) | (seq_points ? 8 : 0) | (cfg->compile_llvm ? 16 : 0);
+       flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0) | (seq_points ? 8 : 0) | (cfg->compile_llvm ? 16 : 0) | (jinfo->has_try_block_holes ? 32 : 0);
 
        encode_value (flags, p, &p);
 
@@ -3126,38 +3580,83 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                encode_value (jinfo->used_regs, p, &p);
        }
 
+       /*Encode the number of holes before the number of clauses to make decoding easier*/
+       if (jinfo->has_try_block_holes) {
+               MonoTryBlockHoleTableJitInfo *table = mono_jit_info_get_try_block_hole_table_info (jinfo);
+               encode_value (table->num_holes, p, &p);
+       }
+
        /* Exception table */
-       if (jinfo->num_clauses)
-               encode_value (jinfo->num_clauses, p, &p);
+       if (cfg->compile_llvm) {
+               /*
+                * When using LLVM, we can't emit some data, like pc offsets, this reg/offset etc.,
+                * since the information is only available to llc. Instead, we let llc save the data
+                * into the LSDA, and read it from there at runtime.
+                */
+               /* The assembly might be CIL stripped so emit the data ourselves */
+               if (header->num_clauses)
+                       encode_value (header->num_clauses, p, &p);
 
-       for (k = 0; k < jinfo->num_clauses; ++k) {
-               MonoJitExceptionInfo *ei = &jinfo->clauses [k];
+               for (k = 0; k < header->num_clauses; ++k) {
+                       MonoExceptionClause *clause;
 
-               encode_value (ei->flags, p, &p);
-               encode_value (ei->exvar_offset, p, &p);
+                       clause = &header->clauses [k];
 
-               if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
-                       encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
-               else {
-                       if (ei->data.catch_class) {
+                       encode_value (clause->flags, p, &p);
+                       if (clause->data.catch_class) {
                                encode_value (1, p, &p);
-                               encode_klass_ref (acfg, ei->data.catch_class, p, &p);
+                               encode_klass_ref (acfg, clause->data.catch_class, p, &p);
                        } else {
                                encode_value (0, p, &p);
                        }
+
+                       /* Emit a list of nesting clauses */
+                       for (i = 0; i < header->num_clauses; ++i) {
+                               gint32 cindex1 = k;
+                               MonoExceptionClause *clause1 = &header->clauses [cindex1];
+                               gint32 cindex2 = i;
+                               MonoExceptionClause *clause2 = &header->clauses [cindex2];
+
+                               if (cindex1 != cindex2 && clause1->try_offset >= clause2->try_offset && clause1->handler_offset <= clause2->handler_offset)
+                                       encode_value (i, p, &p);
+                       }
+                       encode_value (-1, p, &p);
                }
+       } else {
+               if (jinfo->num_clauses)
+                       encode_value (jinfo->num_clauses, p, &p);
+
+               for (k = 0; k < jinfo->num_clauses; ++k) {
+                       MonoJitExceptionInfo *ei = &jinfo->clauses [k];
 
-               encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
-               encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
-               encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
+                       encode_value (ei->flags, p, &p);
+                       encode_value (ei->exvar_offset, p, &p);
+
+                       if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
+                               encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
+                       else {
+                               if (ei->data.catch_class) {
+                                       encode_value (1, p, &p);
+                                       encode_klass_ref (acfg, ei->data.catch_class, p, &p);
+                               } else {
+                                       encode_value (0, p, &p);
+                               }
+                       }
+
+                       encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
+                       encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
+                       encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
+               }
        }
 
        if (jinfo->has_generic_jit_info) {
                MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (jinfo);
 
-               encode_value (gi->has_this ? 1 : 0, p, &p);
-               encode_value (gi->this_reg, p, &p);
-               encode_value (gi->this_offset, p, &p);
+               if (!cfg->compile_llvm) {
+                       encode_value (gi->has_this ? 1 : 0, p, &p);
+                       encode_value (gi->this_reg, p, &p);
+                       encode_value (gi->this_offset, p, &p);
+               }
 
                /* 
                 * Need to encode jinfo->method too, since it is not equal to 'method'
@@ -3166,18 +3665,33 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                encode_method_ref (acfg, jinfo->method, p, &p);
        }
 
+       if (jinfo->has_try_block_holes) {
+               MonoTryBlockHoleTableJitInfo *table = mono_jit_info_get_try_block_hole_table_info (jinfo);
+               for (i = 0; i < table->num_holes; ++i) {
+                       MonoTryBlockHoleJitInfo *hole = &table->holes [i];
+                       encode_value (hole->clause, p, &p);
+                       encode_value (hole->length, p, &p);
+                       encode_value (hole->offset, p, &p);
+               }
+       }
+
        if (seq_points) {
-               int il_offset, native_offset, last_il_offset, last_native_offset;
+               int il_offset, native_offset, last_il_offset, last_native_offset, j;
 
                encode_value (seq_points->len, p, &p);
                last_il_offset = last_native_offset = 0;
-               for (i = 0; i < seq_points->len; i += 2) {
-                       il_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i));
-                       native_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i + 1));
+               for (i = 0; i < seq_points->len; ++i) {
+                       SeqPoint *sp = &seq_points->seq_points [i];
+                       il_offset = sp->il_offset;
+                       native_offset = sp->native_offset;
                        encode_value (il_offset - last_il_offset, p, &p);
                        encode_value (native_offset - last_native_offset, p, &p);
                        last_il_offset = il_offset;
                        last_native_offset = native_offset;
+
+                       encode_value (sp->next_len, p, &p);
+                       for (j = 0; j < sp->next_len; ++j)
+                               encode_value (sp->next [j], p, &p);
                }
        }
                
@@ -3209,6 +3723,20 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
        gboolean no_special_static, cant_encode;
        gpointer iter = NULL;
 
+       if (!klass) {
+               buf_size = 16;
+
+               p = buf = g_malloc (buf_size);
+
+               /* Mark as unusable */
+               encode_value (-1, p, &p);
+
+               res = add_to_blob (acfg, buf, p - buf);
+               g_free (buf);
+
+               return res;
+       }
+               
        buf_size = 10240 + (klass->vtable_size * 16);
        p = buf = g_malloc (buf_size);
 
@@ -3295,21 +3823,27 @@ emit_plt (MonoAotCompile *acfg)
 
        emit_section_change (acfg, ".text", 0);
        emit_global (acfg, symbol, TRUE);
-#ifdef TARGET_X86
-       /* This section will be made read-write by the AOT loader */
-       emit_alignment (acfg, mono_pagesize ());
-#else
        emit_alignment (acfg, 16);
-#endif
        emit_label (acfg, symbol);
        emit_label (acfg, acfg->plt_symbol);
 
        for (i = 0; i < acfg->plt_offset; ++i) {
                char label [128];
                char *debug_sym = NULL;
+               MonoPltEntry *plt_entry = NULL;
                MonoJumpInfo *ji;
 
-               sprintf (label, "%sp_%d", acfg->temp_prefix, i);
+               if (i == 0) {
+                       /* 
+                        * The first plt entry is used to transfer code to the AOT loader. 
+                        */
+                       arch_emit_plt_entry (acfg, i);
+                       continue;
+               }
+
+               plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
+               ji = plt_entry->ji;
+               sprintf (label, "%s", plt_entry->symbol);
 
                if (acfg->llvm) {
                        /*
@@ -3319,10 +3853,9 @@ emit_plt (MonoAotCompile *acfg)
                         * FIXME: Avoid the got slot.
                         * FIXME: Add support to the binary writer.
                         */
-                       ji = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
                        if (ji && is_direct_callable (acfg, NULL, ji) && !acfg->use_bin_writer) {
                                MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, ji->data.method);
-                               fprintf (acfg->fp, "\n.set %s, .Lm_%x\n", label, get_method_index (acfg, callee_cfg->orig_method));
+                               fprintf (acfg->fp, "\n.set %s, %s\n", label, callee_cfg->asm_symbol);
                                continue;
                        }
                }
@@ -3330,50 +3863,43 @@ emit_plt (MonoAotCompile *acfg)
                emit_label (acfg, label);
 
                if (acfg->aot_opts.write_symbols) {
-                       MonoJumpInfo *ji = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
-
-                       if (ji) {
-                               switch (ji->type) {
-                               case MONO_PATCH_INFO_METHOD:
-                                       debug_sym = get_debug_sym (ji->data.method, "plt_", cache);
-                                       break;
-                               case MONO_PATCH_INFO_INTERNAL_METHOD:
-                                       debug_sym = g_strdup_printf ("plt__jit_icall_%s", ji->data.name);
-                                       break;
-                               case MONO_PATCH_INFO_CLASS_INIT:
-                                       debug_sym = g_strdup_printf ("plt__class_init_%s", mono_type_get_name (&ji->data.klass->byval_arg));
-                                       sanitize_symbol (debug_sym);
-                                       break;
-                               case MONO_PATCH_INFO_RGCTX_FETCH:
-                                       debug_sym = g_strdup_printf ("plt__rgctx_fetch_%d", acfg->label_generator ++);
-                                       break;
-                               case MONO_PATCH_INFO_ICALL_ADDR: {
-                                       char *s = get_debug_sym (ji->data.method, "", cache);
+                       switch (ji->type) {
+                       case MONO_PATCH_INFO_METHOD:
+                               debug_sym = get_debug_sym (ji->data.method, "plt_", cache);
+                               break;
+                       case MONO_PATCH_INFO_INTERNAL_METHOD:
+                               debug_sym = g_strdup_printf ("plt__jit_icall_%s", ji->data.name);
+                               break;
+                       case MONO_PATCH_INFO_CLASS_INIT:
+                               debug_sym = g_strdup_printf ("plt__class_init_%s", mono_type_get_name (&ji->data.klass->byval_arg));
+                               sanitize_symbol (debug_sym);
+                               break;
+                       case MONO_PATCH_INFO_RGCTX_FETCH:
+                               debug_sym = g_strdup_printf ("plt__rgctx_fetch_%d", acfg->label_generator ++);
+                               break;
+                       case MONO_PATCH_INFO_ICALL_ADDR: {
+                               char *s = get_debug_sym (ji->data.method, "", cache);
                                        
-                                       debug_sym = g_strdup_printf ("plt__icall_native_%s", s);
-                                       g_free (s);
-                                       break;
-                               }
-                               case MONO_PATCH_INFO_JIT_ICALL_ADDR:
-                                       debug_sym = g_strdup_printf ("plt__jit_icall_native_%s", ji->data.name);
-                                       break;
-                               case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
-                                       debug_sym = g_strdup_printf ("plt__generic_class_init");
-                                       break;
-                               default:
-                                       break;
-                               }
+                               debug_sym = g_strdup_printf ("plt__icall_native_%s", s);
+                               g_free (s);
+                               break;
+                       }
+                       case MONO_PATCH_INFO_JIT_ICALL_ADDR:
+                               debug_sym = g_strdup_printf ("plt__jit_icall_native_%s", ji->data.name);
+                               break;
+                       case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
+                               debug_sym = g_strdup_printf ("plt__generic_class_init");
+                               break;
+                       default:
+                               break;
+                       }
 
-                               if (debug_sym) {
-                                       emit_local_symbol (acfg, debug_sym, NULL, TRUE);
-                                       emit_label (acfg, debug_sym);
-                               }
+                       if (debug_sym) {
+                               emit_local_symbol (acfg, debug_sym, NULL, TRUE);
+                               emit_label (acfg, debug_sym);
                        }
                }
 
-               /* 
-                * The first plt entry is used to transfer code to the AOT loader. 
-                */
                arch_emit_plt_entry (acfg, i);
 
                if (debug_sym) {
@@ -3392,8 +3918,7 @@ emit_plt (MonoAotCompile *acfg)
 }
 
 static G_GNUC_UNUSED void
-emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code, 
-                                guint32 code_size, int got_offset, MonoJumpInfo *ji, GSList *unwind_ops)
+emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
 {
        char start_symbol [256];
        char symbol [256];
@@ -3401,6 +3926,21 @@ emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code,
        MonoJumpInfo *patch_info;
        guint8 *buf, *p;
        GPtrArray *patches;
+       char *name;
+       guint8 *code;
+       guint32 code_size;
+       MonoJumpInfo *ji;
+       GSList *unwind_ops;
+
+       name = info->name;
+       code = info->code;
+       code_size = info->code_size;
+       ji = info->ji;
+       unwind_ops = info->unwind_ops;
+
+#ifdef __native_client_codegen__
+       mono_nacl_fix_patches (code, ji);
+#endif
 
        /* Emit code */
 
@@ -3408,7 +3948,7 @@ emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code,
 
        emit_section_change (acfg, ".text", 0);
        emit_global (acfg, start_symbol, TRUE);
-       emit_alignment (acfg, 16);
+       emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
        emit_label (acfg, start_symbol);
 
        sprintf (symbol, "%snamed_%s", acfg->temp_prefix, name);
@@ -3442,7 +3982,7 @@ emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code,
 
        info_offset = add_to_blob (acfg, buf, p - buf);
 
-       emit_section_change (acfg, ".text", 0);
+       emit_section_change (acfg, RODATA_SECT, 0);
        emit_global (acfg, symbol, FALSE);
        emit_label (acfg, symbol);
 
@@ -3468,10 +4008,7 @@ emit_trampolines (MonoAotCompile *acfg)
        MonoAotTrampoline ntype;
 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
        int tramp_type;
-       guint32 code_size;
-       MonoJumpInfo *ji;
        guint8 *code;
-       GSList *unwind_ops;
 #endif
 
        if (!acfg->aot_opts.full_aot)
@@ -3479,9 +4016,11 @@ emit_trampolines (MonoAotCompile *acfg)
        
        g_assert (acfg->image->assembly);
 
-       /* Currently, we only emit most trampolines into the mscorlib AOT image. */
+       /* Currently, we emit most trampolines into the mscorlib AOT image. */
        if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
+               MonoTrampInfo *info;
+
                /*
                 * Emit the generic trampolines.
                 *
@@ -3490,58 +4029,57 @@ emit_trampolines (MonoAotCompile *acfg)
                 * method.
                 */
                for (tramp_type = 0; tramp_type < MONO_TRAMPOLINE_NUM; ++tramp_type) {
-                       code = mono_arch_create_trampoline_code_full (tramp_type, &code_size, &ji, &unwind_ops, TRUE);
-
-                       /* Emit trampoline code */
-
-                       sprintf (symbol, "generic_trampoline_%d", tramp_type);
-
-                       emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, unwind_ops);
+                       mono_arch_create_generic_trampoline (tramp_type, &info, TRUE);
+                       emit_trampoline (acfg, acfg->got_offset, info);
                }
 
-               code = mono_arch_get_nullified_class_init_trampoline (&code_size);
-               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_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_trampoline (acfg, "monitor_exit_trampoline", code, code_size, acfg->got_offset, ji, NULL);
+               mono_arch_get_nullified_class_init_trampoline (&info);
+               emit_trampoline (acfg, acfg->got_offset, info);
+#if defined(MONO_ARCH_MONITOR_OBJECT_REG)
+               mono_arch_create_monitor_enter_trampoline (&info, TRUE);
+               emit_trampoline (acfg, acfg->got_offset, info);
+               mono_arch_create_monitor_exit_trampoline (&info, TRUE);
+               emit_trampoline (acfg, acfg->got_offset, info);
 #endif
 
-               code = mono_arch_create_generic_class_init_trampoline_full (&code_size, &ji, TRUE);
-               emit_trampoline (acfg, "generic_class_init_trampoline", code, code_size, acfg->got_offset, ji, NULL);
+               mono_arch_create_generic_class_init_trampoline (&info, TRUE);
+               emit_trampoline (acfg, acfg->got_offset, info);
 
                /* Emit the exception related code pieces */
-               code = mono_arch_get_restore_context_full (&code_size, &ji, TRUE);
-               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_trampoline (acfg, "call_filter", code, code_size, acfg->got_offset, ji, NULL);
-               code = mono_arch_get_throw_exception_full (&code_size, &ji, TRUE);
-               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_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_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_trampoline (acfg, "throw_corlib_exception", code, code_size, acfg->got_offset, ji, NULL);
+               code = mono_arch_get_restore_context (&info, TRUE);
+               emit_trampoline (acfg, acfg->got_offset, info);
+               code = mono_arch_get_call_filter (&info, TRUE);
+               emit_trampoline (acfg, acfg->got_offset, info);
+               code = mono_arch_get_throw_exception (&info, TRUE);
+               emit_trampoline (acfg, acfg->got_offset, info);
+               code = mono_arch_get_rethrow_exception (&info, TRUE);
+               emit_trampoline (acfg, acfg->got_offset, info);
+               code = mono_arch_get_throw_corlib_exception (&info, TRUE);
+               emit_trampoline (acfg, acfg->got_offset, info);
+
+#if defined(MONO_ARCH_HAVE_GET_TRAMPOLINES)
+               {
+                       GSList *l = mono_arch_get_trampolines (TRUE);
 
-#if defined(TARGET_AMD64)
-               code = mono_arch_get_throw_pending_exception_full (&code_size, &ji, TRUE);
-               emit_trampoline (acfg, "throw_pending_exception", code, code_size, acfg->got_offset, ji, NULL);
+                       while (l) {
+                               MonoTrampInfo *info = l->data;
+
+                               emit_trampoline (acfg, acfg->got_offset, info);
+                               l = l->next;
+                       }
+               }
 #endif
 
                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_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL);
+                       code = mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, TRUE);
+                       emit_trampoline (acfg, acfg->got_offset, info);
 
                        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_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL);
+                       code = mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, TRUE);
+                       emit_trampoline (acfg, acfg->got_offset, info);
                }
 
                {
@@ -3550,9 +4088,9 @@ emit_trampolines (MonoAotCompile *acfg)
                        /* delegate_invoke_impl trampolines */
                        l = mono_arch_get_delegate_invoke_impls ();
                        while (l) {
-                               MonoAotTrampInfo *info = l->data;
+                               MonoTrampInfo *info = l->data;
 
-                               emit_trampoline (acfg, info->name, info->code, info->code_size, acfg->got_offset, NULL, NULL);
+                               emit_trampoline (acfg, acfg->got_offset, info);
                                l = l->next;
                        }
                }
@@ -3609,7 +4147,7 @@ emit_trampolines (MonoAotCompile *acfg)
                        }
 
                        emit_global (acfg, symbol, TRUE);
-                       emit_alignment (acfg, 16);
+                       emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
                        emit_label (acfg, symbol);
 
                        acfg->trampoline_got_offset_base [ntype] = tramp_got_offset;
@@ -3633,6 +4171,10 @@ emit_trampolines (MonoAotCompile *acfg)
                                default:
                                        g_assert_not_reached ();
                                }
+#ifdef __native_client_codegen__
+                               /* align to avoid 32-byte boundary crossings */
+                               emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
+#endif
 
                                if (!acfg->trampoline_size [ntype]) {
                                        g_assert (tramp_size);
@@ -3693,18 +4235,20 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->ntrampolines = atoi (arg + strlen ("ntrampolines="));
                } else if (str_begins_with (arg, "nrgctx-trampolines=")) {
                        opts->nrgctx_trampolines = atoi (arg + strlen ("nrgctx-trampolines="));
+               } else if (str_begins_with (arg, "nimt-trampolines=")) {
+                       opts->nimt_trampolines = atoi (arg + strlen ("nimt-trampolines="));
                } else if (str_begins_with (arg, "autoreg")) {
                        opts->autoreg = TRUE;
                } else if (str_begins_with (arg, "tool-prefix=")) {
                        opts->tool_prefix = g_strdup (arg + strlen ("tool-prefix="));
-               } else if (str_begins_with (arg, "autoreg")) {
-                       opts->autoreg = TRUE;
                } else if (str_begins_with (arg, "soft-debug")) {
                        opts->soft_debug = TRUE;
                } else if (str_begins_with (arg, "print-skipped")) {
                        opts->print_skipped_methods = TRUE;
                } else if (str_begins_with (arg, "stats")) {
                        opts->stats = TRUE;
+               } else if (str_begins_with (arg, "mtriple=")) {
+                       opts->mtriple = g_strdup (arg + strlen ("mtriple="));
                } else {
                        fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
                        exit (1);
@@ -3763,7 +4307,13 @@ can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
                        case MONO_WRAPPER_ALLOC:
                        case MONO_WRAPPER_REMOTING_INVOKE:
                        case MONO_WRAPPER_UNKNOWN:
+                       case MONO_WRAPPER_WRITE_BARRIER:
                                break;
+                       case MONO_WRAPPER_MANAGED_TO_MANAGED:
+                               if (!strcmp (method->name, "ElementAddr"))
+                                       return TRUE;
+                               else
+                                       return FALSE;
                        default:
                                //printf ("Skip (wrapper call): %d -> %s\n", patch_info->type, mono_method_full_name (patch_info->data.method, TRUE));
                                return FALSE;
@@ -3805,9 +4355,6 @@ can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
        return TRUE;
 }
 
-static void
-add_generic_class (MonoAotCompile *acfg, MonoClass *klass);
-
 /*
  * compile_method:
  *
@@ -3965,15 +4512,17 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                                                        add_extra_method_with_depth (acfg, m, depth + 1);
                                                }
                                        }
-                                       add_generic_class (acfg, m->klass);
+                                       add_generic_class_with_depth (acfg, m->klass, depth + 5);
                                }
+                               if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED && !strcmp (m->name, "ElementAddr"))
+                                       add_extra_method_with_depth (acfg, m, depth + 1);
                                break;
                        }
                        case MONO_PATCH_INFO_VTABLE: {
                                MonoClass *klass = patch_info->data.klass;
 
                                if (klass->generic_class && !mono_generic_context_is_sharable (&klass->generic_class->context, FALSE))
-                                       add_generic_class (acfg, klass);
+                                       add_generic_class_with_depth (acfg, klass, depth + 5);
                                break;
                        }
                        default:
@@ -3987,6 +4536,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                switch (patch_info->type) {
                case MONO_PATCH_INFO_GOT_OFFSET:
                case MONO_PATCH_INFO_NONE:
+               case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
                        break;
                case MONO_PATCH_INFO_IMAGE:
                        /* The assembly is stored in GOT slot 0 */
@@ -4123,7 +4673,7 @@ load_profile_files (MonoAotCompile *acfg)
 
        file_index = 0;
        while (TRUE) {
-               tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%s-%d", g_get_home_dir (), acfg->image->assembly_name, acfg->image->guid, file_index);
+               tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%d", g_get_home_dir (), acfg->image->assembly_name, file_index);
 
                if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) {
                        g_free (tmp);
@@ -4139,21 +4689,38 @@ load_profile_files (MonoAotCompile *acfg)
                file_index ++;
 
                res = fscanf (infile, "%32s\n", ver);
-               if ((res != 1) || strcmp (ver, "#VER:1") != 0) {
+               if ((res != 1) || strcmp (ver, "#VER:2") != 0) {
                        printf ("Profile file has wrong version or invalid.\n");
                        fclose (infile);
                        continue;
                }
 
                while (TRUE) {
-                       res = fscanf (infile, "%d\n", &token);
-                       if (res < 1)
+                       char name [1024];
+                       MonoMethodDesc *desc;
+                       MonoMethod *method;
+
+                       if (fgets (name, 1023, infile) == NULL)
                                break;
 
-                       method_index = mono_metadata_token_index (token) - 1;
+                       /* Kill the newline */
+                       if (strlen (name) > 0)
+                               name [strlen (name) - 1] = '\0';
+
+                       desc = mono_method_desc_new (name, TRUE);
+
+                       method = mono_method_desc_search_in_image (desc, acfg->image);
 
-                       if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index)))
-                               acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
+                       if (method && mono_method_get_token (method)) {
+                               token = mono_method_get_token (method);
+                               method_index = mono_metadata_token_index (token) - 1;
+
+                               if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index))) {
+                                       acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
+                               }
+                       } else {
+                               //printf ("No method found matching '%s'.\n", name);
+                       }
                }
                fclose (infile);
        }
@@ -4183,7 +4750,6 @@ mono_aot_get_method_name (MonoCompile *cfg)
 {
        guint32 method_index = get_method_index (llvm_acfg, cfg->orig_method);
 
-       /* LLVM converts these to .Lm_%x */
        return g_strdup_printf ("m_%x", method_index);
 }
 
@@ -4197,7 +4763,7 @@ char*
 mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
 {
        MonoJumpInfo *ji = mono_mempool_alloc (llvm_acfg->mempool, sizeof (MonoJumpInfo));
-       int offset;
+       MonoPltEntry *plt_entry;
 
        ji->type = type;
        ji->data.target = data;
@@ -4205,9 +4771,9 @@ mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
        if (!can_encode_patch (llvm_acfg, ji))
                return NULL;
 
-       offset = get_plt_offset (llvm_acfg, ji);
+       plt_entry = get_plt_entry (llvm_acfg, ji);
 
-       return g_strdup_printf (".Lp_%d", offset);
+       return g_strdup_printf (plt_entry->symbol);
 }
 
 MonoJumpInfo*
@@ -4236,6 +4802,7 @@ emit_llvm_file (MonoAotCompile *acfg)
        char *command, *opts;
        int i;
        MonoJumpInfo *patch_info;
+       const char *llc_args;
 
        /*
         * When using LLVM, we let llvm emit the got since the LLVM IL needs to refer
@@ -4250,13 +4817,31 @@ emit_llvm_file (MonoAotCompile *acfg)
                                        if (!is_plt_patch (patch_info))
                                                get_got_offset (acfg, patch_info);
                                        else
-                                               get_plt_offset (acfg, patch_info);
+                                               get_plt_entry (acfg, patch_info);
                                }
                        }
                }
        }
+
        acfg->final_got_size = acfg->got_offset + acfg->plt_offset;
 
+       if (acfg->aot_opts.full_aot) {
+               int ntype;
+
+               /* 
+                * Need to add the got entries used by the trampolines.
+                * This is only a conservative approximation.
+                */
+               if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
+                       /* For the generic + rgctx trampolines */
+                       acfg->final_got_size += 200;
+                       /* For the specific trampolines */
+                       for (ntype = 0; ntype < MONO_AOT_TRAMP_NUM; ++ntype)
+                               acfg->final_got_size += acfg->num_trampolines [ntype] * 2;
+               }
+       }
+
+
        mono_llvm_emit_aot_module ("temp.bc", acfg->final_got_size);
 
        /*
@@ -4264,8 +4849,13 @@ emit_llvm_file (MonoAotCompile *acfg)
         * a lot of time, and doesn't seem to save much space.
         * The following optimizations cannot be enabled:
         * - 'tailcallelim'
+        * - 'jump-threading' changes our blockaddress references to int constants.
+        * The opt list below was produced by taking the output of:
+        * llvm-as < /dev/null | opt -O2 -disable-output -debug-pass=Arguments
+        * then removing tailcallelim + the global opts, and adding a second gvn.
         */
        opts = g_strdup ("-instcombine -simplifycfg");
+       opts = g_strdup ("-simplifycfg -domtree -domfrontier -scalarrepl -instcombine -simplifycfg -basiccg -prune-eh -inline -functionattrs -domtree -domfrontier -scalarrepl -simplify-libcalls -instcombine -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loopsimplify -domfrontier -loopsimplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loopsimplify -lcssa -iv-users -indvars -loop-deletion -loopsimplify -lcssa -loop-unroll -instcombine -memdep -gvn -memdep -memcpyopt -sccp -instcombine -domtree -memdep -dse -adce -gvn -simplifycfg -preverify -domtree -verify");
 #if 1
        command = g_strdup_printf ("opt -f %s -o temp.opt.bc temp.bc", opts);
        printf ("Executing opt: %s\n", command);
@@ -4275,8 +4865,20 @@ emit_llvm_file (MonoAotCompile *acfg)
 #endif
        g_free (opts);
 
-       //command = g_strdup_printf ("llc -march=arm -mtriple=arm-linux-gnueabi -f -relocation-model=pic -unwind-tables temp.bc");
-       command = g_strdup_printf ("llc -f -relocation-model=pic -unwind-tables -o temp.s temp.opt.bc");
+#if !LLVM_CHECK_VERSION(2, 8)
+       /* LLVM 2.8 removed the -f flag ??? */
+       llc_args = "-f";
+#else
+       llc_args = "";
+#endif
+
+       if (!acfg->aot_opts.mtriple) {
+               fprintf (stderr, "The mtriple= option is required when compiling using LLVM.\n");
+               exit (1);
+       }
+
+       command = g_strdup_printf ("llc -mtriple=%s %s %s -relocation-model=pic -unwind-tables -o %s temp.opt.bc", acfg->aot_opts.mtriple, llc_args, acfg->llc_args ? acfg->llc_args->str : "", acfg->tmpfname);
+
        printf ("Executing llc: %s\n", command);
 
        if (system (command) != 0) {
@@ -4290,6 +4892,7 @@ emit_code (MonoAotCompile *acfg)
 {
        int i;
        char symbol [256];
+       char end_symbol [256];
        GList *l;
 
 #if defined(TARGET_POWERPC64)
@@ -4300,11 +4903,26 @@ emit_code (MonoAotCompile *acfg)
        emit_pointer (acfg, acfg->got_symbol);
 #endif
 
-       if (!acfg->llvm) {
-               sprintf (symbol, "methods");
-               emit_section_change (acfg, ".text", 0);
-               emit_global (acfg, symbol, TRUE);
-               emit_alignment (acfg, 8);
+       /* 
+        * This global symbol is used to compute the address of each method using the
+        * code_offsets array. It is also used to compute the memory ranges occupied by
+        * AOT code, so it must be equal to the address of the first emitted method.
+        */
+       sprintf (symbol, "methods");
+       emit_section_change (acfg, ".text", 0);
+       emit_global (acfg, symbol, TRUE);
+       emit_alignment (acfg, 8);
+       if (acfg->llvm) {
+               for (i = 0; i < acfg->nmethods; ++i) {
+                       if (acfg->cfgs [i] && acfg->cfgs [i]->compile_llvm) {
+                               fprintf (acfg->fp, "\n.set methods, %s\n", acfg->cfgs [i]->asm_symbol);
+                               break;
+                       }
+               }
+               if (i == acfg->nmethods)
+                       /* No LLVM compiled methods */
+                       emit_label (acfg, symbol);
+       } else {
                emit_label (acfg, symbol);
        }
 
@@ -4315,14 +4933,45 @@ emit_code (MonoAotCompile *acfg)
        emit_zero_bytes (acfg, 16);
 
        for (l = acfg->method_order; l != NULL; l = l->next) {
+               MonoCompile *cfg;
+               MonoMethod *method;
+
                i = GPOINTER_TO_UINT (l->data);
 
-               if (acfg->cfgs [i]) {
-                       if (acfg->cfgs [i]->compile_llvm)
-                               acfg->stats.llvm_count ++;
-                       else
-                               emit_method_code (acfg, acfg->cfgs [i]);
+               cfg = acfg->cfgs [i];
+
+               if (!cfg)
+                       continue;
+
+               method = cfg->orig_method;
+
+               /* Emit unbox trampoline */
+               if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+                       char call_target [256];
+
+                       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);
+#ifdef __native_client_codegen__
+                       emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
+#endif
+                       emit_global (acfg, symbol, TRUE);
+                       emit_label (acfg, symbol);
+
+                       sprintf (call_target, "%s", cfg->asm_symbol);
+
+                       arch_emit_unbox_trampoline (acfg, cfg->orig_method, call_target);
                }
+
+               if (cfg->compile_llvm)
+                       acfg->stats.llvm_count ++;
+               else
+                       emit_method_code (acfg, cfg);
        }
 
        sprintf (symbol, "methods_end");
@@ -4332,17 +4981,17 @@ emit_code (MonoAotCompile *acfg)
        emit_label (acfg, symbol);
 
        sprintf (symbol, "code_offsets");
-       emit_section_change (acfg, ".text", 1);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
        acfg->stats.offsets_size += acfg->nmethods * 4;
 
+       sprintf (end_symbol, "methods");
        for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i]) {
-                       sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
-                       emit_symbol_diff (acfg, symbol, "methods", 0);
+                       emit_symbol_diff (acfg, acfg->cfgs [i]->asm_symbol, end_symbol, 0);
                } else {
                        emit_int32 (acfg, 0xffffffff);
                }
@@ -4372,7 +5021,7 @@ emit_info (MonoAotCompile *acfg)
        }
 
        sprintf (symbol, "method_info_offsets");
-       emit_section_change (acfg, ".text", 1);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
@@ -4384,27 +5033,6 @@ emit_info (MonoAotCompile *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;
-} 
-
 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
 #define mix(a,b,c) { \
        a -= c;  a ^= rot(c, 4);  c += b; \
@@ -4435,11 +5063,11 @@ mono_aot_type_hash (MonoType *t1)
        case MONO_TYPE_CLASS:
        case MONO_TYPE_SZARRAY:
                /* check if the distribution is good enough */
-               return ((hash << 5) - hash) ^ mono_aot_str_hash (t1->data.klass->name);
+               return ((hash << 5) - hash) ^ mono_metadata_str_hash (t1->data.klass->name);
        case MONO_TYPE_PTR:
-               return ((hash << 5) - hash) ^ mono_aot_type_hash (t1->data.type);
+               return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type);
        case MONO_TYPE_ARRAY:
-               return ((hash << 5) - hash) ^ mono_aot_type_hash (&t1->data.array->eklass->byval_arg);
+               return ((hash << 5) - hash) ^ mono_metadata_type_hash (&t1->data.array->eklass->byval_arg);
        case MONO_TYPE_GENERICINST:
                return ((hash << 5) - hash) ^ 0;
        }
@@ -4456,17 +5084,21 @@ mono_aot_method_hash (MonoMethod *method)
 {
        MonoMethodSignature *sig;
        MonoClass *klass;
-       int i;
+       int i, hindex;
        int hashes_count;
        guint32 *hashes_start, *hashes;
        guint32 a, b, c;
+       MonoGenericInst *ginst = NULL;
 
        /* Similar to the hash in mono_method_get_imt_slot () */
 
        sig = mono_method_signature (method);
 
-       hashes_count = sig->param_count + 5;
-       hashes_start = malloc (hashes_count * sizeof (guint32));
+       if (method->is_inflated)
+               ginst = ((MonoMethodInflated*)method)->context.method_inst;
+
+       hashes_count = sig->param_count + 5 + (ginst ? ginst->type_argc : 0);
+       hashes_start = g_malloc0 (hashes_count * sizeof (guint32));
        hashes = hashes_start;
 
        /* Some wrappers are assigned to random classes */
@@ -4478,24 +5110,30 @@ mono_aot_method_hash (MonoMethod *method)
        if (!method->wrapper_type) {
                char *full_name = mono_type_full_name (&klass->byval_arg);
 
-               hashes [0] = mono_aot_str_hash (full_name);
+               hashes [0] = mono_metadata_str_hash (full_name);
                hashes [1] = 0;
                g_free (full_name);
        } else {
-               hashes [0] = mono_aot_str_hash (klass->name);
-               hashes [1] = mono_aot_str_hash (klass->name_space);
+               hashes [0] = mono_metadata_str_hash (klass->name);
+               hashes [1] = mono_metadata_str_hash (klass->name_space);
        }
        if (method->wrapper_type == MONO_WRAPPER_STFLD || method->wrapper_type == MONO_WRAPPER_LDFLD || method->wrapper_type == MONO_WRAPPER_LDFLDA)
                /* The method name includes a stringified pointer */
                hashes [2] = 0;
        else
-               hashes [2] = mono_aot_str_hash (method->name);
+               hashes [2] = mono_metadata_str_hash (method->name);
        hashes [3] = method->wrapper_type;
        hashes [4] = mono_aot_type_hash (sig->ret);
+       hindex = 5;
        for (i = 0; i < sig->param_count; i++) {
-               hashes [5 + i] = mono_aot_type_hash (sig->params [i]);
+               hashes [hindex ++] = mono_aot_type_hash (sig->params [i]);
        }
-       
+       if (ginst) {
+               for (i = 0; i < ginst->type_argc; ++i)
+                       hashes [hindex ++] = mono_aot_type_hash (ginst->type_argv [i]);
+       }               
+       g_assert (hindex == hashes_count);
+
        /* Setup internal state */
        a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
 
@@ -4546,12 +5184,6 @@ mono_aot_wrapper_name (MonoMethod *method)
                else
                        name = g_strdup_printf ("%s (%s)", method->name, tmpsig);
                break;
-       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 these 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);
@@ -4607,23 +5239,6 @@ mono_aot_get_array_helper_from_wrapper (MonoMethod *method)
        return m;
 }
 
-/*
- * mono_aot_tramp_info_create:
- *
- *   Create a MonoAotTrampInfo structure from the arguments.
- */
-MonoAotTrampInfo*
-mono_aot_tramp_info_create (const char *name, guint8 *code, guint32 code_size)
-{
-       MonoAotTrampInfo *info = g_new0 (MonoAotTrampInfo, 1);
-
-       info->name = (char*)name;
-       info->code = code;
-       info->code_size = code_size;
-
-       return info;
-}
-
 #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
 
 typedef struct HashEntry {
@@ -4661,11 +5276,13 @@ emit_extra_methods (MonoAotCompile *acfg)
                if (!cfg)
                        continue;
 
-               buf_size = 512;
+               buf_size = 10240;
                p = buf = g_malloc (buf_size);
 
                nmethods ++;
 
+               method = cfg->method_to_register;
+
                name = NULL;
                if (method->wrapper_type) {
                        /* 
@@ -4754,7 +5371,7 @@ emit_extra_methods (MonoAotCompile *acfg)
 
        /* Emit the table */
        sprintf (symbol, "extra_method_table");
-       emit_section_change (acfg, ".text", 0);
+       emit_section_change (acfg, RODATA_SECT, 0);
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
@@ -4783,7 +5400,7 @@ emit_extra_methods (MonoAotCompile *acfg)
         * This is used by mono_aot_find_jit_info ().
         */
        sprintf (symbol, "extra_method_info_offsets");
-       emit_section_change (acfg, ".text", 0);
+       emit_section_change (acfg, RODATA_SECT, 0);
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
@@ -4815,7 +5432,7 @@ emit_exception_info (MonoAotCompile *acfg)
        }
 
        sprintf (symbol, "ex_info_offsets");
-       emit_section_change (acfg, ".text", 1);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
@@ -4837,7 +5454,7 @@ emit_unwind_info (MonoAotCompile *acfg)
         */
 
        sprintf (symbol, "unwind_info");
-       emit_section_change (acfg, ".text", 1);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
        emit_global (acfg, symbol, FALSE);
@@ -4872,7 +5489,7 @@ emit_class_info (MonoAotCompile *acfg)
                offsets [i] = emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
 
        sprintf (symbol, "class_info_offsets");
-       emit_section_change (acfg, ".text", 1);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
@@ -4907,8 +5524,10 @@ emit_class_name_table (MonoAotCompile *acfg)
        for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
                token = MONO_TOKEN_TYPE_DEF | (i + 1);
                klass = mono_class_get (acfg->image, token);
+               if (!klass)
+                       continue;
                full_name = mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME);
-               hash = mono_aot_str_hash (full_name) % table_size;
+               hash = mono_metadata_str_hash (full_name) % table_size;
                g_free (full_name);
 
                /* FIXME: Allocate from the mempool */
@@ -4931,7 +5550,7 @@ emit_class_name_table (MonoAotCompile *acfg)
 
        /* Emit the table */
        sprintf (symbol, "class_name_table");
-       emit_section_change (acfg, ".text", 0);
+       emit_section_change (acfg, RODATA_SECT, 0);
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
@@ -4968,7 +5587,7 @@ emit_image_table (MonoAotCompile *acfg)
         */
 
        sprintf (symbol, "mono_image_table");
-       emit_section_change (acfg, ".text", 1);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
@@ -5007,9 +5626,9 @@ emit_got_info (MonoAotCompile *acfg)
        acfg->plt_got_offset_base = acfg->got_offset;
        first_plt_got_patch = acfg->got_patches->len;
        for (i = 1; i < acfg->plt_offset; ++i) {
-               MonoJumpInfo *patch_info = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
+               MonoPltEntry *plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
 
-               g_ptr_array_add (acfg->got_patches, patch_info);
+               g_ptr_array_add (acfg->got_patches, plt_entry->ji);
        }
 
        acfg->got_offset += acfg->plt_offset;
@@ -5026,7 +5645,7 @@ emit_got_info (MonoAotCompile *acfg)
         */
 
        /* Encode info required to decode shared GOT entries */
-       buf_size = acfg->got_patches->len * 64;
+       buf_size = acfg->got_patches->len * 128;
        p = buf = mono_mempool_alloc (acfg->mempool, buf_size);
        got_info_offsets = mono_mempool_alloc (acfg->mempool, acfg->got_patches->len * sizeof (guint32));
        acfg->plt_got_info_offsets = mono_mempool_alloc (acfg->mempool, acfg->plt_offset * sizeof (guint32));
@@ -5051,7 +5670,7 @@ emit_got_info (MonoAotCompile *acfg)
 
        /* Emit got_info_offsets table */
        sprintf (symbol, "got_info_offsets");
-       emit_section_change (acfg, ".text", 1);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
@@ -5112,7 +5731,7 @@ emit_globals_table (MonoAotCompile *acfg)
        for (i = 0; i < acfg->globals->len; ++i) {
                char *name = g_ptr_array_index (acfg->globals, i);
 
-               hash = mono_aot_str_hash (name) % table_size;
+               hash = mono_metadata_str_hash (name) % table_size;
 
                /* FIXME: Allocate from the mempool */
                new_entry = g_new0 (GlobalsTableEntry, 1);
@@ -5134,7 +5753,7 @@ emit_globals_table (MonoAotCompile *acfg)
 
        /* Emit the table */
        sprintf (symbol, ".Lglobals_hash");
-       emit_section_change (acfg, ".text", 0);
+       emit_section_change (acfg, RODATA_SECT, 0);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5161,7 +5780,7 @@ emit_globals_table (MonoAotCompile *acfg)
                char *name = g_ptr_array_index (acfg->globals, i);
 
                sprintf (symbol, "name_%d", i);
-               emit_section_change (acfg, ".text", 1);
+               emit_section_change (acfg, RODATA_SECT, 1);
                emit_label (acfg, symbol);
                emit_string (acfg, name);
        }
@@ -5223,7 +5842,7 @@ emit_globals (MonoAotCompile *acfg)
                 * Emit a global symbol which can be passed by an embedding app to
                 * mono_aot_register_module ().
                 */
-#if defined(__MACH__)
+#if defined(__MACH__) && !defined(__native_client_codegen__)
                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);
@@ -5283,6 +5902,15 @@ emit_file_info (MonoAotCompile *acfg)
 {
        char symbol [128];
        int i;
+       int gc_name_offset;
+       const char *gc_name;
+
+       /*
+        * The managed allocators are GC specific, so can't use an AOT image created by one GC
+        * in another.
+        */
+       gc_name = mono_gc_get_gc_name ();
+       gc_name_offset = add_to_blob (acfg, (guint8*)gc_name, strlen (gc_name) + 1);
 
        sprintf (symbol, "mono_aot_file_info");
        emit_section_change (acfg, ".data", 0);
@@ -5290,13 +5918,14 @@ emit_file_info (MonoAotCompile *acfg)
        emit_label (acfg, symbol);
        emit_global (acfg, symbol, FALSE);
 
-       /* The data emitted here must match MonoAotFileInfo in aot-runtime.c. */
+       /* The data emitted here must match MonoAotFileInfo. */
        emit_int32 (acfg, acfg->plt_got_offset_base);
        emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
        emit_int32 (acfg, acfg->plt_offset);
        emit_int32 (acfg, acfg->nmethods);
        emit_int32 (acfg, acfg->flags);
        emit_int32 (acfg, acfg->opts);
+       emit_int32 (acfg, gc_name_offset);
 
        for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
                emit_int32 (acfg, acfg->num_trampolines [i]);
@@ -5312,7 +5941,7 @@ emit_blob (MonoAotCompile *acfg)
        char symbol [128];
 
        sprintf (symbol, "blob");
-       emit_section_change (acfg, ".text", 1);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
@@ -5338,7 +5967,7 @@ emit_dwarf_info (MonoAotCompile *acfg)
                if (cfg->compile_llvm)
                        continue;
 
-               sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
+               sprintf (symbol, "%s", cfg->asm_symbol);
                sprintf (symbol2, "%sme_%x", acfg->temp_prefix, i);
 
                mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, symbol, symbol2, 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 ()));
@@ -5475,10 +6104,18 @@ compile_asm (MonoAotCompile *acfg)
 #define LD_OPTIONS "-m elf64ppc"
 #elif defined(sparc) && SIZEOF_VOID_P == 8
 #define AS_OPTIONS "-xarch=v9"
+#elif defined(TARGET_X86) && defined(__APPLE__) && !defined(__native_client_codegen__)
+#define AS_OPTIONS "-arch i386 -W"
 #else
 #define AS_OPTIONS ""
 #endif
 
+#ifdef __native_client_codegen__
+#define AS_NAME "nacl-as"
+#else
+#define AS_NAME "as"
+#endif
+
 #ifndef LD_OPTIONS
 #define LD_OPTIONS ""
 #endif
@@ -5504,7 +6141,7 @@ compile_asm (MonoAotCompile *acfg)
        } else {
                objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
        }
-       command = g_strdup_printf ("%sas %s %s -o %s", tool_prefix, AS_OPTIONS, acfg->tmpfname, objfile);
+       command = g_strdup_printf ("%s%s %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS, acfg->as_args ? acfg->as_args->str : "", objfile, acfg->tmpfname);
        printf ("Executing the native assembler: %s\n", command);
        if (system (command) != 0) {
                g_free (command);
@@ -5534,6 +6171,8 @@ compile_asm (MonoAotCompile *acfg)
        command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
 #elif defined(HOST_WIN32)
        command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
+#elif defined(TARGET_X86) && defined(__APPLE__) && !defined(__native_client_codegen__)
+       command = g_strdup_printf ("gcc -m32 -dynamiclib -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
 #else
        command = g_strdup_printf ("%sld %s %s -shared -o %s %s.o", tool_prefix, EH_LD_OPTIONS, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
 #endif
@@ -5594,8 +6233,8 @@ acfg_create (MonoAssembly *ass, guint32 opts)
        acfg->methods = g_ptr_array_new ();
        acfg->method_indexes = g_hash_table_new (NULL, NULL);
        acfg->method_depth = 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->plt_offset_to_entry = g_hash_table_new (NULL, NULL);
+       acfg->patch_to_plt_entry = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
        acfg->patch_to_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
        acfg->patch_to_got_offset_by_type = g_new0 (GHashTable*, MONO_PATCH_INFO_NUM);
        for (i = 0; i < MONO_PATCH_INFO_NUM; ++i)
@@ -5638,8 +6277,8 @@ acfg_free (MonoAotCompile *acfg)
        g_ptr_array_free (acfg->unwind_ops, TRUE);
        g_hash_table_destroy (acfg->method_indexes);
        g_hash_table_destroy (acfg->method_depth);
-       g_hash_table_destroy (acfg->plt_offset_to_patch);
-       g_hash_table_destroy (acfg->patch_to_plt_offset);
+       g_hash_table_destroy (acfg->plt_offset_to_entry);
+       g_hash_table_destroy (acfg->patch_to_plt_entry);
        g_hash_table_destroy (acfg->patch_to_got_offset);
        g_hash_table_destroy (acfg->method_to_cfg);
        g_hash_table_destroy (acfg->token_info_hash);
@@ -5657,7 +6296,7 @@ int
 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 {
        MonoImage *image = ass->image;
-       int res;
+       int i, res;
        MonoAotCompile *acfg;
        char *outfile_name, *tmp_outfile_name, *p;
        TV_DECLARE (atv);
@@ -5671,6 +6310,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        acfg->aot_opts.write_symbols = TRUE;
        acfg->aot_opts.ntrampolines = 1024;
        acfg->aot_opts.nrgctx_trampolines = 1024;
+       acfg->aot_opts.nimt_trampolines = 128;
 
        mono_aot_parse_options (aot_options, &acfg->aot_opts);
 
@@ -5699,13 +6339,14 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        fprintf (stderr, "The soft-debug AOT option requires the --debug option.\n");
                        return 1;
                }
+               acfg->flags |= MONO_AOT_FILE_FLAG_DEBUG;
        }
 
-#ifdef ENABLE_LLVM
-       acfg->llvm = TRUE;
-       acfg->aot_opts.asm_writer = TRUE;
-       acfg->flags |= MONO_AOT_FILE_FLAG_WITH_LLVM;
-#endif
+       if (mono_use_llvm) {
+               acfg->llvm = TRUE;
+               acfg->aot_opts.asm_writer = TRUE;
+               acfg->flags |= MONO_AOT_FILE_FLAG_WITH_LLVM;
+       }
 
        if (acfg->aot_opts.full_aot)
                acfg->flags |= MONO_AOT_FILE_FLAG_FULL_AOT;
@@ -5716,13 +6357,13 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 #ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
        acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = acfg->aot_opts.full_aot ? acfg->aot_opts.nrgctx_trampolines : 0;
 #endif
-       acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? 128 : 0;
+       acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? acfg->aot_opts.nimt_trampolines : 0;
 
-       acfg->got_symbol = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
+       acfg->got_symbol_base = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
        acfg->plt_symbol = g_strdup_printf ("mono_aot_%s_plt", acfg->image->assembly->aname.name);
 
        /* Get rid of characters which cannot occur in symbols */
-       for (p = acfg->got_symbol; *p; ++p) {
+       for (p = acfg->got_symbol_base; *p; ++p) {
                if (!(isalnum (*p) || *p == '_'))
                        *p = '_';
        }
@@ -5731,6 +6372,18 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        *p = '_';
        }
 
+       acfg->temp_prefix = img_writer_get_temp_label_prefix (NULL);
+
+       /*
+        * The prefix LLVM likes to put in front of symbol names on darwin.
+        * The mach-os specs require this for globals, but LLVM puts them in front of all
+        * symbols. We need to handle this, since we need to refer to LLVM generated
+        * symbols.
+        */
+       acfg->llvm_label_prefix = "";
+
+       arch_process_target_triple (acfg);
+
        acfg->method_index = 1;
 
        collect_methods (acfg);
@@ -5742,8 +6395,10 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        acfg->plt_offset = 1;
 
 #ifdef ENABLE_LLVM
-       llvm_acfg = acfg;
-       mono_llvm_create_aot_module (acfg->got_symbol);
+       if (acfg->llvm) {
+               llvm_acfg = acfg;
+               mono_llvm_create_aot_module (acfg->got_symbol_base);
+       }
 #endif
 
        /* GOT offset 0 is reserved for the address of the current assembly */
@@ -5760,6 +6415,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
                ji->type = MONO_PATCH_INFO_MSCORLIB_GOT_ADDR;
                get_got_offset (acfg, ji);
+
+               /* This is very common */
+               ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
+               ji->type = MONO_PATCH_INFO_GC_CARD_TABLE_ADDR;
+               get_got_offset (acfg, ji);
        }
 
        TV_GETTIME (atv);
@@ -5773,7 +6433,18 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        TV_GETTIME (atv);
 
 #ifdef ENABLE_LLVM
-       emit_llvm_file (acfg);
+       if (acfg->llvm) {
+               if (acfg->aot_opts.asm_only) {
+                       if (acfg->aot_opts.outfile)
+                               acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
+                       else
+                               acfg->tmpfname = g_strdup_printf ("%s.s", acfg->image->name);
+               } else {
+                       acfg->tmpfname = g_strdup ("temp.s");
+               }
+
+               emit_llvm_file (acfg);
+       }
 #endif
 
        if (!acfg->aot_opts.asm_only && !acfg->aot_opts.asm_writer && bin_writer_supported ()) {
@@ -5800,8 +6471,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                if (acfg->llvm) {
                        /* Append to the .s file created by llvm */
                        /* FIXME: Use multiple files instead */
-                       acfg->tmpfname = g_strdup ("temp.s");
-                       acfg->fp = fopen (acfg->tmpfname, "a");
+                       acfg->fp = fopen (acfg->tmpfname, "a+");
                } else {
                        if (acfg->aot_opts.asm_only) {
                                if (acfg->aot_opts.outfile)
@@ -5821,7 +6491,17 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                outfile_name = NULL;
        }
 
-       acfg->temp_prefix = img_writer_get_temp_label_prefix (acfg->w);
+       acfg->got_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, acfg->got_symbol_base);
+
+       /* Compute symbols for methods */
+       for (i = 0; i < acfg->nmethods; ++i) {
+               if (acfg->cfgs [i]) {
+                       MonoCompile *cfg = acfg->cfgs [i];
+                       int method_index = get_method_index (acfg, cfg->orig_method);
+
+                       cfg->asm_symbol = g_strdup_printf ("%s%sm_%x", acfg->temp_prefix, acfg->llvm_label_prefix, method_index);
+               }
+       }
 
        if (!acfg->aot_opts.nodebug)
                acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE);
@@ -5829,7 +6509,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        img_writer_emit_start (acfg->w);
 
        if (acfg->dwarf)
-               mono_dwarf_writer_emit_base_info (acfg->dwarf, arch_get_cie_program ());
+               mono_dwarf_writer_emit_base_info (acfg->dwarf, mono_unwind_get_cie_program ());
 
        emit_code (acfg);
 
@@ -5875,7 +6555,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        acfg->stats.gen_time = TV_ELAPSED (atv, btv);
 
        if (acfg->llvm)
-               g_assert (acfg->got_offset == acfg->final_got_size);
+               g_assert (acfg->got_offset <= acfg->final_got_size);
 
        printf ("Code: %d Info: %d Ex Info: %d Unwind Info: %d Class Info: %d PLT: %d GOT Info: %d GOT: %d Offsets: %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, (int)(acfg->got_offset * sizeof (gpointer)), acfg->stats.offsets_size);
 
@@ -5931,311 +6611,6 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        
        return 0;
 }
-/*
- * Support for emitting debug info for JITted code.
- *
- *   This works as follows:
- * - the runtime writes out an xdb.s file containing DWARF debug info.
- * - the user calls a gdb macro
- * - the macro compiles and loads this shared library using add-symbol-file.
- *
- * This is based on the xdebug functionality in the Kaffe Java VM.
- * 
- * We emit assembly code instead of using the ELF writer, so we can emit debug info
- * incrementally as each method is JITted, and the debugger doesn't have to call
- * into the runtime to emit the shared library, which would cause all kinds of
- * complications, like threading issues, and the fact that the ELF writer's
- * emit_writeout () function cannot be called more than once.
- * GDB 7.0 and later has a JIT interface.
- */
-
-#define USE_GDB_JIT_INTERFACE
-
-/* The recommended gdb macro is: */
-/*
-  define xdb
-  shell rm -f xdb.so && as --64 -o xdb.o xdb.s && ld -shared -o xdb.so xdb.o
-  add-symbol-file xdb.so 0
-  end
-*/
-
-/*
- * GDB JIT interface definitions.
- *
- *     http://sources.redhat.com/gdb/onlinedocs/gdb_30.html
- */
-typedef enum
-{
-  JIT_NOACTION = 0,
-  JIT_REGISTER_FN,
-  JIT_UNREGISTER_FN
-} jit_actions_t;
-
-struct jit_code_entry
-{
-  struct jit_code_entry *next_entry;
-  struct jit_code_entry *prev_entry;
-  const char *symfile_addr;
-  guint64 symfile_size;
-};
-
-struct jit_descriptor
-{
-  guint32 version;
-  /* This type should be jit_actions_t, but we use guint32
-     to be explicit about the bitwidth.  */
-  guint32 action_flag;
-  struct jit_code_entry *relevant_entry;
-  struct jit_code_entry *first_entry;
-};
-
-
-#ifdef _MSC_VER
-#define MONO_NOINLINE __declspec (noinline)
-#else
-#define MONO_NOINLINE __attribute__((noinline))
-#endif
-
-/* GDB puts a breakpoint in this function.  */
-void MONO_NOINLINE __jit_debug_register_code(void);
-
-#if defined(ENABLE_LLVM) && ((LLVM_MAJOR_VERSION == 2 && LLVM_MINOR_VERSION >= 7) || LLVM_MAJOR_VERSION > 2)
-/* LLVM already defines these */
-extern struct jit_descriptor __jit_debug_descriptor;
-#else
-
-/* Make sure to specify the version statically, because the
-   debugger may check the version before we can set it.  */
-struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
-
-void MONO_NOINLINE __jit_debug_register_code(void) { };
-#endif
-
-static MonoImageWriter *xdebug_w;
-static MonoDwarfWriter *xdebug_writer;
-static FILE *xdebug_fp, *il_file;
-static gboolean use_gdb_interface, save_symfiles;
-static int il_file_line_index;
-static GHashTable *xdebug_syms;
-
-void
-mono_xdebug_init (char *options)
-{
-       MonoImageWriter *w;
-       char **args, **ptr;
-
-       args = g_strsplit (options, ",", -1);
-       for (ptr = args; ptr && *ptr; ptr ++) {
-               char *arg = *ptr;
-
-               if (!strcmp (arg, "gdb"))
-                       use_gdb_interface = TRUE;
-               if (!strcmp (arg, "save-symfiles"))
-                       save_symfiles = TRUE;
-       }
-
-       /* This file will contain the IL code for methods which don't have debug info */
-       il_file = fopen ("xdb.il", "w");
-
-       if (use_gdb_interface)
-               return;
-
-       unlink ("xdb.s");
-       xdebug_fp = fopen ("xdb.s", "w");
-       
-       w = img_writer_create (xdebug_fp, FALSE);
-
-       img_writer_emit_start (w);
-
-       xdebug_writer = mono_dwarf_writer_create (w, il_file, 0, TRUE);
-
-       /* Emit something so the file has a text segment */
-       img_writer_emit_section_change (w, ".text", 0);
-       img_writer_emit_string (w, "");
-
-       mono_dwarf_writer_emit_base_info (xdebug_writer, arch_get_cie_program ());
-}
-
-static void
-xdebug_begin_emit (MonoImageWriter **out_w, MonoDwarfWriter **out_dw)
-{
-       MonoImageWriter *w;
-       MonoDwarfWriter *dw;
-
-       w = img_writer_create (NULL, TRUE);
-
-       img_writer_emit_start (w);
-
-       /* This file will contain the IL code for methods which don't have debug info */
-       if (!il_file)
-               il_file = fopen ("xdb.il", "w");
-
-       dw = mono_dwarf_writer_create (w, il_file, il_file_line_index, FALSE);
-
-       mono_dwarf_writer_emit_base_info (dw, arch_get_cie_program ());
-
-       *out_w = w;
-       *out_dw = dw;
-}
-
-static void
-xdebug_end_emit (MonoImageWriter *w, MonoDwarfWriter *dw, MonoMethod *method)
-{
-       guint8 *img;
-       guint32 img_size;
-       struct jit_code_entry *entry;
-
-       il_file_line_index = mono_dwarf_writer_get_il_file_line_index (dw);
-       mono_dwarf_writer_close (dw);
-
-       img_writer_emit_writeout (w);
-
-       img = img_writer_get_output (w, &img_size);
-
-       img_writer_destroy (w);
-
-       if (FALSE) {
-               /* Save the symbol files to help debugging */
-               FILE *fp;
-               char *file_name;
-               static int file_counter;
-
-               file_counter ++;
-               file_name = g_strdup_printf ("xdb-%d.o", file_counter);
-               //printf ("%s -> %s\n", mono_method_full_name (method, TRUE), file_name);
-
-               fp = fopen (file_name, "w");
-               fwrite (img, img_size, 1, fp);
-               fclose (fp);
-               g_free (file_name);
-       }
-
-       /* Register the image with GDB */
-
-       entry = g_malloc (sizeof (struct jit_code_entry));
-
-       entry->symfile_addr = (const char*)img;
-       entry->symfile_size = img_size;
-
-       entry->next_entry = __jit_debug_descriptor.first_entry;
-       if (__jit_debug_descriptor.first_entry)
-               __jit_debug_descriptor.first_entry->prev_entry = entry;
-       __jit_debug_descriptor.first_entry = entry;
-       
-       __jit_debug_descriptor.relevant_entry = entry;
-       __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
-
-       __jit_debug_register_code ();
-}
-
-/*
- * mono_xdebug_flush:
- *
- *   This could be called from inside gdb to flush the debugging information not yet
- * registered with gdb.
- */
-static void
-mono_xdebug_flush (void)
-{
-       if (xdebug_w)
-               xdebug_end_emit (xdebug_w, xdebug_writer, NULL);
-
-       xdebug_begin_emit (&xdebug_w, &xdebug_writer);
-}
-
-static int xdebug_method_count;
-
-/*
- * mono_save_xdebug_info:
- *
- *   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)
-{
-       if (use_gdb_interface) {
-               mono_loader_lock ();
-
-               if (!xdebug_syms)
-                       xdebug_syms = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
-               /*
-                * gdb is not designed to handle 1000s of symbol files (one per method). So we
-                * group them into groups of 100.
-                */
-               if ((xdebug_method_count % 100) == 0)
-                       mono_xdebug_flush ();
-
-               xdebug_method_count ++;
-
-               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 ()));
-
-#if 0
-               /* 
-                * Emit a symbol for the code by emitting it at the beginning of the text 
-                * segment, and setting the text segment to have an absolute address.
-                * This symbol can be used to set breakpoints in gdb.
-                * FIXME: This doesn't work when multiple methods are emitted into the same file.
-                */
-               sym = get_debug_sym (cfg->jit_info->method, "", xdebug_syms);
-               img_writer_emit_section_change (w, ".text", 0);
-               if (!xdebug_text_addr) {
-                       xdebug_text_addr = cfg->jit_info->code_start;
-                       img_writer_set_section_addr (w, (gssize)xdebug_text_addr);
-               }
-               img_writer_emit_global_with_size (w, sym, cfg->jit_info->code_size, TRUE);
-               img_writer_emit_label (w, sym);
-               img_writer_emit_bytes (w, cfg->jit_info->code_start, cfg->jit_info->code_size);
-               g_free (sym);
-#endif
-               
-               mono_loader_unlock ();
-       } else {
-               if (!xdebug_writer)
-                       return;
-
-               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_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)
-{
-       if (use_gdb_interface) {
-               MonoImageWriter *w;
-               MonoDwarfWriter *dw;
-
-               mono_loader_lock ();
-
-               xdebug_begin_emit (&w, &dw);
-
-               mono_dwarf_writer_emit_trampoline (dw, tramp_name, NULL, NULL, code, code_size, unwind_info);
-
-               xdebug_end_emit (w, dw, NULL);
-               
-               mono_loader_unlock ();
-       } else {
-               if (!xdebug_writer)
-                       return;
-
-               mono_loader_lock ();
-               mono_dwarf_writer_emit_trampoline (xdebug_writer, tramp_name, NULL, NULL, code, code_size, unwind_info);
-               fflush (xdebug_fp);
-               mono_loader_unlock ();
-       }
-}
 
 #else
 
@@ -6247,19 +6622,4 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        return 0;
 }
 
-void
-mono_xdebug_init (char *options)
-{
-}
-
-void
-mono_save_xdebug_info (MonoCompile *cfg)
-{
-}
-
-void
-mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32 code_size, GSList *unwind_info)
-{
-}
-
 #endif