[aot] Don't error out if a method fails to JIT in full-aot mode. This was a regressio...
[mono.git] / mono / mini / aot-compiler.c
index b91dfaedb245b11461172e3fae477c04cbee5ee8..5bfa4d0920387d4bcbaf388a254e24f328622407 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * aot-compiler.c: mono Ahead of Time compiler
+/**
+ * \file
+ * mono Ahead of Time compiler
  *
  * Author:
  *   Dietmar Maurer (dietmar@ximian.com)
@@ -55,8 +56,8 @@
 #include <mono/utils/mono-rand.h>
 #include <mono/utils/json.h>
 #include <mono/utils/mono-threads-coop.h>
-#include <mono/profiler/mono-profiler-aot.h>
-#include <mono/io-layer/io-layer.h>
+#include <mono/profiler/aot.h>
+#include <mono/utils/w32api.h>
 
 #include "aot-compiler.h"
 #include "seq-points.h"
@@ -77,7 +78,7 @@
 #define TARGET_WIN32_MSVC
 #endif
 
-#if defined(__linux__) || defined(__native_client_codegen__)
+#if defined(__linux__)
 #define RODATA_SECT ".rodata"
 #elif defined(TARGET_MACH)
 #define RODATA_SECT ".section __TEXT, __const"
@@ -149,7 +150,7 @@ typedef struct MonoAotOptions {
        char *outfile;
        char *llvm_outfile;
        char *data_outfile;
-       char *profile_file;
+       GList *profile_files;
        gboolean save_temps;
        gboolean write_symbols;
        gboolean metadata_only;
@@ -182,6 +183,7 @@ typedef struct MonoAotOptions {
        int nrgctx_fetch_trampolines;
        gboolean print_skipped_methods;
        gboolean stats;
+       gboolean verbose;
        char *tool_prefix;
        char *ld_flags;
        char *mtriple;
@@ -190,6 +192,7 @@ typedef struct MonoAotOptions {
        char *instances_logfile_path;
        char *logfile;
        gboolean dump_json;
+       gboolean profile_only;
 } MonoAotOptions;
 
 typedef enum {
@@ -295,6 +298,7 @@ typedef struct MonoAotCompile {
        guint32 label_generator;
        gboolean llvm;
        gboolean has_jitted_code;
+       gboolean is_full_aot;
        MonoAotFileFlags flags;
        MonoDynamicStream blob;
        gboolean blob_closed;
@@ -310,7 +314,8 @@ typedef struct MonoAotCompile {
        int objc_selector_index, objc_selector_index_2;
        GPtrArray *objc_selectors;
        GHashTable *objc_selector_to_index;
-       ProfileData *profile_data;
+       GList *profile_data;
+       GHashTable *profile_methods;
        FILE *logfile;
        FILE *instances_logfile;
        FILE *data_outfile;
@@ -381,7 +386,7 @@ static void
 add_gsharedvt_wrappers (MonoAotCompile *acfg, MonoMethodSignature *sig, gboolean gsharedvt_in, gboolean gsharedvt_out);
 
 static void
-add_profile_instances (MonoAotCompile *acfg);
+add_profile_instances (MonoAotCompile *acfg, ProfileData *data);
 
 static void
 aot_printf (MonoAotCompile *acfg, const gchar *format, ...)
@@ -416,7 +421,7 @@ aot_printerrf (MonoAotCompile *acfg, const gchar *format, ...)
 }
 
 static void
-report_loader_error (MonoAotCompile *acfg, MonoError *error, const char *format, ...)
+report_loader_error (MonoAotCompile *acfg, MonoError *error, gboolean fatal, const char *format, ...)
 {
        FILE *output;
        va_list args;
@@ -434,7 +439,10 @@ report_loader_error (MonoAotCompile *acfg, MonoError *error, const char *format,
        va_end (args);
        mono_error_cleanup (error);
 
-       g_error ("FullAOT cannot continue if there are loader errors");
+       if (acfg->is_full_aot && fatal) {
+               fprintf (output, "FullAOT cannot continue if there are loader errors.\n");
+               exit (1);
+       }
 }
 
 /* Wrappers around the image writer functions */
@@ -945,10 +953,8 @@ emit_code_bytes (MonoAotCompile *acfg, const guint8* buf, int size)
 #ifdef TARGET_X86
 #ifdef TARGET_WIN32
 #define AOT_TARGET_STR "X86 (WIN32)"
-#elif defined(__native_client_codegen__)
-#define AOT_TARGET_STR "X86 (native client codegen)"
 #else
-#define AOT_TARGET_STR "X86 (!native client codegen)"
+#define AOT_TARGET_STR "X86"
 #endif
 #endif
 
@@ -2891,7 +2897,7 @@ encode_klass_ref_inner (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, gui
                if (par->gshared_constraint) {
                        MonoGSharedGenericParam *gpar = (MonoGSharedGenericParam*)par;
                        encode_type (acfg, par->gshared_constraint, p, &p);
-                       encode_klass_ref (acfg, mono_class_from_generic_parameter (gpar->parent, NULL, klass->byval_arg.type == MONO_TYPE_MVAR), p, &p);
+                       encode_klass_ref (acfg, mono_class_from_generic_parameter_internal (gpar->parent), p, &p);
                } else {
                        encode_value (klass->byval_arg.type, p, &p);
                        encode_value (mono_type_get_generic_param_num (&klass->byval_arg), p, &p);
@@ -3826,7 +3832,7 @@ add_wrappers (MonoAotCompile *acfg)
                gboolean skip = FALSE;
 
                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));
+               report_loader_error (acfg, &error, TRUE, "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) ||
@@ -3972,6 +3978,8 @@ add_wrappers (MonoAotCompile *acfg)
                                add_method (acfg, m);
                        if ((m = mono_gc_get_managed_allocator_by_type (i, MANAGED_ALLOCATOR_SLOW_PATH)))
                                add_method (acfg, m);
+                       if ((m = mono_gc_get_managed_allocator_by_type (i, MANAGED_ALLOCATOR_PROFILER)))
+                               add_method (acfg, m);
                }
 
                /* write barriers */
@@ -4175,7 +4183,7 @@ add_wrappers (MonoAotCompile *acfg)
                MonoError error;
                token = MONO_TOKEN_METHOD_DEF | (i + 1);
                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));
+               report_loader_error (acfg, &error, TRUE, "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) {
@@ -4208,7 +4216,7 @@ add_wrappers (MonoAotCompile *acfg)
                guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
 
                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));
+               report_loader_error (acfg, &error, TRUE, "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)) {
@@ -4232,7 +4240,7 @@ add_wrappers (MonoAotCompile *acfg)
                int j;
 
                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));
+               report_loader_error (acfg, &error, TRUE, "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
@@ -4242,7 +4250,7 @@ add_wrappers (MonoAotCompile *acfg)
                cattr = mono_custom_attrs_from_method_checked (method, &error);
                if (!is_ok (&error)) {
                        char *name = mono_method_get_full_name (method);
-                       report_loader_error (acfg, &error, "Failed to load custom attributes from method %s due to %s\n", name, mono_error_get_message (&error));
+                       report_loader_error (acfg, &error, TRUE, "Failed to load custom attributes from method %s due to %s\n", name, mono_error_get_message (&error));
                        g_free (name);
                }
 
@@ -4327,7 +4335,9 @@ add_wrappers (MonoAotCompile *acfg)
                                        named += slen;
                                }
 
-                               wrapper = mono_marshal_get_managed_wrapper (method, klass, 0);
+                               wrapper = mono_marshal_get_managed_wrapper (method, klass, 0, &error);
+                               mono_error_assert_ok (&error);
+
                                add_method (acfg, wrapper);
                                if (export_name)
                                        g_hash_table_insert (acfg->export_names, wrapper, export_name);
@@ -4419,7 +4429,13 @@ method_has_type_vars (MonoMethod *method)
 static
 gboolean mono_aot_mode_is_full (MonoAotOptions *opts)
 {
-       return opts->mode == MONO_AOT_MODE_FULL;
+       return opts->mode == MONO_AOT_MODE_FULL || opts->mode == MONO_AOT_MODE_INTERP;
+}
+
+static
+gboolean mono_aot_mode_is_interp (MonoAotOptions *opts)
+{
+       return opts->mode == MONO_AOT_MODE_INTERP;
 }
 
 static
@@ -5241,11 +5257,11 @@ compute_line_numbers (MonoMethod *method, int code_size, MonoDebugMethodJitInfo
                if (il_offset == -1 || il_offset == prev_il_offset)
                        continue;
                prev_il_offset = il_offset;
-               loc = mono_debug_symfile_lookup_location (minfo, il_offset);
+               loc = mono_debug_method_lookup_location (minfo, il_offset);
                if (!(loc && loc->source_file))
                        continue;
                if (loc->row == prev_line) {
-                       mono_debug_symfile_free_location (loc);
+                       mono_debug_free_source_location (loc);
                        continue;
                }
                prev_line = loc->row;
@@ -5344,7 +5360,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                options = "";
                        prologue_end = TRUE;
                        fprintf (acfg->fp, ".loc %d %d 0%s\n", findex, loc->row, options);
-                       mono_debug_symfile_free_location (loc);
+                       mono_debug_free_source_location (loc);
                }
 
                skip = FALSE;
@@ -5737,7 +5753,8 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                encode_value (patch_info->data.index, p, &p);
                break;
        case MONO_PATCH_INFO_INTERNAL_METHOD:
-       case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
+       case MONO_PATCH_INFO_JIT_ICALL_ADDR:
+       case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
                guint32 len = strlen (patch_info->data.name);
 
                encode_value (len, p, &p);
@@ -5803,6 +5820,8 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                break;
        case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
                break;
+       case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
+               break;
        case MONO_PATCH_INFO_RGCTX_FETCH:
        case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
                MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry;
@@ -6124,11 +6143,23 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg, gboolean stor
                        clause = &header->clauses [k];
 
                        encode_value (clause->flags, p, &p);
-                       if (clause->data.catch_class) {
-                               encode_value (1, p, &p);
-                               encode_klass_ref (acfg, clause->data.catch_class, p, &p);
-                       } else {
-                               encode_value (0, p, &p);
+                       if (!(clause->flags == MONO_EXCEPTION_CLAUSE_FILTER || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
+                               if (clause->data.catch_class) {
+                                       guint8 *buf2, *p2;
+                                       int len;
+
+                                       buf2 = (guint8 *)g_malloc (4096);
+                                       p2 = buf2;
+                                       encode_klass_ref (acfg, clause->data.catch_class, p2, &p2);
+                                       len = p2 - buf2;
+                                       g_assert (len < 4096);
+                                       encode_value (len, p, &p);
+                                       memcpy (p, buf2, len);
+                                       p += p2 - buf2;
+                                       g_free (buf2);
+                               } else {
+                                       encode_value (0, p, &p);
+                               }
                        }
 
                        /* Emit the IL ranges too, since they might not be available at runtime */
@@ -6710,10 +6741,6 @@ emit_trampolines (MonoAotCompile *acfg)
 #ifdef DISABLE_REMOTING
                        if (tramp_type == MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING)
                                continue;
-#endif
-#ifndef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
-                       if (tramp_type == MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD)
-                               continue;
 #endif
                        mono_arch_create_generic_trampoline ((MonoTrampolineType)tramp_type, &info, acfg->aot_opts.use_trampolines_page? 2: TRUE);
                        emit_trampoline (acfg, acfg->got_offset, info);
@@ -6794,10 +6821,10 @@ emit_trampolines (MonoAotCompile *acfg)
                        }
                }
 
-#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD_AOT
-               mono_arch_create_handler_block_trampoline (&info, TRUE);
-               emit_trampoline (acfg, acfg->got_offset, info);
-#endif
+               if (mono_aot_mode_is_interp (&acfg->aot_opts)) {
+                       mono_arch_get_enter_icall_trampoline (&info);
+                       emit_trampoline (acfg, acfg->got_offset, info);
+               }
 
 #endif /* #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES */
 
@@ -7132,6 +7159,7 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->write_symbols = TRUE;
                } else if (str_begins_with (arg, "no-write-symbols")) {
                        opts->write_symbols = FALSE;
+               // Intentionally undocumented -- one-off experiment
                } else if (str_begins_with (arg, "metadata-only")) {
                        opts->metadata_only = TRUE;
                } else if (str_begins_with (arg, "bind-to-runtime-version")) {
@@ -7140,6 +7168,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->mode = MONO_AOT_MODE_FULL;
                } else if (str_begins_with (arg, "hybrid")) {
                        opts->mode = MONO_AOT_MODE_HYBRID;                      
+               } else if (str_begins_with (arg, "interp")) {
+                       opts->mode = MONO_AOT_MODE_INTERP;
                } else if (str_begins_with (arg, "threads=")) {
                        opts->nthreads = atoi (arg + strlen ("threads="));
                } else if (str_begins_with (arg, "static")) {
@@ -7153,6 +7183,7 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->nodebug = TRUE;
                } else if (str_begins_with (arg, "dwarfdebug")) {
                        opts->dwarf_debug = TRUE;
+               // Intentionally undocumented -- No one remembers what this does. It appears to be ARM-only
                } else if (str_begins_with (arg, "nopagetrampolines")) {
                        opts->use_trampolines_page = FALSE;
                } else if (str_begins_with (arg, "ntrampolines=")) {
@@ -7171,6 +7202,7 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->ld_flags = g_strdup (arg + strlen ("ld-flags="));                 
                } else if (str_begins_with (arg, "soft-debug")) {
                        opts->soft_debug = TRUE;
+               // Intentionally undocumented x2-- deprecated
                } else if (str_begins_with (arg, "gen-seq-points-file=")) {
                        fprintf (stderr, "Mono Warning: aot option gen-seq-points-file= is deprecated.\n");
                } else if (str_begins_with (arg, "gen-seq-points-file")) {
@@ -7189,8 +7221,10 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->print_skipped_methods = TRUE;
                } else if (str_begins_with (arg, "stats")) {
                        opts->stats = TRUE;
+               // Intentionally undocumented-- has no known function other than to debug the compiler
                } else if (str_begins_with (arg, "no-instances")) {
                        opts->no_instances = TRUE;
+               // Intentionally undocumented x4-- Used for internal debugging of compiler
                } else if (str_begins_with (arg, "log-generics")) {
                        opts->log_generics = TRUE;
                } else if (str_begins_with (arg, "log-instances=")) {
@@ -7211,8 +7245,10 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                } else if (str_begins_with (arg, "info")) {
                        printf ("AOT target setup: %s.\n", AOT_TARGET_STR);
                        exit (0);
+               // Intentionally undocumented: Used for precise stack maps, which are not available yet
                } else if (str_begins_with (arg, "gc-maps")) {
                        mini_gc_enable_gc_maps_for_aot ();
+               // Intentionally undocumented: Used for internal debugging
                } else if (str_begins_with (arg, "dump")) {
                        opts->dump_json = TRUE;
                } else if (str_begins_with (arg, "llvmonly")) {
@@ -7222,39 +7258,52 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                } else if (str_begins_with (arg, "data-outfile=")) {
                        opts->data_outfile = g_strdup (arg + strlen ("data-outfile="));
                } else if (str_begins_with (arg, "profile=")) {
-                       opts->profile_file = g_strdup (arg + strlen ("profile="));
+                       opts->profile_files = g_list_append (opts->profile_files, g_strdup (arg + strlen ("profile=")));
+               } else if (!strcmp (arg, "profile-only")) {
+                       opts->profile_only = TRUE;
+               } else if (!strcmp (arg, "verbose")) {
+                       opts->verbose = 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 ("    llvm-path=\n");
-                       printf ("    temp-path=\n");
-                       printf ("    save-temps\n");
-                       printf ("    keep-temps\n");
-                       printf ("    write-symbols\n");
-                       printf ("    metadata-only\n");
+                       printf ("    asmonly\n");
                        printf ("    bind-to-runtime-version\n");
+                       printf ("    bitcode\n");
+                       printf ("    data-outfile=\n");
+                       printf ("    direct-icalls\n");
+                       printf ("    direct-pinvoke\n");
+                       printf ("    dwarfdebug\n");
                        printf ("    full\n");
-                       printf ("    threads=\n");
-                       printf ("    static\n");
-                       printf ("    asmonly\n");
-                       printf ("    asmwriter\n");
+                       printf ("    hybrid\n");
+                       printf ("    info\n");
+                       printf ("    keep-temps\n");
+                       printf ("    llvm\n");
+                       printf ("    llvmonly\n");
+                       printf ("    llvm-outfile=\n");
+                       printf ("    llvm-path=\n");
+                       printf ("    msym-dir=\n");
+                       printf ("    mtriple\n");
+                       printf ("    nimt-trampolines=\n");
                        printf ("    nodebug\n");
-                       printf ("    dwarfdebug\n");
-                       printf ("    ntrampolines=\n");
+                       printf ("    no-direct-calls\n");
+                       printf ("    no-write-symbols\n");
                        printf ("    nrgctx-trampolines=\n");
-                       printf ("    nimt-trampolines=\n");
+                       printf ("    nrgctx-fetch-trampolines=\n");
                        printf ("    ngsharedvt-trampolines=\n");
-                       printf ("    tool-prefix=\n");
+                       printf ("    ntrampolines=\n");
+                       printf ("    outfile=\n");
+                       printf ("    profile=\n");
+                       printf ("    profile-only\n");
+                       printf ("    print-skipped-methods\n");
                        printf ("    readonly-value=\n");
+                       printf ("    save-temps\n");
                        printf ("    soft-debug\n");
-                       printf ("    msym-dir=\n");
-                       printf ("    gc-maps\n");
-                       printf ("    print-skipped\n");
-                       printf ("    no-instances\n");
+                       printf ("    static\n");
                        printf ("    stats\n");
-                       printf ("    dump\n");
-                       printf ("    info\n");
+                       printf ("    temp-path=\n");
+                       printf ("    tool-prefix=\n");
+                       printf ("    threads=\n");
+                       printf ("    write-symbols\n");
+                       printf ("    verbose\n");
                        printf ("    help/?\n");
                        exit (0);
                } else {
@@ -7544,6 +7593,9 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
        if (method->wrapper_type == MONO_WRAPPER_COMINTEROP)
                return;
 
+       if (acfg->aot_opts.profile_only && !method->is_inflated && !g_hash_table_lookup (acfg->profile_methods, method))
+               return;
+
        InterlockedIncrement (&acfg->stats.mcount);
 
 #if 0
@@ -7584,8 +7636,9 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                return;
        }
        if (cfg->exception_type != MONO_EXCEPTION_NONE) {
-               if (acfg->aot_opts.print_skipped_methods)
-                       printf ("Skip (JIT failure): %s\n", mono_method_get_full_name (method));
+               /* Some instances cannot be JITted due to constraints etc. */
+               if (!method->is_inflated)
+                       report_loader_error (acfg, &cfg->error, FALSE, "Unable to compile method '%s' due to: '%s'.\n", mono_method_get_full_name (method), mono_error_get_message (&cfg->error));
                /* Let the exception happen at runtime */
                return;
        }
@@ -7864,6 +7917,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
 
        g_hash_table_insert (acfg->method_to_cfg, cfg->orig_method, cfg);
 
+       /* Update global stats while holding a lock. */
        mono_update_jit_stats (cfg);
 
        /*
@@ -7879,14 +7933,15 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
 static mono_thread_start_return_t WINAPI
 compile_thread_main (gpointer user_data)
 {
-       MonoDomain *domain = ((MonoDomain **)user_data) [0];
-       MonoAotCompile *acfg = ((MonoAotCompile **)user_data) [1];
-       GPtrArray *methods = ((GPtrArray **)user_data) [2];
+       MonoAotCompile *acfg = ((MonoAotCompile **)user_data) [0];
+       GPtrArray *methods = ((GPtrArray **)user_data) [1];
        int i;
 
        MonoError error;
-       MonoThread *thread = mono_thread_attach (domain);
-       mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "AOT compiler"), TRUE, &error);
+       MonoInternalThread *internal = mono_thread_internal_current ();
+       MonoString *str = mono_string_new_checked (mono_domain_get (), "AOT compiler", &error);
+       mono_error_assert_ok (&error);
+       mono_thread_set_name_internal (internal, str, TRUE, FALSE, &error);
        mono_error_assert_ok (&error);
 
        for (i = 0; i < methods->len; ++i)
@@ -8047,48 +8102,452 @@ append_mangled_signature (GString *s, MonoMethodSignature *sig)
        return TRUE;
 }
 
-/*
- * mono_aot_get_mangled_method_name:
- *
- *   Return a unique mangled name for METHOD, or NULL.
- */
-char*
-mono_aot_get_mangled_method_name (MonoMethod *method)
+static void
+append_mangled_wrapper_type (GString *s, guint32 wrapper_type) 
 {
-       WrapperInfo *info;
-       GString *s;
-       gboolean supported;
+       const char *label;
 
-       // FIXME: Add more cases
-       if (method->wrapper_type != MONO_WRAPPER_UNKNOWN)
-               return NULL;
-       info = mono_marshal_get_wrapper_info (method);
-       if (!(info && (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG)))
-               return NULL;
+       switch (wrapper_type) {
+       case MONO_WRAPPER_REMOTING_INVOKE:
+               label = "remoting_invoke";
+               break;
+       case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
+               label = "remoting_invoke_check";
+               break;
+       case MONO_WRAPPER_XDOMAIN_INVOKE:
+               label = "remoting_invoke_xdomain";
+               break;
+       case MONO_WRAPPER_PROXY_ISINST:
+               label = "proxy_isinst";
+               break;
+       case MONO_WRAPPER_LDFLD:
+               label = "ldfld";
+               break;
+       case MONO_WRAPPER_LDFLDA:
+               label = "ldflda";
+               break;
+       case MONO_WRAPPER_STFLD: 
+               label = "stfld";
+               break;
+       case MONO_WRAPPER_ALLOC:
+               label = "alloc";
+               break;
+       case MONO_WRAPPER_WRITE_BARRIER:
+               label = "write_barrier";
+               break;
+       case MONO_WRAPPER_STELEMREF:
+               label = "stelemref";
+               break;
+       case MONO_WRAPPER_UNKNOWN:
+               label = "unknown";
+               break;
+       case MONO_WRAPPER_MANAGED_TO_NATIVE:
+               label = "man2native";
+               break;
+       case MONO_WRAPPER_SYNCHRONIZED:
+               label = "synch";
+               break;
+       case MONO_WRAPPER_MANAGED_TO_MANAGED:
+               label = "man2man";
+               break;
+       case MONO_WRAPPER_CASTCLASS:
+               label = "castclass";
+               break;
+       case MONO_WRAPPER_RUNTIME_INVOKE:
+               label = "run_invoke";
+               break;
+       case MONO_WRAPPER_DELEGATE_INVOKE:
+               label = "del_inv";
+               break;
+       case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
+               label = "del_beg_inv";
+               break;
+       case MONO_WRAPPER_DELEGATE_END_INVOKE:
+               label = "del_end_inv";
+               break;
+       case MONO_WRAPPER_NATIVE_TO_MANAGED:
+               label = "native2man";
+               break;
+       default:
+               g_assert_not_reached ();
+       }
 
-       s = g_string_new ("");
+       g_string_append_printf (s, "%s_", label);
+}
 
-       g_string_append_printf (s, "aot_method_w_");
+static void
+append_mangled_wrapper_subtype (GString *s, WrapperSubtype subtype) 
+{
+       const char *label;
 
-       switch (info->subtype) {
+       switch (subtype) 
+       {
+       case WRAPPER_SUBTYPE_NONE:
+               return;
+       case WRAPPER_SUBTYPE_ELEMENT_ADDR:
+               label = "elem_addr";
+               break;
+       case WRAPPER_SUBTYPE_STRING_CTOR:
+               label = "str_ctor";
+               break;
+       case WRAPPER_SUBTYPE_VIRTUAL_STELEMREF:
+               label = "virt_stelem";
+               break;
+       case WRAPPER_SUBTYPE_FAST_MONITOR_ENTER:
+               label = "fast_mon_enter";
+               break;
+       case WRAPPER_SUBTYPE_FAST_MONITOR_ENTER_V4:
+               label = "fast_mon_enter_4";
+               break;
+       case WRAPPER_SUBTYPE_FAST_MONITOR_EXIT:
+               label = "fast_monitor_exit";
+               break;
+       case WRAPPER_SUBTYPE_PTR_TO_STRUCTURE:
+               label = "ptr2struct";
+               break;
+       case WRAPPER_SUBTYPE_STRUCTURE_TO_PTR:
+               label = "struct2ptr";
+               break;
+       case WRAPPER_SUBTYPE_CASTCLASS_WITH_CACHE:
+               label = "castclass_w_cache";
+               break;
+       case WRAPPER_SUBTYPE_ISINST_WITH_CACHE:
+               label = "isinst_w_cache";
+               break;
+       case WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL:
+               label = "run_inv_norm";
+               break;
+       case WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC:
+               label = "run_inv_dyn";
+               break;
+       case WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT:
+               label = "run_inv_dir";
+               break;
+       case WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL:
+               label = "run_inv_vir";
+               break;
+       case WRAPPER_SUBTYPE_ICALL_WRAPPER:
+               label = "icall";
+               break;
+       case WRAPPER_SUBTYPE_NATIVE_FUNC_AOT:
+               label = "native_func_aot";
+               break;
+       case WRAPPER_SUBTYPE_PINVOKE:
+               label = "pinvoke";
+               break;
+       case WRAPPER_SUBTYPE_SYNCHRONIZED_INNER:
+               label = "synch_inner";
+               break;
+       case WRAPPER_SUBTYPE_GSHAREDVT_IN:
+               label = "gshared_in";
+               break;
+       case WRAPPER_SUBTYPE_GSHAREDVT_OUT:
+               label = "gshared_out";
+               break;
+       case WRAPPER_SUBTYPE_ARRAY_ACCESSOR:
+               label = "array_acc";
+               break;
+       case WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER:
+               label = "generic_arry_help";
+               break;
+       case WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL:
+               label = "del_inv_virt";
+               break;
+       case WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND:
+               label = "del_inv_bound";
+               break;
        case WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG:
-               g_string_append_printf (s, "gsharedvt_in_");
+               label = "gsharedvt_in_sig";
                break;
        case WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG:
-               g_string_append_printf (s, "gsharedvt_out_");
+               label = "gsharedvt_out_sig";
                break;
        default:
                g_assert_not_reached ();
+       }
+
+       g_string_append_printf (s, "%s_", label);
+}
+
+static char *
+sanitize_mangled_string (const char *input)
+{
+       GString *s = g_string_new ("");
+
+       for (int i=0; input [i] != '\0'; i++) {
+               char c = input [i];
+               switch (c) {
+               case '.':
+                       g_string_append (s, "_dot_");
+                       break;
+               case ' ':
+                       g_string_append (s, "_");
+                       break;
+               case '`':
+                       g_string_append (s, "_bt_");
+                       break;
+               case '<':
+                       g_string_append (s, "_le_");
+                       break;
+               case '>':
+                       g_string_append (s, "_gt_");
+                       break;
+               case '/':
+                       g_string_append (s, "_sl_");
+                       break;
+               case '[':
+                       g_string_append (s, "_lbrack_");
+                       break;
+               case ']':
+                       g_string_append (s, "_rbrack_");
+                       break;
+               case '(':
+                       g_string_append (s, "_lparen_");
+                       break;
+               case '-':
+                       g_string_append (s, "_dash_");
+                       break;
+               case ')':
+                       g_string_append (s, "_rparen_");
+                       break;
+               case ',':
+                       g_string_append (s, "_comma_");
+                       break;
+               default:
+                       g_string_append_c (s, c);
+               }
+       }
+
+       return g_string_free (s, FALSE);
+}
+
+static gboolean
+append_mangled_klass (GString *s, MonoClass *klass)
+{
+       char *klass_desc = mono_class_full_name (klass);
+       g_string_append_printf (s, "_%s_%s_", klass->name_space, klass_desc);
+       g_free (klass_desc);
+
+       // Success
+       return TRUE;
+}
+
+static gboolean
+append_mangled_method (GString *s, MonoMethod *method);
+
+static gboolean
+append_mangled_wrapper (GString *s, MonoMethod *method) 
+{
+       gboolean success = TRUE;
+       WrapperInfo *info = mono_marshal_get_wrapper_info (method);
+       g_string_append_printf (s, "wrapper_");
+
+       append_mangled_wrapper_type (s, method->wrapper_type);
+
+       switch (method->wrapper_type) {
+       case MONO_WRAPPER_REMOTING_INVOKE:
+       case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
+       case MONO_WRAPPER_XDOMAIN_INVOKE: {
+               MonoMethod *m = mono_marshal_method_from_wrapper (method);
+               g_assert (m);
+               success = success && append_mangled_method (s, m);
+               break;
+       }
+       case MONO_WRAPPER_PROXY_ISINST:
+       case MONO_WRAPPER_LDFLD:
+       case MONO_WRAPPER_LDFLDA:
+       case MONO_WRAPPER_STFLD: {
+               g_assert (info);
+               success = success && append_mangled_klass (s, info->d.proxy.klass);
+               break;
+       }
+       case MONO_WRAPPER_ALLOC: {
+               /* The GC name is saved once in MonoAotFileInfo */
+               g_assert (info->d.alloc.alloc_type != -1);
+               g_string_append_printf (s, "%d_", info->d.alloc.alloc_type);
+               // SlowAlloc, etc
+               g_string_append_printf (s, "%s_", method->name);
+               break;
+       }
+       case MONO_WRAPPER_WRITE_BARRIER: {
+               break;
+       }
+       case MONO_WRAPPER_STELEMREF: {
+               append_mangled_wrapper_subtype (s, info->subtype);
+               if (info->subtype == WRAPPER_SUBTYPE_VIRTUAL_STELEMREF)
+                       g_string_append_printf (s, "%d", info->d.virtual_stelemref.kind);
+               break;
+       }
+       case MONO_WRAPPER_UNKNOWN: {
+               append_mangled_wrapper_subtype (s, info->subtype);
+               if (info->subtype == WRAPPER_SUBTYPE_PTR_TO_STRUCTURE ||
+                       info->subtype == WRAPPER_SUBTYPE_STRUCTURE_TO_PTR)
+                       success = success && append_mangled_klass (s, method->klass);
+               else if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER)
+                       success = success && append_mangled_method (s, info->d.synchronized_inner.method);
+               else if (info->subtype == WRAPPER_SUBTYPE_ARRAY_ACCESSOR)
+                       success = success && append_mangled_method (s, info->d.array_accessor.method);
+               else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG)
+                       append_mangled_signature (s, info->d.gsharedvt.sig);
+               else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG)
+                       append_mangled_signature (s, info->d.gsharedvt.sig);
+               break;
+       }
+       case MONO_WRAPPER_MANAGED_TO_NATIVE: {
+               append_mangled_wrapper_subtype (s, info->subtype);
+               if (info->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
+                       g_string_append_printf (s, "%s", method->name);
+               } else if (info->subtype == WRAPPER_SUBTYPE_NATIVE_FUNC_AOT) {
+                       success = success && append_mangled_method (s, info->d.managed_to_native.method);
+               } else {
+                       g_assert (info->subtype == WRAPPER_SUBTYPE_NONE || info->subtype == WRAPPER_SUBTYPE_PINVOKE);
+                       success = success && append_mangled_method (s, info->d.managed_to_native.method);
+               }
+               break;
+       }
+       case MONO_WRAPPER_SYNCHRONIZED: {
+               MonoMethod *m;
+
+               m = mono_marshal_method_from_wrapper (method);
+               g_assert (m);
+               g_assert (m != method);
+               success = success && append_mangled_method (s, m);
+               break;
+       }
+       case MONO_WRAPPER_MANAGED_TO_MANAGED: {
+               append_mangled_wrapper_subtype (s, info->subtype);
+
+               if (info->subtype == WRAPPER_SUBTYPE_ELEMENT_ADDR) {
+                       g_string_append_printf (s, "%d_", info->d.element_addr.rank);
+                       g_string_append_printf (s, "%d_", info->d.element_addr.elem_size);
+               } else if (info->subtype == WRAPPER_SUBTYPE_STRING_CTOR) {
+                       success = success && append_mangled_method (s, info->d.string_ctor.method);
+               } else {
+                       g_assert_not_reached ();
+               }
+               break;
+       }
+       case MONO_WRAPPER_CASTCLASS: {
+               append_mangled_wrapper_subtype (s, info->subtype);
                break;
        }
+       case MONO_WRAPPER_RUNTIME_INVOKE: {
+               append_mangled_wrapper_subtype (s, info->subtype);
+               if (info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT || info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL)
+                       success = success && append_mangled_method (s, info->d.runtime_invoke.method);
+               else if (info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL)
+                       success = success && append_mangled_signature (s, info->d.runtime_invoke.sig);
+               break;
+       }
+       case MONO_WRAPPER_DELEGATE_INVOKE:
+       case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
+       case MONO_WRAPPER_DELEGATE_END_INVOKE: {
+               if (method->is_inflated) {
+                       /* These wrappers are identified by their class */
+                       g_string_append_printf (s, "i_");
+                       success = success && append_mangled_klass (s, method->klass);
+               } else {
+                       WrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+                       g_string_append_printf (s, "u_");
+                       if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE)
+                               append_mangled_wrapper_subtype (s, info->subtype);
+                       g_string_append_printf (s, "u_sigstart");
+               }
+               break;
+       }
+       case MONO_WRAPPER_NATIVE_TO_MANAGED: {
+               g_assert (info);
+               success = success && append_mangled_method (s, info->d.native_to_managed.method);
+               success = success && append_mangled_klass (s, method->klass);
+               break;
+       }
+       default:
+               g_assert_not_reached ();
+       }
+       return success && append_mangled_signature (s, mono_method_signature (method));
+}
+
+static void
+append_mangled_context (GString *str, MonoGenericContext *context)
+{
+       GString *res = g_string_new ("");
+
+       g_string_append_printf (res, "gens_");
+       g_string_append (res, "00");
+
+       gboolean good = context->class_inst && context->class_inst->type_argc > 0;
+       good = good || (context->method_inst && context->method_inst->type_argc > 0);
+       g_assert (good);
 
-       supported = append_mangled_signature (s, info->d.gsharedvt.sig);
-       if (!supported) {
+       if (context->class_inst)
+               mono_ginst_get_desc (res, context->class_inst);
+       if (context->method_inst) {
+               if (context->class_inst)
+                       g_string_append (res, "11");
+               mono_ginst_get_desc (res, context->method_inst);
+       }
+       g_string_append_printf (str, "gens_%s", res->str);
+}      
+
+static gboolean
+append_mangled_method (GString *s, MonoMethod *method)
+{
+       if (method->wrapper_type)
+               return append_mangled_wrapper (s, method);
+
+       g_string_append_printf (s, "%s_", method->klass->image->assembly->aname.name);
+
+       if (method->is_inflated) {
+               g_string_append_printf (s, "inflated_");
+               MonoMethodInflated *imethod = (MonoMethodInflated*) method;
+               g_assert (imethod->context.class_inst != NULL || imethod->context.method_inst != NULL);
+
+               append_mangled_context (s, &imethod->context);
+               g_string_append_printf (s, "_declared_by_");
+               append_mangled_method (s, imethod->declaring);
+       } else if (method->is_generic) {
+               g_string_append_printf (s, "generic_");
+               append_mangled_klass (s, method->klass);
+               g_string_append_printf (s, "_%s_", method->name);
+
+               MonoGenericContainer *container = mono_method_get_generic_container (method);
+               g_string_append_printf (s, "_%s");
+               append_mangled_context (s, &container->context);
+
+               return append_mangled_signature (s, mono_method_signature (method));
+       } else {
+               g_string_append_printf (s, "_");
+               append_mangled_klass (s, method->klass);
+               g_string_append_printf (s, "_%s_", method->name);
+               if (!append_mangled_signature (s, mono_method_signature (method))) {
+                       g_string_free (s, TRUE);
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+/*
+ * mono_aot_get_mangled_method_name:
+ *
+ *   Return a unique mangled name for METHOD, or NULL.
+ */
+char*
+mono_aot_get_mangled_method_name (MonoMethod *method)
+{
+       GString *s = g_string_new ("aot_");
+       if (!append_mangled_method (s, method)) {
                g_string_free (s, TRUE);
                return NULL;
+       } else {
+               char *out = g_string_free (s, FALSE);
+               // Scrub method and class names
+               char *cleaned = sanitize_mangled_string (out);
+               g_free (out);
+               return cleaned;
        }
-
-       return g_string_free (s, FALSE);
 }
 
 gboolean
@@ -8188,7 +8647,7 @@ execute_system (const char * command)
 {
        int status = 0;
 
-#if HOST_WIN32
+#if defined(HOST_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.
        char * quoted_command = g_strdup_printf ("\"%s\"", command);
@@ -8305,7 +8764,7 @@ emit_llvm_file (MonoAotCompile *acfg)
        g_string_append_printf (acfg->llc_args, " -disable-tail-calls");
 #endif
 
-#if defined(TARGET_MACH) && defined(TARGET_ARM)
+#if ( defined(TARGET_MACH) && defined(TARGET_ARM) ) || defined(TARGET_ORBIS)
        /* ios requires PIC code now */
        g_string_append_printf (acfg->llc_args, " -relocation-model=pic");
 #else
@@ -9809,7 +10268,7 @@ collect_methods (MonoAotCompile *acfg)
                        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));
+               report_loader_error (acfg, &error, TRUE, "Failed to load method token 0x%x due to %s\n", i, mono_error_get_message (&error));
 
                if (method->is_generic || mono_class_is_gtd (method->klass)) {
                        MonoMethod *gshared;
@@ -9856,6 +10315,9 @@ compile_methods (MonoAotCompile *acfg)
                        methods [i] = (MonoMethod *)g_ptr_array_index (acfg->methods, i);
                i = 0;
                while (i < methods_len) {
+                       MonoError error;
+                       MonoInternalThread *thread;
+
                        frag = g_ptr_array_new ();
                        for (j = 0; j < len; ++j) {
                                if (i < methods_len) {
@@ -9865,11 +10327,13 @@ compile_methods (MonoAotCompile *acfg)
                        }
 
                        user_data = g_new0 (gpointer, 3);
-                       user_data [0] = mono_domain_get ();
-                       user_data [1] = acfg;
-                       user_data [2] = frag;
+                       user_data [0] = acfg;
+                       user_data [1] = frag;
                        
-                       thread_handle = mono_threads_create_thread (compile_thread_main, (gpointer) user_data, NULL, NULL);
+                       thread = mono_thread_create_internal (mono_domain_get (), compile_thread_main, (gpointer) user_data, MONO_THREAD_CREATE_FLAGS_NONE, &error);
+                       mono_error_assert_ok (&error);
+
+                       thread_handle = mono_threads_open_thread_handle (thread->handle);
                        g_ptr_array_add (threads, thread_handle);
                }
                g_free (methods);
@@ -9905,19 +10369,13 @@ compile_asm (MonoAotCompile *acfg)
 #define AS_OPTIONS "-a64 -mppc64"
 #elif defined(sparc) && SIZEOF_VOID_P == 8
 #define AS_OPTIONS "-xarch=v9"
-#elif defined(TARGET_X86) && defined(TARGET_MACH) && !defined(__native_client_codegen__)
+#elif defined(TARGET_X86) && defined(TARGET_MACH)
 #define AS_OPTIONS "-arch i386"
 #else
 #define AS_OPTIONS ""
 #endif
 
-#ifdef __native_client_codegen__
-#if defined(TARGET_AMD64)
-#define AS_NAME "nacl64-as"
-#else
-#define AS_NAME "nacl-as"
-#endif
-#elif defined(TARGET_OSX)
+#if defined(TARGET_OSX)
 #define AS_NAME "clang"
 #elif defined(TARGET_WIN32_MSVC)
 #define AS_NAME "clang.exe"
@@ -9946,7 +10404,7 @@ compile_asm (MonoAotCompile *acfg)
 #elif defined(TARGET_WIN32) && !defined(TARGET_ANDROID)
 #define LD_NAME "gcc"
 #define LD_OPTIONS "-shared"
-#elif defined(TARGET_X86) && defined(TARGET_MACH) && !defined(__native_client_codegen__)
+#elif defined(TARGET_X86) && defined(TARGET_MACH)
 #define LD_NAME "clang"
 #define LD_OPTIONS "-m32 -dynamiclib"
 #elif defined(TARGET_ARM) && !defined(TARGET_ANDROID)
@@ -10314,7 +10772,8 @@ load_profile_file (MonoAotCompile *acfg, char *filename)
                }
        }
 
-       acfg->profile_data = data;
+       fclose (infile);
+       acfg->profile_data = g_list_append (acfg->profile_data, data);
 }
 
 static void
@@ -10372,9 +10831,8 @@ resolve_class (ClassProfileData *cdata)
  * Resolve the profile data to the corresponding loaded classes/methods etc. if possible.
  */
 static void
-resolve_profile_data (MonoAotCompile *acfg)
+resolve_profile_data (MonoAotCompile *acfg, ProfileData *data)
 {
-       ProfileData *data = acfg->profile_data;
        GHashTableIter iter;
        gpointer key, value;
        int i;
@@ -10404,8 +10862,11 @@ resolve_profile_data (MonoAotCompile *acfg)
        while (g_hash_table_iter_next (&iter, &key, &value)) {
                ClassProfileData *cdata = (ClassProfileData*)value;
 
-               if (!cdata->image->image)
+               if (!cdata->image->image) {
+                       if (acfg->aot_opts.verbose)
+                               printf ("Unable to load class '%s.%s' because its image '%s' is not loaded.\n", cdata->ns, cdata->name, cdata->image->name);
                        continue;
+               }
 
                resolve_class (cdata);
                /*
@@ -10424,8 +10885,11 @@ resolve_profile_data (MonoAotCompile *acfg)
 
                resolve_class (mdata->klass);
                klass = mdata->klass->klass;
-               if (!klass)
+               if (!klass) {
+                       if (acfg->aot_opts.verbose)
+                               printf ("Unable to load method '%s' because its class '%s.%s' is not loaded.\n", mdata->name, mdata->klass->ns, mdata->klass->name);
                        continue;
+               }
                miter = NULL;
                while ((m = mono_class_get_methods (klass, &miter))) {
                        MonoError error;
@@ -10459,11 +10923,16 @@ resolve_profile_data (MonoAotCompile *acfg)
                        gboolean match = !strcmp (sig_str, mdata->signature);
                        g_free (sig_str);
                        if (!match)
+
                                continue;
                        //printf ("%s\n", mono_method_full_name (m, 1));
                        mdata->method = m;
                        break;
                }
+               if (!mdata->method) {
+                       if (acfg->aot_opts.verbose)
+                               printf ("Unable to load method '%s' from class '%s', not found.\n", mdata->name, mono_class_full_name (klass));
+               }
        }
 }
 
@@ -10499,9 +10968,8 @@ is_local_inst (MonoGenericInst *inst, MonoImage *image)
 }
 
 static void
-add_profile_instances (MonoAotCompile *acfg)
+add_profile_instances (MonoAotCompile *acfg, ProfileData *data)
 {
-       ProfileData *data = acfg->profile_data;
        GHashTableIter iter;
        gpointer key, value;
        int count = 0;
@@ -10509,6 +10977,23 @@ add_profile_instances (MonoAotCompile *acfg)
        if (!data)
                return;
 
+       if (acfg->aot_opts.profile_only) {
+               /* Add methods referenced by the profile */
+               g_hash_table_iter_init (&iter, data->methods);
+               while (g_hash_table_iter_next (&iter, &key, &value)) {
+                       MethodProfileData *mdata = (MethodProfileData*)value;
+                       MonoMethod *m = mdata->method;
+
+                       if (!m)
+                               continue;
+                       if (m->is_inflated)
+                               continue;
+                       add_extra_method (acfg, m);
+                       g_hash_table_insert (acfg->profile_methods, m, m);
+                       count ++;
+               }
+       }
+
        /*
         * Add method instances 'related' to this assembly to the AOT image.
         */
@@ -10596,6 +11081,7 @@ acfg_create (MonoAssembly *ass, guint32 opts)
        acfg->plt_entry_debug_sym_cache = g_hash_table_new (g_str_hash, g_str_equal);
        acfg->gsharedvt_in_signatures = g_hash_table_new ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal);
        acfg->gsharedvt_out_signatures = g_hash_table_new ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal);
+       acfg->profile_methods = g_hash_table_new (NULL, NULL);
        mono_os_mutex_init_recursive (&acfg->mutex);
 
        init_got_info (&acfg->got_info);
@@ -10884,6 +11370,13 @@ add_preinit_got_slots (MonoAotCompile *acfg)
        get_got_offset (acfg, FALSE, ji);
        get_got_offset (acfg, TRUE, ji);
 
+       /* Called by native-to-managed wrappers on possibly unattached threads */
+       ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
+       ji->type = MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL;
+       ji->data.name = "mono_threads_attach_coop";
+       get_got_offset (acfg, FALSE, ji);
+       get_got_offset (acfg, TRUE, ji);
+
        for (i = 0; i < sizeof (preinited_jit_icalls) / sizeof (char*); ++i) {
                ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
                ji->type = MONO_PATCH_INFO_INTERNAL_METHOD;
@@ -11017,8 +11510,10 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                }
        }
 
-       if (mono_aot_mode_is_full (&acfg->aot_opts))
+       if (mono_aot_mode_is_full (&acfg->aot_opts)) {
                acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_FULL_AOT);
+               acfg->is_full_aot = TRUE;
+       }
 
        if (mono_threads_is_coop_enabled ())
                acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_SAFEPOINTS);
@@ -11031,10 +11526,15 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                }
        }
 
-       if (acfg->aot_opts.profile_file)
-               load_profile_file (acfg, acfg->aot_opts.profile_file);
+       if (acfg->aot_opts.profile_files) {
+               GList *l;
 
-       {
+               for (l = acfg->aot_opts.profile_files; l; l = l->next) {
+                       load_profile_file (acfg, (char*)l->data);
+               }
+       }
+
+       if (!mono_aot_mode_is_interp (&acfg->aot_opts)) {
                int method_index;
 
        for (method_index = 0; method_index < acfg->image->tables [MONO_TABLE_METHOD].rows; ++method_index) {
@@ -11097,13 +11597,21 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        if (mono_aot_mode_is_full (&acfg->aot_opts) || mono_aot_mode_is_hybrid (&acfg->aot_opts))
                mono_set_partial_sharing_supported (TRUE);
 
-       res = collect_methods (acfg);
-       if (!res)
-               return 1;
+       if (!mono_aot_mode_is_interp (&acfg->aot_opts)) {
+               res = collect_methods (acfg);
 
-       resolve_profile_data (acfg);
+               if (!res)
+                       return 1;
+       }
+
+       {
+               GList *l;
 
-       add_profile_instances (acfg);
+               for (l = acfg->profile_data; l; l = l->next)
+                       resolve_profile_data (acfg, (ProfileData*)l->data);
+               for (l = acfg->profile_data; l; l = l->next)
+                       add_profile_instances (acfg, (ProfileData*)l->data);
+       }
 
        acfg->cfgs_size = acfg->methods->len + 32;
        acfg->cfgs = g_new0 (MonoCompile*, acfg->cfgs_size);
@@ -11115,10 +11623,30 @@ 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->image->assembly, acfg->global_prefix, TRUE, acfg->aot_opts.static_link, acfg->aot_opts.llvm_only);
+               mono_llvm_create_aot_module (acfg->image->assembly, acfg->global_prefix, acfg->nshared_got_entries, TRUE, acfg->aot_opts.static_link, acfg->aot_opts.llvm_only);
        }
 #endif
 
+       if (mono_aot_mode_is_interp (&acfg->aot_opts)) {
+               MonoMethod *wrapper;
+               MonoMethodSignature *sig;
+
+               /* object object:interp_in_static (object,intptr,intptr,intptr) */
+               sig = mono_create_icall_signature ("object object ptr ptr ptr");
+               wrapper = mini_get_interp_in_wrapper (sig);
+               add_method (acfg, wrapper);
+
+               /* int object:interp_in_static (intptr,int,intptr) */
+               sig = mono_create_icall_signature ("int32 ptr int32 ptr");
+               wrapper = mini_get_interp_in_wrapper (sig);
+               add_method (acfg, wrapper);
+
+               /* void object:interp_in_static (object,intptr,intptr,intptr) */
+               sig = mono_create_icall_signature ("void object ptr ptr ptr");
+               wrapper = mini_get_interp_in_wrapper (sig);
+               add_method (acfg, wrapper);
+       }
+
        TV_GETTIME (atv);
 
        compile_methods (acfg);
@@ -11164,8 +11692,14 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        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+");
+               if (strcmp (acfg->aot_opts.temp_path, "") == 0) {
+                       int i = g_file_open_tmp ("mono_aot_XXXXXX", &acfg->tmpfname, NULL);
+                       acfg->fp = fdopen (i, "w+");
+               } else {
+                       acfg->tmpbasename = g_build_filename (acfg->aot_opts.temp_path, "temp", NULL);
+                       acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
+                       acfg->fp = fopen (acfg->tmpfname, "w+");
+               }
        }
        if (acfg->fp == 0 && !acfg->aot_opts.llvm_only) {
                aot_printerrf (acfg, "Unable to open file '%s': %s\n", acfg->tmpfname, strerror (errno));