[aot] Encode the various aot tables into binary ourselves instead of relying on the...
[mono.git] / mono / mini / aot-compiler.c
index cbc56aac47d467ad3b26b97206aa4d0de59f7221..787a0b127627166dc79d15ed00f845c1922849f7 100644 (file)
@@ -99,7 +99,7 @@ typedef struct MonoAotOptions {
        gboolean write_symbols;
        gboolean metadata_only;
        gboolean bind_to_runtime_version;
-       gboolean full_aot;
+       MonoAotMode mode;
        gboolean no_dlsym;
        gboolean static_link;
        gboolean asm_only;
@@ -130,6 +130,7 @@ typedef struct MonoAotOptions {
        gboolean autoreg;
        char *mtriple;
        char *llvm_path;
+       char *temp_path;
        char *instances_logfile_path;
        char *logfile;
        gboolean dump_json;
@@ -212,12 +213,10 @@ typedef struct MonoAotCompile {
        GHashTable *unwind_info_offsets;
        GPtrArray *unwind_ops;
        guint32 unwind_info_offset;
-       char *got_symbol_base;
-       char *llvm_got_symbol_base;
+       char *global_prefix;
        char *got_symbol;
        char *llvm_got_symbol;
        char *plt_symbol;
-       char *methods_symbol;
        char *llvm_eh_frame_symbol;
        GHashTable *method_label_hash;
        const char *temp_prefix;
@@ -227,6 +226,7 @@ typedef struct MonoAotCompile {
        int align_pad_value;
        guint32 label_generator;
        gboolean llvm;
+       gboolean has_jitted_code;
        MonoAotFileFlags flags;
        MonoDynamicStream blob;
        MonoClass **typespec_classes;
@@ -360,52 +360,52 @@ report_loader_error (MonoAotCompile *acfg, MonoError *error, const char *format,
 static inline void
 emit_section_change (MonoAotCompile *acfg, const char *section_name, int subsection_index)
 {
-       img_writer_emit_section_change (acfg->w, section_name, subsection_index);
+       mono_img_writer_emit_section_change (acfg->w, section_name, subsection_index);
 }
 
 static inline void
 emit_local_symbol (MonoAotCompile *acfg, const char *name, const char *end_label, gboolean func) 
 { 
-       img_writer_emit_local_symbol (acfg->w, name, end_label, func); 
+       mono_img_writer_emit_local_symbol (acfg->w, name, end_label, func); 
 }
 
 static inline void
 emit_label (MonoAotCompile *acfg, const char *name) 
 { 
-       img_writer_emit_label (acfg->w, name); 
+       mono_img_writer_emit_label (acfg->w, name); 
 }
 
 static inline void
 emit_bytes (MonoAotCompile *acfg, const guint8* buf, int size) 
 { 
-       img_writer_emit_bytes (acfg->w, buf, size); 
+       mono_img_writer_emit_bytes (acfg->w, buf, size); 
 }
 
 static inline void
 emit_string (MonoAotCompile *acfg, const char *value) 
 { 
-       img_writer_emit_string (acfg->w, value); 
+       mono_img_writer_emit_string (acfg->w, value); 
 }
 
 static inline void
 emit_line (MonoAotCompile *acfg) 
 { 
-       img_writer_emit_line (acfg->w); 
+       mono_img_writer_emit_line (acfg->w); 
 }
 
 static inline void
 emit_alignment (MonoAotCompile *acfg, int size)
 { 
-       img_writer_emit_alignment (acfg->w, size);
+       mono_img_writer_emit_alignment (acfg->w, size);
 }
 
 static inline void
 emit_alignment_code (MonoAotCompile *acfg, int size)
 {
        if (acfg->align_pad_value)
-               img_writer_emit_alignment_fill (acfg->w, size, acfg->align_pad_value);
+               mono_img_writer_emit_alignment_fill (acfg->w, size, acfg->align_pad_value);
        else
-               img_writer_emit_alignment (acfg->w, size);
+               mono_img_writer_emit_alignment (acfg->w, size);
 }
 
 static inline void
@@ -432,7 +432,7 @@ emit_padding (MonoAotCompile *acfg, int size)
 static inline void
 emit_pointer (MonoAotCompile *acfg, const char *target) 
 { 
-       img_writer_emit_pointer (acfg->w, target); 
+       mono_img_writer_emit_pointer (acfg->w, target); 
 }
 
 static inline void
@@ -440,55 +440,55 @@ emit_pointer_2 (MonoAotCompile *acfg, const char *prefix, const char *target)
 { 
        if (prefix [0] != '\0') {
                char *s = g_strdup_printf ("%s%s", prefix, target);
-               img_writer_emit_pointer (acfg->w, s);
+               mono_img_writer_emit_pointer (acfg->w, s);
                g_free (s);
        } else {
-               img_writer_emit_pointer (acfg->w, target);
+               mono_img_writer_emit_pointer (acfg->w, target);
        }
 }
 
 static inline void
 emit_int16 (MonoAotCompile *acfg, int value) 
 { 
-       img_writer_emit_int16 (acfg->w, value); 
+       mono_img_writer_emit_int16 (acfg->w, value); 
 }
 
 static inline void
 emit_int32 (MonoAotCompile *acfg, int value) 
 { 
-       img_writer_emit_int32 (acfg->w, value); 
+       mono_img_writer_emit_int32 (acfg->w, value); 
 }
 
 static inline void
 emit_symbol_diff (MonoAotCompile *acfg, const char *end, const char* start, int offset) 
 { 
-       img_writer_emit_symbol_diff (acfg->w, end, start, offset); 
+       mono_img_writer_emit_symbol_diff (acfg->w, end, start, offset); 
 }
 
 static inline void
 emit_zero_bytes (MonoAotCompile *acfg, int num) 
 { 
-       img_writer_emit_zero_bytes (acfg->w, num); 
+       mono_img_writer_emit_zero_bytes (acfg->w, num); 
 }
 
 static inline void
 emit_byte (MonoAotCompile *acfg, guint8 val) 
 { 
-       img_writer_emit_byte (acfg->w, val); 
+       mono_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);
+       mono_img_writer_emit_nacl_call_alignment (acfg->w);
 }
 #endif
 
 static G_GNUC_UNUSED void
 emit_global_inner (MonoAotCompile *acfg, const char *name, gboolean func)
 {
-       img_writer_emit_global (acfg->w, name, func);
+       mono_img_writer_emit_global (acfg->w, name, func);
 }
 
 static void
@@ -496,28 +496,28 @@ emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
 {
        if (acfg->aot_opts.no_dlsym) {
                g_ptr_array_add (acfg->globals, g_strdup (name));
-               img_writer_emit_local_symbol (acfg->w, name, NULL, func);
+               mono_img_writer_emit_local_symbol (acfg->w, name, NULL, func);
        } else {
-               img_writer_emit_global (acfg->w, name, func);
+               mono_img_writer_emit_global (acfg->w, name, func);
        }
 }
 
 static void
 emit_symbol_size (MonoAotCompile *acfg, const char *name, const char *end_label)
 {
-       img_writer_emit_symbol_size (acfg->w, name, end_label);
+       mono_img_writer_emit_symbol_size (acfg->w, name, end_label);
 }
 
 static void
 emit_string_symbol (MonoAotCompile *acfg, const char *name, const char *value)
 {
-       img_writer_emit_section_change (acfg->w, RODATA_SECT, 1);
+       mono_img_writer_emit_section_change (acfg->w, RODATA_SECT, 1);
 #ifdef TARGET_MACH
        /* 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);
+       mono_img_writer_emit_label (acfg->w, name);
+       mono_img_writer_emit_string (acfg->w, value);
 }
 
 static G_GNUC_UNUSED void
@@ -607,10 +607,40 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
        *endbuf = p;
 }
 
+static void
+encode_int (gint32 val, guint8 *buf, guint8 **endbuf)
+{
+       // FIXME: Big-endian
+       buf [0] = (val >> 0) & 0xff;
+       buf [1] = (val >> 8) & 0xff;
+       buf [2] = (val >> 16) & 0xff;
+       buf [3] = (val >> 24) & 0xff;
+
+       *endbuf = buf + 4;
+}
+
+static void
+encode_int16 (guint16 val, guint8 *buf, guint8 **endbuf)
+{
+       buf [0] = (val >> 0) & 0xff;
+       buf [1] = (val >> 8) & 0xff;
+
+       *endbuf = buf + 2;
+}
+
+static void
+encode_string (const char *s, guint8 *buf, guint8 **endbuf)
+{
+       int len = strlen (s);
+
+       memcpy (buf, s, len + 1);
+       *endbuf = buf + len + 1;
+}
+
 static void
 emit_unset_mode (MonoAotCompile *acfg)
 {
-       img_writer_emit_unset_mode (acfg->w);
+       mono_img_writer_emit_unset_mode (acfg->w);
 }
 
 static G_GNUC_UNUSED void
@@ -816,7 +846,7 @@ arch_emit_direct_call (MonoAotCompile *acfg, const char *target, gboolean extern
                code = buf;
                ARM_BL (code, 0);
 
-               img_writer_emit_reloc (acfg->w, R_ARM_CALL, target, -8);
+               mono_img_writer_emit_reloc (acfg->w, R_ARM_CALL, target, -8);
                emit_bytes (acfg, buf, 4);
        } else {
                emit_unset_mode (acfg);
@@ -878,8 +908,8 @@ arch_emit_direct_call (MonoAotCompile *acfg, const char *target, gboolean extern
  * arch_emit_got_offset:
  *
  *   The memory pointed to by CODE should hold native code for computing the GOT
- * address. Emit this code while patching it with the offset between code and
- * the GOT. CODE_SIZE is set to the number of bytes emitted.
+ * address (OP_LOAD_GOTADDR). Emit this code while patching it with the offset
+ * between code and the GOT. CODE_SIZE is set to the number of bytes emitted.
  */
 static void
 arch_emit_got_offset (MonoAotCompile *acfg, guint8 *code, int *code_size)
@@ -920,14 +950,12 @@ arch_emit_got_offset (MonoAotCompile *acfg, guint8 *code, int *code_size)
  * arch_emit_got_access:
  *
  *   The memory pointed to by CODE should hold native code for loading a GOT
- * slot. Emit this code while patching it so it accesses the GOT slot GOT_SLOT.
- * CODE_SIZE is set to the number of bytes emitted.
+ * slot (OP_AOTCONST/OP_GOT_ENTRY). Emit this code while patching it so it accesses the
+ * GOT slot GOT_SLOT. CODE_SIZE is set to the number of bytes emitted.
  */
 static void
-arch_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *code_size)
+arch_emit_got_access (MonoAotCompile *acfg, const char *got_symbol, guint8 *code, int got_slot, int *code_size)
 {
-       /* This needs to emit the same code as OP_AOTCONST */
-
 #ifdef TARGET_AMD64
        /* mov reg, got+offset(%rip) */
        if (acfg->llvm) {
@@ -942,11 +970,11 @@ arch_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *cod
                dreg = ((code [2] >> 3) & 0x7) + (rex_r ? 8 : 0);
 
                emit_unset_mode (acfg);
-               fprintf (acfg->fp, "mov %s+%d(%%rip), %s\n", acfg->got_symbol, (unsigned int) ((got_slot * sizeof (gpointer))), mono_arch_regname (dreg));
+               fprintf (acfg->fp, "mov %s+%d(%%rip), %s\n", got_symbol, (unsigned int) ((got_slot * sizeof (gpointer))), mono_arch_regname (dreg));
                *code_size = 7;
        } else {
                emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
-               emit_symbol_diff (acfg, acfg->got_symbol, ".", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
+               emit_symbol_diff (acfg, got_symbol, ".", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
                *code_size = mono_arch_get_patch_offset (code) + 4;
        }
 #elif defined(TARGET_X86)
@@ -955,7 +983,7 @@ arch_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *cod
        *code_size = mono_arch_get_patch_offset (code) + 4;
 #elif defined(TARGET_ARM)
        emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
-       emit_symbol_diff (acfg, acfg->got_symbol, ".", (unsigned int) ((got_slot * sizeof (gpointer))) - 12);
+       emit_symbol_diff (acfg, got_symbol, ".", (unsigned int) ((got_slot * sizeof (gpointer))) - 12);
        *code_size = mono_arch_get_patch_offset (code) + 4;
 #elif defined(TARGET_ARM64)
        emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
@@ -1000,7 +1028,7 @@ arch_emit_objc_selector_ref (MonoAotCompile *acfg, guint8 *code, int index, int
        sprintf (symbol2, "L_OBJC_SELECTOR_REFERENCES_%d", index);
 
        emit_label (acfg, symbol1);
-       img_writer_emit_unset_mode (acfg->w);
+       mono_img_writer_emit_unset_mode (acfg->w);
        fprintf (acfg->fp, ".long %s-(%s+12)", symbol2, symbol1);
 
        *code_size = 12;
@@ -1015,20 +1043,22 @@ arch_emit_objc_selector_ref (MonoAotCompile *acfg, guint8 *code, int index, int
 /*
  * arch_emit_plt_entry:
  *
- *   Emit code for the PLT entry with index INDEX.
+ *   Emit code for the PLT entry.
+ * The plt entry should look like this:
+ * <indirect jump to GOT_SYMBOL + OFFSET>
+ * <INFO_OFFSET embedded into the instruction stream>
  */
 static void
-arch_emit_plt_entry (MonoAotCompile *acfg, int index)
+arch_emit_plt_entry (MonoAotCompile *acfg, const char *got_symbol, int offset, int info_offset)
 {
 #if defined(TARGET_X86)
-               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]);
+               emit_int32 (acfg, info_offset);
 #elif defined(__native_client_codegen__)
                const guint8 kSizeOfNaClJmp = 11;
                guint8 bytes[kSizeOfNaClJmp];
@@ -1039,7 +1069,7 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                /* 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_int32 (acfg, info_offset);
                emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
 #endif /*__native_client_codegen__*/
 #elif defined(TARGET_AMD64)
@@ -1047,13 +1077,13 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                if (acfg->use_bin_writer) {
                        emit_byte (acfg, '\xff');
                        emit_byte (acfg, '\x25');
-                       emit_symbol_diff (acfg, acfg->got_symbol, ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) -4);
+                       emit_symbol_diff (acfg, got_symbol, ".", offset - 4);
                } else {
                        emit_unset_mode (acfg);
-                       fprintf (acfg->fp, "jmp *%s+%d(%%rip)\n", acfg->got_symbol, (int)((acfg->plt_got_offset_base + index) * sizeof (gpointer)));
+                       fprintf (acfg->fp, "jmp *%s+%d(%%rip)\n", got_symbol, offset);
                }
                /* Used by mono_aot_get_plt_info_offset */
-               emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+               emit_int32 (acfg, info_offset);
                acfg->stats.plt_size += 10;
 #elif defined(__native_client_codegen__)
                guint8 buf [256];
@@ -1064,7 +1094,7 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                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);
+               emit_symbol_diff (acfg, got_symbol, ".", offset - 4);
 
                amd64_jump_reg (code, AMD64_R11);
                /* This should be constant for the plt patch */
@@ -1073,7 +1103,7 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
 
                /* 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_int32 (acfg, info_offset);
                emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
 #endif /*__native_client_codegen__*/
 #elif defined(TARGET_ARM)
@@ -1084,14 +1114,12 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                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);
+               emit_symbol_diff (acfg, got_symbol, ".", offset - 4);
                /* Used by mono_aot_get_plt_info_offset */
-               emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+               emit_int32 (acfg, info_offset);
 #elif defined(TARGET_ARM64)
-               arm64_emit_plt_entry (acfg, index);
+               arm64_emit_plt_entry (acfg, got_symbol, offset, info_offset);
 #elif defined(TARGET_POWERPC)
-               guint32 offset = (acfg->plt_got_offset_base + index) * sizeof (gpointer);
-
                /* The GOT address is guaranteed to be in r30 by OP_LOAD_GOTADDR */
                g_assert (!acfg->use_bin_writer);
                emit_unset_mode (acfg);
@@ -1105,24 +1133,22 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
 #endif
                fprintf (acfg->fp, "mtctr 11\n");
                fprintf (acfg->fp, "bctr\n");
-               emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+               emit_int32 (acfg, info_offset);
 #else
                g_assert_not_reached ();
 #endif
 }
 
+/*
+ * arch_emit_llvm_plt_entry:
+ *
+ *   Same as arch_emit_plt_entry, but handles calls from LLVM generated code.
+ * This is only needed on arm to handle thumb interop.
+ */
 static void
-arch_emit_llvm_plt_entry (MonoAotCompile *acfg, int index)
+arch_emit_llvm_plt_entry (MonoAotCompile *acfg, const char *got_symbol, int offset, int info_offset)
 {
 #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 */
@@ -1139,8 +1165,8 @@ arch_emit_llvm_plt_entry (MonoAotCompile *acfg, int index)
        fprintf (acfg->fp, ".2byte 0x44fc\n");
        fprintf (acfg->fp, ".4byte 0xc000f8dc\n");
        fprintf (acfg->fp, ".2byte 0x4760\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]);
+       emit_symbol_diff (acfg, got_symbol, ".", offset + 4);
+       emit_int32 (acfg, info_offset);
        emit_unset_mode (acfg);
        emit_set_arm_mode (acfg);
 #else
@@ -1170,24 +1196,25 @@ arch_emit_specific_trampoline_pages (MonoAotCompile *acfg)
        guint8 *code;
        guint8 *loop_start, *loop_branch_back, *loop_end_check, *imt_found_check;
        int i;
+       int pagesize = MONO_AOT_TRAMP_PAGE_SIZE;
 #define COMMON_TRAMP_SIZE 16
-       int count = (mono_pagesize () - COMMON_TRAMP_SIZE) / 8;
+       int count = (pagesize - COMMON_TRAMP_SIZE) / 8;
        int imm8, rot_amount;
        char symbol [128];
 
        if (!acfg->aot_opts.use_trampolines_page)
                return;
 
-       acfg->tramp_page_size = mono_pagesize ();
+       acfg->tramp_page_size = pagesize;
 
        sprintf (symbol, "%sspecific_trampolines_page", acfg->user_symbol_prefix);
-       emit_alignment (acfg, mono_pagesize ());
+       emit_alignment (acfg, pagesize);
        emit_global (acfg, symbol, TRUE);
        emit_label (acfg, symbol);
 
        /* emit the generic code first, the trampoline address + 8 is in the lr register */
        code = buf;
-       imm8 = mono_arm_is_rotated_imm8 (mono_pagesize (), &rot_amount);
+       imm8 = mono_arm_is_rotated_imm8 (pagesize, &rot_amount);
        ARM_SUB_REG_IMM (code, ARMREG_LR, ARMREG_LR, imm8, rot_amount);
        ARM_LDR_IMM (code, ARMREG_R1, ARMREG_LR, -8);
        ARM_LDR_IMM (code, ARMREG_PC, ARMREG_LR, -4);
@@ -1215,7 +1242,7 @@ arch_emit_specific_trampoline_pages (MonoAotCompile *acfg)
        emit_global (acfg, symbol, TRUE);
        emit_label (acfg, symbol);
        code = buf;
-       imm8 = mono_arm_is_rotated_imm8 (mono_pagesize (), &rot_amount);
+       imm8 = mono_arm_is_rotated_imm8 (pagesize, &rot_amount);
        ARM_SUB_REG_IMM (code, ARMREG_IP, ARMREG_IP, imm8, rot_amount);
        ARM_LDR_IMM (code, MONO_ARCH_RGCTX_REG, ARMREG_IP, -8);
        ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, -4);
@@ -1242,7 +1269,7 @@ arch_emit_specific_trampoline_pages (MonoAotCompile *acfg)
        emit_label (acfg, symbol);
        code = buf;
        ARM_PUSH (code, (1 << ARMREG_R0) | (1 << ARMREG_R1) | (1 << ARMREG_R2) | (1 << ARMREG_R3));
-       imm8 = mono_arm_is_rotated_imm8 (mono_pagesize (), &rot_amount);
+       imm8 = mono_arm_is_rotated_imm8 (pagesize, &rot_amount);
        ARM_SUB_REG_IMM (code, ARMREG_IP, ARMREG_IP, imm8, rot_amount);
        ARM_LDR_IMM (code, ARMREG_R0, ARMREG_IP, -8);
        ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, -4);
@@ -1272,7 +1299,7 @@ arch_emit_specific_trampoline_pages (MonoAotCompile *acfg)
        /* Need at least two free registers, plus a slot for storing the pc */
        ARM_PUSH (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_R2));
 
-       imm8 = mono_arm_is_rotated_imm8 (mono_pagesize (), &rot_amount);
+       imm8 = mono_arm_is_rotated_imm8 (pagesize, &rot_amount);
        ARM_SUB_REG_IMM (code, ARMREG_IP, ARMREG_IP, imm8, rot_amount);
        ARM_LDR_IMM (code, ARMREG_R0, ARMREG_IP, -8);
 
@@ -1597,7 +1624,7 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoCompile *cfg, MonoMethod *
                code = buf;
                ARM_B (code, 0);
 
-               img_writer_emit_reloc (acfg->w, R_ARM_JUMP24, call_target, -8);
+               mono_img_writer_emit_reloc (acfg->w, R_ARM_JUMP24, call_target, -8);
                emit_bytes (acfg, buf, 4);
        } else {
                if (acfg->thumb_mixed && cfg->compile_llvm)
@@ -2336,11 +2363,12 @@ add_to_blob_aligned (MonoAotCompile *acfg, const guint8 *data, guint32 data_len,
  * a given entry. Returns the size of the table.
  */
 static guint32
-emit_offset_table (MonoAotCompile *acfg, int noffsets, int group_size, gint32 *offsets)
+emit_offset_table (MonoAotCompile *acfg, const char *symbol, int noffsets, int group_size, gint32 *offsets)
 {
        gint32 current_offset;
        int i, buf_size, ngroups, index_entry_size;
        guint8 *p, *buf;
+       guint8 *data_p, *data_buf;
        guint32 *index_offsets;
 
        ngroups = (noffsets + (group_size - 1)) / group_size;
@@ -2364,30 +2392,46 @@ emit_offset_table (MonoAotCompile *acfg, int noffsets, int group_size, gint32 *o
                }
                current_offset = offsets [i];
        }
+       data_buf = buf;
+       data_p = p;
 
        if (ngroups && index_offsets [ngroups - 1] < 65000)
                index_entry_size = 2;
        else
                index_entry_size = 4;
 
+       buf_size = (data_p - data_buf) + (ngroups * 4) + 16;
+       p = buf = g_malloc0 (buf_size);
+
        /* Emit the header */
-       emit_int32 (acfg, noffsets);
-       emit_int32 (acfg, group_size);
-       emit_int32 (acfg, ngroups);
-       emit_int32 (acfg, index_entry_size);
+       encode_int (noffsets, p, &p);
+       encode_int (group_size, p, &p);
+       encode_int (ngroups, p, &p);
+       encode_int (index_entry_size, p, &p);
 
        /* Emit the index */
        for (i = 0; i < ngroups; ++i) {
                if (index_entry_size == 2)
-                       emit_int16 (acfg, index_offsets [i]);
+                       encode_int16 (index_offsets [i], p, &p);
                else
-                       emit_int32 (acfg, index_offsets [i]);
+                       encode_int (index_offsets [i], p, &p);
        }
-
        /* Emit the data */
+       memcpy (p, data_buf, data_p - data_buf);
+       p += data_p - data_buf;
+
+       g_assert (p - buf <= buf_size);
+
+       emit_section_change (acfg, RODATA_SECT, 1);
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+
        emit_bytes (acfg, buf, p - buf);
 
-    return (int)(p - buf) + (ngroups * 4);
+       g_free (buf);
+       g_free (data_buf);
+
+    return (int)(p - buf);
 }
 
 static guint32
@@ -3070,7 +3114,6 @@ is_plt_patch (MonoJumpInfo *patch_info)
        case MONO_PATCH_INFO_ICALL_ADDR:
        case MONO_PATCH_INFO_CLASS_INIT:
        case MONO_PATCH_INFO_RGCTX_FETCH:
-       case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
        case MONO_PATCH_INFO_MONITOR_ENTER:
        case MONO_PATCH_INFO_MONITOR_ENTER_V4:
        case MONO_PATCH_INFO_MONITOR_EXIT:
@@ -3215,6 +3258,16 @@ add_method_with_index (MonoAotCompile *acfg, MonoMethod *method, int index, gboo
                g_ptr_array_add (acfg->extra_methods, method);
 }
 
+static gboolean
+prefer_gsharedvt_method (MonoAotCompile *acfg, MonoMethod *method)
+{
+       /* One instantiation with valuetypes is generated for each async method */
+       if (method->klass->image == mono_defaults.corlib && (!strcmp (method->klass->name, "AsyncMethodBuilderCore") || !strcmp (method->klass->name, "AsyncVoidMethodBuilder")))
+               return TRUE;
+       else
+               return FALSE;
+}
+
 static guint32
 get_method_index (MonoAotCompile *acfg, MonoMethod *method)
 {
@@ -3255,8 +3308,11 @@ add_method (MonoAotCompile *acfg, MonoMethod *method)
 static void
 add_extra_method_with_depth (MonoAotCompile *acfg, MonoMethod *method, int depth)
 {
-       if (mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE))
+       if (mono_method_is_generic_sharable_full (method, TRUE, TRUE, FALSE))
                method = mini_get_shared_method (method);
+       else if ((acfg->opts & MONO_OPT_GSHAREDVT) && prefer_gsharedvt_method (acfg, method) && mono_method_is_generic_sharable_full (method, FALSE, FALSE, TRUE))
+               /* Use the gsharedvt version */
+               return;
 
        if (acfg->aot_opts.log_generics)
                aot_printf (acfg, "%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE));
@@ -3563,7 +3619,12 @@ add_wrappers (MonoAotCompile *acfg)
                        /* Managed Allocators */
                        nallocators = mono_gc_get_managed_allocator_types ();
                        for (i = 0; i < nallocators; ++i) {
-                               m = mono_gc_get_managed_allocator_by_type (i);
+                               m = mono_gc_get_managed_allocator_by_type (i, TRUE);
+                               if (m)
+                                       add_method (acfg, m);
+                       }
+                       for (i = 0; i < nallocators; ++i) {
+                               m = mono_gc_get_managed_allocator_by_type (i, FALSE);
                                if (m)
                                        add_method (acfg, m);
                        }
@@ -3659,8 +3720,18 @@ add_wrappers (MonoAotCompile *acfg)
                                for (j = 0; j < cattr->num_attrs; ++j)
                                        if (cattr->attrs [j].ctor && (!strcmp (cattr->attrs [j].ctor->klass->name, "MonoNativeFunctionWrapperAttribute") || !strcmp (cattr->attrs [j].ctor->klass->name, "UnmanagedFunctionPointerAttribute")))
                                                break;
-                               if (j < cattr->num_attrs)
-                                       add_method (acfg, mono_marshal_get_native_func_wrapper_aot (klass));
+                               if (j < cattr->num_attrs) {
+                                       MonoMethod *invoke;
+                                       MonoMethod *wrapper;
+                                       MonoMethod *del_invoke;
+
+                                       /* Add wrappers needed by mono_ftnptr_to_delegate () */
+                                       invoke = mono_get_delegate_invoke (klass);
+                                       wrapper = mono_marshal_get_native_func_wrapper_aot (klass);
+                                       del_invoke = mono_marshal_get_delegate_invoke_internal (invoke, FALSE, TRUE, wrapper);
+                                       add_method (acfg, wrapper);
+                                       add_method (acfg, del_invoke);
+                               }
                        }
                } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->generic_container) {
                        MonoError error;
@@ -3976,13 +4047,19 @@ method_has_type_vars (MonoMethod *method)
        return FALSE;
 }
 
+static
+gboolean mono_aot_mode_is_full (MonoAotOptions *opts)
+{
+       return opts->mode == MONO_AOT_MODE_FULL;
+}
+
 static void add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, const char *ref);
 
 static void
 add_generic_class (MonoAotCompile *acfg, MonoClass *klass, gboolean force, const char *ref)
 {
        /* This might lead to a huge code blowup so only do it if neccesary */
-       if (!acfg->aot_opts.full_aot && !force)
+       if (!mono_aot_mode_is_full (&acfg->aot_opts) && !force)
                return;
 
        add_generic_class_with_depth (acfg, klass, 0, ref);
@@ -4201,6 +4278,42 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth,
                        add_generic_class (acfg, mono_class_inflate_generic_class (gcomparer, &ctx), FALSE, "EqualityComparer<T>");
                }
        }
+
+       /* Add an instance of EnumComparer<T> which is created dynamically by EqualityComparer<T> for enums */
+       if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "EqualityComparer`1")) {
+               MonoClass *enum_comparer;
+               MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+               MonoGenericContext ctx;
+               MonoType *args [16];
+
+               if (mono_class_is_enum (tclass)) {
+                       memset (&ctx, 0, sizeof (ctx));
+                       args [0] = &tclass->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+
+                       enum_comparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "EnumEqualityComparer`1");
+                       g_assert (enum_comparer);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (enum_comparer, &ctx), FALSE, "EqualityComparer<T>");
+               }
+       }
+
+       /* Add an instance of ObjectComparer<T> which is created dynamically by Comparer<T> for enums */
+       if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "Comparer`1")) {
+               MonoClass *comparer;
+               MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+               MonoGenericContext ctx;
+               MonoType *args [16];
+
+               if (mono_class_is_enum (tclass)) {
+                       memset (&ctx, 0, sizeof (ctx));
+                       args [0] = &tclass->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+
+                       comparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "ObjectComparer`1");
+                       g_assert (comparer);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (comparer, &ctx), FALSE, "Comparer<T>");
+               }
+       }
 }
 
 static void
@@ -4879,7 +4992,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
 
                                        got_slot = get_got_offset (acfg, FALSE, patch_info);
 
-                                       arch_emit_got_access (acfg, code + i, got_slot, &code_size);
+                                       arch_emit_got_access (acfg, acfg->got_symbol, code + i, got_slot, &code_size);
                                        i += code_size - INST_LEN;
                                }
                                skip = TRUE;
@@ -4987,7 +5100,9 @@ get_debug_sym (MonoMethod *method, const char *prefix, GHashTable *cache)
        memcpy (name2, prefix, strlen (prefix));
        j = strlen (prefix);
        for (i = 0; i < len; ++i) {
-               if (isalnum (name1 [i])) {
+               if (i == 0 && name1 [0] >= '0' && name1 [0] <= '9') {
+                       name2 [j ++] = '_';
+               } else if (isalnum (name1 [i])) {
                        name2 [j ++] = name1 [i];
                } else if (name1 [i] == ' ' && name1 [i + 1] == '(' && name1 [i + 2] == ')') {
                        i += 2;
@@ -5234,7 +5349,6 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                encode_patch (acfg, entry->data, p, &p);
                break;
        }
-       case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
        case MONO_PATCH_INFO_MONITOR_ENTER:
        case MONO_PATCH_INFO_MONITOR_ENTER_V4:
        case MONO_PATCH_INFO_MONITOR_EXIT:
@@ -5291,6 +5405,8 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                encode_klass_ref (acfg, patch_info->data.virt_method->klass, p, &p);
                encode_method_ref (acfg, patch_info->data.virt_method->method, p, &p);
                break;
+       case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
+               break;
        default:
                g_warning ("unable to handle jump info %d", patch_info->type);
                g_assert_not_reached ();
@@ -5326,7 +5442,6 @@ static void
 emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
 {
        MonoMethod *method;
-       GList *l;
        int pindex, buf_size, n_patches;
        GPtrArray *patches;
        MonoJumpInfo *patch_info;
@@ -5359,16 +5474,7 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
                /* Not needed when loading the method */
                encode_value (0, p, &p);
 
-       /* String table */
-       if (cfg->opt & MONO_OPT_SHARED) {
-               encode_value (g_list_length (cfg->ldstr_list), p, &p);
-               for (l = cfg->ldstr_list; l; l = l->next) {
-                       encode_value ((long)l->data, p, &p);
-               }
-       }
-       else
-               /* Used only in shared mode */
-               g_assert (!cfg->ldstr_list);
+       g_assert (!(cfg->opt & MONO_OPT_SHARED));
 
        n_patches = 0;
        for (pindex = 0; pindex < patches->len; ++pindex) {
@@ -5473,7 +5579,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg, gboolean stor
        }
 
        seq_points = cfg->seq_point_info;
-       seq_points_size = (store_seq_points)? seq_point_info_get_write_size (seq_points) : 0;
+       seq_points_size = (store_seq_points)? mono_seq_point_info_get_write_size (seq_points) : 0;
 
        buf_size = header->num_clauses * 256 + debug_info_size + 2048 + seq_points_size + cfg->gc_map_size;
 
@@ -5559,7 +5665,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg, gboolean stor
                        encode_value (ei->flags, p, &p);
 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
                        /* Not used for catch clauses */
-                       if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
+                       if (ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
                                encode_value (ei->exvar_offset, p, &p);
 #else
                        encode_value (ei->exvar_offset, p, &p);
@@ -5653,41 +5759,15 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg, gboolean stor
                p += p2 - buf2;
                g_free (buf2);
 
-               if (gsctx && (gsctx->var_is_vt || gsctx->mvar_is_vt)) {
-                       MonoMethodInflated *inflated;
-                       MonoGenericContext *context;
-                       MonoGenericInst *inst;
-
-                       g_assert (jinfo->d.method->is_inflated);
-                       inflated = (MonoMethodInflated*)jinfo->d.method;
-                       context = &inflated->context;
-
+               if (gsctx && gsctx->is_gsharedvt) {
                        encode_value (1, p, &p);
-                       if (context->class_inst) {
-                               inst = context->class_inst;
-
-                               encode_value (inst->type_argc, p, &p);
-                               for (i = 0; i < inst->type_argc; ++i)
-                                       encode_value (gsctx->var_is_vt [i], p, &p);
-                       } else {
-                               encode_value (0, p, &p);
-                       }
-                       if (context->method_inst) {
-                               inst = context->method_inst;
-
-                               encode_value (inst->type_argc, p, &p);
-                               for (i = 0; i < inst->type_argc; ++i)
-                                       encode_value (gsctx->mvar_is_vt [i], p, &p);
-                       } else {
-                               encode_value (0, p, &p);
-                       }
                } else {
                        encode_value (0, p, &p);
                }
        }
 
        if (seq_points_size)
-               p += seq_point_info_write (seq_points, p);
+               p += mono_seq_point_info_write (seq_points, p);
 
        g_assert (debug_info_size < buf_size);
 
@@ -5848,9 +5928,6 @@ get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cac
        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
                debug_sym = g_strdup_printf ("%s_jit_icall_native_%s", prefix, ji->data.name);
                break;
-       case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
-               debug_sym = g_strdup_printf ("%s_generic_class_init", prefix);
-               break;
        default:
                break;
        }
@@ -5922,7 +5999,7 @@ emit_plt (MonoAotCompile *acfg)
 
                emit_label (acfg, plt_entry->symbol);
 
-               arch_emit_plt_entry (acfg, i);
+               arch_emit_plt_entry (acfg, acfg->got_symbol, (acfg->plt_got_offset_base + i) * sizeof (gpointer), acfg->plt_got_info_offsets [i]);
 
                if (debug_sym)
                        emit_symbol_size (acfg, debug_sym, ".");
@@ -5969,7 +6046,7 @@ emit_plt (MonoAotCompile *acfg)
                        if (acfg->llvm)
                                emit_global_inner (acfg, plt_entry->llvm_symbol, TRUE);
 
-                       arch_emit_llvm_plt_entry (acfg, i);
+                       arch_emit_llvm_plt_entry (acfg, acfg->got_symbol, (acfg->plt_got_offset_base + i) * sizeof (gpointer), acfg->plt_got_info_offsets [i]);
 
                        if (debug_sym) {
                                emit_symbol_size (acfg, debug_sym, ".");
@@ -6114,7 +6191,7 @@ emit_trampolines (MonoAotCompile *acfg)
        int tramp_type;
 #endif
 
-       if (!acfg->aot_opts.full_aot)
+       if (!mono_aot_mode_is_full (&acfg->aot_opts))
                return;
        
        g_assert (acfg->image->assembly);
@@ -6145,8 +6222,6 @@ emit_trampolines (MonoAotCompile *acfg)
                        emit_trampoline (acfg, acfg->got_offset, info);
                }
 
-               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, FALSE, TRUE);
                emit_trampoline (acfg, acfg->got_offset, info);
@@ -6158,9 +6233,6 @@ emit_trampolines (MonoAotCompile *acfg)
                emit_trampoline (acfg, acfg->got_offset, info);
 #endif
 
-               mono_arch_create_generic_class_init_trampoline (&info, TRUE);
-               emit_trampoline (acfg, acfg->got_offset, info);
-
                /* Emit the exception related code pieces */
                mono_arch_get_restore_context (&info, TRUE);
                emit_trampoline (acfg, acfg->got_offset, info);
@@ -6429,6 +6501,21 @@ add_readonly_value (MonoAotOptions *opts, const char *val)
        readonly_values = rdv;
 }
 
+static gchar *
+clean_path (gchar * path)
+{
+       if (!path)
+               return NULL;
+
+       if (g_str_has_suffix (path, G_DIR_SEPARATOR_S))
+               return path;
+
+       gchar *clean = g_strconcat (path, G_DIR_SEPARATOR_S, NULL);
+       g_free (path);
+
+       return clean;
+}
+
 static void
 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
 {
@@ -6442,6 +6529,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->outfile = g_strdup (arg + strlen ("outfile="));
                } else if (str_begins_with (arg, "llvm-outfile=")) {
                        opts->llvm_outfile = g_strdup (arg + strlen ("llvm-outfile="));
+               } else if (str_begins_with (arg, "temp-path=")) {
+                       opts->temp_path = clean_path (g_strdup (arg + strlen ("temp-path=")));
                } else if (str_begins_with (arg, "save-temps")) {
                        opts->save_temps = TRUE;
                } else if (str_begins_with (arg, "keep-temps")) {
@@ -6455,7 +6544,9 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                } else if (str_begins_with (arg, "bind-to-runtime-version")) {
                        opts->bind_to_runtime_version = TRUE;
                } else if (str_begins_with (arg, "full")) {
-                       opts->full_aot = TRUE;
+                       opts->mode = MONO_AOT_MODE_FULL;
+               } else if (str_begins_with (arg, "hybrid")) {
+                       opts->mode = MONO_AOT_MODE_HYBRID;                      
                } else if (str_begins_with (arg, "threads=")) {
                        opts->nthreads = atoi (arg + strlen ("threads="));
                } else if (str_begins_with (arg, "static")) {
@@ -6513,12 +6604,7 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                } 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="));
-                       if (!g_str_has_suffix (opts->llvm_path, G_DIR_SEPARATOR_S)) {
-                               gchar *old = opts->llvm_path;
-                               opts->llvm_path = g_strconcat (opts->llvm_path, G_DIR_SEPARATOR_S, NULL);
-                               g_free (old);
-                       }
+                       opts->llvm_path = clean_path (g_strdup (arg + strlen ("llvm-path=")));
                } else if (!strcmp (arg, "llvm")) {
                        opts->llvm = TRUE;
                } else if (str_begins_with (arg, "readonly-value=")) {
@@ -6534,6 +6620,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        printf ("Supported options for --aot:\n");
                        printf ("    outfile=\n");
                        printf ("    llvm-outfile=\n");
+                       printf ("    llvm-path=\n");
+                       printf ("    temp-path=\n");
                        printf ("    save-temps\n");
                        printf ("    keep-temps\n");
                        printf ("    write-symbols\n");
@@ -6760,13 +6848,13 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
         * does not need to support them by creating a fake GOT etc.
         */
        flags = JIT_FLAG_AOT;
-       if (acfg->aot_opts.full_aot)
+       if (mono_aot_mode_is_full (&acfg->aot_opts))
                flags |= JIT_FLAG_FULL_AOT;
        if (acfg->llvm)
                flags |= JIT_FLAG_LLVM;
        if (acfg->aot_opts.no_direct_calls)
                flags |= JIT_FLAG_NO_DIRECT_ICALLS;
-       cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), flags, 0);
+       cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), flags, 0, index);
        mono_loader_clear_error ();
 
        if (cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
@@ -6854,6 +6942,9 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                return;
        }
 
+       if (!cfg->compile_llvm)
+               acfg->has_jitted_code = TRUE;
+
        if (method->is_inflated && acfg->aot_opts.log_instances) {
                if (acfg->instances_logfile)
                        fprintf (acfg->instances_logfile, "%s ### %d\n", mono_method_full_name (method, TRUE), cfg->code_size);
@@ -6875,9 +6966,9 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                                if (m->is_inflated) {
                                        if (!(mono_class_generic_sharing_enabled (m->klass) &&
                                                  mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE)) &&
-                                               !method_has_type_vars (m)) {
+                                               (!method_has_type_vars (m) || mono_method_is_generic_sharable_full (m, TRUE, TRUE, FALSE))) {
                                                if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
-                                                       if (acfg->aot_opts.full_aot)
+                                                       if (mono_aot_mode_is_full (&acfg->aot_opts) && !method_has_type_vars (m))
                                                                add_extra_method_with_depth (acfg, mono_marshal_get_native_wrapper (m, TRUE, TRUE), depth + 1);
                                                } else {
                                                        add_extra_method_with_depth (acfg, m, depth + 1);
@@ -7239,8 +7330,10 @@ execute_system (const char * command)
        g_free (wstr);
 
        g_free (command);
-#else
+#elif defined (HAVE_SYSTEM)
        status = system (command);
+#else
+       g_assert_not_reached ();
 #endif
 
        return status;
@@ -7363,19 +7456,6 @@ emit_code (MonoAotCompile *acfg)
         */
        emit_section_change (acfg, ".text", 0);
        emit_alignment_code (acfg, 8);
-       if (acfg->llvm) {
-               for (i = 0; i < acfg->nmethods; ++i) {
-                       if (acfg->cfgs [i] && acfg->cfgs [i]->compile_llvm) {
-                               acfg->methods_symbol = g_strdup (acfg->cfgs [i]->asm_symbol);
-                               break;
-                       }
-               }
-       }
-       if (!acfg->methods_symbol) {
-               sprintf (symbol, "methods");
-               emit_label (acfg, symbol);
-               acfg->methods_symbol = g_strdup (symbol);
-       }
        emit_label (acfg, "jit_code_start");
 
        /* 
@@ -7407,7 +7487,7 @@ emit_code (MonoAotCompile *acfg)
                method = cfg->orig_method;
 
                /* Emit unbox trampoline */
-               if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
+               if (mono_aot_mode_is_full (&acfg->aot_opts) && cfg->orig_method->klass->valuetype) {
                        sprintf (symbol, "ut_%d", get_method_index (acfg, method));
 
                        emit_section_change (acfg, ".text", 0);
@@ -7502,7 +7582,7 @@ emit_code (MonoAotCompile *acfg)
 
                method = cfg->orig_method;
 
-               if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
+               if (mono_aot_mode_is_full (&acfg->aot_opts) && cfg->orig_method->klass->valuetype) {
                        index = get_method_index (acfg, method);
 
                        emit_int32 (acfg, index);
@@ -7532,7 +7612,7 @@ emit_code (MonoAotCompile *acfg)
 
                method = cfg->orig_method;
 
-               if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
+               if (mono_aot_mode_is_full (&acfg->aot_opts) && cfg->orig_method->klass->valuetype) {
 #ifdef MONO_ARCH_AOT_SUPPORTED
                        int call_size;
 
@@ -7550,7 +7630,6 @@ static void
 emit_info (MonoAotCompile *acfg)
 {
        int oindex, i;
-       char symbol [256];
        gint32 *offsets;
 
        offsets = g_new0 (gint32, acfg->nmethods);
@@ -7566,12 +7645,7 @@ emit_info (MonoAotCompile *acfg)
                }
        }
 
-       sprintf (symbol, "method_info_offsets");
-       emit_section_change (acfg, RODATA_SECT, 1);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-
-       acfg->stats.offsets_size += emit_offset_table (acfg, acfg->nmethods, 10, offsets);
+       acfg->stats.offsets_size += emit_offset_table (acfg, "method_info_offsets", acfg->nmethods, 10, offsets);
 
        g_free (offsets);
 }
@@ -7866,54 +7940,60 @@ emit_extra_methods (MonoAotCompile *acfg)
 
        //printf ("MAX: %d\n", max_chain_length);
 
-       /* Emit the table */
-       sprintf (symbol, "extra_method_table");
-       emit_section_change (acfg, RODATA_SECT, 0);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
+       buf_size = table->len * 12 + 4;
+       p = buf = g_malloc (buf_size);
+       encode_int (table_size, p, &p);
 
-       emit_int32 (acfg, table_size);
        for (i = 0; i < table->len; ++i) {
                HashEntry *entry = g_ptr_array_index (table, i);
 
                if (entry == NULL) {
-                       emit_int32 (acfg, 0);
-                       emit_int32 (acfg, 0);
-                       emit_int32 (acfg, 0);
+                       encode_int (0, p, &p);
+                       encode_int (0, p, &p);
+                       encode_int (0, p, &p);
                } else {
                        //g_assert (entry->key > 0);
-                       emit_int32 (acfg, entry->key);
-                       emit_int32 (acfg, entry->value);
+                       encode_int (entry->key, p, &p);
+                       encode_int (entry->value, p, &p);
                        if (entry->next)
-                               emit_int32 (acfg, entry->next->index);
+                               encode_int (entry->next->index, p, &p);
                        else
-                               emit_int32 (acfg, 0);
+                               encode_int (0, p, &p);
                }
        }
+       g_assert (p - buf <= buf_size);
 
-       /* 
-        * Emit a table reverse mapping method indexes to their index in extra_method_info.
-        * This is used by mono_aot_find_jit_info ().
-        */
-       sprintf (symbol, "extra_method_info_offsets");
+       /* Emit the table */
+       sprintf (symbol, "extra_method_table");
        emit_section_change (acfg, RODATA_SECT, 0);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       emit_bytes (acfg, buf, p - buf);
 
-       emit_int32 (acfg, acfg->extra_methods->len);
+       /* 
+        * Emit a table reverse mapping method indexes to their index in extra_method_info.
+        * This is used by mono_aot_find_jit_info ().
+        */
+       buf_size = acfg->extra_methods->len * 8 + 4;
+       p = buf = g_malloc (buf_size);
+       encode_int (acfg->extra_methods->len, p, &p);
        for (i = 0; i < acfg->extra_methods->len; ++i) {
                MonoMethod *method = g_ptr_array_index (acfg->extra_methods, i);
 
-               emit_int32 (acfg, get_method_index (acfg, method));
-               emit_int32 (acfg, info_offsets [i]);
+               encode_int (get_method_index (acfg, method), p, &p);
+               encode_int (info_offsets [i], p, &p);
        }
+       sprintf (symbol, "extra_method_info_offsets");
+       emit_section_change (acfg, RODATA_SECT, 0);
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+       emit_bytes (acfg, buf, p - buf);
 }      
 
 static void
 emit_exception_info (MonoAotCompile *acfg)
 {
        int i;
-       char symbol [256];
        gint32 *offsets;
        SeqPointData sp_data;
        gboolean seq_points_to_file = FALSE;
@@ -7934,10 +8014,10 @@ emit_exception_info (MonoAotCompile *acfg)
 
                        if (method_seq_points_to_file) {
                                if (!seq_points_to_file) {
-                                       seq_point_data_init (&sp_data, acfg->nmethods);
+                                       mono_seq_point_data_init (&sp_data, acfg->nmethods);
                                        seq_points_to_file = TRUE;
                                }
-                               seq_point_data_add (&sp_data, cfg->method->token, cfg->method_index, cfg->seq_point_info);
+                               mono_seq_point_data_add (&sp_data, cfg->method->token, cfg->method_index, cfg->seq_point_info);
                        }
                } else {
                        offsets [i] = 0;
@@ -7947,17 +8027,12 @@ emit_exception_info (MonoAotCompile *acfg)
        if (seq_points_to_file) {
                char *seq_points_aot_file;
                mono_image_get_aot_seq_point_path (acfg->image, &seq_points_aot_file);
-               seq_point_data_write (&sp_data, seq_points_aot_file);
-               seq_point_data_free (&sp_data);
+               mono_seq_point_data_write (&sp_data, seq_points_aot_file);
+               mono_seq_point_data_free (&sp_data);
                g_free (seq_points_aot_file);
        }
 
-       sprintf (symbol, "ex_info_offsets");
-       emit_section_change (acfg, RODATA_SECT, 1);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-
-       acfg->stats.offsets_size += emit_offset_table (acfg, acfg->nmethods, 10, offsets);
+       acfg->stats.offsets_size += emit_offset_table (acfg, "ex_info_offsets", acfg->nmethods, 10, offsets);
        g_free (offsets);
 }
 
@@ -8000,19 +8075,13 @@ static void
 emit_class_info (MonoAotCompile *acfg)
 {
        int i;
-       char symbol [256];
        gint32 *offsets;
 
        offsets = g_new0 (gint32, acfg->image->tables [MONO_TABLE_TYPEDEF].rows);
        for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
                offsets [i] = emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
 
-       sprintf (symbol, "class_info_offsets");
-       emit_section_change (acfg, RODATA_SECT, 1);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-
-       acfg->stats.offsets_size += emit_offset_table (acfg, acfg->image->tables [MONO_TABLE_TYPEDEF].rows, 10, offsets);
+       acfg->stats.offsets_size += emit_offset_table (acfg, "class_info_offsets", acfg->image->tables [MONO_TABLE_TYPEDEF].rows, 10, offsets);
        g_free (offsets);
 }
 
@@ -8024,11 +8093,12 @@ typedef struct ClassNameTableEntry {
 static void
 emit_class_name_table (MonoAotCompile *acfg)
 {
-       int i, table_size;
+       int i, table_size, buf_size;
        guint32 token, hash;
        MonoClass *klass;
        GPtrArray *table;
        char *full_name;
+       guint8 *buf, *p;
        char symbol [256];
        ClassNameTableEntry *entry, *new_entry;
 
@@ -8070,48 +8140,57 @@ emit_class_name_table (MonoAotCompile *acfg)
        }
 
        /* Emit the table */
-       sprintf (symbol, "class_name_table");
-       emit_section_change (acfg, RODATA_SECT, 0);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
+       buf_size = table->len * 4 + 4;
+       p = buf = g_malloc0 (buf_size);
 
        /* FIXME: Optimize memory usage */
        g_assert (table_size < 65000);
-       emit_int16 (acfg, table_size);
+       encode_int16 (table_size, p, &p);
        g_assert (table->len < 65000);
        for (i = 0; i < table->len; ++i) {
                ClassNameTableEntry *entry = g_ptr_array_index (table, i);
 
                if (entry == NULL) {
-                       emit_int16 (acfg, 0);
-                       emit_int16 (acfg, 0);
+                       encode_int16 (0, p, &p);
+                       encode_int16 (0, p, &p);
                } else {
-                       emit_int16 (acfg, mono_metadata_token_index (entry->token));
+                       encode_int16 (mono_metadata_token_index (entry->token), p, &p);
                        if (entry->next)
-                               emit_int16 (acfg, entry->next->index);
+                               encode_int16 (entry->next->index, p, &p);
                        else
-                               emit_int16 (acfg, 0);
+                               encode_int16 (0, p, &p);
                }
        }
+       g_assert (p - buf <= buf_size);
+
+       sprintf (symbol, "class_name_table");
+       emit_section_change (acfg, RODATA_SECT, 0);
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+       emit_bytes (acfg, buf, p - buf);
 }
 
 static void
 emit_image_table (MonoAotCompile *acfg)
 {
-       int i;
+       int i, buf_size;
        char symbol [256];
+       guint8 *buf, *p;
 
        /*
         * The image table is small but referenced in a lot of places.
         * So we emit it at once, and reference its elements by an index.
         */
+       buf_size = acfg->image_table->len * 28 + 4;
+       for (i = 0; i < acfg->image_table->len; i++) {
+               MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
+               MonoAssemblyName *aname = &image->assembly->aname;
 
-       sprintf (symbol, "image_table");
-       emit_section_change (acfg, RODATA_SECT, 1);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
+               buf_size += strlen (image->assembly_name) + strlen (image->guid) + (aname->culture ? strlen (aname->culture) : 1) + strlen ((char*)aname->public_key_token) + 4;
+       }
 
-       emit_int32 (acfg, acfg->image_table->len);
+       buf = p = g_malloc0 (buf_size);
+       encode_int (acfg->image_table->len, p, &p);
        for (i = 0; i < acfg->image_table->len; i++) {
                MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
                MonoAssemblyName *aname = &image->assembly->aname;
@@ -8119,24 +8198,34 @@ emit_image_table (MonoAotCompile *acfg)
                /* FIXME: Support multi-module assemblies */
                g_assert (image->assembly->image == image);
 
-               emit_string (acfg, image->assembly_name);
-               emit_string (acfg, image->guid);
-               emit_string (acfg, aname->culture ? aname->culture : "");
-               emit_string (acfg, (const char*)aname->public_key_token);
+               encode_string (image->assembly_name, p, &p);
+               encode_string (image->guid, p, &p);
+               encode_string (aname->culture ? aname->culture : "", p, &p);
+               encode_string ((const char*)aname->public_key_token, p, &p);
 
-               emit_alignment (acfg, 8);
-               emit_int32 (acfg, aname->flags);
-               emit_int32 (acfg, aname->major);
-               emit_int32 (acfg, aname->minor);
-               emit_int32 (acfg, aname->build);
-               emit_int32 (acfg, aname->revision);
+               while (GPOINTER_TO_UINT (p) % 8 != 0)
+                       p ++;
+
+               encode_int (aname->flags, p, &p);
+               encode_int (aname->major, p, &p);
+               encode_int (aname->minor, p, &p);
+               encode_int (aname->build, p, &p);
+               encode_int (aname->revision, p, &p);
        }
+       g_assert (p - buf <= buf_size);
+
+       sprintf (symbol, "image_table");
+       emit_section_change (acfg, RODATA_SECT, 1);
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+       emit_bytes (acfg, buf, p - buf);
+
+       g_free (buf);
 }
 
 static void
 emit_got_info (MonoAotCompile *acfg, gboolean llvm)
 {
-       char symbol [256];
        int i, first_plt_got_patch = 0, buf_size;
        guint8 *p, *buf;
        guint32 *got_info_offsets;
@@ -8197,16 +8286,9 @@ emit_got_info (MonoAotCompile *acfg, gboolean llvm)
        }
 
        /* Emit got_info_offsets table */
-       if (llvm)
-               sprintf (symbol, "llvm_got_info_offsets");
-       else
-               sprintf (symbol, "got_info_offsets");
-       emit_section_change (acfg, RODATA_SECT, 1);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
 
        /* No need to emit offsets for the got plt entries, the plt embeds them directly */
-       acfg->stats.offsets_size += emit_offset_table (acfg, llvm ? acfg->llvm_got_offset : first_plt_got_patch, 10, (gint32*)got_info_offsets);
+       acfg->stats.offsets_size += emit_offset_table (acfg, llvm ? "llvm_got_info_offsets" : "got_info_offsets", llvm ? acfg->llvm_got_offset : first_plt_got_patch, 10, (gint32*)got_info_offsets);
 }
 
 static void
@@ -8371,37 +8453,113 @@ emit_mem_end (MonoAotCompile *acfg)
        emit_label (acfg, symbol);
 }
 
-/*
- * Emit a structure containing all the information not stored elsewhere.
- */
 static void
-emit_file_info (MonoAotCompile *acfg)
+init_aot_file_info (MonoAotCompile *acfg, MonoAotFileInfo *info, int gc_name_offset)
 {
-       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);
+       info->version = MONO_AOT_FILE_VERSION;
+       info->plt_got_offset_base = acfg->plt_got_offset_base;
+       info->got_size = acfg->got_offset * sizeof (gpointer);
+       info->plt_size = acfg->plt_offset;
+       info->nmethods = acfg->nmethods;
+       info->flags = acfg->flags;
+       info->opts = acfg->opts;
+       info->simd_opts = acfg->simd_opts;
+       info->gc_name_index = gc_name_offset;
+       for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
+               info->num_trampolines [i] = acfg->num_trampolines [i];
+       for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
+               info->trampoline_got_offset_base [i] = acfg->trampoline_got_offset_base [i];
+       for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
+               info->trampoline_size [i] = acfg->trampoline_size [i];
+       info->num_rgctx_fetch_trampolines = acfg->aot_opts.nrgctx_fetch_trampolines;
 
-       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", "");
+#if defined (TARGET_ARM) && defined (TARGET_MACH)
+       {
+               MonoType t;
+               int align = 0;
+
+               memset (&t, 0, sizeof (MonoType));
+               t.type = MONO_TYPE_R8;
+               mono_type_size (&t, &align);
+               info->double_align = align;
+
+               memset (&t, 0, sizeof (MonoType));
+               t.type = MONO_TYPE_I8;
+               mono_type_size (&t, &align);
+               info->long_align = align;
        }
+#else
+       info->double_align = MONO_ABI_ALIGNOF (double);
+       info->long_align = MONO_ABI_ALIGNOF (gint64);
+#endif
+       info->generic_tramp_num = MONO_TRAMPOLINE_NUM;
+       info->tramp_page_size = acfg->tramp_page_size;
+       for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
+               info->tramp_page_code_offsets [i] = acfg->tramp_page_code_offsets [i];
+}
 
-       /* Emit a string holding the assembly name */
-       emit_string_symbol (acfg, "assembly_name", acfg->image->assembly->aname.name);
+static void
+emit_aot_file_info (MonoAotCompile *acfg, MonoAotFileInfo *info)
+{
+       char symbol [256];
+       int i, sindex;
+       const char **symbols;
 
-       /*
-        * 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);
+       symbols = g_new0 (const char *, MONO_AOT_FILE_INFO_NUM_SYMBOLS);
+       sindex = 0;
+       symbols [sindex ++] = acfg->got_symbol;
+       if (acfg->llvm) {
+               symbols [sindex ++] = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, acfg->llvm_got_symbol);
+               symbols [sindex ++] = acfg->llvm_eh_frame_symbol;
+       } else {
+               symbols [sindex ++] = NULL;
+               symbols [sindex ++] = NULL;
+       }
+       symbols [sindex ++] = "jit_code_start";
+       symbols [sindex ++] = "jit_code_end";
+       symbols [sindex ++] = "method_addresses";
+       symbols [sindex ++] = "blob";
+       symbols [sindex ++] = "class_name_table";
+       symbols [sindex ++] = "class_info_offsets";
+       symbols [sindex ++] = "method_info_offsets";
+       symbols [sindex ++] = "ex_info_offsets";
+       symbols [sindex ++] = "extra_method_info_offsets";
+       symbols [sindex ++] = "extra_method_table";
+       symbols [sindex ++] = "got_info_offsets";
+       if (acfg->llvm)
+               symbols [sindex ++] = "llvm_got_info_offsets";
+       else
+               symbols [sindex ++] = NULL;
+       symbols [sindex ++] = "mem_end";
+       symbols [sindex ++] = "image_table";
+       symbols [sindex ++] = "assembly_guid";
+       symbols [sindex ++] = "runtime_version";
+       if (acfg->num_trampoline_got_entries) {
+               symbols [sindex ++] = "specific_trampolines";
+               symbols [sindex ++] = "static_rgctx_trampolines";
+               symbols [sindex ++] = "imt_thunks";
+               symbols [sindex ++] = "gsharedvt_arg_trampolines";
+       } else {
+               symbols [sindex ++] = NULL;
+               symbols [sindex ++] = NULL;
+               symbols [sindex ++] = NULL;
+               symbols [sindex ++] = NULL;
+       }
+       if (acfg->aot_opts.static_link) {
+               symbols [sindex ++] = "globals";
+       } else {
+               symbols [sindex ++] = NULL;
+       }
+       symbols [sindex ++] = "assembly_name";
+       symbols [sindex ++] = "plt";
+       symbols [sindex ++] = "plt_end";
+       symbols [sindex ++] = "unwind_info";
+       symbols [sindex ++] = "unbox_trampolines";
+       symbols [sindex ++] = "unbox_trampolines_end";
+       symbols [sindex ++] = "unbox_trampoline_addresses";
+       g_assert (sindex == MONO_AOT_FILE_INFO_NUM_SYMBOLS);
 
        sprintf (symbol, "%smono_aot_file_info", acfg->user_symbol_prefix);
        emit_section_change (acfg, ".data", 0);
@@ -8412,117 +8570,39 @@ emit_file_info (MonoAotCompile *acfg)
 
        /* The data emitted here must match MonoAotFileInfo. */
 
-       emit_int32 (acfg, MONO_AOT_FILE_VERSION);
-       emit_int32 (acfg, 0);
+       emit_int32 (acfg, info->version);
+       emit_int32 (acfg, info->dummy);
 
        /* 
         * 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);
-       if (acfg->llvm)
-               emit_pointer (acfg, acfg->llvm_got_symbol);
-       else
-               emit_pointer (acfg, NULL);
-       emit_pointer (acfg, acfg->methods_symbol);
-       emit_pointer (acfg, "jit_code_start");
-       emit_pointer (acfg, "jit_code_end");
-       if (acfg->llvm) {
-               /*
-                * Emit a reference to the mono_eh_frame table created by our modified LLVM compiler.
-                */
-               emit_pointer (acfg, acfg->llvm_eh_frame_symbol);
-       } 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, "method_addresses");
-       emit_pointer (acfg, "extra_method_info_offsets");
-       emit_pointer (acfg, "extra_method_table");
-       emit_pointer (acfg, "got_info_offsets");
-       if (acfg->llvm)
-               emit_pointer (acfg, "llvm_got_info_offsets");
-       else
-               emit_pointer (acfg, NULL);
-       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");
-               emit_pointer (acfg, "gsharedvt_arg_trampolines");
-       } else {
-               emit_pointer (acfg, NULL);
-               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_pointer (acfg, "unbox_trampolines");
-       emit_pointer (acfg, "unbox_trampolines_end");
-       emit_pointer (acfg, "unbox_trampoline_addresses");
-
-       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, acfg->simd_opts);
-       emit_int32 (acfg, gc_name_offset);
+       for (i = 0; i < MONO_AOT_FILE_INFO_NUM_SYMBOLS; ++i)
+               emit_pointer (acfg, symbols [i]);
+
+       emit_int32 (acfg, info->plt_got_offset_base);
+       emit_int32 (acfg, info->got_size);
+       emit_int32 (acfg, info->plt_size);
+       emit_int32 (acfg, info->nmethods);
+       emit_int32 (acfg, info->flags);
+       emit_int32 (acfg, info->opts);
+       emit_int32 (acfg, info->simd_opts);
+       emit_int32 (acfg, info->gc_name_index);
+       emit_int32 (acfg, info->num_rgctx_fetch_trampolines);
+       emit_int32 (acfg, info->double_align);
+       emit_int32 (acfg, info->long_align);
+       emit_int32 (acfg, info->generic_tramp_num);
+       emit_int32 (acfg, info->tramp_page_size);
 
        for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
-               emit_int32 (acfg, acfg->num_trampolines [i]);
+               emit_int32 (acfg, info->num_trampolines [i]);
        for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
-               emit_int32 (acfg, acfg->trampoline_got_offset_base [i]);
+               emit_int32 (acfg, info->trampoline_got_offset_base [i]);
        for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
-               emit_int32 (acfg, acfg->trampoline_size [i]);
-       emit_int32 (acfg, acfg->aot_opts.nrgctx_fetch_trampolines);
-
-#if defined (TARGET_ARM) && defined (TARGET_MACH)
-       {
-               MonoType t;
-               int align = 0;
-
-               memset (&t, 0, sizeof (MonoType));
-               t.type = MONO_TYPE_R8;
-               mono_type_size (&t, &align);
-               emit_int32 (acfg, align);
-
-               memset (&t, 0, sizeof (MonoType));
-               t.type = MONO_TYPE_I8;
-               mono_type_size (&t, &align);
-
-               emit_int32 (acfg, align);
-       }
-#else
-       emit_int32 (acfg, MONO_ABI_ALIGNOF (double));
-       emit_int32 (acfg, MONO_ABI_ALIGNOF (gint64));
-#endif
-       emit_int32 (acfg, MONO_TRAMPOLINE_NUM);
-       emit_int32 (acfg, acfg->tramp_page_size);
+               emit_int32 (acfg, info->trampoline_size [i]);
        for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
-               emit_int32 (acfg, acfg->tramp_page_code_offsets [i]);
+               emit_int32 (acfg, info->tramp_page_code_offsets [i]);
 
        if (acfg->aot_opts.static_link) {
                char *p;
@@ -8548,6 +8628,43 @@ emit_file_info (MonoAotCompile *acfg)
        }
 }
 
+/*
+ * Emit a structure containing all the information not stored elsewhere.
+ */
+static void
+emit_file_info (MonoAotCompile *acfg)
+{
+       int gc_name_offset;
+       const char *gc_name;
+       char *build_info;
+       MonoAotFileInfo *info;
+
+       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_string_symbol (acfg, "assembly_guid" , acfg->image->guid);
+
+       /* 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
+        * in another.
+        */
+       gc_name = mono_gc_get_gc_name ();
+       gc_name_offset = add_to_blob (acfg, (guint8*)gc_name, strlen (gc_name) + 1);
+
+       info = g_new0 (MonoAotFileInfo, 1);
+       init_aot_file_info (acfg, info, gc_name_offset);
+
+       emit_aot_file_info (acfg, info);
+}
+
 static void
 emit_blob (MonoAotCompile *acfg)
 {
@@ -8565,6 +8682,7 @@ static void
 emit_objc_selectors (MonoAotCompile *acfg)
 {
        int i;
+       char symbol [128];
 
        if (!acfg->objc_selectors || acfg->objc_selectors->len == 0)
                return;
@@ -8579,13 +8697,16 @@ emit_objc_selectors (MonoAotCompile *acfg)
         * EOF
         */
 
-       img_writer_emit_unset_mode (acfg->w);
+       mono_img_writer_emit_unset_mode (acfg->w);
        g_assert (acfg->fp);
        fprintf (acfg->fp, ".section    __DATA,__objc_selrefs,literal_pointers,no_dead_strip\n");
        fprintf (acfg->fp, ".align      3\n");
        for (i = 0; i < acfg->objc_selectors->len; ++i) {
-               fprintf (acfg->fp, "L_OBJC_SELECTOR_REFERENCES_%d:\n", i);
-               fprintf (acfg->fp, ".long       L_OBJC_METH_VAR_NAME_%d\n", i);
+               sprintf (symbol, "L_OBJC_SELECTOR_REFERENCES_%d", i);
+               emit_label (acfg, symbol);
+               sprintf (symbol, "L_OBJC_METH_VAR_NAME_%d", i);
+               emit_pointer (acfg, symbol);
+
        }
        fprintf (acfg->fp, ".section    __TEXT,__cstring,cstring_literals\n");
        for (i = 0; i < acfg->objc_selectors->len; ++i) {
@@ -8649,7 +8770,7 @@ collect_methods (MonoAotCompile *acfg)
                /* Load all methods eagerly to skip the slower lazy loading code */
                mono_class_setup_methods (method->klass);
 
-               if (acfg->aot_opts.full_aot && method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
+               if (mono_aot_mode_is_full (&acfg->aot_opts) && method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
                        /* Compile the wrapper instead */
                        /* We do this here instead of add_wrappers () because it is easy to do it here */
                        MonoMethod *wrapper = mono_marshal_get_native_wrapper (method, check_for_pending_exc, TRUE);
@@ -8671,6 +8792,10 @@ collect_methods (MonoAotCompile *acfg)
                }
                */
 
+               if (method->is_generic || method->klass->generic_container)
+                       /* Compile the ref shared version instead */
+                       method = mini_get_shared_method (method);
+
                /* Since we add the normal methods first, their index will be equal to their zero based token index */
                add_method_with_index (acfg, method, i, FALSE);
                acfg->method_index ++;
@@ -8688,14 +8813,6 @@ collect_methods (MonoAotCompile *acfg)
                method = mono_get_method_checked (acfg->image, token, NULL, NULL, &error);
                report_loader_error (acfg, &error, "Failed to load method token 0x%x due to %s\n", i, mono_error_get_message (&error));
 
-               /*
-               if (strcmp (method->name, "gshared2"))
-                       continue;
-               */
-               /*
-               if (!strstr (method->klass->image->name, "mini"))
-                       continue;
-               */
                if (method->is_generic || method->klass->generic_container) {
                        MonoMethod *gshared;
 
@@ -8706,7 +8823,7 @@ collect_methods (MonoAotCompile *acfg)
 
        add_generic_instances (acfg);
 
-       if (acfg->aot_opts.full_aot)
+       if (mono_aot_mode_is_full (&acfg->aot_opts))
                add_wrappers (acfg);
        return TRUE;
 }
@@ -8819,6 +8936,8 @@ compile_asm (MonoAotCompile *acfg)
 #define LD_NAME "gcc -shared --dll"
 #elif defined(TARGET_X86) && defined(TARGET_MACH) && !defined(__native_client_codegen__)
 #define LD_NAME "clang -m32 -dynamiclib"
+#elif defined(TARGET_ARM) && !defined(TARGET_ANDROID)
+#define LD_NAME "gcc --shared"
 #endif
 
        if (acfg->aot_opts.asm_only) {
@@ -8914,7 +9033,7 @@ compile_asm (MonoAotCompile *acfg)
         * gas generates 'mapping symbols' each time code and data is mixed, which 
         * happens a lot in emit_and_reloc_code (), so we need to get rid of them.
         */
-       command = g_strdup_printf ("%sstrip --strip-symbol=\\$a --strip-symbol=\\$d %s", tool_prefix, tmp_outfile_name);
+       command = g_strdup_printf ("\"%sstrip\" --strip-symbol=\\$a --strip-symbol=\\$d %s", tool_prefix, tmp_outfile_name);
        aot_printf (acfg, "Stripping the binary: %s\n", command);
        if (execute_system (command) != 0) {
                g_free (tmp_outfile_name);
@@ -9018,7 +9137,7 @@ acfg_free (MonoAotCompile *acfg)
 {
        int i;
 
-       img_writer_destroy (acfg->w);
+       mono_img_writer_destroy (acfg->w);
        for (i = 0; i < acfg->nmethods; ++i)
                if (acfg->cfgs [i])
                        g_free (acfg->cfgs [i]);
@@ -9076,14 +9195,14 @@ static void aot_dump (MonoAotCompile *acfg)
        char * dumpname;
 
        JsonWriter writer;
-       json_writer_init (&writer);
+       mono_json_writer_init (&writer);
 
-       json_writer_object_begin(&writer);
+       mono_json_writer_object_begin(&writer);
 
        // Methods
-       json_writer_indent (&writer);
-       json_writer_object_key(&writer, "methods");
-       json_writer_array_begin (&writer);
+       mono_json_writer_indent (&writer);
+       mono_json_writer_object_key(&writer, "methods");
+       mono_json_writer_array_begin (&writer);
 
        int i;
        for (i = 0; i < acfg->nmethods; ++i) {
@@ -9097,53 +9216,53 @@ static void aot_dump (MonoAotCompile *acfg)
 
                method = cfg->orig_method;
 
-               json_writer_indent (&writer);
-               json_writer_object_begin(&writer);
+               mono_json_writer_indent (&writer);
+               mono_json_writer_object_begin(&writer);
 
-               json_writer_indent (&writer);
-               json_writer_object_key(&writer, "name");
-               json_writer_printf (&writer, "\"%s\",\n", method->name);
+               mono_json_writer_indent (&writer);
+               mono_json_writer_object_key(&writer, "name");
+               mono_json_writer_printf (&writer, "\"%s\",\n", method->name);
 
-               json_writer_indent (&writer);
-               json_writer_object_key(&writer, "signature");
-               json_writer_printf (&writer, "\"%s\",\n", mono_method_full_name (method,
+               mono_json_writer_indent (&writer);
+               mono_json_writer_object_key(&writer, "signature");
+               mono_json_writer_printf (&writer, "\"%s\",\n", mono_method_full_name (method,
                        /*signature=*/TRUE));
 
-               json_writer_indent (&writer);
-               json_writer_object_key(&writer, "code_size");
-               json_writer_printf (&writer, "\"%d\",\n", cfg->code_size);
+               mono_json_writer_indent (&writer);
+               mono_json_writer_object_key(&writer, "code_size");
+               mono_json_writer_printf (&writer, "\"%d\",\n", cfg->code_size);
 
                klass = method->klass;
 
-               json_writer_indent (&writer);
-               json_writer_object_key(&writer, "class");
-               json_writer_printf (&writer, "\"%s\",\n", klass->name);
+               mono_json_writer_indent (&writer);
+               mono_json_writer_object_key(&writer, "class");
+               mono_json_writer_printf (&writer, "\"%s\",\n", klass->name);
 
-               json_writer_indent (&writer);
-               json_writer_object_key(&writer, "namespace");
-               json_writer_printf (&writer, "\"%s\",\n", klass->name_space);
+               mono_json_writer_indent (&writer);
+               mono_json_writer_object_key(&writer, "namespace");
+               mono_json_writer_printf (&writer, "\"%s\",\n", klass->name_space);
 
-               json_writer_indent (&writer);
-               json_writer_object_key(&writer, "wrapper_type");
-               json_writer_printf (&writer, "\"%s\",\n", get_wrapper_type_name(method->wrapper_type));
+               mono_json_writer_indent (&writer);
+               mono_json_writer_object_key(&writer, "wrapper_type");
+               mono_json_writer_printf (&writer, "\"%s\",\n", get_wrapper_type_name(method->wrapper_type));
 
-               json_writer_indent_pop (&writer);
-               json_writer_indent (&writer);
-               json_writer_object_end (&writer);
-               json_writer_printf (&writer, ",\n");
+               mono_json_writer_indent_pop (&writer);
+               mono_json_writer_indent (&writer);
+               mono_json_writer_object_end (&writer);
+               mono_json_writer_printf (&writer, ",\n");
        }
 
-       json_writer_indent_pop (&writer);
-       json_writer_indent (&writer);
-       json_writer_array_end (&writer);
-       json_writer_printf (&writer, ",\n");
+       mono_json_writer_indent_pop (&writer);
+       mono_json_writer_indent (&writer);
+       mono_json_writer_array_end (&writer);
+       mono_json_writer_printf (&writer, ",\n");
 
        // PLT entries
 #ifdef DUMP_PLT
-       json_writer_indent_push (&writer);
-       json_writer_indent (&writer);
-       json_writer_object_key(&writer, "plt");
-       json_writer_array_begin (&writer);
+       mono_json_writer_indent_push (&writer);
+       mono_json_writer_indent (&writer);
+       mono_json_writer_object_key(&writer, "plt");
+       mono_json_writer_array_begin (&writer);
 
        for (i = 0; i < acfg->plt_offset; ++i) {
                MonoPltEntry *plt_entry = NULL;
@@ -9158,44 +9277,44 @@ static void aot_dump (MonoAotCompile *acfg)
                plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
                ji = plt_entry->ji;
 
-               json_writer_indent (&writer);
-               json_writer_printf (&writer, "{ ");
-               json_writer_object_key(&writer, "symbol");
-               json_writer_printf (&writer, "\"%s\" },\n", plt_entry->symbol);
+               mono_json_writer_indent (&writer);
+               mono_json_writer_printf (&writer, "{ ");
+               mono_json_writer_object_key(&writer, "symbol");
+               mono_json_writer_printf (&writer, "\"%s\" },\n", plt_entry->symbol);
        }
 
-       json_writer_indent_pop (&writer);
-       json_writer_indent (&writer);
-       json_writer_array_end (&writer);
-       json_writer_printf (&writer, ",\n");
+       mono_json_writer_indent_pop (&writer);
+       mono_json_writer_indent (&writer);
+       mono_json_writer_array_end (&writer);
+       mono_json_writer_printf (&writer, ",\n");
 #endif
 
        // GOT entries
 #ifdef DUMP_GOT
-       json_writer_indent_push (&writer);
-       json_writer_indent (&writer);
-       json_writer_object_key(&writer, "got");
-       json_writer_array_begin (&writer);
+       mono_json_writer_indent_push (&writer);
+       mono_json_writer_indent (&writer);
+       mono_json_writer_object_key(&writer, "got");
+       mono_json_writer_array_begin (&writer);
 
-       json_writer_indent_push (&writer);
+       mono_json_writer_indent_push (&writer);
        for (i = 0; i < acfg->got_info.got_patches->len; ++i) {
                MonoJumpInfo *ji = g_ptr_array_index (acfg->got_info.got_patches, i);
 
-               json_writer_indent (&writer);
-               json_writer_printf (&writer, "{ ");
-               json_writer_object_key(&writer, "patch_name");
-               json_writer_printf (&writer, "\"%s\" },\n", get_patch_name (ji->type));
+               mono_json_writer_indent (&writer);
+               mono_json_writer_printf (&writer, "{ ");
+               mono_json_writer_object_key(&writer, "patch_name");
+               mono_json_writer_printf (&writer, "\"%s\" },\n", get_patch_name (ji->type));
        }
 
-       json_writer_indent_pop (&writer);
-       json_writer_indent (&writer);
-       json_writer_array_end (&writer);
-       json_writer_printf (&writer, ",\n");
+       mono_json_writer_indent_pop (&writer);
+       mono_json_writer_indent (&writer);
+       mono_json_writer_array_end (&writer);
+       mono_json_writer_printf (&writer, ",\n");
 #endif
 
-       json_writer_indent_pop (&writer);
-       json_writer_indent (&writer);
-       json_writer_object_end (&writer);
+       mono_json_writer_indent_pop (&writer);
+       mono_json_writer_indent (&writer);
+       mono_json_writer_object_end (&writer);
 
        dumpname = g_strdup_printf ("%s.json", g_path_get_basename (acfg->image->name));
        dumpfile = fopen (dumpname, "w+");
@@ -9204,7 +9323,7 @@ static void aot_dump (MonoAotCompile *acfg)
        fprintf (dumpfile, "%s", writer.text->str);
        fclose (dumpfile);
 
-       json_writer_destroy (&writer);
+       mono_json_writer_destroy (&writer);
 }
 
 int
@@ -9229,6 +9348,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        acfg->aot_opts.nrgctx_fetch_trampolines = 128;
        acfg->aot_opts.ngsharedvt_arg_trampolines = 128;
        acfg->aot_opts.llvm_path = g_strdup ("");
+       acfg->aot_opts.temp_path = g_strdup ("");
 #ifdef MONOTOUCH
        acfg->aot_opts.use_trampolines_page = TRUE;
 #endif
@@ -9254,7 +9374,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        aot_printf (acfg, "Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
 
 #ifndef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
-       if (acfg->aot_opts.full_aot) {
+       if (mono_aot_mode_is_full (&acfg->aot_opts)) {
                aot_printerrf (acfg, "--aot=full is not supported on this platform.\n");
                return 1;
        }
@@ -9302,11 +9422,17 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                 * Emit all LLVM code into a separate assembly/object file and link with it
                 * normally.
                 */
-               if (!acfg->aot_opts.asm_only)
+               if (!acfg->aot_opts.asm_only) {
                        acfg->llvm_owriter = TRUE;
+               } else if (acfg->aot_opts.llvm_outfile) {
+                       int len = strlen (acfg->aot_opts.llvm_outfile);
+
+                       if (len >= 2 && acfg->aot_opts.llvm_outfile [len - 2] == '.' && acfg->aot_opts.llvm_outfile [len - 1] == 'o')
+                               acfg->llvm_owriter = TRUE;
+               }
        }
 
-       if (acfg->aot_opts.full_aot)
+       if (mono_aot_mode_is_full (&acfg->aot_opts))
                acfg->flags |= MONO_AOT_FILE_FLAG_FULL_AOT;
 
        if (acfg->aot_opts.instances_logfile_path) {
@@ -9319,20 +9445,23 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        load_profile_files (acfg);
 
-       acfg->num_trampolines [MONO_AOT_TRAMP_SPECIFIC] = acfg->aot_opts.full_aot ? acfg->aot_opts.ntrampolines : 0;
+       acfg->num_trampolines [MONO_AOT_TRAMP_SPECIFIC] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.ntrampolines : 0;
 #ifdef MONO_ARCH_GSHARED_SUPPORTED
-       acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = acfg->aot_opts.full_aot ? acfg->aot_opts.nrgctx_trampolines : 0;
+       acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.nrgctx_trampolines : 0;
 #endif
-       acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? acfg->aot_opts.nimt_trampolines : 0;
+       acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.nimt_trampolines : 0;
 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
        if (acfg->opts & MONO_OPT_GSHAREDVT)
-               acfg->num_trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = acfg->aot_opts.full_aot ? acfg->aot_opts.ngsharedvt_arg_trampolines : 0;
+               acfg->num_trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.ngsharedvt_arg_trampolines : 0;
 #endif
 
-       acfg->temp_prefix = img_writer_get_temp_label_prefix (NULL);
+       acfg->temp_prefix = mono_img_writer_get_temp_label_prefix (NULL);
 
        arch_init (acfg);
 
+       if (acfg->llvm && acfg->thumb_mixed)
+               acfg->flags |= MONO_AOT_FILE_FLAG_LLVM_THUMB;
+
        acfg->assembly_name_sym = g_strdup (acfg->image->assembly->aname.name);
        /* Get rid of characters which cannot occur in symbols */
        for (p = acfg->assembly_name_sym; *p; ++p) {
@@ -9340,19 +9469,17 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        *p = '_';
        }
 
-       acfg->got_symbol_base = g_strdup_printf ("mono_aot_%s_got", acfg->assembly_name_sym);
-       acfg->llvm_got_symbol_base = g_strdup_printf ("mono_aot_%s_llvm_got", acfg->assembly_name_sym);
-       acfg->plt_symbol = g_strdup_printf ("%smono_aot_%s_plt", acfg->llvm_label_prefix, acfg->assembly_name_sym);
-
-       acfg->got_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, acfg->got_symbol_base);
-       if (acfg->llvm) {
-               acfg->llvm_got_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, acfg->llvm_got_symbol_base);
-               acfg->llvm_eh_frame_symbol = g_strdup_printf ("mono_aot_%s_eh_frame", acfg->assembly_name_sym);
+       acfg->global_prefix = g_strdup_printf ("mono_aot_%s", acfg->assembly_name_sym);
+       acfg->plt_symbol = g_strdup_printf ("%s_plt", acfg->global_prefix);
+       acfg->got_symbol = g_strdup_printf ("%s_got", acfg->global_prefix);
+       if (acfg->llvm) {
+               acfg->llvm_got_symbol = g_strdup_printf ("%s_llvm_got", acfg->global_prefix);
+               acfg->llvm_eh_frame_symbol = g_strdup_printf ("%s_eh_frame", acfg->global_prefix);
        }
 
        acfg->method_index = 1;
 
-       if (acfg->aot_opts.full_aot)
+       if (mono_aot_mode_is_full (&acfg->aot_opts))
                mono_set_partial_sharing_supported (TRUE);
 
        res = collect_methods (acfg);
@@ -9368,7 +9495,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 #ifdef ENABLE_LLVM
        if (acfg->llvm) {
                llvm_acfg = acfg;
-               mono_llvm_create_aot_module (acfg->llvm_got_symbol_base, TRUE, TRUE);
+               mono_llvm_create_aot_module (acfg->global_prefix, TRUE);
        }
 #endif
 
@@ -9430,11 +9557,18 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        }
                        g_assert (acfg->aot_opts.llvm_outfile);
                        acfg->llvm_sfile = g_strdup (acfg->aot_opts.llvm_outfile);
+                       if (acfg->llvm_owriter)
+                               acfg->llvm_ofile = g_strdup (acfg->aot_opts.llvm_outfile);
+                       else
+                               acfg->llvm_sfile = g_strdup (acfg->aot_opts.llvm_outfile);
                } else {
-                       acfg->tmpbasename = g_strdup_printf ("%s", "temp");
+                       acfg->tmpbasename = (strcmp (acfg->aot_opts.temp_path, "") == 0) ?
+                               g_strdup_printf ("%s", "temp") :
+                               g_build_filename (acfg->aot_opts.temp_path, "temp", NULL);
+                               
                        acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
-                       acfg->llvm_sfile = g_strdup ("temp-llvm.s");
-                       acfg->llvm_ofile = g_strdup ("temp-llvm.o");
+                       acfg->llvm_sfile = g_strdup_printf ("%s-llvm.s", acfg->tmpbasename);
+                       acfg->llvm_ofile = g_strdup_printf ("%s-llvm.o", acfg->tmpbasename);
                }
 
                res = emit_llvm_file (acfg);
@@ -9443,7 +9577,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        }
 #endif
 
-       if (!acfg->aot_opts.asm_only && !acfg->aot_opts.asm_writer && bin_writer_supported ()) {
+       if (!acfg->aot_opts.asm_only && !acfg->aot_opts.asm_writer && mono_bin_writer_supported ()) {
                if (acfg->aot_opts.outfile)
                        outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
                else
@@ -9461,7 +9595,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        return 1;
                }
 
-               acfg->w = img_writer_create (acfg->fp, TRUE);
+               acfg->w = mono_img_writer_create (acfg->fp, TRUE);
                acfg->use_bin_writer = TRUE;
        } else {
                if (acfg->aot_opts.asm_only) {
@@ -9478,7 +9612,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        aot_printerrf (acfg, "Unable to open file '%s': %s\n", acfg->tmpfname, strerror (errno));
                        return 1;
                }
-               acfg->w = img_writer_create (acfg->fp, FALSE);
+               acfg->w = mono_img_writer_create (acfg->fp, FALSE);
                
                tmp_outfile_name = NULL;
                outfile_name = NULL;
@@ -9517,26 +9651,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE, !acfg->gas_line_numbers);
        }
 
-       img_writer_emit_start (acfg->w);
+       mono_img_writer_emit_start (acfg->w);
 
        if (acfg->dwarf)
                mono_dwarf_writer_emit_base_info (acfg->dwarf, g_path_get_basename (acfg->image->name), 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_alignment_code (acfg, 8);
-               emit_label (acfg, symbol);
-               emit_zero_bytes (acfg, 16);
-
-               fprintf (acfg->fp, ".arm\n");
-       }
-
        emit_code (acfg);
 
        emit_info (acfg);
@@ -9623,7 +9742,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                aot_printf (acfg, "%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
 
        TV_GETTIME (atv);
-       res = img_writer_emit_writeout (acfg->w);
+       res = mono_img_writer_emit_writeout (acfg->w);
        if (res != 0) {
                acfg_free (acfg);
                return res;