X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Faot-compiler.c;h=236bdd2d7b68cb82f057ff2f67e74417275ecb85;hb=9302c31f81abd2f5bbf9a8ddd27993e1ece55db2;hp=59a123ed0573475ceb7e0551c9ee6c1b7171bbfb;hpb=c078f357c6b4122d1993eeddaadc58f925417d5e;p=mono.git diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index 59a123ed057..236bdd2d7b6 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) @@ -297,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; @@ -437,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) { + fprintf (output, "FullAOT cannot continue if there are loader errors.\n"); + exit (1); + } } /* Wrappers around the image writer functions */ @@ -7137,6 +7142,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")) { @@ -7158,6 +7164,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=")) { @@ -7176,6 +7183,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")) { @@ -7194,8 +7202,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=")) { @@ -7216,8 +7226,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")) { @@ -7234,36 +7246,44 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) 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); @@ -7597,11 +7617,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)); - if (cfg->exception_message) - printf ("Caused by: %s\n", cfg->exception_message); - } + /* Some instances cannot be JITted due to constraints etc. */ + if (!method->is_inflated) + report_loader_error (acfg, &cfg->error, "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; } @@ -8062,48 +8080,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); + + 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; + } + } - supported = append_mangled_signature (s, info->d.gsharedvt.sig); - if (!supported) { + 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 @@ -11065,8 +11487,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);