Merge pull request #1588 from BrzVlad/feature-aot-wbarrier
[mono.git] / mono / mini / aot-compiler.c
index 9543e792dbfbc95c0d5014d88c21d4e888ee8017..650e05ca67022f92accf8c6d6f854f6a353a1820 100644 (file)
@@ -109,6 +109,7 @@ typedef struct MonoAotOptions {
        gboolean soft_debug;
        gboolean log_generics;
        gboolean log_instances;
+       gboolean gen_seq_points_file;
        gboolean direct_pinvoke;
        gboolean direct_icalls;
        gboolean no_direct_calls;
@@ -125,6 +126,7 @@ typedef struct MonoAotOptions {
        gboolean print_skipped_methods;
        gboolean stats;
        char *tool_prefix;
+       char *ld_flags;
        gboolean autoreg;
        char *mtriple;
        char *llvm_path;
@@ -197,8 +199,6 @@ typedef struct MonoAotCompile {
        mono_mutex_t mutex;
        gboolean use_bin_writer;
        gboolean gas_line_numbers;
-       /* Whenever to emit LLVM code into a separate object file */
-       gboolean llvm_separate;
        /* Whenever to emit an object file directly from llc */
        gboolean llvm_owriter;
        MonoImageWriter *w;
@@ -333,24 +333,34 @@ aot_printerrf (MonoAotCompile *acfg, const gchar *format, ...)
        va_end (args);
 }
 
-/* Wrappers around the image writer functions */
-
-static inline void
-emit_section_change (MonoAotCompile *acfg, const char *section_name, int subsection_index)
+static void
+report_loader_error (MonoAotCompile *acfg, MonoError *error, const char *format, ...)
 {
-       img_writer_emit_section_change (acfg->w, section_name, subsection_index);
-}
+       FILE *output;
+       va_list args;
 
-static inline void
-emit_push_section (MonoAotCompile *acfg, const char *section_name, int subsection)
-{
-       img_writer_emit_push_section (acfg->w, section_name, subsection);
+       if (mono_error_ok (error))
+               return;
+
+       if (acfg->logfile)
+               output = acfg->logfile;
+       else
+               output = stderr;
+
+       va_start (args, format);
+       vfprintf (output, format, args);
+       va_end (args);
+       mono_error_cleanup (error);
+
+       g_error ("FullAOT cannot continue if there are loader errors");
 }
 
+/* Wrappers around the image writer functions */
+
 static inline void
-emit_pop_section (MonoAotCompile *acfg)
+emit_section_change (MonoAotCompile *acfg, const char *section_name, int subsection_index)
 {
-       img_writer_emit_pop_section (acfg->w);
+       img_writer_emit_section_change (acfg->w, section_name, subsection_index);
 }
 
 static inline void
@@ -419,12 +429,6 @@ emit_padding (MonoAotCompile *acfg, int size)
        }
 }
 
-static inline void
-emit_pointer_unaligned (MonoAotCompile *acfg, const char *target) 
-{ 
-       img_writer_emit_pointer_unaligned (acfg->w, target); 
-}
-
 static inline void
 emit_pointer (MonoAotCompile *acfg, const char *target) 
 { 
@@ -640,7 +644,7 @@ emit_code_bytes (MonoAotCompile *acfg, const guint8* buf, int size)
 
 /* ARCHITECTURE SPECIFIC CODE */
 
-#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_POWERPC)
+#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_POWERPC) || defined(TARGET_ARM64)
 #define EMIT_DWARF_INFO 1
 #endif
 
@@ -926,7 +930,7 @@ arch_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *cod
 
 #ifdef TARGET_AMD64
        /* mov reg, got+offset(%rip) */
-       if (acfg->llvm_separate) {
+       if (acfg->llvm) {
                /* The GOT symbol is in the LLVM module, the clang assembler has problems emitting symbol diffs for it */
                int dreg;
                int rex_r;
@@ -1356,7 +1360,7 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
        /* This should be exactly 8 bytes long */
        *tramp_size = 8;
        /* call *<offset>(%rip) */
-       if (acfg->llvm_separate) {
+       if (acfg->llvm) {
                emit_unset_mode (acfg);
                fprintf (acfg->fp, "call *%s+%d(%%rip)\n", acfg->got_symbol, (int)(offset * sizeof (gpointer)));
                emit_zero_bytes (acfg, 2);
@@ -1547,7 +1551,7 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoCompile *cfg, MonoMethod *
 
        emit_bytes (acfg, buf, code - buf);
        /* jump <method> */
-       if (acfg->llvm_separate) {
+       if (acfg->llvm) {
                emit_unset_mode (acfg);
                fprintf (acfg->fp, "jmp %s\n", call_target);
        } else {
@@ -1633,7 +1637,7 @@ arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_
        /* This should be exactly 13 bytes long */
        *tramp_size = 13;
 
-       if (acfg->llvm_separate) {
+       if (acfg->llvm) {
                emit_unset_mode (acfg);
                fprintf (acfg->fp, "mov %s+%d(%%rip), %%r10\n", acfg->got_symbol, (int)(offset * sizeof (gpointer)));
                fprintf (acfg->fp, "jmp *%s+%d(%%rip)\n", acfg->got_symbol, (int)((offset + 1) * sizeof (gpointer)));
@@ -1808,7 +1812,7 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
 
        /* MONO_ARCH_IMT_SCRATCH_REG is a free register */
 
-       if (acfg->llvm_separate) {
+       if (acfg->llvm) {
                emit_unset_mode (acfg);
                fprintf (acfg->fp, "mov %s+%d(%%rip), %s\n", acfg->got_symbol, (int)(offset * sizeof (gpointer)), mono_arch_regname (MONO_ARCH_IMT_SCRATCH_REG));
        }
@@ -1847,7 +1851,7 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
        mono_amd64_patch (labels [3], code);
        x86_breakpoint (code);
 
-       if (!acfg->llvm_separate) {
+       if (!acfg->llvm) {
                /* mov <OFFSET>(%rip), MONO_ARCH_IMT_SCRATCH_REG */
                amd64_emit_rex (mov_buf_ptr, sizeof(gpointer), MONO_ARCH_IMT_SCRATCH_REG, 0, AMD64_RIP);
                *(mov_buf_ptr)++ = (unsigned char)0x8b; /* mov opcode */
@@ -2494,13 +2498,13 @@ encode_klass_ref_inner (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, gui
                encode_value (container ? 1 : 0, p, &p);
                if (container) {
                        encode_value (container->is_method, p, &p);
-                       g_assert (par->serial == 0);
+                       g_assert (par->gshared_constraint == 0);
                        if (container->is_method)
                                encode_method_ref (acfg, container->owner.method, p, &p);
                        else
                                encode_klass_ref (acfg, container->owner.klass, p, &p);
                } else {
-                       encode_value (par->serial, p, &p);
+                       encode_value (par->gshared_constraint, p, &p);
                }
        } else if (klass->byval_arg.type == MONO_TYPE_PTR) {
                encode_value (MONO_AOT_TYPEREF_PTR, p, &p);
@@ -3405,11 +3409,13 @@ add_wrappers (MonoAotCompile *acfg)
         * callers.
         */
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+               MonoError error;
                MonoMethod *method;
                guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
                gboolean skip = FALSE;
 
-               method = mono_get_method (acfg->image, token, NULL);
+               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 ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
                        (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
@@ -3537,6 +3543,12 @@ add_wrappers (MonoAotCompile *acfg)
                        }
                }
 
+               /* write barriers */
+               if (mono_gc_is_moving ()) {
+                       add_method (acfg, mono_gc_get_specific_write_barrier (FALSE));
+                       add_method (acfg, mono_gc_get_specific_write_barrier (TRUE));
+               }
+
                /* Stelemref wrappers */
                {
                        MonoMethod **wrappers;
@@ -3708,8 +3720,10 @@ add_wrappers (MonoAotCompile *acfg)
 
        /* Synchronized wrappers */
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+               MonoError error;
                token = MONO_TOKEN_METHOD_DEF | (i + 1);
-               method = mono_get_method (acfg->image, token, NULL);
+               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 (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
                        if (method->is_generic) {
@@ -3737,10 +3751,12 @@ add_wrappers (MonoAotCompile *acfg)
 
        /* pinvoke wrappers */
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+               MonoError error;
                MonoMethod *method;
                guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
 
-               method = mono_get_method (acfg->image, token, NULL);
+               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 ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
                        (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
@@ -3750,12 +3766,14 @@ add_wrappers (MonoAotCompile *acfg)
  
        /* native-to-managed wrappers */
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+               MonoError error;
                MonoMethod *method;
                guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
                MonoCustomAttrInfo *cattr;
                int j;
 
-               method = mono_get_method (acfg->image, token, NULL);
+               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));
 
                /* 
                 * Only generate native-to-managed wrappers for methods which have an
@@ -3773,7 +3791,7 @@ add_wrappers (MonoAotCompile *acfg)
                                MonoMethodSignature *sig = mono_method_signature (e->ctor);
                                const char *p = (const char*)e->data;
                                const char *named;
-                               int slen, num_named, named_type, data_type;
+                               int slen, num_named, named_type;
                                char *n;
                                MonoType *t;
                                MonoClass *klass;
@@ -3818,13 +3836,12 @@ add_wrappers (MonoAotCompile *acfg)
                                if (num_named == 1) {
                                        int name_len;
                                        char *name;
-                                       MonoType *prop_type;
 
                                        /* parse ExportSymbol attribute */
                                        named = p;
                                        named_type = *named;
                                        named += 1;
-                                       data_type = *named;
+                                       /* data_type = *named; */
                                        named += 1;
 
                                        name_len = mono_metadata_decode_blob_size (named, &named);
@@ -3836,8 +3853,6 @@ add_wrappers (MonoAotCompile *acfg)
                                        g_assert (named_type == 0x54);
                                        g_assert (!strcmp (name, "ExportSymbol"));
 
-                                       prop_type = &mono_defaults.string_class->byval_arg;
-
                                        /* load_cattr_value (), string case */
                                        g_assert (*named != (char)0xff);
                                        slen = mono_metadata_decode_value (named, &named);
@@ -4226,11 +4241,16 @@ add_generic_instances (MonoAotCompile *acfg)
                return;
 
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHODSPEC].rows; ++i) {
+               MonoError error;
                token = MONO_TOKEN_METHOD_SPEC | (i + 1);
-               method = mono_get_method (acfg->image, token, NULL);
+               method = mono_get_method_checked (acfg->image, token, NULL, NULL, &error);
 
-               if (!method)
+               if (!method) {
+                       aot_printerrf (acfg, "Failed to load methodspec 0x%x due to %s.\n", token, mono_error_get_message (&error));
+                       aot_printerrf (acfg, "Run with MONO_LOG_LEVEL=debug for more information.\n");
+                       mono_error_cleanup (&error);
                        continue;
+               }
 
                if (method->klass->image != acfg->image)
                        continue;
@@ -4485,6 +4505,9 @@ is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patc
                        if (callee_cfg->method->wrapper_type == MONO_WRAPPER_ALLOC)
                                /* sgen does some initialization when the allocator method is created */
                                direct_callable = FALSE;
+                       if (callee_cfg->method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER)
+                               /* we don't know at compile time whether sgen is concurrent or not */
+                               direct_callable = FALSE;
 
                        if (direct_callable)
                                return TRUE;
@@ -4663,10 +4686,9 @@ get_file_index (MonoAotCompile *acfg, const char *source_file)
 static void
 emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, guint32 code_len, MonoJumpInfo *relocs, gboolean got_only, MonoDebugMethodJitInfo *debug_info)
 {
-       int i, pindex, start_index, method_index;
+       int i, pindex, start_index;
        GPtrArray *patches;
        MonoJumpInfo *patch_info;
-       MonoMethodHeader *header;
        MonoDebugSourceLocation **locs = NULL;
        gboolean skip;
 #ifdef MONO_ARCH_AOT_SUPPORTED
@@ -4676,12 +4698,6 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
        const char *direct_pinvoke;
 #endif
 
-       if (method) {
-               header = mono_method_get_header (method);
-
-               method_index = get_method_index (acfg, method);
-       }
-
        if (acfg->gas_line_numbers && method && debug_info) {
                locs = compute_line_numbers (method, code_len, debug_info);
                if (!locs) {
@@ -4984,12 +5000,10 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
        char *debug_sym = NULL;
        char *symbol = NULL;
        int func_alignment = AOT_FUNC_ALIGNMENT;
-       MonoMethodHeader *header;
        char *export_name;
 
        method = cfg->orig_method;
        code = cfg->native_code;
-       header = cfg->header;
 
        method_index = get_method_index (acfg, method);
        symbol = g_strdup_printf ("%sme_%x", acfg->temp_prefix, method_index);
@@ -5003,7 +5017,7 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
        
        emit_label (acfg, cfg->asm_symbol);
 
-       if (acfg->aot_opts.write_symbols && !acfg->global_symbols && !acfg->llvm_separate) {
+       if (acfg->aot_opts.write_symbols && !acfg->global_symbols && !acfg->llvm) {
                /* 
                 * Write a C style symbol for every method, this has two uses:
                 * - it works on platforms where the dwarf debugging info is not
@@ -5011,6 +5025,7 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
                 * - it allows the setting of breakpoints of aot-ed methods.
                 */
                debug_sym = get_debug_sym (method, "", acfg->method_label_hash);
+               cfg->asm_debug_symbol = g_strdup (debug_sym);
 
                if (acfg->need_no_dead_strip)
                        fprintf (acfg->fp, "    .no_dead_strip %s\n", debug_sym);
@@ -5067,6 +5082,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
        case MONO_PATCH_INFO_JIT_TLS_ID:
        case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
+       case MONO_PATCH_INFO_GC_NURSERY_START:
                break;
        case MONO_PATCH_INFO_CASTCLASS_CACHE:
                encode_value (patch_info->data.index, p, &p);
@@ -5238,9 +5254,11 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        }
        case MONO_PATCH_INFO_LDSTR_LIT: {
                const char *s = patch_info->data.target;
+               int len = strlen (s);
 
-               encode_value (strlen (s), p, &p);
-               memcpy (p, s, strlen (s) + 1);
+               encode_value (len, p, &p);
+               memcpy (p, s, len + 1);
+               p += len + 1;
                break;
        }
        default:
@@ -5282,13 +5300,11 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        int pindex, buf_size, n_patches;
        GPtrArray *patches;
        MonoJumpInfo *patch_info;
-       MonoMethodHeader *header;
        guint32 method_index;
        guint8 *p, *buf;
        guint32 first_got_offset;
 
        method = cfg->orig_method;
-       header = mono_method_get_header (method);
 
        method_index = get_method_index (acfg, method);
 
@@ -5341,7 +5357,8 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
                        continue;
                }
 
-               if (patch_info->type == MONO_PATCH_INFO_GC_CARD_TABLE_ADDR) {
+               if (patch_info->type == MONO_PATCH_INFO_GC_CARD_TABLE_ADDR ||
+                               patch_info->type == MONO_PATCH_INFO_GC_NURSERY_START) {
                        /* Stored in a GOT slot initialized at module load time */
                        patch_info->type = MONO_PATCH_INFO_NONE;
                        continue;
@@ -5403,10 +5420,9 @@ get_unwind_info_offset (MonoAotCompile *acfg, guint8 *encoded, guint32 encoded_l
 }
 
 static void
-emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
+emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg, gboolean store_seq_points)
 {
-       MonoMethod *method;
-       int i, k, buf_size, method_index;
+       int i, k, buf_size;
        guint32 debug_info_size, seq_points_size;
        guint8 *code;
        MonoMethodHeader *header;
@@ -5416,12 +5432,9 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        gboolean use_unwind_ops = FALSE;
        MonoSeqPointInfo *seq_points;
 
-       method = cfg->orig_method;
        code = cfg->native_code;
        header = cfg->header;
 
-       method_index = get_method_index (acfg, method);
-
        if (!acfg->aot_opts.nodebug) {
                mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
        } else {
@@ -5430,15 +5443,15 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        }
 
        seq_points = cfg->seq_point_info;
-
-       seq_points_size = (cfg->gen_seq_points)? seq_point_info_get_write_size (seq_points) : 0;
+       seq_points_size = (store_seq_points)? 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;
+
        p = buf = g_malloc (buf_size);
 
        use_unwind_ops = cfg->unwind_ops != NULL;
 
-       flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0) | (seq_points ? 8 : 0) | (cfg->compile_llvm ? 16 : 0) | (jinfo->has_try_block_holes ? 32 : 0) | (cfg->gc_map ? 64 : 0) | (jinfo->has_arch_eh_info ? 128 : 0);
+       flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0) | (seq_points_size ? 8 : 0) | (cfg->compile_llvm ? 16 : 0) | (jinfo->has_try_block_holes ? 32 : 0) | (cfg->gc_map ? 64 : 0) | (jinfo->has_arch_eh_info ? 128 : 0);
 
        encode_value (flags, p, &p);
 
@@ -5564,11 +5577,9 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        if (jinfo->has_generic_jit_info) {
                MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (jinfo);
                MonoGenericSharingContext* gsctx = gi->generic_sharing_context;
-               guint8 *p1;
                guint8 *buf2, *p2;
                int len;
 
-               p1 = p;
                encode_value (gi->nlocs, p, &p);
                if (gi->nlocs) {
                        for (i = 0; i < gi->nlocs; ++i) {
@@ -5639,7 +5650,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                }
        }
 
-       if (seq_points)
+       if (seq_points_size)
                p += seq_point_info_write (seq_points, p);
 
        g_assert (debug_info_size < buf_size);
@@ -5769,7 +5780,7 @@ get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cac
        char *s;
        char *prefix;
 
-       if (acfg->llvm_separate && llvm_acfg->aot_opts.static_link) {
+       if (acfg->llvm && llvm_acfg->aot_opts.static_link) {
                /* Need to add a prefix to create unique symbols */
                prefix = g_strdup_printf ("plt_%s_", acfg->assembly_name_sym);
        } else {
@@ -5835,7 +5846,6 @@ emit_plt (MonoAotCompile *acfg)
        for (i = 0; i < acfg->plt_offset; ++i) {
                char *debug_sym = NULL;
                MonoPltEntry *plt_entry = NULL;
-               MonoJumpInfo *ji;
 
                if (i == 0)
                        /* 
@@ -5844,7 +5854,6 @@ emit_plt (MonoAotCompile *acfg)
                        continue;
 
                plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
-               ji = plt_entry->ji;
 
                debug_sym = plt_entry->debug_sym;
 
@@ -5858,8 +5867,8 @@ emit_plt (MonoAotCompile *acfg)
 
                if (acfg->llvm && !acfg->thumb_mixed) {
                        emit_label (acfg, plt_entry->llvm_symbol);
-                       if (acfg->llvm_separate) {
-                               emit_global (acfg, plt_entry->llvm_symbol, TRUE);
+                       if (acfg->llvm) {
+                               emit_global_inner (acfg, plt_entry->llvm_symbol, TRUE);
 #if defined(TARGET_MACH)
                                fprintf (acfg->fp, ".private_extern %s\n", plt_entry->llvm_symbol);
 #endif
@@ -5894,13 +5903,11 @@ emit_plt (MonoAotCompile *acfg)
                for (i = 0; i < acfg->plt_offset; ++i) {
                        char *debug_sym = NULL;
                        MonoPltEntry *plt_entry = NULL;
-                       MonoJumpInfo *ji;
 
                        if (i == 0)
                                continue;
 
                        plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
-                       ji = plt_entry->ji;
 
                        /* Skip plt entries not actually called by LLVM code */
                        if (!plt_entry->llvm_used)
@@ -5923,6 +5930,9 @@ emit_plt (MonoAotCompile *acfg)
 
                        emit_label (acfg, plt_entry->llvm_symbol);
 
+                       if (acfg->llvm)
+                               emit_global_inner (acfg, plt_entry->llvm_symbol, TRUE);
+
                        arch_emit_llvm_plt_entry (acfg, i);
 
                        if (debug_sym) {
@@ -6430,16 +6440,16 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->autoreg = TRUE;
                } else if (str_begins_with (arg, "tool-prefix=")) {
                        opts->tool_prefix = g_strdup (arg + strlen ("tool-prefix="));
+               } else if (str_begins_with (arg, "ld-flags=")) {
+                       opts->ld_flags = g_strdup (arg + strlen ("ld-flags="));                 
                } else if (str_begins_with (arg, "soft-debug")) {
                        opts->soft_debug = TRUE;
+               } else if (str_begins_with (arg, "gen-seq-points-file")) {
+                       opts->gen_seq_points_file = TRUE;
                } else if (str_begins_with (arg, "direct-pinvoke")) {
                        opts->direct_pinvoke = TRUE;
                } else if (str_begins_with (arg, "direct-icalls")) {
                        opts->direct_icalls = TRUE;
-#if defined(TARGET_ARM) || defined(TARGET_ARM64)
-               } else if (str_begins_with (arg, "iphone-abi")) {
-                       // older full-aot users did depend on this.
-#endif
                } else if (str_begins_with (arg, "no-direct-calls")) {
                        opts->no_direct_calls = TRUE;
                } else if (str_begins_with (arg, "print-skipped")) {
@@ -6461,6 +6471,11 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        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);
+                       }
                } else if (!strcmp (arg, "llvm")) {
                        opts->llvm = TRUE;
                } else if (str_begins_with (arg, "readonly-value=")) {
@@ -6496,6 +6511,7 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        printf ("    tool-prefix=\n");
                        printf ("    readonly-value=\n");
                        printf ("    soft-debug\n");
+                       printf ("    gen-seq-points-file\n");
                        printf ("    gc-maps\n");
                        printf ("    print-skipped\n");
                        printf ("    no-instances\n");
@@ -6705,6 +6721,8 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                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);
        mono_loader_clear_error ();
 
@@ -6860,6 +6878,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                case MONO_PATCH_INFO_GOT_OFFSET:
                case MONO_PATCH_INFO_NONE:
                case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
+               case MONO_PATCH_INFO_GC_NURSERY_START:
                        break;
                case MONO_PATCH_INFO_IMAGE:
                        /* The assembly is stored in GOT slot 0 */
@@ -7110,6 +7129,7 @@ mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
 {
        MonoJumpInfo *ji = mono_mempool_alloc (llvm_acfg->mempool, sizeof (MonoJumpInfo));
        MonoPltEntry *plt_entry;
+       const char *sym = NULL;
 
        ji->type = type;
        ji->data.target = data;
@@ -7117,6 +7137,19 @@ mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
        if (!can_encode_patch (llvm_acfg, ji))
                return NULL;
 
+       if (llvm_acfg->aot_opts.direct_icalls) {
+               if (type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
+                       /* Call to a C function implementing a jit icall */
+                       sym = mono_lookup_jit_icall_symbol (data);
+               } else if (type == MONO_PATCH_INFO_ICALL_ADDR) {
+                       MonoMethod *method = (gpointer)data;
+                       if (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
+                               sym = mono_lookup_icall_symbol (method);
+               }
+               if (sym)
+                       return g_strdup (sym);
+       }
+
        plt_entry = get_plt_entry (llvm_acfg, ji);
        plt_entry->llvm_used = TRUE;
 
@@ -7146,6 +7179,30 @@ mono_aot_patch_info_dup (MonoJumpInfo* ji)
        return res;
 }
 
+static int
+execute_system (const char * command)
+{
+       int status;
+
+#if _WIN32
+       // We need an extra set of quotes around the whole command to properly handle commands 
+       // with spaces since internally the command is called through "cmd /c.
+       command = g_strdup_printf ("\"%s\"", command);
+
+       int size =  MultiByteToWideChar (CP_UTF8, 0 , command , -1, NULL , 0);
+       wchar_t* wstr = g_malloc (sizeof (wchar_t) * size);
+       MultiByteToWideChar (CP_UTF8, 0, command, -1, wstr , size);
+       status = _wsystem (wstr);
+       g_free (wstr);
+
+       g_free (command);
+#else
+       status = system (command);
+#endif
+
+       return status;
+}
+
 #ifdef ENABLE_LLVM
 
 /*
@@ -7191,11 +7248,11 @@ emit_llvm_file (MonoAotCompile *acfg)
         * return OverwriteComplete;
         * Here, if 'Earlier' refers to a memset, and Later has no size info, it mistakenly thinks the memset is redundant.
         */
-       opts = g_strdup ("-targetlibinfo -no-aa -basicaa -notti -instcombine -simplifycfg -sroa -domtree -early-cse -lazy-value-info -correlated-propagation -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loop-simplify -lcssa -indvars -loop-idiom -loop-deletion -loop-unroll -memdep -gvn -memdep -memcpyopt -sccp -instcombine -lazy-value-info -correlated-propagation -domtree -memdep -adce -simplifycfg -instcombine -strip-dead-prototypes -domtree -verify");
+       opts = g_strdup ("-targetlibinfo -no-aa -basicaa -notti -instcombine -simplifycfg -inline-cost -inline -sroa -domtree -early-cse -lazy-value-info -correlated-propagation -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loop-simplify -lcssa -indvars -loop-idiom -loop-deletion -loop-unroll -memdep -gvn -memdep -memcpyopt -sccp -instcombine -lazy-value-info -correlated-propagation -domtree -memdep -adce -simplifycfg -instcombine -strip-dead-prototypes -domtree -verify");
 #if 1
-       command = g_strdup_printf ("%sopt -f %s -o \"%s.opt.bc\" \"%s.bc\"", acfg->aot_opts.llvm_path, opts, acfg->tmpbasename, acfg->tmpbasename);
+       command = g_strdup_printf ("\"%sopt\" -f %s -o \"%s.opt.bc\" \"%s.bc\"", acfg->aot_opts.llvm_path, opts, acfg->tmpbasename, acfg->tmpbasename);
        aot_printf (acfg, "Executing opt: %s\n", command);
-       if (system (command) != 0)
+       if (execute_system (command) != 0)
                return FALSE;
 #endif
        g_free (opts);
@@ -7211,8 +7268,7 @@ emit_llvm_file (MonoAotCompile *acfg)
        if (acfg->aot_opts.mtriple)
                g_string_append_printf (acfg->llc_args, " -mtriple=%s", acfg->aot_opts.mtriple);
 
-       if (acfg->llvm_separate)
-               g_string_append_printf (acfg->llc_args, " -mono-eh-frame-symbol=%s", acfg->llvm_eh_frame_symbol);
+       g_string_append_printf (acfg->llc_args, " -mono-eh-frame-symbol=%s", acfg->llvm_eh_frame_symbol);
 
 #if defined(TARGET_MACH) && defined(TARGET_ARM)
        /* ios requires PIC code now */
@@ -7225,22 +7281,19 @@ emit_llvm_file (MonoAotCompile *acfg)
 #endif
        unlink (acfg->tmpfname);
 
-       if (acfg->llvm_separate) {
-               if (acfg->llvm_owriter) {
-                       /* Emit an object file directly */
-                       output_fname = g_strdup_printf ("%s", acfg->llvm_ofile);
-                       g_string_append_printf (acfg->llc_args, " -filetype=obj");
-               } else {
-                       output_fname = g_strdup_printf ("%s", acfg->llvm_sfile);
-               }
+       if (acfg->llvm_owriter) {
+               /* Emit an object file directly */
+               output_fname = g_strdup_printf ("%s", acfg->llvm_ofile);
+               g_string_append_printf (acfg->llc_args, " -filetype=obj");
        } else {
-               output_fname = g_strdup (acfg->tmpfname);
+               output_fname = g_strdup_printf ("%s", acfg->llvm_sfile);
        }
-       command = g_strdup_printf ("%sllc %s -o \"%s\" \"%s.opt.bc\"", acfg->aot_opts.llvm_path, acfg->llc_args->str, output_fname, acfg->tmpbasename);
+       command = g_strdup_printf ("\"%sllc\" %s -o \"%s\" \"%s.opt.bc\"", acfg->aot_opts.llvm_path, acfg->llc_args->str, output_fname, acfg->tmpbasename);
+       g_free (output_fname);
 
        aot_printf (acfg, "Executing llc: %s\n", command);
 
-       if (system (command) != 0)
+       if (execute_system (command) != 0)
                return FALSE;
        return TRUE;
 }
@@ -7447,6 +7500,7 @@ emit_code (MonoAotCompile *acfg)
 #endif
                }
        }
+       emit_int32 (acfg, 0);
 }
 
 static void
@@ -7537,16 +7591,19 @@ mono_aot_method_hash (MonoMethod *method)
        int hashes_count;
        guint32 *hashes_start, *hashes;
        guint32 a, b, c;
+       MonoGenericInst *class_ginst = NULL;
        MonoGenericInst *ginst = NULL;
 
        /* Similar to the hash in mono_method_get_imt_slot () */
 
        sig = mono_method_signature (method);
 
+       if (method->klass->generic_class)
+               class_ginst = method->klass->generic_class->context.class_inst;
        if (method->is_inflated)
                ginst = ((MonoMethodInflated*)method)->context.method_inst;
 
-       hashes_count = sig->param_count + 5 + (ginst ? ginst->type_argc : 0);
+       hashes_count = sig->param_count + 5 + (class_ginst ? class_ginst->type_argc : 0) + (ginst ? ginst->type_argc : 0);
        hashes_start = g_malloc0 (hashes_count * sizeof (guint32));
        hashes = hashes_start;
 
@@ -7557,7 +7614,12 @@ mono_aot_method_hash (MonoMethod *method)
                klass = mono_defaults.object_class;
 
        if (!method->wrapper_type) {
-               char *full_name = mono_type_full_name (&klass->byval_arg);
+               char *full_name;
+
+               if (klass->generic_class)
+                       full_name = mono_type_full_name (&klass->generic_class->container_class->byval_arg);
+               else
+                       full_name = mono_type_full_name (&klass->byval_arg);
 
                hashes [0] = mono_metadata_str_hash (full_name);
                hashes [1] = 0;
@@ -7577,6 +7639,10 @@ mono_aot_method_hash (MonoMethod *method)
        for (i = 0; i < sig->param_count; i++) {
                hashes [hindex ++] = mono_aot_type_hash (sig->params [i]);
        }
+       if (class_ginst) {
+               for (i = 0; i < class_ginst->type_argc; ++i)
+                       hashes [hindex ++] = mono_aot_type_hash (class_ginst->type_argv [i]);
+       }
        if (ginst) {
                for (i = 0; i < ginst->type_argc; ++i)
                        hashes [hindex ++] = mono_aot_type_hash (ginst->type_argv [i]);
@@ -7732,7 +7798,7 @@ emit_extra_methods (MonoAotCompile *acfg)
                value = get_method_index (acfg, method);
 
                hash = mono_aot_method_hash (method) % table_size;
-               //printf ("X: %s %d\n", mono_method_full_name (method, 1), hash);
+               //printf ("X: %s %x\n", mono_method_full_name (method, 1), mono_aot_method_hash (method));
 
                chain_lengths [hash] ++;
                max_chain_length = MAX (max_chain_length, chain_lengths [hash]);
@@ -7806,17 +7872,43 @@ emit_exception_info (MonoAotCompile *acfg)
        int i;
        char symbol [256];
        gint32 *offsets;
+       SeqPointData sp_data;
+       gboolean seq_points_to_file = FALSE;
 
        offsets = g_new0 (gint32, acfg->nmethods);
        for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i]) {
-                       emit_exception_debug_info (acfg, acfg->cfgs [i]);
-                       offsets [i] = acfg->cfgs [i]->ex_info_offset;
+                       MonoCompile *cfg = acfg->cfgs [i];
+
+                       // By design aot-runtime decode_exception_debug_info is not able to load sequence point debug data from a file.
+                       // As it is not possible to load debug data from a file its is also not possible to store it in a file.
+                       gboolean method_seq_points_to_file = acfg->aot_opts.gen_seq_points_file &&
+                               cfg->gen_seq_points && !cfg->gen_seq_points_debug_data;
+                       gboolean method_seq_points_to_binary = cfg->gen_seq_points && !method_seq_points_to_file;
+                       
+                       emit_exception_debug_info (acfg, cfg, method_seq_points_to_binary);
+                       offsets [i] = cfg->ex_info_offset;
+
+                       if (method_seq_points_to_file) {
+                               if (!seq_points_to_file) {
+                                       seq_point_data_init (&sp_data, acfg->nmethods);
+                                       seq_points_to_file = TRUE;
+                               }
+                               seq_point_data_add (&sp_data, cfg->method->token, cfg->seq_point_info);
+                       }
                } else {
                        offsets [i] = 0;
                }
        }
 
+       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);
+               g_free (seq_points_aot_file);
+       }
+
        sprintf (symbol, "ex_info_offsets");
        emit_section_change (acfg, RODATA_SECT, 1);
        emit_alignment (acfg, 8);
@@ -8485,7 +8577,7 @@ emit_dwarf_info (MonoAotCompile *acfg)
 
                sprintf (symbol2, "%sme_%x", acfg->temp_prefix, i);
 
-               mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, cfg->asm_symbol, symbol2, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->d.method, mono_domain_get ()));
+               mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, cfg->asm_symbol, symbol2, cfg->asm_debug_symbol, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->d.method, mono_domain_get ()));
        }
 #endif
 }
@@ -8498,14 +8590,16 @@ collect_methods (MonoAotCompile *acfg)
 
        /* Collect methods */
        for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
+               MonoError error;
                MonoMethod *method;
                guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
 
-               method = mono_get_method (acfg->image, token, NULL);
+               method = mono_get_method_checked (acfg->image, token, NULL, NULL, &error);
 
                if (!method) {
-                       aot_printerrf (acfg, "Failed to load method 0x%x from '%s'.\n", token, image->name);
+                       aot_printerrf (acfg, "Failed to load method 0x%x from '%s' due to %s.\n", token, image->name, mono_error_get_message (&error));
                        aot_printerrf (acfg, "Run with MONO_LOG_LEVEL=debug for more information.\n");
+                       mono_error_cleanup (&error);
                        return FALSE;
                }
                        
@@ -8541,15 +8635,16 @@ collect_methods (MonoAotCompile *acfg)
 
        /* gsharedvt methods */
        for (mindex = 0; mindex < image->tables [MONO_TABLE_METHOD].rows; ++mindex) {
+               MonoError error;
                MonoMethod *method;
                guint32 token = MONO_TOKEN_METHOD_DEF | (mindex + 1);
 
                if (!(acfg->opts & MONO_OPT_GSHAREDVT))
                        continue;
 
-               method = mono_get_method (acfg->image, token, NULL);
-               if (!method)
-                       continue;
+               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;
@@ -8640,6 +8735,7 @@ compile_asm (MonoAotCompile *acfg)
        char *command, *objfile;
        char *outfile_name, *tmp_outfile_name, *llvm_ofile;
        const char *tool_prefix = acfg->aot_opts.tool_prefix ? acfg->aot_opts.tool_prefix : "";
+       char *ld_flags = acfg->aot_opts.ld_flags ? acfg->aot_opts.ld_flags : g_strdup("");
 
 #if defined(TARGET_AMD64) && !defined(TARGET_MACH)
 #define AS_OPTIONS "--64"
@@ -8661,7 +8757,7 @@ compile_asm (MonoAotCompile *acfg)
 #define AS_NAME "nacl-as"
 #endif
 #elif defined(TARGET_OSX)
-#define AS_NAME "clang -c -x assembler"
+#define AS_NAME "clang"
 #else
 #define AS_NAME "as"
 #endif
@@ -8676,7 +8772,7 @@ compile_asm (MonoAotCompile *acfg)
 #define LD_NAME "gcc -dynamiclib"
 #elif defined(TARGET_AMD64) && defined(TARGET_MACH)
 #define LD_NAME "clang --shared"
-#elif defined(HOST_WIN32)
+#elif defined(TARGET_WIN32) && !defined(TARGET_ANDROID)
 #define LD_NAME "gcc -shared --dll"
 #elif defined(TARGET_X86) && defined(TARGET_MACH) && !defined(__native_client_codegen__)
 #define LD_NAME "clang -m32 -dynamiclib"
@@ -8686,7 +8782,7 @@ compile_asm (MonoAotCompile *acfg)
                aot_printf (acfg, "Output file: '%s'.\n", acfg->tmpfname);
                if (acfg->aot_opts.static_link)
                        aot_printf (acfg, "Linking symbol: '%s'.\n", acfg->static_linking_symbol);
-               if (acfg->llvm_separate)
+               if (acfg->llvm)
                        aot_printf (acfg, "LLVM output file: '%s'.\n", acfg->llvm_sfile);
                return 0;
        }
@@ -8699,18 +8795,23 @@ compile_asm (MonoAotCompile *acfg)
        } else {
                objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
        }
-       command = g_strdup_printf ("%s%s %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS, acfg->as_args ? acfg->as_args->str : "", objfile, acfg->tmpfname);
+
+#ifdef TARGET_OSX
+       g_string_append (acfg->as_args, "-c -x assembler");
+#endif
+
+       command = g_strdup_printf ("\"%s%s\" %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS, acfg->as_args ? acfg->as_args->str : "", objfile, acfg->tmpfname);
        aot_printf (acfg, "Executing the native assembler: %s\n", command);
-       if (system (command) != 0) {
+       if (execute_system (command) != 0) {
                g_free (command);
                g_free (objfile);
                return 1;
        }
 
-       if (acfg->llvm_separate && !acfg->llvm_owriter) {
-               command = g_strdup_printf ("%s%s %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS, acfg->as_args ? acfg->as_args->str : "", acfg->llvm_ofile, acfg->llvm_sfile);
+       if (acfg->llvm && !acfg->llvm_owriter) {
+               command = g_strdup_printf ("\"%s%s\" %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS, acfg->as_args ? acfg->as_args->str : "", acfg->llvm_ofile, acfg->llvm_sfile);
                aot_printf (acfg, "Executing the native assembler: %s\n", command);
-               if (system (command) != 0) {
+               if (execute_system (command) != 0) {
                        g_free (command);
                        g_free (objfile);
                        return 1;
@@ -8733,23 +8834,28 @@ compile_asm (MonoAotCompile *acfg)
 
        tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
 
-       if (acfg->llvm_separate) {
+       if (acfg->llvm) {
                llvm_ofile = g_strdup (acfg->llvm_ofile);
        } else {
                llvm_ofile = g_strdup ("");
        }
 
+       /* replace the ; flags separators with spaces */
+       g_strdelimit (ld_flags, ";", ' ');
+
 #ifdef LD_NAME
-       command = g_strdup_printf ("%s -o %s %s %s.o", LD_NAME, tmp_outfile_name, llvm_ofile, acfg->tmpfname);
+       command = g_strdup_printf ("%s -o %s %s %s.o %s", LD_NAME, tmp_outfile_name, llvm_ofile, acfg->tmpfname, ld_flags);
 #else
-       command = g_strdup_printf ("%sld %s -shared -o %s %s %s.o", tool_prefix, LD_OPTIONS, tmp_outfile_name, llvm_ofile, acfg->tmpfname);
+       command = g_strdup_printf ("\"%sld\" %s -shared -o %s %s %s.o %s", tool_prefix, LD_OPTIONS, tmp_outfile_name, llvm_ofile,
+               acfg->tmpfname, ld_flags);
 #endif
        aot_printf (acfg, "Executing the native linker: %s\n", command);
-       if (system (command) != 0) {
+       if (execute_system (command) != 0) {
                g_free (tmp_outfile_name);
                g_free (outfile_name);
                g_free (command);
                g_free (objfile);
+               g_free (ld_flags);
                return 1;
        }
 
@@ -8757,7 +8863,7 @@ compile_asm (MonoAotCompile *acfg)
 
        /*com = g_strdup_printf ("strip --strip-unneeded %s%s", acfg->image->name, MONO_SOLIB_EXT);
        printf ("Stripping the binary: %s\n", com);
-       system (com);
+       execute_system (com);
        g_free (com);*/
 
 #if defined(TARGET_ARM) && !defined(TARGET_MACH)
@@ -8767,7 +8873,7 @@ compile_asm (MonoAotCompile *acfg)
         */
        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 (system (command) != 0) {
+       if (execute_system (command) != 0) {
                g_free (tmp_outfile_name);
                g_free (outfile_name);
                g_free (command);
@@ -8781,7 +8887,7 @@ compile_asm (MonoAotCompile *acfg)
 #if defined(TARGET_MACH)
        command = g_strdup_printf ("dsymutil %s", outfile_name);
        aot_printf (acfg, "Executing dsymutil: %s\n", command);
-       if (system (command) != 0) {
+       if (execute_system (command) != 0) {
                return 1;
        }
 #endif
@@ -9143,21 +9249,17 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
                mini_llvm_init ();
 
-               if (!acfg->aot_opts.asm_only || acfg->aot_opts.llvm_outfile) {
-                       /*
-                        * Emit all LLVM code into a separate assembly/object file and link with it
-                        * normally.
-                        */
-#if LLVM_API_VERSION >= 3
-                       acfg->llvm_separate = TRUE;
-                       if (!acfg->aot_opts.asm_only)
-                               acfg->llvm_owriter = TRUE;
-#endif
-               }
-               if (acfg->aot_opts.llvm_outfile && !acfg->llvm_separate) {
-                       aot_printerrf (acfg, "The llvm-outputfile= option is not supported on this platform.\n");
+               if (acfg->aot_opts.asm_only && !acfg->aot_opts.llvm_outfile) {
+                       aot_printerrf (acfg, "Compiling with LLVM and the asm-only option requires the llvm-outputfile= option.");
                        return 1;
                }
+
+               /*
+                * Emit all LLVM code into a separate assembly/object file and link with it
+                * normally.
+                */
+               if (!acfg->aot_opts.asm_only)
+                       acfg->llvm_owriter = TRUE;
        }
 
        if (acfg->aot_opts.full_aot)
@@ -9201,19 +9303,13 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        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);
-               if (acfg->llvm_separate)
-                       acfg->llvm_eh_frame_symbol = g_strdup_printf ("mono_aot_%s_eh_frame", acfg->assembly_name_sym);
-               else
-                       acfg->llvm_eh_frame_symbol = g_strdup ("mono_eh_frame");
+               acfg->llvm_eh_frame_symbol = g_strdup_printf ("mono_aot_%s_eh_frame", acfg->assembly_name_sym);
        }
 
        acfg->method_index = 1;
 
-       // FIXME:
-       /*
        if (acfg->aot_opts.full_aot)
                mono_set_partial_sharing_supported (TRUE);
-       */
 
        res = collect_methods (acfg);
        if (!res)
@@ -9228,7 +9324,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, acfg->llvm_separate, acfg->llvm_separate);
+               mono_llvm_create_aot_module (acfg->llvm_got_symbol_base, TRUE, TRUE);
        }
 #endif
 
@@ -9236,7 +9332,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        {
                MonoJumpInfo *ji;
 
-               ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
+               ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
                ji->type = MONO_PATCH_INFO_IMAGE;
                ji->data.image = acfg->image;
 
@@ -9244,18 +9340,23 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                get_got_offset (acfg, TRUE, ji);
 
                /* Slot 1 is reserved for the mscorlib got addr */
-               ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
+               ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
                ji->type = MONO_PATCH_INFO_MSCORLIB_GOT_ADDR;
                get_got_offset (acfg, FALSE, ji);
                get_got_offset (acfg, TRUE, ji);
 
                /* This is very common */
-               ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
+               ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
                ji->type = MONO_PATCH_INFO_GC_CARD_TABLE_ADDR;
                get_got_offset (acfg, FALSE, ji);
                get_got_offset (acfg, TRUE, ji);
 
-               ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
+               ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
+               ji->type = MONO_PATCH_INFO_GC_NURSERY_START;
+               get_got_offset (acfg, FALSE, ji);
+               get_got_offset (acfg, TRUE, ji);
+
+               ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
                ji->type = MONO_PATCH_INFO_JIT_TLS_ID;
                get_got_offset (acfg, FALSE, ji);
                get_got_offset (acfg, TRUE, ji);
@@ -9283,10 +9384,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                                acfg->tmpbasename = g_strdup_printf ("%s", acfg->image->name);
                                acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
                        }
-                       if (acfg->llvm_separate) {
-                               g_assert (acfg->aot_opts.llvm_outfile);
-                               acfg->llvm_sfile = g_strdup (acfg->aot_opts.llvm_outfile);
-                       }
+                       g_assert (acfg->aot_opts.llvm_outfile);
+                       acfg->llvm_sfile = g_strdup (acfg->aot_opts.llvm_outfile);
                } else {
                        acfg->tmpbasename = g_strdup_printf ("%s", "temp");
                        acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
@@ -9321,21 +9420,15 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                acfg->w = img_writer_create (acfg->fp, TRUE);
                acfg->use_bin_writer = TRUE;
        } else {
-               if (acfg->llvm && !acfg->llvm_separate) {
-                       /* Append to the .s file created by llvm */
-                       /* FIXME: Use multiple files instead */
-                       acfg->fp = fopen (acfg->tmpfname, "a+");
+               if (acfg->aot_opts.asm_only) {
+                       if (acfg->aot_opts.outfile)
+                               acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
+                       else
+                               acfg->tmpfname = g_strdup_printf ("%s.s", acfg->image->name);
+                       acfg->fp = fopen (acfg->tmpfname, "w+");
                } else {
-                       if (acfg->aot_opts.asm_only) {
-                               if (acfg->aot_opts.outfile)
-                                       acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
-                               else
-                                       acfg->tmpfname = g_strdup_printf ("%s.s", acfg->image->name);
-                               acfg->fp = fopen (acfg->tmpfname, "w+");
-                       } else {
-                               int i = g_file_open_tmp ("mono_aot_XXXXXX", &acfg->tmpfname, NULL);
-                               acfg->fp = fdopen (i, "w+");
-                       }
+                       int i = g_file_open_tmp ("mono_aot_XXXXXX", &acfg->tmpfname, NULL);
+                       acfg->fp = fdopen (i, "w+");
                }
                if (acfg->fp == 0) {
                        aot_printerrf (acfg, "Unable to open file '%s': %s\n", acfg->tmpfname, strerror (errno));
@@ -9355,10 +9448,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
                        if (COMPILE_LLVM (cfg))
                                cfg->asm_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, cfg->llvm_method_name);
-                       else if (acfg->global_symbols || acfg->llvm_separate)
+                       else if (acfg->global_symbols || acfg->llvm)
                                cfg->asm_symbol = get_debug_sym (cfg->orig_method, "", acfg->method_label_hash);
                        else
                                cfg->asm_symbol = g_strdup_printf ("%s%sm_%x", acfg->temp_prefix, acfg->llvm_label_prefix, method_index);
+                       cfg->asm_debug_symbol = cfg->asm_symbol;
                }
        }