X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Faot-compiler.c;h=5bfa4d0920387d4bcbaf388a254e24f328622407;hb=caa9ed689f20ab27f43ed988848fca7f7834b6b0;hp=b91dfaedb245b11461172e3fae477c04cbee5ee8;hpb=2ba6bcbc48f8b4e145f9ad450fef8d411b728a8e;p=mono.git diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index b91dfaedb24..5bfa4d09203 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -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 #include #include -#include -#include +#include +#include #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));