Merge pull request #1588 from BrzVlad/feature-aot-wbarrier
[mono.git] / mono / mini / aot-compiler.c
index 2e5d4a914652406bd479857462c84c941f192ed5..650e05ca67022f92accf8c6d6f854f6a353a1820 100644 (file)
@@ -50,6 +50,7 @@
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-time.h>
 #include <mono/utils/mono-mmap.h>
+#include <mono/utils/json.h>
 
 #include "mini.h"
 #include "seq-points.h"
@@ -93,6 +94,7 @@ static ReadOnlyValue *readonly_values;
 
 typedef struct MonoAotOptions {
        char *outfile;
+       char *llvm_outfile;
        gboolean save_temps;
        gboolean write_symbols;
        gboolean metadata_only;
@@ -107,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;
@@ -123,11 +126,13 @@ typedef struct MonoAotOptions {
        gboolean print_skipped_methods;
        gboolean stats;
        char *tool_prefix;
+       char *ld_flags;
        gboolean autoreg;
        char *mtriple;
        char *llvm_path;
        char *instances_logfile_path;
        char *logfile;
+       gboolean dump_json;
 } MonoAotOptions;
 
 typedef struct MonoAotStats {
@@ -194,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;
@@ -215,6 +218,7 @@ typedef struct MonoAotCompile {
        char *llvm_got_symbol;
        char *plt_symbol;
        char *methods_symbol;
+       char *llvm_eh_frame_symbol;
        GHashTable *method_label_hash;
        const char *temp_prefix;
        const char *user_symbol_prefix;
@@ -329,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
@@ -415,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) 
 { 
@@ -636,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
 
@@ -922,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;
@@ -1352,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);
@@ -1492,6 +1500,9 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
        /* We clobber ECX, since EAX is used as MONO_ARCH_MONITOR_OBJECT_REG */
 #ifdef MONO_ARCH_MONITOR_OBJECT_REG
        g_assert (MONO_ARCH_MONITOR_OBJECT_REG != X86_ECX);
+#ifdef MONO_ARCH_MONITOR_LOCK_TAKEN_REG
+       g_assert (MONO_ARCH_MONITOR_LOCK_TAKEN_REG != X86_ECX);
+#endif
 #endif
 
        code = buf;
@@ -1540,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 {
@@ -1626,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)));
@@ -1801,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));
        }
@@ -1840,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 */
@@ -2487,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);
@@ -3045,6 +3056,7 @@ is_plt_patch (MonoJumpInfo *patch_info)
        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:
        case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE:
                return TRUE;
@@ -3397,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) ||
@@ -3451,8 +3465,6 @@ add_wrappers (MonoAotCompile *acfg)
        }
 
        if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
-               MonoMethodDesc *desc;
-               MonoMethod *orig_method;
                int nallocators;
 
                /* Runtime invoke wrappers */
@@ -3529,25 +3541,12 @@ add_wrappers (MonoAotCompile *acfg)
                                if (m)
                                        add_method (acfg, m);
                        }
+               }
 
-                       /* Monitor Enter/Exit */
-                       desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE);
-                       orig_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
-                       /* This is a v4 method */
-                       if (orig_method) {
-                               method = mono_monitor_get_fast_path (orig_method);
-                               if (method)
-                                       add_method (acfg, method);
-                       }
-                       mono_method_desc_free (desc);
-
-                       desc = mono_method_desc_new ("Monitor:Exit(object)", FALSE);
-                       orig_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
-                       g_assert (orig_method);
-                       mono_method_desc_free (desc);
-                       method = mono_monitor_get_fast_path (orig_method);
-                       if (method)
-                               add_method (acfg, method);
+               /* 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 */
@@ -3566,22 +3565,6 @@ add_wrappers (MonoAotCompile *acfg)
                /* isinst_with_check wrapper */
                add_method (acfg, mono_marshal_get_isinst_with_cache ());
 
-#if defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
-               {
-                       MonoMethodDesc *desc;
-                       MonoMethod *m;
-
-                       desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE);
-                       m = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
-                       mono_method_desc_free (desc);
-                       if (m) {
-                               m = mono_monitor_get_fast_path (m);
-                               if (m)
-                                       add_method (acfg, m);
-                       }
-               }
-#endif
-
                /* JIT icall wrappers */
                /* FIXME: locking - this is "safe" as full-AOT threads don't mutate the icall hash*/
                g_hash_table_foreach (mono_get_jit_icall_info (), add_jit_icall_wrapper, acfg);
@@ -3654,6 +3637,7 @@ add_wrappers (MonoAotCompile *acfg)
                                        add_method (acfg, mono_marshal_get_native_func_wrapper_aot (klass));
                        }
                } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->generic_container) {
+                       MonoError error;
                        MonoGenericContext ctx;
                        MonoMethod *inst, *gshared;
 
@@ -3664,7 +3648,8 @@ add_wrappers (MonoAotCompile *acfg)
                        method = mono_get_delegate_invoke (klass);
                        create_gsharedvt_inst (acfg, method, &ctx);
 
-                       inst = mono_class_inflate_generic_method (method, &ctx);
+                       inst = mono_class_inflate_generic_method_checked (method, &ctx, &error);
+                       g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
 
                        m = mono_marshal_get_delegate_invoke (inst, NULL);
                        g_assert (m->is_inflated);
@@ -3676,7 +3661,8 @@ add_wrappers (MonoAotCompile *acfg)
                        method = mono_get_delegate_begin_invoke (klass);
                        create_gsharedvt_inst (acfg, method, &ctx);
 
-                       inst = mono_class_inflate_generic_method (method, &ctx);
+                       inst = mono_class_inflate_generic_method_checked (method, &ctx, &error);
+                       g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
 
                        m = mono_marshal_get_delegate_begin_invoke (inst);
                        g_assert (m->is_inflated);
@@ -3688,7 +3674,8 @@ add_wrappers (MonoAotCompile *acfg)
                        method = mono_get_delegate_end_invoke (klass);
                        create_gsharedvt_inst (acfg, method, &ctx);
 
-                       inst = mono_class_inflate_generic_method (method, &ctx);
+                       inst = mono_class_inflate_generic_method_checked (method, &ctx, &error);
+                       g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
 
                        m = mono_marshal_get_delegate_end_invoke (inst);
                        g_assert (m->is_inflated);
@@ -3733,13 +3720,16 @@ 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) {
                                // FIXME:
                        } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && method->klass->generic_container) {
+                               MonoError error;
                                MonoGenericContext ctx;
                                MonoMethod *inst, *gshared, *m;
 
@@ -3747,7 +3737,8 @@ add_wrappers (MonoAotCompile *acfg)
                                 * Create a generic wrapper for a generic instance, and AOT that.
                                 */
                                create_gsharedvt_inst (acfg, method, &ctx);
-                               inst = mono_class_inflate_generic_method (method, &ctx);        
+                               inst = mono_class_inflate_generic_method_checked (method, &ctx, &error);
+                               g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
                                m = mono_marshal_get_synchronized_wrapper (inst);
                                g_assert (m->is_inflated);
                                gshared = mini_get_shared_method_full (m, FALSE, TRUE);
@@ -3760,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)) {
@@ -3773,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
@@ -3796,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;
@@ -3841,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);
@@ -3859,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);
@@ -4249,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;
@@ -4268,6 +4265,7 @@ add_generic_instances (MonoAotCompile *acfg)
                 * FIXME: Handle class_inst as well.
                 */
                if (context && context->method_inst && context->method_inst->is_open) {
+                       MonoError error;
                        MonoGenericContext shared_context;
                        MonoGenericInst *inst;
                        MonoType **type_argv;
@@ -4333,7 +4331,8 @@ add_generic_instances (MonoAotCompile *acfg)
                        else
                                declaring_method = mono_method_get_declaring_generic_method (method);
 
-                       method = mono_class_inflate_generic_method (declaring_method, &shared_context);
+                       method = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
+                       g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
                }
 
                /* 
@@ -4422,10 +4421,12 @@ add_generic_instances (MonoAotCompile *acfg)
                        get_method = mono_class_get_method_from_name (array_klass, "GetGenericValueImpl", 2);
 
                        if (get_method) {
+                               MonoError error;
                                memset (&ctx, 0, sizeof (ctx));
                                args [0] = &mono_defaults.object_class->byval_arg;
                                ctx.method_inst = mono_metadata_get_generic_inst (1, args);
-                               add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (get_method, &ctx), TRUE, TRUE));
+                               add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method_checked (get_method, &ctx, &error), TRUE, TRUE));
+                               g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
                        }
                }
 
@@ -4439,10 +4440,12 @@ add_generic_instances (MonoAotCompile *acfg)
 
                        while ((m = mono_class_get_methods (interlocked_klass, &iter))) {
                                if ((!strcmp (m->name, "CompareExchange") || !strcmp (m->name, "Exchange")) && m->is_generic) {
+                                       MonoError error;
                                        memset (&ctx, 0, sizeof (ctx));
                                        args [0] = &mono_defaults.object_class->byval_arg;
                                        ctx.method_inst = mono_metadata_get_generic_inst (1, args);
-                                       add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (m, &ctx), TRUE, TRUE));
+                                       add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method_checked (m, &ctx, &error), TRUE, TRUE));
+                                       g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
                                }
                        }
                }
@@ -4458,10 +4461,12 @@ add_generic_instances (MonoAotCompile *acfg)
                        if (volatile_klass) {
                                while ((m = mono_class_get_methods (volatile_klass, &iter))) {
                                        if ((!strcmp (m->name, "Read") || !strcmp (m->name, "Write")) && m->is_generic) {
+                                               MonoError error;
                                                memset (&ctx, 0, sizeof (ctx));
                                                args [0] = &mono_defaults.object_class->byval_arg;
                                                ctx.method_inst = mono_metadata_get_generic_inst (1, args);
-                                               add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (m, &ctx), TRUE, TRUE));
+                                               add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method_checked (m, &ctx, &error), TRUE, TRUE));
+                                               g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
                                        }
                                }
                        }
@@ -4500,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;
@@ -4678,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
@@ -4691,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) {
@@ -4999,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);
@@ -5018,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
@@ -5026,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);
@@ -5052,7 +5052,10 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
        emit_line (acfg);
 
        if (acfg->aot_opts.write_symbols) {
-               emit_symbol_size (acfg, debug_sym, ".");
+               if (debug_sym)
+                       emit_symbol_size (acfg, debug_sym, ".");
+               else
+                       emit_symbol_size (acfg, cfg->asm_symbol, ".");
                g_free (debug_sym);
        }
 
@@ -5079,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);
@@ -5206,6 +5210,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        }
        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:
        case MONO_PATCH_INFO_SEQ_POINT_INFO:
                break;
@@ -5249,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:
@@ -5293,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);
 
@@ -5352,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;
@@ -5414,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;
@@ -5427,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 {
@@ -5441,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);
 
@@ -5575,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) {
@@ -5650,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);
@@ -5778,39 +5778,49 @@ get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cac
 {
        char *debug_sym = NULL;
        char *s;
+       char *prefix;
+
+       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 {
+               prefix = g_strdup ("plt_");
+       }
 
        switch (ji->type) {
        case MONO_PATCH_INFO_METHOD:
-               debug_sym = get_debug_sym (ji->data.method, "plt_", cache);
+               debug_sym = get_debug_sym (ji->data.method, prefix, cache);
                break;
        case MONO_PATCH_INFO_INTERNAL_METHOD:
-               debug_sym = g_strdup_printf ("plt__jit_icall_%s", ji->data.name);
+               debug_sym = g_strdup_printf ("%s_jit_icall_%s", prefix, ji->data.name);
                break;
        case MONO_PATCH_INFO_CLASS_INIT:
                s = mono_type_get_name (&ji->data.klass->byval_arg);
-               debug_sym = g_strdup_printf ("plt__class_init_%s", s);
+               debug_sym = g_strdup_printf ("%s__class_init_%s", prefix, s);
                g_free (s);
                break;
        case MONO_PATCH_INFO_RGCTX_FETCH:
-               debug_sym = g_strdup_printf ("plt__rgctx_fetch_%d", acfg->label_generator ++);
+               debug_sym = g_strdup_printf ("%s_rgctx_fetch_%d", prefix, acfg->label_generator ++);
                break;
        case MONO_PATCH_INFO_ICALL_ADDR: {
                char *s = get_debug_sym (ji->data.method, "", cache);
                
-               debug_sym = g_strdup_printf ("plt__icall_native_%s", s);
+               debug_sym = g_strdup_printf ("%s_icall_native_%s", prefix, s);
                g_free (s);
                break;
        }
        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
-               debug_sym = g_strdup_printf ("plt__jit_icall_native_%s", ji->data.name);
+               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 ("plt__generic_class_init");
+               debug_sym = g_strdup_printf ("%s_generic_class_init", prefix);
                break;
        default:
                break;
        }
 
+       g_free (prefix);
+
        return sanitize_symbol (acfg, debug_sym);
 }
 
@@ -5836,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)
                        /* 
@@ -5845,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;
 
@@ -5859,9 +5867,11 @@ 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
                        }
                }
 
@@ -5893,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)
@@ -5922,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) {
@@ -6101,8 +6112,12 @@ emit_trampolines (MonoAotCompile *acfg)
                mono_arch_get_nullified_class_init_trampoline (&info);
                emit_trampoline (acfg, acfg->got_offset, info);
 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
-               mono_arch_create_monitor_enter_trampoline (&info, TRUE);
+               mono_arch_create_monitor_enter_trampoline (&info, FALSE, TRUE);
                emit_trampoline (acfg, acfg->got_offset, info);
+#if defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
+               mono_arch_create_monitor_enter_trampoline (&info, TRUE, TRUE);
+               emit_trampoline (acfg, acfg->got_offset, info);
+#endif
                mono_arch_create_monitor_exit_trampoline (&info, TRUE);
                emit_trampoline (acfg, acfg->got_offset, info);
 #endif
@@ -6382,6 +6397,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
 
                if (str_begins_with (arg, "outfile=")) {
                        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, "save-temps")) {
                        opts->save_temps = TRUE;
                } else if (str_begins_with (arg, "keep-temps")) {
@@ -6423,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")) {
@@ -6454,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=")) {
@@ -6463,9 +6485,12 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        exit (0);
                } else if (str_begins_with (arg, "gc-maps")) {
                        mini_gc_enable_gc_maps_for_aot ();
+               } else if (str_begins_with (arg, "dump")) {
+                       opts->dump_json = TRUE;                 
                } else if (str_begins_with (arg, "help") || str_begins_with (arg, "?")) {
                        printf ("Supported options for --aot:\n");
                        printf ("    outfile=\n");
+                       printf ("    llvm-outfile=\n");
                        printf ("    save-temps\n");
                        printf ("    keep-temps\n");
                        printf ("    write-symbols\n");
@@ -6486,10 +6511,12 @@ 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");
                        printf ("    stats\n");
+                       printf ("    dump\n");
                        printf ("    info\n");
                        printf ("    help/?\n");
                        exit (0);
@@ -6694,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 ();
 
@@ -6814,8 +6843,12 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                                        }
                                        add_generic_class_with_depth (acfg, m->klass, depth + 5, "method");
                                }
-                               if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED && !strcmp (m->name, "ElementAddr"))
-                                       add_extra_method_with_depth (acfg, m, depth + 1);
+                               if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
+                                       WrapperInfo *info = mono_marshal_get_wrapper_info (m);
+
+                                       if (info && info->subtype == WRAPPER_SUBTYPE_ELEMENT_ADDR)
+                                               add_extra_method_with_depth (acfg, m, depth + 1);
+                               }
                                break;
                        }
                        case MONO_PATCH_INFO_VTABLE: {
@@ -6845,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 */
@@ -7095,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;
@@ -7102,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;
 
@@ -7131,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
 
 /*
@@ -7176,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);
@@ -7196,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=mono_eh_frame");
+       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 */
@@ -7210,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;
 }
@@ -7323,11 +7391,8 @@ emit_code (MonoAotCompile *acfg)
                        emit_method_code (acfg, cfg);
        }
 
-       sprintf (symbol, "methods_end");
        emit_section_change (acfg, ".text", 0);
        emit_alignment_code (acfg, 8);
-       emit_label (acfg, symbol);
-
        emit_label (acfg, "jit_code_end");
 
        /* To distinguish it from the next symbol */
@@ -7435,6 +7500,7 @@ emit_code (MonoAotCompile *acfg)
 #endif
                }
        }
+       emit_int32 (acfg, 0);
 }
 
 static void
@@ -7525,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;
 
@@ -7545,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;
@@ -7565,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]);
@@ -7636,10 +7714,12 @@ mono_aot_get_array_helper_from_wrapper (MonoMethod *method)
        g_free (s);
 
        if (m->is_generic) {
+               MonoError error;
                memset (&ctx, 0, sizeof (ctx));
                args [0] = &method->klass->element_class->byval_arg;
                ctx.method_inst = mono_metadata_get_generic_inst (1, args);
-               m = mono_class_inflate_generic_method (m, &ctx);
+               m = mono_class_inflate_generic_method_checked (m, &ctx, &error);
+               g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
        }
 
        return m;
@@ -7718,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]);
@@ -7792,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);
@@ -7988,7 +8094,7 @@ static void
 emit_got_info (MonoAotCompile *acfg, gboolean llvm)
 {
        char symbol [256];
-       int i, first_plt_got_patch, buf_size;
+       int i, first_plt_got_patch = 0, buf_size;
        guint8 *p, *buf;
        guint32 *got_info_offsets;
        GotInfo *info = llvm ? &acfg->llvm_got_info : &acfg->got_info;
@@ -8089,7 +8195,7 @@ emit_globals (MonoAotCompile *acfg)
        int i, table_size;
        guint32 hash;
        GPtrArray *table;
-       char symbol [256];
+       char symbol [1024];
        GlobalsTableEntry *entry, *new_entry;
 
        if (!acfg->aot_opts.static_link)
@@ -8183,6 +8289,7 @@ emit_globals (MonoAotCompile *acfg)
                sprintf (symbol, "name_%d", i);
                emit_pointer (acfg, symbol);
 
+               g_assert (strlen (name) < sizeof (symbol));
                sprintf (symbol, "%s", name);
                emit_pointer (acfg, symbol);
        }
@@ -8282,7 +8389,7 @@ emit_file_info (MonoAotCompile *acfg)
                /*
                 * Emit a reference to the mono_eh_frame table created by our modified LLVM compiler.
                 */
-               emit_pointer (acfg, "mono_eh_frame");
+               emit_pointer (acfg, acfg->llvm_eh_frame_symbol);
        } else {
                emit_pointer (acfg, NULL);
        }
@@ -8299,7 +8406,6 @@ emit_file_info (MonoAotCompile *acfg)
                emit_pointer (acfg, "llvm_got_info_offsets");
        else
                emit_pointer (acfg, NULL);
-       emit_pointer (acfg, "methods_end");
        emit_pointer (acfg, "unwind_info");
        emit_pointer (acfg, "mem_end");
        emit_pointer (acfg, "image_table");
@@ -8471,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
 }
@@ -8484,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;
                }
                        
@@ -8527,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;
@@ -8626,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"
@@ -8647,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
@@ -8662,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"
@@ -8672,6 +8782,8 @@ 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)
+                       aot_printf (acfg, "LLVM output file: '%s'.\n", acfg->llvm_sfile);
                return 0;
        }
 
@@ -8683,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;
@@ -8717,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;
        }
 
@@ -8741,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)
@@ -8751,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);
@@ -8765,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
@@ -8889,6 +9011,159 @@ acfg_free (MonoAotCompile *acfg)
        g_free (acfg);
 }
 
+#define WRAPPER(e,n) n,
+static const char* const
+wrapper_type_names [MONO_WRAPPER_NUM + 1] = {
+#include "mono/metadata/wrapper-types.h"
+       NULL
+};
+
+static G_GNUC_UNUSED const char*
+get_wrapper_type_name (int type)
+{
+       return wrapper_type_names [type];
+}
+
+//#define DUMP_PLT
+//#define DUMP_GOT
+
+static void aot_dump (MonoAotCompile *acfg)
+{
+       FILE *dumpfile;
+       char * dumpname;
+
+       JsonWriter writer;
+       json_writer_init (&writer);
+
+       json_writer_object_begin(&writer);
+
+       // Methods
+       json_writer_indent (&writer);
+       json_writer_object_key(&writer, "methods");
+       json_writer_array_begin (&writer);
+
+       int i;
+       for (i = 0; i < acfg->nmethods; ++i) {
+               MonoCompile *cfg;
+               MonoMethod *method;
+               MonoClass *klass;
+
+               cfg = acfg->cfgs [i];
+               if (!cfg)
+                       continue;
+
+               method = cfg->orig_method;
+
+               json_writer_indent (&writer);
+               json_writer_object_begin(&writer);
+
+               json_writer_indent (&writer);
+               json_writer_object_key(&writer, "name");
+               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,
+                       /*signature=*/TRUE));
+
+               json_writer_indent (&writer);
+               json_writer_object_key(&writer, "code_size");
+               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);
+
+               json_writer_indent (&writer);
+               json_writer_object_key(&writer, "namespace");
+               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));
+
+               json_writer_indent_pop (&writer);
+               json_writer_indent (&writer);
+               json_writer_object_end (&writer);
+               json_writer_printf (&writer, ",\n");
+       }
+
+       json_writer_indent_pop (&writer);
+       json_writer_indent (&writer);
+       json_writer_array_end (&writer);
+       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);
+
+       for (i = 0; i < acfg->plt_offset; ++i) {
+               MonoPltEntry *plt_entry = NULL;
+               MonoJumpInfo *ji;
+
+               if (i == 0)
+                       /* 
+                        * The first plt entry is unused.
+                        */
+                       continue;
+
+               plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
+               ji = plt_entry->ji;
+
+               json_writer_indent (&writer);
+               json_writer_printf (&writer, "{ ");
+               json_writer_object_key(&writer, "symbol");
+               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");
+#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);
+
+       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));
+       }
+
+       json_writer_indent_pop (&writer);
+       json_writer_indent (&writer);
+       json_writer_array_end (&writer);
+       json_writer_printf (&writer, ",\n");
+#endif
+
+       json_writer_indent_pop (&writer);
+       json_writer_indent (&writer);
+       json_writer_object_end (&writer);
+
+       dumpname = g_strdup_printf ("%s.json", g_path_get_basename (acfg->image->name));
+       dumpfile = fopen (dumpname, "w+");
+       g_free (dumpname);
+
+       fprintf (dumpfile, "%s", writer.text->str);
+       fclose (dumpfile);
+
+       json_writer_destroy (&writer);
+}
+
 int
 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 {
@@ -8974,23 +9249,17 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
                mini_llvm_init ();
 
-               if (!acfg->aot_opts.static_link && !acfg->aot_opts.asm_only) {
-                       /*
-                        * Emit all LLVM code into a separate assembly/object file and link with it
-                        * normally.
-                        * FIXME:
-                        * Can't use it when using asm_only or static_link, since it requires changes
-                        * to users because we generate two files now. Also, symbol names have to be
-                        * prefixed by a unique prefix so multiple files can be linked together.
-                        * This also affects the mono_eh_frame symbol emitted by LLVM.
-                        * Can't use this with full aot until the trampolines are updated
-                        * (i.e. get rid of the emit_symbol_diff () stuff).
-                        */
-#if LLVM_API_VERSION >= 3 && defined(TARGET_AMD64)
-                       acfg->llvm_separate = TRUE;
-                       acfg->llvm_owriter = TRUE;
-#endif
+               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)
@@ -9032,16 +9301,15 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        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)
+       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->method_index = 1;
 
-       // FIXME:
-       /*
        if (acfg->aot_opts.full_aot)
                mono_set_partial_sharing_supported (TRUE);
-       */
 
        res = collect_methods (acfg);
        if (!res)
@@ -9056,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
 
@@ -9064,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;
 
@@ -9072,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);
@@ -9104,7 +9377,6 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                gboolean res;
 
                if (acfg->aot_opts.asm_only) {
-                       g_assert (!acfg->llvm_separate);
                        if (acfg->aot_opts.outfile) {
                                acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
                                acfg->tmpbasename = g_strdup (acfg->tmpfname);
@@ -9112,6 +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);
                        }
+                       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);
@@ -9146,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));
@@ -9180,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;
                }
        }
 
@@ -9343,6 +9612,9 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        aot_printf (acfg, "JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000);
 
+       if (acfg->aot_opts.dump_json)
+               aot_dump (acfg);
+
        acfg_free (acfg);
        
        return 0;