Merge remote branch 'upstream/master'
[mono.git] / mono / mini / aot-compiler.c
index a62bcd583021514a93ea5699ea9eef3024d159f2..6f13e974c20ccf7feab18eea589ede91e123fbf4 100644 (file)
 
 #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
@@ -105,6 +113,7 @@ typedef struct MonoAotOptions {
        gboolean stats;
        char *tool_prefix;
        gboolean autoreg;
+       char *mtriple;
 } MonoAotOptions;
 
 typedef struct MonoAotStats {
@@ -123,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;
@@ -172,8 +181,19 @@ typedef struct MonoAotCompile {
        gboolean llvm;
        MonoAotFileFlags flags;
        MonoDynamicStream blob;
+       MonoClass **typespec_classes;
+       GString *llc_args;
+       GString *as_args;
+       gboolean thumb_mixed;
 } MonoAotCompile;
 
+typedef struct {
+       int plt_offset;
+       char *symbol, *llvm_symbol, *debug_sym;
+       MonoJumpInfo *ji;
+       gboolean jit_used, llvm_used;
+} MonoPltEntry;
+
 #define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
 #define mono_acfg_unlock(acfg) LeaveCriticalSection (&((acfg)->mutex))
 
@@ -318,6 +338,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)
 {
@@ -344,12 +372,20 @@ 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);
 }
 
+static void
+emit_local_string_symbol (MonoAotCompile *acfg, const char *name, const char *value)
+{
+       img_writer_emit_section_change (acfg->w, RODATA_SECT, 1);
+       img_writer_emit_label (acfg->w, name);
+       img_writer_emit_string (acfg->w, value);
+}
+
 static G_GNUC_UNUSED void
 emit_uleb128 (MonoAotCompile *acfg, guint32 value)
 {
@@ -448,6 +484,10 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #else
 #define AOT_FUNC_ALIGNMENT 16
 #endif
+#if (defined(TARGET_X86) || defined(TARGET_AMD64)) && 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"
@@ -457,22 +497,39 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #define PPC_LDX_OP "lwzx"
 #endif
 
-//#define TARGET_ARM
+static void
+arch_init (MonoAotCompile *acfg)
+{
+       acfg->llc_args = g_string_new ("");
+       acfg->as_args = g_string_new ("");
+
+       /*
+        * 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 = "";
 
 #ifdef TARGET_ARM
-#define LLVM_LABEL_PREFIX "_"
+       if (acfg->aot_opts.mtriple && 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
-#define LLVM_LABEL_PREFIX ""
+               g_string_append (acfg->llc_args, " -soft-float");
 #endif
+       }
+       if (acfg->aot_opts.mtriple && strstr (acfg->aot_opts.mtriple, "thumb"))
+               acfg->thumb_mixed = TRUE;
 
-#ifdef TARGET_ARM
-/* iphone */
-#define LLC_TARGET_ARGS "-march=arm -mattr=+v6 -mtriple=arm-apple-darwin"
-/* ELF */
-//#define LLC_TARGET_ARGS "-march=arm -mtriple=arm-linux-gnueabi -soft-float"
-#else
-#define LLC_TARGET_ARGS ""
+       if (acfg->aot_opts.mtriple)
+               mono_arch_set_target (acfg->aot_opts.mtriple);
 #endif
+}
 
 /*
  * arch_emit_direct_call:
@@ -542,6 +599,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:
@@ -635,16 +697,29 @@ 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);
+#if defined(__default_codegen__)
+               /* 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]);
+#elif defined(__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);
+#endif /*__native_client_codegen__*/
 #elif defined(TARGET_AMD64)
+#if defined(__default_codegen__)
                /*
                 * We can't emit jumps because they are 32 bits only so they can't be patched.
                 * So we make indirect calls through GOT entries which are patched by the AOT 
@@ -656,39 +731,38 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                emit_symbol_diff (acfg, acfg->got_symbol, ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) -4);
                /* Used by mono_aot_get_plt_info_offset */
                emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+#elif defined(__native_client_codegen__)
+               guint8 buf [256];
+               guint8 *buf_aligned = ALIGN_TO(buf, kNaClAlignment);
+               guint8 *code = buf_aligned;
+
+               /* mov <OFFSET>(%rip), %r11d */
+               emit_byte (acfg, '\x45');
+               emit_byte (acfg, '\x8b');
+               emit_byte (acfg, '\x1d');
+               emit_symbol_diff (acfg, acfg->got_symbol, ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) -4);
+
+               amd64_jump_reg (code, AMD64_R11);
+               /* This should be constant for the plt patch */
+               g_assert ((size_t)(code-buf_aligned) == 10);
+               emit_bytes (acfg, buf_aligned, code - buf_aligned);
+
+               /* Hide data in a push imm32 so it passes validation */
+               emit_byte (acfg, 0x68);  /* push */
+               emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+               emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
+#endif /*__native_client_codegen__*/
 #elif defined(TARGET_ARM)
                guint8 buf [256];
                guint8 *code;
 
-               /* FIXME:
-                * - optimize OP_AOTCONST implementation
-                * - optimize the PLT entries
-                * - optimize SWITCH AOT implementation
-                */
                code = buf;
-               if (acfg->use_bin_writer && FALSE) {
-                       /* FIXME: mono_arch_patch_plt_entry () needs to decode this */
-                       /* We only emit 1 relocation since we implement it ourselves anyway */
-                       img_writer_emit_reloc (acfg->w, R_ARM_ALU_PC_G0_NC, acfg->got_symbol, ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) - 8);
-                       /* FIXME: A 2 instruction encoding is sufficient in most cases */
-                       ARM_ADD_REG_IMM (code, ARMREG_IP, ARMREG_PC, 0, 0);
-                       ARM_ADD_REG_IMM (code, ARMREG_IP, ARMREG_IP, 0, 0);
-                       ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, 0);
-                       emit_bytes (acfg, buf, code - buf);
-                       /* Used by mono_aot_get_plt_info_offset */
-                       emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
-               } else {
-                       ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
-                       ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_IP);
-                       emit_bytes (acfg, buf, code - buf);
-                       emit_symbol_diff (acfg, acfg->got_symbol, ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) - 4);
-                       /* Used by mono_aot_get_plt_info_offset */
-                       emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
-               }
-               /* 
-                * The plt_got_info_offset is computed automatically by 
-                * mono_aot_get_plt_info_offset (), so no need to save it here.
-                */
+               ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
+               ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_IP);
+               emit_bytes (acfg, buf, code - buf);
+               emit_symbol_diff (acfg, acfg->got_symbol, ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) - 4);
+               /* Used by mono_aot_get_plt_info_offset */
+               emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
 #elif defined(TARGET_POWERPC)
                guint32 offset = (acfg->plt_got_offset_base + index) * sizeof (gpointer);
 
@@ -711,6 +785,33 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
 #endif
 }
 
+static void
+arch_emit_llvm_plt_entry (MonoAotCompile *acfg, int index)
+{
+#if defined(TARGET_ARM)
+#if 0
+       /* LLVM calls the PLT entries using bl, so emit a stub */
+       /* FIXME: Too much overhead on every call */
+       fprintf (acfg->fp, ".thumb_func\n");
+       fprintf (acfg->fp, "bx pc\n");
+       fprintf (acfg->fp, "nop\n");
+       fprintf (acfg->fp, ".arm\n");
+#endif
+       /* LLVM calls the PLT entries using bl, so these have to be thumb2 */
+       fprintf (acfg->fp, ".thumb_func\n");
+       /* The code below should be 12 bytes long */
+       fprintf (acfg->fp, "ldr ip, [pc, #8]\n");
+       /* thumb can't encode ld pc, [pc, ip] */
+       fprintf (acfg->fp, "add ip, pc, ip\n");
+       fprintf (acfg->fp, "ldr ip, [ip, #0]\n");
+       fprintf (acfg->fp, "bx ip\n");
+       emit_symbol_diff (acfg, acfg->got_symbol, ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) + 4);
+       emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+#else
+       g_assert_not_reached ();
+#endif
+}
+
 /*
  * arch_emit_specific_trampoline:
  *
@@ -734,6 +835,7 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
         * - all the trampolines should be of the same length.
         */
 #if defined(TARGET_AMD64)
+#if defined(__default_codegen__)
        /* This should be exactly 16 bytes long */
        *tramp_size = 16;
        /* call *<offset>(%rip) */
@@ -742,8 +844,61 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
        emit_byte (acfg, '\x15');
        emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
        /* This should be relative to the start of the trampoline */
-       emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4 + 19);
+       emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset+1) * sizeof (gpointer)) + 7);
        emit_zero_bytes (acfg, 5);
+#elif defined(__native_client_codegen__)
+       guint8 buf [256];
+       guint8 *buf_aligned = ALIGN_TO(buf, kNaClAlignment);
+       guint8 *code = buf_aligned;
+       guint8 *call_start;
+       size_t call_len;
+       int got_offset;
+
+       /* Emit this call in 'code' so we can find out how long it is. */
+       amd64_call_reg (code, AMD64_R11);
+       call_start = mono_arch_nacl_skip_nops (buf_aligned);
+       call_len = code - call_start;
+
+       /* The tramp_size is twice the NaCl alignment because it starts with */ 
+       /* a call which needs to be aligned to the end of the boundary.      */
+       *tramp_size = kNaClAlignment*2;
+       {
+               /* Emit nops to align call site below which is 7 bytes plus */
+               /* the length of the call sequence emitted above.           */
+               /* Note: this requires the specific trampoline starts on a  */
+               /* kNaclAlignedment aligned address, which it does because  */
+               /* it's its own function that is aligned.                   */
+               guint8 nop_buf[256];
+               guint8 *nopbuf_aligned = ALIGN_TO (nop_buf, kNaClAlignment);
+               guint8 *nopbuf_end = mono_arch_nacl_pad (nopbuf_aligned, kNaClAlignment - 7 - (call_len));
+               emit_bytes (acfg, nopbuf_aligned, nopbuf_end - nopbuf_aligned);
+       }
+       /* The trampoline is stored at the offset'th pointer, the -4 is  */
+       /* present because RIP relative addressing starts at the end of  */
+       /* the current instruction, while the label "." is relative to   */
+       /* the beginning of the current asm location, which in this case */
+       /* is not the mov instruction, but the offset itself, due to the */
+       /* way the bytes and ints are emitted here.                      */
+       got_offset = (offset * sizeof(gpointer)) - 4;
+
+       /* mov <OFFSET>(%rip), %r11d */
+       emit_byte (acfg, '\x45');
+       emit_byte (acfg, '\x8b');
+       emit_byte (acfg, '\x1d');
+       emit_symbol_diff (acfg, acfg->got_symbol, ".", got_offset);
+
+       /* naclcall %r11 */
+       emit_bytes (acfg, call_start, call_len);
+
+       /* The arg is stored at the offset+1 pointer, relative to beginning */
+       /* of trampoline: 7 for mov, plus the call length, and 1 for push.  */
+       got_offset = ((offset + 1) * sizeof(gpointer)) + 7 + call_len + 1;
+
+       /* We can't emit this data directly, hide in a "push imm32" */
+       emit_byte (acfg, '\x68'); /* push */
+       emit_symbol_diff (acfg, acfg->got_symbol, ".", got_offset);
+       emit_alignment (acfg, kNaClAlignment);
+#endif /*__native_client_codegen__*/
 #elif defined(TARGET_ARM)
        guint8 buf [128];
        guint8 *code;
@@ -807,6 +962,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
@@ -819,32 +1008,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 */
@@ -863,9 +1062,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));
@@ -889,6 +1085,7 @@ static void
 arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
 {
 #if defined(TARGET_AMD64)
+#if defined(__default_codegen__)
        /* This should be exactly 13 bytes long */
        *tramp_size = 13;
 
@@ -902,6 +1099,31 @@ arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_
        emit_byte (acfg, '\xff');
        emit_byte (acfg, '\x25');
        emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset + 1) * sizeof (gpointer)) - 4);
+#elif defined(__native_client_codegen__)
+       guint8 buf [128];
+       guint8 *buf_aligned = ALIGN_TO(buf, kNaClAlignment);
+       guint8 *code = buf_aligned;
+
+       /* mov <OFFSET>(%rip), %r10d */
+       emit_byte (acfg, '\x45');
+       emit_byte (acfg, '\x8b');
+       emit_byte (acfg, '\x15');
+       emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
+
+       /* mov <OFFSET>(%rip), %r11d */
+       emit_byte (acfg, '\x45');
+       emit_byte (acfg, '\x8b');
+       emit_byte (acfg, '\x1d');
+       emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset + 1) * sizeof (gpointer)) - 4);
+
+       /* nacljmp *%r11 */
+       amd64_jump_reg (code, AMD64_R11);
+       emit_bytes (acfg, buf_aligned, code - buf_aligned);
+
+       emit_alignment (acfg, kNaClAlignment);
+       *tramp_size = kNaClAlignment;
+#endif /*__native_client_codegen__*/
+
 #elif defined(TARGET_ARM)
        guint8 buf [128];
        guint8 *code;
@@ -962,6 +1184,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
@@ -983,48 +1233,145 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
 {
 #if defined(TARGET_AMD64)
        guint8 *buf, *code;
+#if defined(__native_client_codegen__)
+       guint8 *buf_alloc;
+#endif
        guint8 *labels [3];
+       guint8 mov_buf[3];
+       guint8 *mov_buf_ptr = mov_buf;
 
+       const int kSizeOfMove = 7;
+#if defined(__default_codegen__)
        code = buf = g_malloc (256);
+#elif defined(__native_client_codegen__)
+       buf_alloc = g_malloc (256 + kNaClAlignment + kSizeOfMove);
+       buf = ((guint)buf_alloc + kNaClAlignment) & ~kNaClAlignmentMask;
+       /* The RIP relative move below is emitted first */
+       buf += kSizeOfMove;
+       code = buf;
+#endif
 
        /* 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 */
+       /* MONO_ARCH_IMT_SCRATCH_REG 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, MONO_ARCH_IMT_SCRATCH_REG, 0, 0);
        labels [1] = code;
-       amd64_branch8 (code, X86_CC_Z, FALSE, 0);
+       amd64_branch8 (code, X86_CC_Z, 0, FALSE);
 
        /* Check key */
-       amd64_alu_membase_reg (code, X86_CMP, AMD64_R10, 0, MONO_ARCH_IMT_REG);
+       amd64_alu_membase_reg_size (code, X86_CMP, MONO_ARCH_IMT_SCRATCH_REG, 0, MONO_ARCH_IMT_REG, sizeof (gpointer));
        labels [2] = code;
-       amd64_branch8 (code, X86_CC_Z, FALSE, 0);
+       amd64_branch8 (code, X86_CC_Z, 0, FALSE);
 
        /* Loop footer */
-       amd64_alu_reg_imm (code, X86_ADD, AMD64_R10, 2 * sizeof (gpointer));
+       amd64_alu_reg_imm (code, X86_ADD, MONO_ARCH_IMT_SCRATCH_REG, 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, MONO_ARCH_IMT_SCRATCH_REG, MONO_ARCH_IMT_SCRATCH_REG, sizeof (gpointer), sizeof (gpointer));
+       amd64_jump_membase (code, MONO_ARCH_IMT_SCRATCH_REG, 0);
 
        /* No match */
        /* FIXME: */
        mono_amd64_patch (labels [1], code);
        x86_breakpoint (code);
 
-       /* mov <OFFSET>(%rip), %r10 */
-       emit_byte (acfg, '\x4d');
-       emit_byte (acfg, '\x8b');
-       emit_byte (acfg, '\x15');
+       /* mov <OFFSET>(%rip), MONO_ARCH_IMT_SCRATCH_REG */
+       amd64_emit_rex (mov_buf_ptr, sizeof(gpointer), MONO_ARCH_IMT_SCRATCH_REG, 0, AMD64_RIP);
+       *(mov_buf_ptr)++ = (unsigned char)0x8b; /* mov opcode */
+       x86_address_byte (mov_buf_ptr, 0, MONO_ARCH_IMT_SCRATCH_REG & 0x7, 5);
+       emit_bytes (acfg, mov_buf, mov_buf_ptr - mov_buf);
        emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
 
        emit_bytes (acfg, buf, code - buf);
        
-       *tramp_size = code - buf + 7;
+       *tramp_size = code - buf + kSizeOfMove;
+#if defined(__native_client_codegen__)
+       /* The tramp will be padded to the next kNaClAlignment bundle. */
+       *tramp_size = ALIGN_TO ((*tramp_size), kNaClAlignment);
+#endif
+
+#if defined(__default_codegen__)
+       g_free (buf);
+#elif defined(__native_client_codegen__)
+       g_free (buf_alloc); 
+#endif
+
+#elif defined(TARGET_X86)
+       guint8 *buf, *code;
+#ifdef __native_client_codegen__
+       guint8 *buf_alloc;
+#endif
+       guint8 *labels [3];
+
+#if defined(__default_codegen__)
+       code = buf = g_malloc (256);
+#elif defined(__native_client_codegen__)
+       buf_alloc = g_malloc (256 + kNaClAlignment);
+       code = buf = ((guint)buf_alloc + kNaClAlignment) & ~kNaClAlignmentMask;
+#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;
+
+#if defined(__default_codegen__)
+       g_free (buf);
+#elif defined(__native_client_codegen__)
+       g_free (buf_alloc); 
+#endif
+
 #elif defined(TARGET_ARM)
        guint8 buf [128];
        guint8 *code, *code2, *labels [16];
@@ -1258,6 +1605,7 @@ stream_init (MonoDynamicStream *sh)
        sh->data = g_malloc (4096);
 
        /* So offsets are > 0 */
+       sh->data [0] = 0;
        sh->index ++;
 }
 
@@ -1296,7 +1644,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);
@@ -1304,6 +1652,24 @@ add_to_blob (MonoAotCompile *acfg, guint8 *data, guint32 data_len)
        return add_stream_data (&acfg->blob, (char*)data, data_len);
 }
 
+static guint32
+add_to_blob_aligned (MonoAotCompile *acfg, const guint8 *data, guint32 data_len, guint32 align)
+{
+       char buf [4] = {0};
+       guint32 count;
+
+       if (acfg->blob.alloc_size == 0)
+               stream_init (&acfg->blob);
+
+       count = acfg->blob.index % align;
+
+       /* we assume the stream data will be aligned */
+       if (count)
+               add_stream_data (&acfg->blob, buf, 4 - count);
+
+       return add_stream_data (&acfg->blob, (char*)data, data_len);
+}
+
 /*
  * emit_offset_table:
  *
@@ -1387,16 +1753,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;
@@ -1603,21 +1974,34 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                case MONO_WRAPPER_ALLOC: {
                        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_WRITE_BARRIER:
                        break;
-               case MONO_WRAPPER_STELEMREF:
+               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)
+                       if (strcmp (method->name, "FastMonitorEnter") == 0) {
                                encode_value (MONO_AOT_WRAPPER_MONO_ENTER, p, &p);
-                       else if (strcmp (method->name, "FastMonitorExit") == 0)
+                       } else if (strcmp (method->name, "FastMonitorExit") == 0) {
                                encode_value (MONO_AOT_WRAPPER_MONO_EXIT, p, &p);
-                       else
+                       } else if (strcmp (method->name, "PtrToStructure") == 0) {
+                               encode_value (MONO_AOT_WRAPPER_PTR_TO_STRUCTURE, p, &p);
+                               encode_klass_ref (acfg, method->klass, p, &p);
+                       } else if (strcmp (method->name, "StructureToPtr") == 0) {
+                               encode_value (MONO_AOT_WRAPPER_STRUCTURE_TO_PTR, p, &p);
+                               encode_klass_ref (acfg, method->klass, p, &p);
+                       } else {
                                g_assert_not_reached ();
+                       }
                        break;
                case MONO_WRAPPER_SYNCHRONIZED:
                case MONO_WRAPPER_MANAGED_TO_NATIVE:
@@ -1742,6 +2126,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:
  *
@@ -1768,36 +2172,68 @@ 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)
 {
-       int res = -1;
+#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 ("%sp_%d", 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)
+{
+       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);
+               res->llvm_symbol = g_strdup_printf ("%s_llvm", res->symbol);
+
+               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;
@@ -2015,6 +2451,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;
@@ -2151,6 +2589,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)));
+               }
        }
 
        /* 
@@ -2273,7 +2722,7 @@ add_wrappers (MonoAotCompile *acfg)
                                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, NULL));
+                               add_method (acfg, mono_marshal_get_managed_wrapper (method, klass, 0));
                        }
                }
 
@@ -2336,13 +2785,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;
@@ -2372,7 +2833,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) {
@@ -2410,14 +2871,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);
                        }
                }
 
@@ -2441,13 +2902,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;
@@ -2458,7 +2940,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);
        }
 }
 
@@ -2481,6 +2963,9 @@ add_generic_instances (MonoAotCompile *acfg)
                token = MONO_TOKEN_METHOD_SPEC | (i + 1);
                method = mono_get_method (acfg->image, token, NULL);
 
+               if (!method)
+                       continue;
+
                if (method->klass->image != acfg->image)
                        continue;
 
@@ -2585,7 +3070,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 */
@@ -2599,7 +3084,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);
@@ -2607,7 +3092,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);
                }
        }
 
@@ -2632,22 +3117,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
@@ -2716,7 +3201,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
        MonoMethodHeader *header;
        gboolean skip, direct_call;
        guint32 got_slot;
-       char direct_call_target [128];
+       char direct_call_target [1024];
 
        if (method) {
                header = mono_method_get_header (method);
@@ -2768,7 +3253,8 @@ 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, callee_cfg->asm_symbol);
+                                               g_assert (strlen (callee_cfg->asm_symbol) < 1000);
+                                               sprintf (direct_call_target, "%s", callee_cfg->asm_symbol);
                                                patch_info->type = MONO_PATCH_INFO_NONE;
                                                acfg->stats.direct_calls ++;
                                        }
@@ -2777,14 +3263,15 @@ 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, "%s%sp_%d", acfg->llvm_label_prefix, acfg->temp_prefix, plt_offset);
+                                               sprintf (direct_call_target, "%s", plt_entry->symbol);
                
                                                /* Nullify the patch */
                                                patch_info->type = MONO_PATCH_INFO_NONE;
+                                               plt_entry->jit_used = TRUE;
                                        }
                                }
 
@@ -2847,7 +3334,7 @@ get_debug_sym (MonoMethod *method, const char *prefix, GHashTable *cache)
 {
        char *name1, *name2, *cached;
        int i, j, len, count;
-               
+
        name1 = mono_method_full_name (method, TRUE);
        len = strlen (name1);
        name2 = malloc (strlen (prefix) + len + 16);
@@ -2894,7 +3381,7 @@ 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);
 
@@ -2956,6 +3443,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);
@@ -3157,6 +3645,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;
@@ -3228,7 +3722,7 @@ emit_exception_debug_info (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);
 
@@ -3241,14 +3735,14 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
 
        seq_points = cfg->seq_point_info;
 
-       buf_size = header->num_clauses * 256 + debug_info_size + 1024 + (seq_points ? (seq_points->len * 64) : 0);
+       buf_size = header->num_clauses * 256 + debug_info_size + 1024 + (seq_points ? (seq_points->len * 64) : 0) + cfg->gc_map_size;
        p = buf = g_malloc (buf_size);
 
 #ifdef MONO_ARCH_HAVE_XP_UNWIND
        use_unwind_ops = cfg->unwind_ops != NULL;
 #endif
 
-       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);
+       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) | (cfg->gc_map ? 64 : 0);
 
        encode_value (flags, p, &p);
 
@@ -3275,6 +3769,11 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
 
        /* Exception table */
        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);
@@ -3291,6 +3790,18 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                        } 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)
@@ -3322,9 +3833,11 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        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'
@@ -3363,7 +3876,6 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                }
        }
                
-
        g_assert (debug_info_size < buf_size);
 
        encode_value (debug_info_size, p, &p);
@@ -3373,12 +3885,23 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                g_free (debug_info);
        }
 
+       /* GC Map */
+       if (cfg->gc_map) {
+               encode_value (cfg->gc_map_size, p, &p);
+               /* The GC map requires 4 bytes of alignment */
+               while ((gsize)p % 4)
+                       p ++;
+               memcpy (p, cfg->gc_map, cfg->gc_map_size);
+               p += cfg->gc_map_size;
+       }
+
        acfg->stats.ex_info_size += p - buf;
 
        g_assert (p - buf < buf_size);
 
        /* Emit info */
-       cfg->ex_info_offset = add_to_blob (acfg, buf, p - buf);
+       /* The GC Map requires 4 byte alignment */
+       cfg->ex_info_offset = add_to_blob_aligned (acfg, buf, p - buf, cfg->gc_map ? 4 : 1);
        g_free (buf);
 }
 
@@ -3391,6 +3914,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);
 
@@ -3454,14 +3991,49 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
        return res;
 }
 
+static char*
+get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cache)
+{
+       char *debug_sym;
+
+       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;
+       }
+
+       return debug_sym;
+}
+
 /*
  * Calls made from AOTed code are routed through a table of jumps similar to the
- * ELF PLT (Program Linkage Table). The differences are the following:
- * - the ELF PLT entries make an indirect jump though the GOT so they expect the
- *   GOT pointer to be in EBX. We want to avoid this, so our table contains direct
- *   jumps. This means the jumps need to be patched when the address of the callee is
- *   known. Initially the PLT entries jump to code which transfers control to the
- *   AOT runtime through the first PLT entry.
+ * ELF PLT (Program Linkage Table). Initially the PLT entries jump to code which transfers
+ * control to the AOT runtime through a trampoline.
  */
 static void
 emit_plt (MonoAotCompile *acfg)
@@ -3476,22 +4048,23 @@ emit_plt (MonoAotCompile *acfg)
        sprintf (symbol, "plt");
 
        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_alignment (acfg, NACL_SIZE(16, kNaClAlignment));
        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, "%s%sp_%d", acfg->llvm_label_prefix, acfg->temp_prefix, i);
+               if (i == 0)
+                       /* 
+                        * The first plt entry is unused.
+                        */
+                       continue;
+
+               plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
+               ji = plt_entry->ji;
 
                if (acfg->llvm) {
                        /*
@@ -3501,81 +4074,102 @@ 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, %s\n", label, callee_cfg->asm_symbol);
+
+                               if (acfg->thumb_mixed && !callee_cfg->compile_llvm) {
+                                       /* LLVM calls the PLT entries using bl, so emit a stub */
+                                       emit_label (acfg, plt_entry->llvm_symbol);
+                                       fprintf (acfg->fp, ".thumb_func\n");
+                                       fprintf (acfg->fp, "bx pc\n");
+                                       fprintf (acfg->fp, "nop\n");
+                                       fprintf (acfg->fp, ".arm\n");
+                                       fprintf (acfg->fp, "b %s\n", callee_cfg->asm_symbol);
+                               } else {
+                                       fprintf (acfg->fp, "\n.set %s, %s\n", plt_entry->llvm_symbol, callee_cfg->asm_symbol);
+                               }
                                continue;
                        }
                }
 
-               emit_label (acfg, label);
+               if (acfg->aot_opts.write_symbols)
+                       plt_entry->debug_sym = get_plt_entry_debug_sym (acfg, ji, cache);
+               debug_sym = plt_entry->debug_sym;
 
-               if (acfg->aot_opts.write_symbols) {
-                       MonoJumpInfo *ji = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
+               if (acfg->thumb_mixed && !plt_entry->jit_used)
+                       /* Emit only a thumb version */
+                       continue;
 
-                       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);
-                                       
-                                       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 (!acfg->thumb_mixed)
+                       emit_label (acfg, plt_entry->llvm_symbol);
 
-                               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. 
-                */
+               emit_label (acfg, plt_entry->symbol);
+
                arch_emit_plt_entry (acfg, i);
 
-               if (debug_sym) {
+               if (debug_sym)
                        emit_symbol_size (acfg, debug_sym, ".");
-                       g_free (debug_sym);
+       }
+
+       if (acfg->thumb_mixed) {
+               /* 
+                * Emit a separate set of PLT entries using thumb2 which is called by LLVM generated
+                * code.
+                */
+               for (i = 0; i < acfg->plt_offset; ++i) {
+                       char *debug_sym = NULL;
+                       MonoPltEntry *plt_entry = NULL;
+                       MonoJumpInfo *ji;
+
+                       if (i == 0)
+                               continue;
+
+                       plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
+                       ji = plt_entry->ji;
+
+                       if (ji && is_direct_callable (acfg, NULL, ji) && !acfg->use_bin_writer)
+                               continue;
+
+                       /* Skip plt entries not actually called by LLVM code */
+                       if (!plt_entry->llvm_used)
+                               continue;
+
+                       if (acfg->aot_opts.write_symbols) {
+                               if (plt_entry->debug_sym)
+                                       debug_sym = g_strdup_printf ("%s_thumb", plt_entry->debug_sym);
+                       }
+
+                       if (debug_sym) {
+                               emit_local_symbol (acfg, debug_sym, NULL, TRUE);
+                               emit_label (acfg, debug_sym);
+                       }
+
+                       emit_label (acfg, plt_entry->llvm_symbol);
+
+                       arch_emit_llvm_plt_entry (acfg, i);
+
+                       if (debug_sym) {
+                               emit_symbol_size (acfg, debug_sym, ".");
+                               g_free (debug_sym);
+                       }
                }
        }
 
        emit_symbol_size (acfg, acfg->plt_symbol, ".");
 
        sprintf (symbol, "plt_end");
-       emit_global (acfg, symbol, TRUE);
        emit_label (acfg, symbol);
 
        g_hash_table_destroy (cache);
 }
 
 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];
@@ -3583,6 +4177,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 */
 
@@ -3590,7 +4199,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);
@@ -3624,7 +4233,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);
 
@@ -3650,10 +4259,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)
@@ -3664,6 +4270,8 @@ emit_trampolines (MonoAotCompile *acfg)
        /* 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.
                 *
@@ -3672,60 +4280,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);
-#ifdef MONO_ARCH_HAVE_THROW_EXCEPTION_BY_NAME
-               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);
-#endif
-               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);
                }
 
                {
@@ -3734,9 +4339,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;
                        }
                }
@@ -3792,8 +4397,7 @@ emit_trampolines (MonoAotCompile *acfg)
                                g_assert_not_reached ();
                        }
 
-                       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;
@@ -3817,6 +4421,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);
@@ -3889,6 +4497,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        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);
@@ -3995,9 +4605,6 @@ can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
        return TRUE;
 }
 
-static void
-add_generic_class (MonoAotCompile *acfg, MonoClass *klass);
-
 /*
  * compile_method:
  *
@@ -4155,7 +4762,7 @@ 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);
@@ -4165,7 +4772,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                                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:
@@ -4179,6 +4786,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 */
@@ -4389,14 +4997,6 @@ mono_aot_get_got_offset (MonoJumpInfo *ji)
 
 char*
 mono_aot_get_method_name (MonoCompile *cfg)
-{
-       guint32 method_index = get_method_index (llvm_acfg, cfg->orig_method);
-
-       return g_strdup_printf ("m_%x", method_index);
-}
-
-char*
-mono_aot_get_method_debug_name (MonoCompile *cfg)
 {
        return get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash);
 }
@@ -4405,7 +5005,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;
@@ -4413,9 +5013,10 @@ 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);
+       plt_entry->llvm_used = TRUE;
 
-       return g_strdup_printf ("%sp_%d", llvm_acfg->temp_prefix, offset);
+       return g_strdup_printf (plt_entry->llvm_symbol);
 }
 
 MonoJumpInfo*
@@ -4444,7 +5045,6 @@ emit_llvm_file (MonoAotCompile *acfg)
        char *command, *opts;
        int i;
        MonoJumpInfo *patch_info;
-       char *llc_target_args;
 
        /*
         * When using LLVM, we let llvm emit the got since the LLVM IL needs to refer
@@ -4459,7 +5059,7 @@ 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);
                                }
                        }
                }
@@ -4491,12 +5091,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 -jump-threading -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 -jump-threading -domtree -memdep -dse -adce -gvn -simplifycfg -preverify -domtree -verify");
+       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);
@@ -4506,10 +5107,18 @@ emit_llvm_file (MonoAotCompile *acfg)
 #endif
        g_free (opts);
 
-       llc_target_args = g_strdup (LLC_TARGET_ARGS);
+       if (!acfg->llc_args)
+               acfg->llc_args = g_string_new ("");
+
+       /* Verbose asm slows down llc greatly */
+       g_string_append (acfg->llc_args, " -asm-verbose=false");
+
+       if (acfg->aot_opts.mtriple)
+               g_string_append_printf (acfg->llc_args, " -mtriple=%s", acfg->aot_opts.mtriple);
 
-       command = g_strdup_printf ("llc %s -f -relocation-model=pic -unwind-tables -o %s temp.opt.bc", llc_target_args, acfg->tmpfname);
-       g_free (llc_target_args);
+       unlink (acfg->tmpfname);
+
+       command = g_strdup_printf ("llc %s -relocation-model=pic -unwind-tables -disable-gnu-eh-frame -enable-mono-eh-frame -o %s temp.opt.bc", acfg->llc_args->str, acfg->tmpfname);
 
        printf ("Executing llc: %s\n", command);
 
@@ -4542,7 +5151,6 @@ emit_code (MonoAotCompile *acfg)
         */
        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) {
@@ -4562,7 +5170,17 @@ emit_code (MonoAotCompile *acfg)
         * Emit some padding so the local symbol for the first method doesn't have the
         * same address as 'methods'.
         */
+#if defined(__default_codegen__)
        emit_zero_bytes (acfg, 16);
+#elif defined(__native_client_codegen__)
+       {
+               const int kPaddingSize = 16;
+               guint8 pad_buffer[kPaddingSize];
+               mono_arch_nacl_pad (pad_buffer, kPaddingSize);
+               emit_bytes (acfg, pad_buffer, kPaddingSize);
+       }
+#endif
+       
 
        for (l = acfg->method_order; l != NULL; l = l->next) {
                MonoCompile *cfg;
@@ -4589,12 +5207,15 @@ emit_code (MonoAotCompile *acfg)
                        }
 
                        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, cfg->generic_sharing_context, call_target);
+                       arch_emit_unbox_trampoline (acfg, cfg->orig_method, call_target);
                }
 
                if (cfg->compile_llvm)
@@ -4605,13 +5226,11 @@ emit_code (MonoAotCompile *acfg)
 
        sprintf (symbol, "methods_end");
        emit_section_change (acfg, ".text", 0);
-       emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
        sprintf (symbol, "code_offsets");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -4650,8 +5269,7 @@ emit_info (MonoAotCompile *acfg)
        }
 
        sprintf (symbol, "method_info_offsets");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -4713,17 +5331,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 */
@@ -4749,10 +5371,16 @@ mono_aot_method_hash (MonoMethod *method)
                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);
 
@@ -4858,23 +5486,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 {
@@ -4912,7 +5523,7 @@ emit_extra_methods (MonoAotCompile *acfg)
                if (!cfg)
                        continue;
 
-               buf_size = 512;
+               buf_size = 10240;
                p = buf = g_malloc (buf_size);
 
                nmethods ++;
@@ -4921,25 +5532,39 @@ emit_extra_methods (MonoAotCompile *acfg)
 
                name = NULL;
                if (method->wrapper_type) {
+                       gboolean encode_ref = FALSE;
+
                        /* 
                         * We encode some wrappers using their name, since encoding them
-                        * directly would be difficult. This also avoids creating the wrapper
-                        * methods at runtime, since they are not needed anyway.
+                        * directly would be difficult. This works because at runtime, we only need to
+                        * check whenever a method ref matches an existing MonoMethod. The downside is
+                        * that the method names are large, so we use the binary encoding if possible.
                         */
                        switch (method->wrapper_type) {
                        case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
                        case MONO_WRAPPER_SYNCHRONIZED:
-                               /* encode_method_ref () can handle these */
+                               encode_ref = TRUE;
                                break;
+                       case MONO_WRAPPER_MANAGED_TO_NATIVE:
+                               /* Skip JIT icall wrappers */
+                               if (!strstr (method->name, "__icall_wrapper"))
+                                       encode_ref = TRUE;
+                               break;
+                       case MONO_WRAPPER_UNKNOWN:
+                               if (!strcmp (method->name, "PtrToStructure") || !strcmp (method->name, "StructureToPtr"))
+                                       encode_ref = TRUE;
+                               break;
                        case MONO_WRAPPER_RUNTIME_INVOKE:
                                if (mono_marshal_method_from_wrapper (method) != method && !strstr (method->name, "virtual"))
                                        /* Direct wrapper, encode normally */
-                                       break;
-                               /* Fall through */
+                                       encode_ref = TRUE;
+                               break;
                        default:
-                               name = mono_aot_wrapper_name (method);
                                break;
                        }
+
+                       if (!encode_ref)
+                               name = mono_aot_wrapper_name (method);
                }
 
                if (name) {
@@ -5007,8 +5632,7 @@ emit_extra_methods (MonoAotCompile *acfg)
 
        /* Emit the table */
        sprintf (symbol, "extra_method_table");
-       emit_section_change (acfg, ".text", 0);
-       emit_global (acfg, symbol, FALSE);
+       emit_section_change (acfg, RODATA_SECT, 0);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5036,8 +5660,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_global (acfg, symbol, FALSE);
+       emit_section_change (acfg, RODATA_SECT, 0);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5068,8 +5691,7 @@ emit_exception_info (MonoAotCompile *acfg)
        }
 
        sprintf (symbol, "ex_info_offsets");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5090,10 +5712,9 @@ 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);
 
        for (i = 0; i < acfg->unwind_ops->len; ++i) {
                guint32 index = GPOINTER_TO_UINT (g_ptr_array_index (acfg->unwind_ops, i));
@@ -5125,8 +5746,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_global (acfg, symbol, FALSE);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5160,6 +5780,8 @@ 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_metadata_str_hash (full_name) % table_size;
                g_free (full_name);
@@ -5184,8 +5806,7 @@ emit_class_name_table (MonoAotCompile *acfg)
 
        /* Emit the table */
        sprintf (symbol, "class_name_table");
-       emit_section_change (acfg, ".text", 0);
-       emit_global (acfg, symbol, FALSE);
+       emit_section_change (acfg, RODATA_SECT, 0);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5220,9 +5841,8 @@ emit_image_table (MonoAotCompile *acfg)
         * So we emit it at once, and reference its elements by an index.
         */
 
-       sprintf (symbol, "mono_image_table");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
+       sprintf (symbol, "image_table");
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5260,9 +5880,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;
@@ -5279,7 +5899,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));
@@ -5304,8 +5924,7 @@ emit_got_info (MonoAotCompile *acfg)
 
        /* Emit got_info_offsets table */
        sprintf (symbol, "got_info_offsets");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5331,13 +5950,6 @@ emit_got (MonoAotCompile *acfg)
                sprintf (symbol, "got_end");
                emit_label (acfg, symbol);
        }
-
-       sprintf (symbol, "mono_aot_got_addr");
-       emit_section_change (acfg, ".data", 0);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-       emit_pointer (acfg, acfg->got_symbol);
 }
 
 typedef struct GlobalsTableEntry {
@@ -5387,7 +5999,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);
 
@@ -5414,7 +6026,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);
        }
@@ -5448,16 +6060,14 @@ emit_globals (MonoAotCompile *acfg)
 {
        char *build_info;
 
-       emit_string_symbol (acfg, "mono_assembly_guid" , acfg->image->guid);
-
-       emit_string_symbol (acfg, "mono_aot_version", MONO_AOT_FILE_VERSION);
+       emit_local_string_symbol (acfg, "assembly_guid" , acfg->image->guid);
 
        if (acfg->aot_opts.bind_to_runtime_version) {
                build_info = mono_get_runtime_build_info ();
-               emit_string_symbol (acfg, "mono_runtime_version", build_info);
+               emit_local_string_symbol (acfg, "runtime_version", build_info);
                g_free (build_info);
        } else {
-               emit_string_symbol (acfg, "mono_runtime_version", "");
+               emit_local_string_symbol (acfg, "runtime_version", "");
        }
 
        /* 
@@ -5476,7 +6086,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);
@@ -5523,7 +6133,6 @@ emit_mem_end (MonoAotCompile *acfg)
 
        sprintf (symbol, "mem_end");
        emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 }
@@ -5536,6 +6145,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);
@@ -5543,13 +6161,65 @@ 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, MONO_AOT_FILE_VERSION);
+       emit_int32 (acfg, 0);
+
+       /* 
+        * We emit pointers to our data structures instead of emitting global symbols which
+        * point to them, to reduce the number of globals, and because using globals leads to
+        * various problems (i.e. arm/thumb).
+        */
+       emit_pointer (acfg, acfg->got_symbol);
+       emit_pointer (acfg, "methods");
+       if (acfg->llvm) {
+               /*
+                * Emit a reference to the mono_eh_frame table created by our modified LLVM compiler.
+                */
+               emit_pointer (acfg, "mono_eh_frame");
+       } else {
+               emit_pointer (acfg, NULL);
+       }
+       emit_pointer (acfg, "blob");
+       emit_pointer (acfg, "class_name_table");
+       emit_pointer (acfg, "class_info_offsets");
+       emit_pointer (acfg, "method_info_offsets");
+       emit_pointer (acfg, "ex_info_offsets");
+       emit_pointer (acfg, "code_offsets");
+       emit_pointer (acfg, "extra_method_info_offsets");
+       emit_pointer (acfg, "extra_method_table");
+       emit_pointer (acfg, "got_info_offsets");
+       emit_pointer (acfg, "methods_end");
+       emit_pointer (acfg, "unwind_info");
+       emit_pointer (acfg, "mem_end");
+       emit_pointer (acfg, "image_table");
+       emit_pointer (acfg, "plt");
+       emit_pointer (acfg, "plt_end");
+       emit_pointer (acfg, "assembly_guid");
+       emit_pointer (acfg, "runtime_version");
+       if (acfg->num_trampoline_got_entries) {
+               emit_pointer (acfg, "specific_trampolines");
+               emit_pointer (acfg, "static_rgctx_trampolines");
+               emit_pointer (acfg, "imt_thunks");
+       } else {
+               emit_pointer (acfg, NULL);
+               emit_pointer (acfg, NULL);
+               emit_pointer (acfg, NULL);
+       }
+       if (acfg->thumb_mixed) {
+               emit_pointer (acfg, "thumb_end");
+       } else {
+               emit_pointer (acfg, NULL);
+       }
+
        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]);
@@ -5565,8 +6235,7 @@ emit_blob (MonoAotCompile *acfg)
        char symbol [128];
 
        sprintf (symbol, "blob");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
+       emit_section_change (acfg, RODATA_SECT, 1);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5728,19 +6397,27 @@ 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__
+#if defined(TARGET_AMD64)
+#define AS_NAME "nacl64-as"
+#else
+#define AS_NAME "nacl-as"
+#endif
+#else
+#define AS_NAME "as"
+#endif
+
 #ifndef LD_OPTIONS
 #define LD_OPTIONS ""
 #endif
 
-#ifdef ENABLE_LLVM
-#define EH_LD_OPTIONS "--eh-frame-hdr"
-#else
 #define EH_LD_OPTIONS ""
-#endif
 
        if (acfg->aot_opts.asm_only) {
                printf ("Output file: '%s'.\n", acfg->tmpfname);
@@ -5757,7 +6434,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);
@@ -5787,6 +6464,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
@@ -5847,8 +6526,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)
@@ -5891,8 +6570,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);
@@ -5953,13 +6632,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;
@@ -5972,8 +6652,12 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 #endif
        acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? acfg->aot_opts.nimt_trampolines : 0;
 
-       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);
+       acfg->temp_prefix = img_writer_get_temp_label_prefix (NULL);
+
+       arch_init (acfg);
+
+       acfg->got_symbol_base = g_strdup_printf ("%smono_aot_%s_got", acfg->llvm_label_prefix, acfg->image->assembly->aname.name);
+       acfg->plt_symbol = g_strdup_printf ("%smono_aot_%s_plt", acfg->llvm_label_prefix, acfg->image->assembly->aname.name);
 
        /* Get rid of characters which cannot occur in symbols */
        for (p = acfg->got_symbol_base; *p; ++p) {
@@ -5985,8 +6669,6 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        *p = '_';
        }
 
-       acfg->temp_prefix = img_writer_get_temp_label_prefix (NULL);
-
        acfg->method_index = 1;
 
        collect_methods (acfg);
@@ -5998,8 +6680,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_base);
+       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 */
@@ -6016,6 +6700,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);
@@ -6038,9 +6727,9 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                } else {
                        acfg->tmpfname = g_strdup ("temp.s");
                }
-       }
 
-       emit_llvm_file (acfg);
+               emit_llvm_file (acfg);
+       }
 #endif
 
        if (!acfg->aot_opts.asm_only && !acfg->aot_opts.asm_writer && bin_writer_supported ()) {
@@ -6087,16 +6776,6 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                outfile_name = 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 = "";
-       if (acfg->llvm)
-               acfg->llvm_label_prefix = LLVM_LABEL_PREFIX;
-
        acfg->got_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, acfg->got_symbol_base);
 
        /* Compute symbols for methods */
@@ -6105,7 +6784,10 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        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, LLVM_LABEL_PREFIX, method_index);
+                       if (COMPILE_LLVM (cfg))
+                               cfg->asm_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, cfg->llvm_method_name);
+                       else
+                               cfg->asm_symbol = g_strdup_printf ("%s%sm_%x", acfg->temp_prefix, acfg->llvm_label_prefix, method_index);
                }
        }
 
@@ -6117,6 +6799,20 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        if (acfg->dwarf)
                mono_dwarf_writer_emit_base_info (acfg->dwarf, mono_unwind_get_cie_program ());
 
+       if (acfg->thumb_mixed) {
+               char symbol [256];
+               /*
+                * This global symbol marks the end of THUMB code, and the beginning of ARM
+                * code generated by our JIT.
+                */
+               sprintf (symbol, "thumb_end");
+               emit_section_change (acfg, ".text", 0);
+               emit_label (acfg, symbol);
+               fprintf (acfg->fp, ".skip 16\n");
+
+               fprintf (acfg->fp, ".arm\n");
+       }
+
        emit_code (acfg);
 
        emit_info (acfg);