Fix warnings.
[mono.git] / mono / mini / aot-compiler.c
index b982cfd3c0cf86c1b6192f81f1b549eba637fe42..b5516fb8034973468e22a76047c504a9cda3e76a 100644 (file)
@@ -80,7 +80,7 @@
 
 #ifdef TARGET_WIN32
 #define SHARED_EXT ".dll"
-#elif defined(__ppc__) && defined(__MACH__)
+#elif defined(__ppc__) && defined(__APPLE__)
 #define SHARED_EXT ".dylib"
 #elif defined(__APPLE__) && defined(TARGET_X86) && !defined(__native_client_codegen__)
 #define SHARED_EXT ".dylib"
@@ -114,6 +114,7 @@ typedef struct MonoAotOptions {
        char *tool_prefix;
        gboolean autoreg;
        char *mtriple;
+       char *llvm_path;
 } MonoAotOptions;
 
 typedef struct MonoAotStats {
@@ -143,7 +144,7 @@ typedef struct MonoAotCompile {
        GPtrArray *extra_methods;
        GPtrArray *image_table;
        GPtrArray *globals;
-       GList *method_order;
+       GPtrArray *method_order;
        guint32 *plt_got_info_offsets;
        guint32 got_offset, plt_offset, plt_got_offset_base;
        guint32 final_got_size;
@@ -184,12 +185,14 @@ typedef struct MonoAotCompile {
        MonoClass **typespec_classes;
        GString *llc_args;
        GString *as_args;
+       gboolean thumb_mixed, need_no_dead_strip, need_pt_gnu_stack;
 } MonoAotCompile;
 
 typedef struct {
        int plt_offset;
-       char *symbol;
+       char *symbol, *llvm_symbol, *debug_sym;
        MonoJumpInfo *ji;
+       gboolean jit_used, llvm_used;
 } MonoPltEntry;
 
 #define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
@@ -371,7 +374,10 @@ static void
 emit_string_symbol (MonoAotCompile *acfg, const char *name, const char *value)
 {
        img_writer_emit_section_change (acfg->w, RODATA_SECT, 1);
-       emit_global (acfg, name, FALSE);
+#ifdef __APPLE__
+       /* On apple, all symbols need to be aligned to avoid warnings from ld */
+       emit_alignment (acfg, 4);
+#endif
        img_writer_emit_label (acfg->w, name);
        img_writer_emit_string (acfg->w, value);
 }
@@ -474,7 +480,7 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #else
 #define AOT_FUNC_ALIGNMENT 16
 #endif
-#if defined(TARGET_X86) && defined(__native_client_codegen__)
+#if (defined(TARGET_X86) || defined(TARGET_AMD64)) && defined(__native_client_codegen__)
 #undef AOT_FUNC_ALIGNMENT
 #define AOT_FUNC_ALIGNMENT 32
 #endif
@@ -487,6 +493,50 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #define PPC_LDX_OP "lwzx"
 #endif
 
+#ifdef TARGET_AMD64
+#define AOT_TARGET_STR "AMD64"
+#endif
+
+#ifdef TARGET_ARM
+#ifdef __MACH__
+#define AOT_TARGET_STR "ARM (MACH)"
+#else
+#define AOT_TARGET_STR "ARM (!MACH)"
+#endif
+#endif
+
+#ifdef TARGET_POWERPC64
+#ifdef __mono_ilp32__
+#define AOT_TARGET_STR "POWERPC64 (mono ilp32)"
+#else
+#define AOT_TARGET_STR "POWERPC64 (!mono ilp32)"
+#endif
+#else
+#ifdef TARGET_POWERPC
+#ifdef __mono_ilp32__
+#define AOT_TARGET_STR "POWERPC (mono ilp32)"
+#else
+#define AOT_TARGET_STR "POWERPC (!mono ilp32)"
+#endif
+#endif
+#endif
+
+#ifdef TARGET_WIN32
+#define AOT_TARGET_STR "WIN32"
+#endif
+
+#ifdef TARGET_X86
+#ifdef __native_client_codegen__
+#define AOT_TARGET_STR "X86 (native client codegen)"
+#else
+#define AOT_TARGET_STR "X86 (!native client codegen)"
+#endif
+#endif
+
+#ifndef AOT_TARGET_STR
+#define AOT_TARGET_STR ""
+#endif
+
 static void
 arch_init (MonoAotCompile *acfg)
 {
@@ -504,7 +554,6 @@ arch_init (MonoAotCompile *acfg)
 #ifdef TARGET_ARM
        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");
@@ -513,10 +562,21 @@ arch_init (MonoAotCompile *acfg)
                g_string_append (acfg->llc_args, " -soft-float");
 #endif
        }
+       if (acfg->aot_opts.mtriple && strstr (acfg->aot_opts.mtriple, "thumb"))
+               acfg->thumb_mixed = TRUE;
 
        if (acfg->aot_opts.mtriple)
                mono_arch_set_target (acfg->aot_opts.mtriple);
 #endif
+
+#ifdef __APPLE__
+       acfg->llvm_label_prefix = "_";
+       acfg->need_no_dead_strip = TRUE;
+#endif
+
+#if defined(__linux__) && !defined(TARGET_ARM)
+       acfg->need_pt_gnu_stack = TRUE;
+#endif
 }
 
 /*
@@ -686,8 +746,14 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
 {
 #if defined(TARGET_X86)
                guint32 offset = (acfg->plt_got_offset_base + index) * sizeof (gpointer);
-
-#ifdef __native_client_codegen__
+#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];
@@ -699,15 +765,9 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                emit_byte (acfg, 0x68);  /* hide data in a push */
                emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
                emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
-#else
-               /* jmp *<offset>(%ebx) */
-               emit_byte (acfg, 0xff);
-               emit_byte (acfg, 0xa3);
-               emit_int32 (acfg, offset);
-               /* Used by mono_aot_get_plt_info_offset */
-               emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
-#endif  /* __native_client_codegen__ */
+#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 
@@ -719,39 +779,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);
 
@@ -774,6 +833,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 */
+       /* The caller already transitioned to thumb */
+       /* 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:
  *
@@ -797,6 +883,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) */
@@ -805,8 +892,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;
@@ -916,7 +1056,7 @@ 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, const char *call_target)
+arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoCompile *cfg, MonoMethod *method, const char *call_target)
 {
 #if defined(TARGET_AMD64)
        guint8 buf [32];
@@ -949,6 +1089,13 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, const char
        guint8 buf [128];
        guint8 *code;
 
+       if (acfg->thumb_mixed && cfg->compile_llvm) {
+               fprintf (acfg->fp, "add r0, r0, #%d\n", sizeof (MonoObject));
+               fprintf (acfg->fp, "b %s\n", call_target);
+               fprintf (acfg->fp, ".arm\n");
+               return;
+       }
+
        code = buf;
 
        ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, sizeof (MonoObject));
@@ -965,7 +1112,10 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, const char
                img_writer_emit_reloc (acfg->w, R_ARM_JUMP24, call_target, -8);
                emit_bytes (acfg, buf, 4);
        } else {
-               fprintf (acfg->fp, "\n\tb %s\n", call_target);
+               if (acfg->thumb_mixed && cfg->compile_llvm)
+                       fprintf (acfg->fp, "\n\tbx %s\n", call_target);
+               else
+                       fprintf (acfg->fp, "\n\tb %s\n", call_target);
        }
 #elif defined(TARGET_POWERPC)
        int this_pos = 3;
@@ -993,6 +1143,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;
 
@@ -1006,6 +1157,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;
@@ -1115,50 +1291,74 @@ 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) */
 
-       /* R11 is a free register */
+       /* MONO_ARCH_IMT_SCRATCH_REG is a free register */
 
        labels [0] = code;
-       amd64_alu_membase_imm (code, X86_CMP, AMD64_R11, 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_R11, 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_R11, 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_R11, AMD64_R11, sizeof (gpointer), 8);
-       amd64_jump_membase (code, AMD64_R11, 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);
 
-       amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 12345678, 8);
-
-       /* mov <OFFSET>(%rip), %r11 */
-       emit_byte (acfg, '\x4d');
-       emit_byte (acfg, '\x8b');
-       emit_byte (acfg, '\x1d');
+       /* 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__
@@ -1166,11 +1366,11 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
 #endif
        guint8 *labels [3];
 
-#ifdef __native_client_codegen__
+#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;
-#else
-       code = buf = g_malloc (256);
 #endif
 
        /* Allocate a temporary stack slot */
@@ -1223,6 +1423,13 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
        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];
@@ -1503,6 +1710,24 @@ add_to_blob (MonoAotCompile *acfg, const 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:
  *
@@ -1822,12 +2047,19 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                        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:
@@ -1852,6 +2084,15 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                                g_assert_not_reached ();
                        }
                        break;
+               case MONO_WRAPPER_CASTCLASS:
+                       if (!strcmp (method->name, "__castclass_with_cache")) {
+                               encode_value (MONO_AOT_WRAPPER_CASTCLASS_WITH_CACHE, p, &p);
+                       } else if (!strcmp (method->name, "__isinst_with_cache")) {
+                               encode_value (MONO_AOT_WRAPPER_ISINST_WITH_CACHE, p, &p);
+                       } else {
+                               g_assert_not_reached ();
+                       }
+                       break;
                default:
                        g_assert_not_reached ();
                }
@@ -2006,7 +2247,7 @@ is_plt_patch (MonoJumpInfo *patch_info)
 static char*
 get_plt_symbol (MonoAotCompile *acfg, int plt_offset, MonoJumpInfo *patch_info)
 {
-#ifdef __MACH__
+#ifdef __APPLE__
        /* 
         * The Apple linker reorganizes object files, so it doesn't like branches to local
         * labels, since those have no relocations.
@@ -2053,6 +2294,7 @@ get_plt_entry (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
                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);
 
@@ -2132,8 +2374,7 @@ add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra, int d
        index = acfg->method_index;
        add_method_with_index (acfg, method, index, extra);
 
-       /* FIXME: Fix quadratic behavior */
-       acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (index));
+       g_ptr_array_add (acfg->method_order, GUINT_TO_POINTER (index));
 
        g_hash_table_insert (acfg->method_depth, method, GUINT_TO_POINTER (depth));
 
@@ -2424,7 +2665,14 @@ add_wrappers (MonoAotCompile *acfg)
                        klass = mono_class_get (acfg->image, token);
                        if (klass)
                                add_method (acfg, mono_marshal_get_virtual_stelemref (mono_array_class_get (klass, 1)));
+                       else
+                               mono_loader_clear_error ();
                }
+
+               /* castclass_with_check wrapper */
+               add_method (acfg, mono_marshal_get_castclass_with_cache ());
+               /* isinst_with_check wrapper */
+               add_method (acfg, mono_marshal_get_isinst_with_cache ());
        }
 
        /* 
@@ -2457,6 +2705,11 @@ add_wrappers (MonoAotCompile *acfg)
                token = MONO_TOKEN_TYPE_DEF | (i + 1);
                klass = mono_class_get (acfg->image, token);
 
+               if (!klass) {
+                       mono_loader_clear_error ();
+                       continue;
+               }
+
                if (klass->delegate && klass != mono_defaults.delegate_class && klass != mono_defaults.multicastdelegate_class && !klass->generic_container) {
                        method = mono_get_delegate_invoke (klass);
 
@@ -2564,6 +2817,11 @@ add_wrappers (MonoAotCompile *acfg)
                token = MONO_TOKEN_TYPE_DEF | (i + 1);
                klass = mono_class_get (acfg->image, token);
 
+               if (!klass) {
+                       mono_loader_clear_error ();
+                       continue;
+               }
+
                if (klass->valuetype && !klass->generic_container && can_marshal_struct (klass)) {
                        add_method (acfg, mono_marshal_get_struct_to_ptr (klass));
                        add_method (acfg, mono_marshal_get_ptr_to_struct (klass));
@@ -2622,6 +2880,34 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass, gboolean force)
        add_generic_class_with_depth (acfg, klass, 0);
 }
 
+static gboolean
+check_type_depth (MonoType *t, int depth)
+{
+       int i;
+
+       if (depth > 8)
+               return TRUE;
+
+       switch (t->type) {
+       case MONO_TYPE_GENERICINST: {
+               MonoGenericClass *gklass = t->data.generic_class;
+               MonoGenericInst *ginst = gklass->context.class_inst;
+
+               if (ginst) {
+                       for (i = 0; i < ginst->type_argc; ++i) {
+                               if (check_type_depth (ginst->type_argv [i], depth + 1))
+                                       return TRUE;
+                       }
+               }
+               break;
+       }
+       default:
+               break;
+       }
+
+       return FALSE;
+}
+
 /*
  * add_generic_class:
  *
@@ -2644,6 +2930,9 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth)
        if (!klass->generic_class && !klass->rank)
                return;
 
+       if (check_type_depth (&klass->byval_arg, 0))
+               return;
+
        iter = NULL;
        while ((method = mono_class_get_methods (klass, &iter))) {
                if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
@@ -2658,7 +2947,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth)
                 * FIXME: Instances which are referenced by these methods are not added,
                 * for example Array.Resize<int> for List<int>.Add ().
                 */
-               add_extra_method_with_depth (acfg, method, depth);
+               add_extra_method_with_depth (acfg, method, depth + 1);
        }
 
        if (klass->delegate) {
@@ -2892,24 +3181,28 @@ add_generic_instances (MonoAotCompile *acfg)
                token = MONO_TOKEN_TYPE_SPEC | (i + 1);
 
                klass = mono_class_get (acfg->image, token);
-               if (!klass || klass->rank)
+               if (!klass || klass->rank) {
+                       mono_loader_clear_error ();
                        continue;
+               }
 
                add_generic_class (acfg, klass, FALSE);
        }
 
        /* Add types of args/locals */
        for (i = 0; i < acfg->methods->len; ++i) {
-               int j;
+               int j, depth;
 
                method = g_ptr_array_index (acfg->methods, i);
 
+               depth = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_depth, method));
+
                sig = mono_method_signature (method);
 
                if (sig) {
                        for (j = 0; j < sig->param_count; ++j)
                                if (sig->params [j]->type == MONO_TYPE_GENERICINST)
-                                       add_generic_class (acfg, mono_class_from_mono_type (sig->params [j]), FALSE);
+                                       add_generic_class_with_depth (acfg, mono_class_from_mono_type (sig->params [j]), depth + 1);
                }
 
                header = mono_method_get_header (method);
@@ -2917,7 +3210,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]), FALSE);
+                                       add_generic_class_with_depth (acfg, mono_class_from_mono_type (header->locals [j]), depth + 1);
                }
        }
 
@@ -2978,6 +3271,24 @@ add_generic_instances (MonoAotCompile *acfg)
                                add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (get_method, &ctx), TRUE, TRUE));
                        }
                }
+
+               /* Same for CompareExchange<T> */
+               {
+                       MonoGenericContext ctx;
+                       MonoType *args [16];
+                       MonoMethod *cas_method;
+                       MonoClass *interlocked_klass = mono_class_from_name (mono_defaults.corlib, "System.Threading", "Interlocked");
+                       gpointer iter = NULL;
+
+                       while ((cas_method = mono_class_get_methods (interlocked_klass, &iter))) {
+                               if (!strcmp (cas_method->name, "CompareExchange") && cas_method->is_generic) {
+                                       memset (&ctx, 0, sizeof (ctx));
+                                       args [0] = &mono_defaults.object_class->byval_arg;
+                                       ctx.method_inst = mono_metadata_get_generic_inst (1, args);
+                                       add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (cas_method, &ctx), TRUE, TRUE));
+                               }
+                       }
+               }
        }
 }
 
@@ -3096,6 +3407,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                
                                                /* Nullify the patch */
                                                patch_info->type = MONO_PATCH_INFO_NONE;
+                                               plt_entry->jit_used = TRUE;
                                        }
                                }
 
@@ -3226,6 +3538,8 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
                debug_sym = get_debug_sym (method, "", acfg->method_label_hash);
 
                sprintf (symbol, "%sme_%x", acfg->temp_prefix, method_index);
+               if (acfg->need_no_dead_strip)
+                       fprintf (acfg->fp, "    .no_dead_strip %s\n", debug_sym);
                emit_local_symbol (acfg, debug_sym, symbol, TRUE);
                emit_label (acfg, debug_sym);
        }
@@ -3268,6 +3582,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                break;
        case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
        case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
+       case MONO_PATCH_INFO_CASTCLASS_CACHE:
                break;
        case MONO_PATCH_INFO_METHOD_REL:
                encode_value ((gint)patch_info->data.offset, p, &p);
@@ -3406,7 +3721,6 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        MonoMethod *method;
        GList *l;
        int pindex, buf_size, n_patches;
-       guint8 *code;
        GPtrArray *patches;
        MonoJumpInfo *patch_info;
        MonoMethodHeader *header;
@@ -3415,7 +3729,6 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        guint32 first_got_offset;
 
        method = cfg->orig_method;
-       code = cfg->native_code;
        header = mono_method_get_header (method);
 
        method_index = get_method_index (acfg, method);
@@ -3559,14 +3872,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 + 2048 + (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);
 
@@ -3700,7 +4013,6 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                }
        }
                
-
        g_assert (debug_info_size < buf_size);
 
        encode_value (debug_info_size, p, &p);
@@ -3710,12 +4022,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);
 }
 
@@ -3729,6 +4052,8 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
        gpointer iter = NULL;
 
        if (!klass) {
+               mono_loader_clear_error ();
+
                buf_size = 16;
 
                p = buf = g_malloc (buf_size);
@@ -3805,14 +4130,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 = NULL;
+
+       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)
@@ -3827,28 +4187,23 @@ emit_plt (MonoAotCompile *acfg)
        sprintf (symbol, "plt");
 
        emit_section_change (acfg, ".text", 0);
-       emit_global (acfg, symbol, TRUE);
-       emit_alignment (acfg, 16);
+       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;
 
-               if (i == 0) {
+               if (i == 0)
                        /* 
-                        * The first plt entry is used to transfer code to the AOT loader. 
+                        * The first plt entry is unused.
                         */
-                       arch_emit_plt_entry (acfg, i);
                        continue;
-               }
 
                plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
                ji = plt_entry->ji;
-               sprintf (label, "%s", plt_entry->symbol);
 
                if (acfg->llvm) {
                        /*
@@ -3860,63 +4215,103 @@ emit_plt (MonoAotCompile *acfg)
                         */
                        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 */
+                                       fprintf (acfg->fp, "\n.thumb_func\n");
+                                       emit_label (acfg, plt_entry->llvm_symbol);
+                                       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) {
-                       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 && !plt_entry->jit_used)
+                       /* Emit only a thumb version */
+                       continue;
+
+               if (!acfg->thumb_mixed)
+                       emit_label (acfg, plt_entry->llvm_symbol);
+
+               if (debug_sym) {
+                       if (acfg->need_no_dead_strip)
+                               fprintf (acfg->fp, "    .no_dead_strip %s\n", debug_sym);
+                       emit_local_symbol (acfg, debug_sym, NULL, TRUE);
+                       emit_label (acfg, debug_sym);
+               }
+
+               emit_label (acfg, plt_entry->symbol);
+
+               arch_emit_plt_entry (acfg, i);
+
+               if (debug_sym)
+                       emit_symbol_size (acfg, debug_sym, ".");
+       }
+
+       if (acfg->thumb_mixed) {
+               /* Make sure the ARM symbols don't alias the thumb ones */
+               emit_zero_bytes (acfg, 16);
+
+               /* 
+                * 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) {
+#if defined(__APPLE__)
+                               fprintf (acfg->fp, "    .thumb_func %s\n", debug_sym);
+                               fprintf (acfg->fp, "    .no_dead_strip %s\n", debug_sym);
+#endif
                                emit_local_symbol (acfg, debug_sym, NULL, TRUE);
                                emit_label (acfg, debug_sym);
                        }
-               }
+                       fprintf (acfg->fp, "\n.thumb_func\n");
 
-               arch_emit_plt_entry (acfg, i);
+                       emit_label (acfg, plt_entry->llvm_symbol);
 
-               if (debug_sym) {
-                       emit_symbol_size (acfg, debug_sym, ".");
-                       g_free (debug_sym);
+                       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);
@@ -4009,11 +4404,11 @@ static void
 emit_trampolines (MonoAotCompile *acfg)
 {
        char symbol [256];
+       char end_symbol [256];
        int i, tramp_got_offset;
        MonoAotTrampoline ntype;
 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
        int tramp_type;
-       guint8 *code;
 #endif
 
        if (!acfg->aot_opts.full_aot)
@@ -4051,15 +4446,15 @@ emit_trampolines (MonoAotCompile *acfg)
                emit_trampoline (acfg, acfg->got_offset, info);
 
                /* Emit the exception related code pieces */
-               code = mono_arch_get_restore_context (&info, TRUE);
+               mono_arch_get_restore_context (&info, TRUE);
                emit_trampoline (acfg, acfg->got_offset, info);
-               code = mono_arch_get_call_filter (&info, TRUE);
+               mono_arch_get_call_filter (&info, TRUE);
                emit_trampoline (acfg, acfg->got_offset, info);
-               code = mono_arch_get_throw_exception (&info, TRUE);
+               mono_arch_get_throw_exception (&info, TRUE);
                emit_trampoline (acfg, acfg->got_offset, info);
-               code = mono_arch_get_rethrow_exception (&info, TRUE);
+               mono_arch_get_rethrow_exception (&info, TRUE);
                emit_trampoline (acfg, acfg->got_offset, info);
-               code = mono_arch_get_throw_corlib_exception (&info, TRUE);
+               mono_arch_get_throw_corlib_exception (&info, TRUE);
                emit_trampoline (acfg, acfg->got_offset, info);
 
 #if defined(MONO_ARCH_HAVE_GET_TRAMPOLINES)
@@ -4079,11 +4474,11 @@ emit_trampolines (MonoAotCompile *acfg)
                        int offset;
 
                        offset = MONO_RGCTX_SLOT_MAKE_RGCTX (i);
-                       code = mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, TRUE);
+                       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 (offset, &info, TRUE);
+                       mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, TRUE);
                        emit_trampoline (acfg, acfg->got_offset, info);
                }
 
@@ -4151,7 +4546,11 @@ emit_trampolines (MonoAotCompile *acfg)
                                g_assert_not_reached ();
                        }
 
-                       emit_global (acfg, symbol, TRUE);
+                       sprintf (end_symbol, "%s_e", symbol);
+
+                       if (acfg->aot_opts.write_symbols)
+                               emit_local_symbol (acfg, symbol, end_symbol, TRUE);
+
                        emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
                        emit_label (acfg, symbol);
 
@@ -4186,6 +4585,8 @@ emit_trampolines (MonoAotCompile *acfg)
                                        acfg->trampoline_size [ntype] = tramp_size;
                                }
                        }
+
+                       emit_label (acfg, end_symbol);
                }
 
                /* Reserve some entries at the end of the GOT for our use */
@@ -4219,6 +4620,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->save_temps = TRUE;
                } else if (str_begins_with (arg, "write-symbols")) {
                        opts->write_symbols = TRUE;
+               } else if (str_begins_with (arg, "no-write-symbols")) {
+                       opts->write_symbols = FALSE;
                } else if (str_begins_with (arg, "metadata-only")) {
                        opts->metadata_only = TRUE;
                } else if (str_begins_with (arg, "bind-to-runtime-version")) {
@@ -4254,6 +4657,36 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->stats = TRUE;
                } else if (str_begins_with (arg, "mtriple=")) {
                        opts->mtriple = g_strdup (arg + strlen ("mtriple="));
+               } else if (str_begins_with (arg, "llvm-path=")) {
+                       opts->llvm_path = g_strdup (arg + strlen ("llvm-path="));
+               } else if (str_begins_with (arg, "info")) {
+                       printf ("AOT target setup: %s.\n", AOT_TARGET_STR);
+                       exit (0);
+               } else if (str_begins_with (arg, "help") || str_begins_with (arg, "?")) {
+                       printf ("Supported options for --aot:\n");
+                       printf ("    outfile=\n");
+                       printf ("    save-temps\n");
+                       printf ("    keep-temps\n");
+                       printf ("    write-symbols\n");
+                       printf ("    metadata-only\n");
+                       printf ("    bind-to-runtime-version\n");
+                       printf ("    full\n");
+                       printf ("    threads=\n");
+                       printf ("    static\n");
+                       printf ("    asmonly\n");
+                       printf ("    asmwriter\n");
+                       printf ("    nodebug\n");
+                       printf ("    ntrampolines=\n");
+                       printf ("    nrgctx-trampolines=\n");
+                       printf ("    nimt-trampolines=\n");
+                       printf ("    autoreg\n");
+                       printf ("    tool-prefix=\n");
+                       printf ("    soft-debug\n");
+                       printf ("    print-skipped\n");
+                       printf ("    stats\n");
+                       printf ("    info\n");
+                       printf ("    help/?\n");
+                       exit (0);
                } else {
                        fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
                        exit (1);
@@ -4319,6 +4752,13 @@ can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
                                        return TRUE;
                                else
                                        return FALSE;
+                       case MONO_WRAPPER_CASTCLASS:
+                               if (!strcmp (method->name, "__castclass_with_cache"))
+                                       return TRUE;
+                               else if (!strcmp (method->name, "__isinst_with_cache"))
+                                       return TRUE;
+                               else
+                                       return FALSE;
                        default:
                                //printf ("Skip (wrapper call): %d -> %s\n", patch_info->type, mono_method_full_name (patch_info->data.method, TRUE));
                                return FALSE;
@@ -4422,6 +4862,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                return;
        }
        if (cfg->exception_type != MONO_EXCEPTION_NONE) {
+               //printf ("E: %s\n", mono_method_full_name (method, TRUE));
                /* Let the exception happen at runtime */
                return;
        }
@@ -4674,7 +5115,8 @@ load_profile_files (MonoAotCompile *acfg)
        int file_index, res, method_index, i;
        char ver [256];
        guint32 token;
-       GList *unordered;
+       GList *unordered, *l;
+       gboolean found;
 
        file_index = 0;
        while (TRUE) {
@@ -4720,9 +5162,15 @@ load_profile_files (MonoAotCompile *acfg)
                                token = mono_method_get_token (method);
                                method_index = mono_metadata_token_index (token) - 1;
 
-                               if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index))) {
-                                       acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
+                               found = FALSE;
+                               for (i = 0; i < acfg->method_order->len; ++i) {
+                                       if (g_ptr_array_index (acfg->method_order, i) == GUINT_TO_POINTER (method_index)) {
+                                               found = TRUE;
+                                               break;
+                                       }
                                }
+                               if (!found)
+                                       g_ptr_array_add (acfg->method_order, GUINT_TO_POINTER (method_index));
                        } else {
                                //printf ("No method found matching '%s'.\n", name);
                        }
@@ -4732,15 +5180,20 @@ load_profile_files (MonoAotCompile *acfg)
 
        /* Add missing methods */
        unordered = NULL;
-       for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
-               if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (i)))
-                       unordered = g_list_prepend (unordered, GUINT_TO_POINTER (i));
+       for (method_index = 0; method_index < acfg->image->tables [MONO_TABLE_METHOD].rows; ++method_index) {
+               found = FALSE;
+               for (i = 0; i < acfg->method_order->len; ++i) {
+                       if (g_ptr_array_index (acfg->method_order, i) == GUINT_TO_POINTER (method_index)) {
+                               found = TRUE;
+                               break;
+                       }
+               }
+               if (!found)
+                       unordered = g_list_prepend (unordered, GUINT_TO_POINTER (method_index));
        }
        unordered = g_list_reverse (unordered);
-       if (acfg->method_order)
-               g_list_last (acfg->method_order)->next = unordered;
-       else
-               acfg->method_order = unordered;
+       for (l = unordered; l; l = l->next)
+               g_ptr_array_add (acfg->method_order, l->data);
 }
  
 /* Used by the LLVM backend */
@@ -4753,7 +5206,11 @@ mono_aot_get_got_offset (MonoJumpInfo *ji)
 char*
 mono_aot_get_method_name (MonoCompile *cfg)
 {
-       return get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash);
+       if (llvm_acfg->aot_opts.static_link)
+               /* Include the assembly name too to avoid duplicate symbol errors */
+               return g_strdup_printf ("%s_%s", llvm_acfg->image->assembly->aname.name, get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash));
+       else
+               return get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash);
 }
 
 char*
@@ -4769,8 +5226,13 @@ mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
                return NULL;
 
        plt_entry = get_plt_entry (llvm_acfg, ji);
+       plt_entry->llvm_used = TRUE;
 
-       return g_strdup_printf (plt_entry->symbol);
+#if defined(__APPLE__)
+       return g_strdup_printf (plt_entry->llvm_symbol + strlen (llvm_acfg->llvm_label_prefix));
+#else
+       return g_strdup_printf (plt_entry->llvm_symbol);
+#endif
 }
 
 MonoJumpInfo*
@@ -4851,9 +5313,9 @@ emit_llvm_file (MonoAotCompile *acfg)
         * then removing tailcallelim + the global opts, and adding a second gvn.
         */
        opts = g_strdup ("-instcombine -simplifycfg");
-       opts = g_strdup ("-simplifycfg -domtree -domfrontier -scalarrepl -instcombine -simplifycfg -basiccg -prune-eh -inline -functionattrs -domtree -domfrontier -scalarrepl -simplify-libcalls -instcombine -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loopsimplify -domfrontier -loopsimplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loopsimplify -lcssa -iv-users -indvars -loop-deletion -loopsimplify -lcssa -loop-unroll -instcombine -memdep -gvn -memdep -memcpyopt -sccp -instcombine -domtree -memdep -dse -adce -gvn -simplifycfg -preverify -domtree -verify");
+       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 -loop-simplify -domfrontier -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loop-simplify -lcssa -iv-users -indvars -loop-deletion -loop-simplify -lcssa -loop-unroll -instcombine -memdep -gvn -memdep -memcpyopt -sccp -instcombine -domtree -memdep -dse -adce -simplifycfg -preverify -domtree -verify");
 #if 1
-       command = g_strdup_printf ("opt -f %s -o temp.opt.bc temp.bc", opts);
+       command = g_strdup_printf ("%sopt -f %s -o temp.opt.bc temp.bc", acfg->aot_opts.llvm_path, opts);
        printf ("Executing opt: %s\n", command);
        if (system (command) != 0) {
                exit (1);
@@ -4870,9 +5332,13 @@ emit_llvm_file (MonoAotCompile *acfg)
        if (acfg->aot_opts.mtriple)
                g_string_append_printf (acfg->llc_args, " -mtriple=%s", acfg->aot_opts.mtriple);
 
+       if (llvm_acfg->aot_opts.static_link)
+               g_string_append_printf (acfg->llc_args, " -relocation-model=static");
+       else
+               g_string_append_printf (acfg->llc_args, " -relocation-model=pic");
        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);
+       command = g_strdup_printf ("%sllc %s -unwind-tables -disable-gnu-eh-frame -enable-mono-eh-frame -o %s temp.opt.bc", acfg->aot_opts.llvm_path, acfg->llc_args->str, acfg->tmpfname);
 
        printf ("Executing llc: %s\n", command);
 
@@ -4885,10 +5351,9 @@ emit_llvm_file (MonoAotCompile *acfg)
 static void
 emit_code (MonoAotCompile *acfg)
 {
-       int i;
+       int oindex, i;
        char symbol [256];
        char end_symbol [256];
-       GList *l;
 
 #if defined(TARGET_POWERPC64)
        sprintf (symbol, ".Lgot_addr");
@@ -4905,7 +5370,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) {
@@ -4925,13 +5389,22 @@ 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) {
+       for (oindex = 0; oindex < acfg->method_order->len; ++oindex) {
                MonoCompile *cfg;
                MonoMethod *method;
 
-               i = GPOINTER_TO_UINT (l->data);
+               i = GPOINTER_TO_UINT (g_ptr_array_index (acfg->method_order, oindex));
 
                cfg = acfg->cfgs [i];
 
@@ -4942,8 +5415,6 @@ emit_code (MonoAotCompile *acfg)
 
                /* Emit unbox trampoline */
                if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
-                       char call_target [256];
-
                        if (!method->wrapper_type && !method->is_inflated) {
                                g_assert (method->token);
                                sprintf (symbol, "ut_%d", mono_metadata_token_index (method->token) - 1);
@@ -4956,11 +5427,13 @@ emit_code (MonoAotCompile *acfg)
                        emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
 #endif
                        emit_global (acfg, symbol, TRUE);
-                       emit_label (acfg, symbol);
 
-                       sprintf (call_target, "%s", cfg->asm_symbol);
+                       if (acfg->thumb_mixed && cfg->compile_llvm)
+                               fprintf (acfg->fp, "\n.thumb_func\n");
+
+                       emit_label (acfg, symbol);
 
-                       arch_emit_unbox_trampoline (acfg, cfg->orig_method, call_target);
+                       arch_emit_unbox_trampoline (acfg, cfg, cfg->orig_method, cfg->asm_symbol);
                }
 
                if (cfg->compile_llvm)
@@ -4971,13 +5444,26 @@ 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);
 
+       /* 
+        * Add .no_dead_strip directives for all LLVM methods to prevent the OSX linker
+        * from optimizing them away, since it doesn't see that code_offsets references them.
+        * JITted methods don't need this since they are referenced using assembler local
+        * symbols.
+        * FIXME: This is why write-symbols doesn't work on OSX ?
+        */
+       if (acfg->llvm && acfg->need_no_dead_strip) {
+               fprintf (acfg->fp, "\n");
+               for (i = 0; i < acfg->nmethods; ++i) {
+                       if (acfg->cfgs [i] && acfg->cfgs [i]->compile_llvm)
+                               fprintf (acfg->fp, ".no_dead_strip %s\n", acfg->cfgs [i]->asm_symbol);
+               }
+       }
+
        sprintf (symbol, "code_offsets");
        emit_section_change (acfg, RODATA_SECT, 1);
-       emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -4997,15 +5483,14 @@ emit_code (MonoAotCompile *acfg)
 static void
 emit_info (MonoAotCompile *acfg)
 {
-       int i;
+       int oindex, i;
        char symbol [256];
-       GList *l;
        gint32 *offsets;
 
        offsets = g_new0 (gint32, acfg->nmethods);
 
-       for (l = acfg->method_order; l != NULL; l = l->next) {
-               i = GPOINTER_TO_UINT (l->data);
+       for (oindex = 0; oindex < acfg->method_order->len; ++oindex) {
+               i = GPOINTER_TO_UINT (g_ptr_array_index (acfg->method_order, oindex));
 
                if (acfg->cfgs [i]) {
                        emit_method_info (acfg, acfg->cfgs [i]);
@@ -5017,7 +5502,6 @@ emit_info (MonoAotCompile *acfg)
 
        sprintf (symbol, "method_info_offsets");
        emit_section_change (acfg, RODATA_SECT, 1);
-       emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5065,8 +5549,9 @@ mono_aot_type_hash (MonoType *t1)
                return ((hash << 5) - hash) ^ mono_metadata_type_hash (&t1->data.array->eklass->byval_arg);
        case MONO_TYPE_GENERICINST:
                return ((hash << 5) - hash) ^ 0;
+       default:
+               return hash;
        }
-       return hash;
 }
 
 /*
@@ -5280,25 +5765,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) {
@@ -5367,7 +5866,6 @@ emit_extra_methods (MonoAotCompile *acfg)
        /* Emit the table */
        sprintf (symbol, "extra_method_table");
        emit_section_change (acfg, RODATA_SECT, 0);
-       emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5396,7 +5894,6 @@ emit_extra_methods (MonoAotCompile *acfg)
         */
        sprintf (symbol, "extra_method_info_offsets");
        emit_section_change (acfg, RODATA_SECT, 0);
-       emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5428,7 +5925,6 @@ emit_exception_info (MonoAotCompile *acfg)
 
        sprintf (symbol, "ex_info_offsets");
        emit_section_change (acfg, RODATA_SECT, 1);
-       emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5452,7 +5948,6 @@ emit_unwind_info (MonoAotCompile *acfg)
        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));
@@ -5470,18 +5965,6 @@ emit_unwind_info (MonoAotCompile *acfg)
 
                acfg->stats.unwind_info_size += (p - buf) + unwind_info_len;
        }
-
-       /*
-        * Emit a reference to the mono_eh_frame table created by our modified LLVM compiler.
-        */
-       if (acfg->llvm) {
-               sprintf (symbol, "mono_eh_frame_addr");
-               emit_section_change (acfg, ".data", 0);
-               emit_global (acfg, symbol, FALSE);
-               emit_alignment (acfg, 8);
-               emit_label (acfg, symbol);
-               emit_pointer (acfg, "mono_eh_frame");
-       }
 }
 
 static void
@@ -5497,7 +5980,6 @@ emit_class_info (MonoAotCompile *acfg)
 
        sprintf (symbol, "class_info_offsets");
        emit_section_change (acfg, RODATA_SECT, 1);
-       emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5531,8 +6013,10 @@ emit_class_name_table (MonoAotCompile *acfg)
        for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
                token = MONO_TOKEN_TYPE_DEF | (i + 1);
                klass = mono_class_get (acfg->image, token);
-               if (!klass)
+               if (!klass) {
+                       mono_loader_clear_error ();
                        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);
@@ -5558,7 +6042,6 @@ emit_class_name_table (MonoAotCompile *acfg)
        /* Emit the table */
        sprintf (symbol, "class_name_table");
        emit_section_change (acfg, RODATA_SECT, 0);
-       emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5593,9 +6076,8 @@ emit_image_table (MonoAotCompile *acfg)
         * So we emit it at once, and reference its elements by an index.
         */
 
-       sprintf (symbol, "mono_image_table");
+       sprintf (symbol, "image_table");
        emit_section_change (acfg, RODATA_SECT, 1);
-       emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5678,7 +6160,6 @@ emit_got_info (MonoAotCompile *acfg)
        /* Emit got_info_offsets table */
        sprintf (symbol, "got_info_offsets");
        emit_section_change (acfg, RODATA_SECT, 1);
-       emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -5704,13 +6185,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 {
@@ -5719,7 +6193,7 @@ typedef struct GlobalsTableEntry {
 } GlobalsTableEntry;
 
 static void
-emit_globals_table (MonoAotCompile *acfg)
+emit_globals (MonoAotCompile *acfg)
 {
        int i, table_size;
        guint32 hash;
@@ -5727,6 +6201,13 @@ emit_globals_table (MonoAotCompile *acfg)
        char symbol [256];
        GlobalsTableEntry *entry, *new_entry;
 
+       if (!acfg->aot_opts.static_link)
+               return;
+
+       /* 
+        * When static linking, we emit a table containing our globals.
+        */
+
        /*
         * Construct a chained hash table for mapping global names to their index in
         * the globals table.
@@ -5788,12 +6269,15 @@ emit_globals_table (MonoAotCompile *acfg)
 
                sprintf (symbol, "name_%d", i);
                emit_section_change (acfg, RODATA_SECT, 1);
+#ifdef __APPLE__
+               emit_alignment (acfg, 4);
+#endif
                emit_label (acfg, symbol);
                emit_string (acfg, name);
        }
 
        /* Emit the globals table */
-       sprintf (symbol, ".Lglobals");
+       sprintf (symbol, "globals");
        emit_section_change (acfg, ".data", 0);
        /* This is not a global, since it is accessed by the init function */
        emit_alignment (acfg, 8);
@@ -5816,60 +6300,6 @@ emit_globals_table (MonoAotCompile *acfg)
        emit_int32 (acfg, 0);
 }
 
-static void
-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);
-
-       if (acfg->aot_opts.bind_to_runtime_version) {
-               build_info = mono_get_runtime_build_info ();
-               emit_string_symbol (acfg, "mono_runtime_version", build_info);
-               g_free (build_info);
-       } else {
-               emit_string_symbol (acfg, "mono_runtime_version", "");
-       }
-
-       /* 
-        * When static linking, we emit a global which will point to the symbol table.
-        */
-       if (acfg->aot_opts.static_link) {
-               char symbol [256];
-               char *p;
-
-               /* Emit a string holding the assembly name */
-               emit_string_symbol (acfg, "mono_aot_assembly_name", acfg->image->assembly->aname.name);
-
-               emit_globals_table (acfg);
-
-               /* 
-                * Emit a global symbol which can be passed by an embedding app to
-                * mono_aot_register_module ().
-                */
-#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);
-#endif
-
-               /* Get rid of characters which cannot occur in symbols */
-               p = symbol;
-               for (p = symbol; *p; ++p) {
-                       if (!(isalnum (*p) || *p == '_'))
-                               *p = '_';
-               }
-               acfg->static_linking_symbol = g_strdup (symbol);
-               emit_global_inner (acfg, symbol, FALSE);
-               emit_alignment (acfg, 8);
-               emit_label (acfg, symbol);
-               sprintf (symbol, "%sglobals", acfg->temp_prefix);
-               emit_pointer (acfg, symbol);
-       }
-}
-
 static void
 emit_autoreg (MonoAotCompile *acfg)
 {
@@ -5896,7 +6326,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);
 }
@@ -5907,10 +6336,24 @@ emit_mem_end (MonoAotCompile *acfg)
 static void
 emit_file_info (MonoAotCompile *acfg)
 {
-       char symbol [128];
+       char symbol [256];
        int i;
        int gc_name_offset;
        const char *gc_name;
+       char *build_info;
+
+       emit_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, "runtime_version", build_info);
+               g_free (build_info);
+       } else {
+               emit_string_symbol (acfg, "runtime_version", "");
+       }
+
+       /* Emit a string holding the assembly name */
+       emit_string_symbol (acfg, "assembly_name", acfg->image->assembly->aname.name);
 
        /*
         * The managed allocators are GC specific, so can't use an AOT image created by one GC
@@ -5923,9 +6366,67 @@ emit_file_info (MonoAotCompile *acfg)
        emit_section_change (acfg, ".data", 0);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
-       emit_global (acfg, symbol, FALSE);
+       if (!acfg->aot_opts.static_link)
+               emit_global (acfg, symbol, FALSE);
 
        /* 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);
+       }
+       if (acfg->aot_opts.static_link) {
+               emit_pointer (acfg, "globals");
+       } else {
+               emit_pointer (acfg, NULL);
+       }
+       emit_pointer (acfg, "assembly_name");
+
        emit_int32 (acfg, acfg->plt_got_offset_base);
        emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
        emit_int32 (acfg, acfg->plt_offset);
@@ -5940,6 +6441,52 @@ emit_file_info (MonoAotCompile *acfg)
                emit_int32 (acfg, acfg->trampoline_got_offset_base [i]);
        for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
                emit_int32 (acfg, acfg->trampoline_size [i]);
+
+#if defined (TARGET_ARM) && defined (__APPLE__)
+       {
+               MonoType t;
+               int align = 0;
+
+               t.type = MONO_TYPE_R8;
+               mono_type_size (&t, &align);
+
+               emit_int32 (acfg, align);
+
+               t.type = MONO_TYPE_I8;
+               mono_type_size (&t, &align);
+
+               emit_int32 (acfg, align);
+       }
+#else
+       emit_int32 (acfg, __alignof__ (double));
+       emit_int32 (acfg, __alignof__ (gint64));
+#endif
+
+       if (acfg->aot_opts.static_link) {
+               char *p;
+
+               /* 
+                * Emit a global symbol which can be passed by an embedding app to
+                * mono_aot_register_module (). The symbol points to a pointer to the the file info
+                * structure.
+                */
+#if defined(__APPLE__) && !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);
+#endif
+
+               /* Get rid of characters which cannot occur in symbols */
+               p = symbol;
+               for (p = symbol; *p; ++p) {
+                       if (!(isalnum (*p) || *p == '_'))
+                               *p = '_';
+               }
+               acfg->static_linking_symbol = g_strdup (symbol);
+               emit_global_inner (acfg, symbol, FALSE);
+               emit_label (acfg, symbol);
+               emit_pointer (acfg, "mono_aot_file_info");
+       }
 }
 
 static void
@@ -5949,7 +6496,6 @@ emit_blob (MonoAotCompile *acfg)
 
        sprintf (symbol, "blob");
        emit_section_change (acfg, RODATA_SECT, 1);
-       emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
@@ -6118,7 +6664,11 @@ compile_asm (MonoAotCompile *acfg)
 #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
@@ -6170,7 +6720,7 @@ compile_asm (MonoAotCompile *acfg)
 
 #if defined(sparc)
        command = g_strdup_printf ("ld -shared -G -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
-#elif defined(__ppc__) && defined(__MACH__)
+#elif defined(__ppc__) && defined(__APPLE__)
        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);
@@ -6195,7 +6745,7 @@ compile_asm (MonoAotCompile *acfg)
        system (com);
        g_free (com);*/
 
-#if defined(TARGET_ARM) && !defined(__MACH__)
+#if defined(TARGET_ARM) && !defined(__APPLE__)
        /* 
         * gas generates 'mapping symbols' each time code and data is mixed, which 
         * happens a lot in emit_and_reloc_code (), so we need to get rid of them.
@@ -6255,6 +6805,7 @@ acfg_create (MonoAssembly *ass, guint32 opts)
        acfg->unwind_info_offsets = g_hash_table_new (NULL, NULL);
        acfg->unwind_ops = g_ptr_array_new ();
        acfg->method_label_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+       acfg->method_order = g_ptr_array_new ();
        InitializeCriticalSection (&acfg->mutex);
 
        return acfg;
@@ -6314,6 +6865,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        acfg->aot_opts.ntrampolines = 1024;
        acfg->aot_opts.nrgctx_trampolines = 1024;
        acfg->aot_opts.nimt_trampolines = 128;
+       acfg->aot_opts.llvm_path = g_strdup ("");
 
        mono_aot_parse_options (aot_options, &acfg->aot_opts);
 
@@ -6349,6 +6901,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                acfg->llvm = TRUE;
                acfg->aot_opts.asm_writer = TRUE;
                acfg->flags |= MONO_AOT_FILE_FLAG_WITH_LLVM;
+
+               if (acfg->aot_opts.soft_debug) {
+                       fprintf (stderr, "The 'soft-debug' option is not supported when compiling with LLVM.\n");
+                       exit (1);
+               }
        }
 
        if (acfg->aot_opts.full_aot)
@@ -6366,7 +6923,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        arch_init (acfg);
 
-       acfg->got_symbol_base = g_strdup_printf ("%smono_aot_%s_got", acfg->llvm_label_prefix, acfg->image->assembly->aname.name);
+       acfg->got_symbol_base = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
        acfg->plt_symbol = g_strdup_printf ("%smono_aot_%s_plt", acfg->llvm_label_prefix, acfg->image->assembly->aname.name);
 
        /* Get rid of characters which cannot occur in symbols */
@@ -6509,6 +7066,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);
+               emit_zero_bytes (acfg, 16);
+
+               fprintf (acfg->fp, ".arm\n");
+       }
+
        emit_code (acfg);
 
        emit_info (acfg);
@@ -6548,6 +7119,13 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        emit_mem_end (acfg);
 
+       if (acfg->need_pt_gnu_stack) {
+               /* This is required so the .so doesn't have an executable stack */
+               /* The bin writer already emits this */
+               if (!acfg->use_bin_writer)
+                       fprintf (acfg->fp, "\n.section  .note.GNU-stack,\"\",@progbits\n");
+       }
+
        TV_GETTIME (btv);
 
        acfg->stats.gen_time = TV_ELAPSED (atv, btv);