X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini.c;h=dd2e12aa9512080c4494af31cf29b4c537535ce4;hb=bfc76bafbf72f8e10c4d2cc7b12e779715c527fa;hp=5b42ca510f34ffa07def506ffdb86ffff3612339;hpb=4adc1028a529e790f028ecf1c806975622bf3255;p=mono.git diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 5b42ca510f3..dd2e12aa951 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -1,5 +1,6 @@ -/* - * mini.c: The new Mono code generator. +/** + * \file + * The new Mono code generator. * * Authors: * Paolo Molaro (lupus@ximian.com) @@ -35,7 +36,6 @@ #include #include #include -#include "mono/metadata/profiler.h" #include #include #include @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,7 @@ #include #include #include -#include +#include #include "mini.h" #include "seq-points.h" @@ -76,8 +77,9 @@ #include "debugger-agent.h" #include "llvm-runtime.h" #include "mini-llvm.h" +#include "lldb.h" -MonoTraceSpec *mono_jit_trace_calls; +MonoCallSpec *mono_jit_trace_calls; MonoMethodDesc *mono_inject_async_exc_method; int mono_inject_async_exc_pos; MonoMethodDesc *mono_break_at_bb_method; @@ -85,6 +87,10 @@ int mono_break_at_bb_bb_num; gboolean mono_do_x86_stack_align = TRUE; gboolean mono_using_xdebug; +/* Counters */ +static guint32 discarded_code; +static double discarded_jit_time; + #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex) #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex) static mono_mutex_t jit_mutex; @@ -140,12 +146,6 @@ mono_emit_unwind_op (MonoCompile *cfg, int when, int tag, int reg, int val) } } -#define MONO_INIT_VARINFO(vi,id) do { \ - (vi)->range.first_use.pos.bid = 0xffff; \ - (vi)->reg = -1; \ - (vi)->idx = (id); \ -} while (0) - /** * mono_unlink_bblock: * @@ -365,6 +365,8 @@ handle_enum: case MONO_TYPE_TYPEDBYREF: return OP_STOREV_MEMBASE; case MONO_TYPE_GENERICINST: + if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type))) + return OP_STOREX_MEMBASE; type = &type->data.generic_class->container_class->byval_arg; goto handle_enum; case MONO_TYPE_VAR: @@ -419,6 +421,8 @@ mono_type_to_load_membase (MonoCompile *cfg, MonoType *type) case MONO_TYPE_TYPEDBYREF: return OP_LOADV_MEMBASE; case MONO_TYPE_GENERICINST: + if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type))) + return OP_LOADX_MEMBASE; if (mono_type_generic_inst_is_valuetype (type)) return OP_LOADV_MEMBASE; else @@ -671,8 +675,10 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, cfg->varinfo [num] = inst; - MONO_INIT_VARINFO (&cfg->vars [num], num); - MONO_VARINFO (cfg, num)->vreg = vreg; + cfg->vars [num].idx = num; + cfg->vars [num].vreg = vreg; + cfg->vars [num].range.first_use.pos.bid = 0xffff; + cfg->vars [num].reg = -1; if (vreg != -1) set_vreg_to_inst (cfg, vreg, inst); @@ -1375,9 +1381,8 @@ mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_ printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE)); if (count > atoi (g_getenv ("COUNT3"))) slot = 0xffffff; - else { + else mono_print_ins (inst); - } } #endif @@ -1609,20 +1614,19 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s } } +#if 0 { static int count = 0; count ++; - /* if (count == atoi (g_getenv ("COUNT"))) printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE)); if (count > atoi (g_getenv ("COUNT"))) slot = 0xffffff; - else { + else mono_print_ins (inst); - } - */ } +#endif if (inst->flags & MONO_INST_LMF) { /* @@ -1948,104 +1952,6 @@ mono_destroy_compile (MonoCompile *cfg) g_free (cfg); } -static MonoInst* -mono_create_tls_get_offset (MonoCompile *cfg, int offset) -{ - MonoInst* ins; - - if (!cfg->backend->have_tls_get) - return NULL; - - if (offset == -1) - return NULL; - - MONO_INST_NEW (cfg, ins, OP_TLS_GET); - ins->dreg = mono_alloc_preg (cfg); - ins->inst_offset = offset; - return ins; -} - -gboolean -mini_tls_get_supported (MonoCompile *cfg, MonoTlsKey key) -{ - if (!cfg->backend->have_tls_get) - return FALSE; - - if (cfg->compile_aot) - return cfg->backend->have_tls_get_reg; - else - return mini_get_tls_offset (key) != -1; -} - -MonoInst* -mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key) -{ - if (!cfg->backend->have_tls_get) - return NULL; - -#ifdef HAVE_KW_THREAD - /* - * MONO_THREAD_VAR_OFFSET definitions don't work when loading mono as a - * dynamic library. This means that we need to be conservative and don't - * aot code that contains these tls chunks. - * - * FIXME Remove HAVE_KW_THREAD altogether and use only pthread since it - * simplifies the code alot. - */ - if (!cfg->full_aot) - cfg->disable_aot = TRUE; -#endif - /* - * TLS offsets might be different at AOT time, so load them from a GOT slot and - * use a different opcode. - */ - if (cfg->compile_aot) { - if (cfg->backend->have_tls_get_reg) { - MonoInst *ins, *c; - - EMIT_NEW_TLS_OFFSETCONST (cfg, c, key); - MONO_INST_NEW (cfg, ins, OP_TLS_GET_REG); - ins->dreg = mono_alloc_preg (cfg); - ins->sreg1 = c->dreg; - return ins; - } else { - return NULL; - } - } - - return mono_create_tls_get_offset (cfg, mini_get_tls_offset (key)); -} - -MonoInst* -mono_get_jit_tls_intrinsic (MonoCompile *cfg) -{ - return mono_create_tls_get (cfg, TLS_KEY_JIT_TLS); -} - -MonoInst* -mono_get_domain_intrinsic (MonoCompile* cfg) -{ - return mono_create_tls_get (cfg, TLS_KEY_DOMAIN); -} - -MonoInst* -mono_get_thread_intrinsic (MonoCompile* cfg) -{ - return mono_create_tls_get (cfg, TLS_KEY_THREAD); -} - -MonoInst* -mono_get_lmf_intrinsic (MonoCompile* cfg) -{ - return mono_create_tls_get (cfg, TLS_KEY_LMF); -} - -MonoInst* -mono_get_lmf_addr_intrinsic (MonoCompile* cfg) -{ - return mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR); -} - void mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target) { @@ -2138,8 +2044,10 @@ mono_compile_create_vars (MonoCompile *cfg) cfg->args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*)); - if (sig->hasthis) + if (sig->hasthis) { cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG); + cfg->this_arg = cfg->args [0]; + } for (i = 0; i < sig->param_count; ++i) { cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG); @@ -2168,8 +2076,11 @@ mono_compile_create_vars (MonoCompile *cfg) if (cfg->verbose_level > 2) g_print ("creating locals\n"); - for (i = 0; i < header->num_locals; ++i) + for (i = 0; i < header->num_locals; ++i) { + if (cfg->verbose_level > 2) + g_print ("\tlocal [%d]: ", i); cfg->locals [i] = mono_compile_create_var (cfg, header->locals [i], OP_LOCAL); + } if (cfg->verbose_level > 2) g_print ("locals done\n"); @@ -2242,18 +2153,11 @@ mono_postprocess_patches (MonoCompile *cfg) } case MONO_PATCH_INFO_SWITCH: { gpointer *table; -#if defined(__native_client__) && defined(__native_client_codegen__) - /* This memory will leak. */ - /* TODO: can we free this when */ - /* making the final jump table? */ - table = g_malloc0 (sizeof(gpointer) * patch_info->data.table->table_size); -#else if (cfg->method->dynamic) { table = (void **)mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size); } else { table = (void **)mono_domain_code_reserve (cfg->domain, sizeof (gpointer) * patch_info->data.table->table_size); } -#endif for (i = 0; i < patch_info->data.table->table_size; i++) { /* Might be NULL if the switch is eliminated */ @@ -2327,9 +2231,6 @@ mono_codegen (MonoCompile *cfg) mono_bb_deduplicate_op_il_seq_points (cfg, bb); } - if (cfg->prof_options & MONO_PROFILE_COVERAGE) - cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks); - code = mono_arch_emit_prolog (cfg); cfg->code_len = code - cfg->native_code; @@ -2352,6 +2253,9 @@ mono_codegen (MonoCompile *cfg) mono_arch_emit_epilog (cfg); cfg->epilog_end = cfg->code_len; } + + if (bb->clause_hole) + mono_cfg_add_try_hole (cfg, bb->clause_hole, cfg->native_code + bb->native_offset, bb); } mono_arch_emit_exceptions (cfg); @@ -2364,7 +2268,7 @@ mono_codegen (MonoCompile *cfg) /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */ #ifdef MONO_ARCH_HAVE_UNWIND_TABLE - unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo); + unwindlen = mono_arch_unwindinfo_init_method_unwind_info (cfg); #endif if (cfg->method->dynamic) { @@ -2409,13 +2313,10 @@ mono_codegen (MonoCompile *cfg) if (cfg->verbose_level > 0) { char* nm = mono_method_get_full_name (cfg->method); - char *opt_descr = mono_opt_descr (cfg->opt); - g_print ("Method %s emitted at %p to %p (code length %d) [%s] with opts %s\n", + g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n", nm, - cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name, - opt_descr); + cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name); g_free (nm); - g_free (opt_descr); } { @@ -2478,17 +2379,14 @@ mono_codegen (MonoCompile *cfg) } else { mono_domain_code_commit (code_domain, cfg->native_code, cfg->code_size, cfg->code_len); } -#if defined(__native_client_codegen__) && defined(__native_client__) - cfg->native_code = code_dest; -#endif - mono_profiler_code_buffer_new (cfg->native_code, cfg->code_len, MONO_PROFILER_CODE_BUFFER_METHOD, cfg->method); + MONO_PROFILER_RAISE (jit_code_buffer, (cfg->native_code, cfg->code_len, MONO_PROFILER_CODE_BUFFER_METHOD, cfg->method)); mono_arch_flush_icache (cfg->native_code, cfg->code_len); mono_debug_close_method (cfg); #ifdef MONO_ARCH_HAVE_UNWIND_TABLE - mono_arch_unwindinfo_install_unwind_info (&cfg->arch.unwindinfo, cfg->native_code, cfg->code_len); + mono_arch_unwindinfo_install_method_unwind_info (&cfg->arch.unwindinfo, cfg->native_code, cfg->code_len); #endif } @@ -2756,27 +2654,15 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) MonoExceptionClause *ec = &header->clauses [i]; MonoJitExceptionInfo *ei = &jinfo->clauses [i]; MonoBasicBlock *tblock; - MonoInst *exvar, *spvar; + MonoInst *exvar; ei->flags = ec->flags; if (G_UNLIKELY (cfg->verbose_level >= 4)) printf ("IL clause: try 0x%x-0x%x handler 0x%x-0x%x filter 0x%x\n", ec->try_offset, ec->try_offset + ec->try_len, ec->handler_offset, ec->handler_offset + ec->handler_len, ec->flags == MONO_EXCEPTION_CLAUSE_FILTER ? ec->data.filter_offset : 0); - /* - * The spvars are needed by mono_arch_install_handler_block_guard (). - */ - if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) { - int region; - - region = ((i + 1) << 8) | MONO_REGION_FINALLY | ec->flags; - spvar = mono_find_spvar_for_region (cfg, region); - g_assert (spvar); - ei->exvar_offset = spvar->inst_offset; - } else { - exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset); - ei->exvar_offset = exvar ? exvar->inst_offset : 0; - } + exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset); + ei->exvar_offset = exvar ? exvar->inst_offset : 0; if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) { tblock = cfg->cil_offset_to_bb [ec->data.filter_offset]; @@ -2939,7 +2825,8 @@ is_open_method (MonoMethod *method) return FALSE; } -static void mono_insert_nop_in_empty_bb (MonoCompile *cfg) +static void +mono_insert_nop_in_empty_bb (MonoCompile *cfg) { MonoBasicBlock *bb; for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { @@ -2961,12 +2848,8 @@ mono_create_gc_safepoint (MonoCompile *cfg, MonoBasicBlock *bblock) if (cfg->verbose_level > 1) printf ("ADDING SAFE POINT TO BB %d\n", bblock->block_num); -#if defined(__native_client_codegen__) - NEW_AOTCONST (cfg, poll_addr, MONO_PATCH_INFO_GC_SAFE_POINT_FLAG, (gpointer)&__nacl_thread_suspension_needed); -#else g_assert (mono_threads_is_coop_enabled ()); NEW_AOTCONST (cfg, poll_addr, MONO_PATCH_INFO_GC_SAFE_POINT_FLAG, (gpointer)&mono_polling_required); -#endif MONO_INST_NEW (cfg, ins, OP_GC_SAFE_POINT); ins->sreg1 = poll_addr->dreg; @@ -3011,19 +2894,13 @@ mono_insert_safepoints (MonoCompile *cfg) { MonoBasicBlock *bb; -#if !defined(__native_client_codegen__) if (!mono_threads_is_coop_enabled ()) return; -#endif if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) { WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method); -#if defined(__native_client__) || defined(__native_client_codegen__) - gpointer poll_func = &mono_nacl_gc; -#else g_assert (mono_threads_is_coop_enabled ()); gpointer poll_func = &mono_threads_state_poll; -#endif if (info && info->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER && info->d.icall.func == poll_func) { if (cfg->verbose_level > 1) @@ -3141,11 +3018,6 @@ init_backend (MonoBackend *backend) #endif #ifdef MONO_ARCH_GSHARED_SUPPORTED backend->gshared_supported = 1; -#endif - if (MONO_ARCH_HAVE_TLS_GET) - backend->have_tls_get = 1; -#ifdef MONO_ARCH_HAVE_TLS_GET_REG - backend->have_tls_get_reg = 1; #endif if (MONO_ARCH_USE_FPSTACK) backend->use_fpstack = 1; @@ -3198,7 +3070,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl MonoMethodSignature *sig; MonoError err; MonoCompile *cfg; - int i, code_size_ratio; + int i; gboolean try_generic_shared, try_llvm = FALSE; MonoMethod *method_to_compile, *method_to_register; gboolean method_is_gshared = FALSE; @@ -3211,11 +3083,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl gboolean llvm = (flags & JIT_FLAG_LLVM) ? 1 : 0; #endif static gboolean verbose_method_inited; - static const char *verbose_method_name; + static char *verbose_method_name; InterlockedIncrement (&mono_jit_stats.methods_compiled); - if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION) - mono_profiler_method_jit (method); + MONO_PROFILER_RAISE (jit_begin, (method)); if (MONO_METHOD_COMPILE_BEGIN_ENABLED ()) MONO_PROBE_METHOD_COMPILE_BEGIN (method); @@ -3253,9 +3124,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl if (opts & MONO_OPT_GSHARED) { if (try_generic_shared) - mono_stats.generics_sharable_methods++; + InterlockedIncrement (&mono_stats.generics_sharable_methods); else if (mono_method_is_generic_impl (method)) - mono_stats.generics_unsharable_methods++; + InterlockedIncrement (&mono_stats.generics_unsharable_methods); } #ifdef ENABLE_LLVM @@ -3278,7 +3149,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl cfg->method = method_to_compile; cfg->mempool = mono_mempool_new (); cfg->opt = opts; - cfg->prof_options = mono_profiler_get_events (); cfg->run_cctors = run_cctors; cfg->domain = domain; cfg->verbose_level = mini_verbose; @@ -3292,7 +3162,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl cfg->llvm_only = (flags & JIT_FLAG_LLVM_ONLY) != 0; cfg->backend = current_backend; -#ifdef PLATFORM_ANDROID +#ifdef HOST_ANDROID if (cfg->method->wrapper_type != MONO_WRAPPER_NONE) { /* FIXME: Why is this needed */ cfg->gen_seq_points = FALSE; @@ -3304,13 +3174,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl cfg->gen_seq_points = FALSE; cfg->gen_sdb_seq_points = FALSE; } - /* coop / nacl requires loop detection to happen */ -#if defined(__native_client_codegen__) - cfg->opt |= MONO_OPT_LOOP; -#else + /* coop requires loop detection to happen */ if (mono_threads_is_coop_enabled ()) cfg->opt |= MONO_OPT_LOOP; -#endif cfg->explicit_null_checks = debug_options.explicit_null_checks || (flags & JIT_FLAG_EXPLICIT_NULL_CHECKS); cfg->soft_breakpoints = debug_options.soft_breakpoints; cfg->check_pinvoke_callconv = debug_options.check_pinvoke_callconv; @@ -3334,7 +3200,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl if (cfg->gen_seq_points) cfg->seq_points = g_ptr_array_new (); - mono_error_init (&cfg->error); + error_init (&cfg->error); if (cfg->compile_aot && !try_generic_shared && (method->is_generic || mono_class_is_gtd (method->klass) || method_is_gshared)) { cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED; @@ -3376,7 +3242,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl } cfg->method_to_register = method_to_register; - mono_error_init (&err); + error_init (&err); sig = mono_method_signature_checked (cfg->method, &err); if (!sig) { cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD; @@ -3427,8 +3293,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl } #endif + cfg->prof_flags = mono_profiler_get_call_instrumentation_flags (cfg->method); + /* The debugger has no liveness information, so avoid sharing registers/stack slots */ - if (debug_options.mdb_optimizations) { + if (debug_options.mdb_optimizations || MONO_CFG_PROFILE_CALL_CONTEXT (cfg)) { cfg->disable_reuse_registers = TRUE; cfg->disable_reuse_stack_slots = TRUE; /* @@ -3702,6 +3570,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl cfg->disable_ssa = TRUE; } + if (cfg->num_varinfo > 10000 && !cfg->llvm_only) + /* Disable llvm for overly complex methods */ + cfg->disable_ssa = TRUE; + if (cfg->opt & MONO_OPT_LOOP) { MONO_TIME_TRACK (mono_jit_stats.jit_compile_dominator_info, mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM)); MONO_TIME_TRACK (mono_jit_stats.jit_compute_natural_loops, mono_compute_natural_loops (cfg)); @@ -3974,20 +3846,21 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl } #endif - if (!cfg->compile_aot) - mono_save_xdebug_info (cfg); - MONO_TIME_TRACK (mono_jit_stats.jit_gc_create_gc_map, mini_gc_create_gc_map (cfg)); - MONO_TIME_TRACK (mono_jit_stats.jit_save_seq_point_info, mono_save_seq_point_info (cfg)); + if (!cfg->compile_aot) { + mono_save_xdebug_info (cfg); + mono_lldb_save_method_info (cfg); + } + if (cfg->verbose_level >= 2) { char *id = mono_method_full_name (cfg->method, FALSE); mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3); g_free (id); } - if (!cfg->compile_aot) { + if (!cfg->compile_aot && !(flags & JIT_FLAG_DISCARD_RESULTS)) { mono_domain_lock (cfg->domain); mono_jit_info_table_add (cfg->domain, cfg->jit_info); @@ -4003,23 +3876,28 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl /* collect statistics */ #ifndef DISABLE_PERFCOUNTERS - mono_perfcounters->jit_methods++; - mono_perfcounters->jit_bytes += header->code_size; + InterlockedIncrement (&mono_perfcounters->jit_methods); + InterlockedAdd (&mono_perfcounters->jit_bytes, header->code_size); #endif - mono_jit_stats.allocated_code_size += cfg->code_len; - code_size_ratio = cfg->code_len; - if (code_size_ratio > mono_jit_stats.biggest_method_size && mono_jit_stats.enabled) { - mono_jit_stats.biggest_method_size = code_size_ratio; - g_free (mono_jit_stats.biggest_method); - mono_jit_stats.biggest_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name); - } - code_size_ratio = (code_size_ratio * 100) / header->code_size; - if (code_size_ratio > mono_jit_stats.max_code_size_ratio && mono_jit_stats.enabled) { - mono_jit_stats.max_code_size_ratio = code_size_ratio; - g_free (mono_jit_stats.max_ratio_method); - mono_jit_stats.max_ratio_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name); + gint32 code_size_ratio = cfg->code_len; + InterlockedAdd (&mono_jit_stats.allocated_code_size, code_size_ratio); + InterlockedAdd (&mono_jit_stats.native_code_size, code_size_ratio); + /* FIXME: use an explicit function to read booleans */ + if ((gboolean)InterlockedRead ((gint32*)&mono_jit_stats.enabled)) { + if (code_size_ratio > InterlockedRead (&mono_jit_stats.biggest_method_size)) { + InterlockedWrite (&mono_jit_stats.biggest_method_size, code_size_ratio); + char *biggest_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name); + biggest_method = InterlockedExchangePointer ((gpointer*)&mono_jit_stats.biggest_method, biggest_method); + g_free (biggest_method); + } + code_size_ratio = (code_size_ratio * 100) / header->code_size; + if (code_size_ratio > InterlockedRead (&mono_jit_stats.max_code_size_ratio)) { + InterlockedWrite (&mono_jit_stats.max_code_size_ratio, code_size_ratio); + char *max_ratio_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name); + max_ratio_method = InterlockedExchangePointer ((gpointer*)&mono_jit_stats.max_ratio_method, max_ratio_method); + g_free (max_ratio_method); + } } - mono_jit_stats.native_code_size += cfg->code_len; if (MONO_METHOD_COMPILE_END_ENABLED ()) MONO_PROBE_METHOD_COMPILE_END (method, TRUE); @@ -4029,6 +3907,34 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl return cfg; } +gboolean +mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used) +{ + int i; + MonoGenericContainer *container; + MonoGenericInst *ginst; + + if (mono_class_is_ginst (klass)) { + container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class); + ginst = mono_class_get_generic_class (klass)->context.class_inst; + } else if (mono_class_is_gtd (klass) && context_used) { + container = mono_class_get_generic_container (klass); + ginst = container->context.class_inst; + } else { + return FALSE; + } + + for (i = 0; i < container->type_argc; ++i) { + MonoType *type; + if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))) + continue; + type = ginst->type_argv [i]; + if (mini_type_is_reference (type)) + return TRUE; + } + return FALSE; +} + void* mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) { @@ -4094,14 +4000,26 @@ GTimer *mono_time_track_start () return g_timer_new (); } -void mono_time_track_end (double *time, GTimer *timer) +/* + * mono_time_track_end: + * + * Uses UnlockedAddDouble () to update \param time. + */ +void mono_time_track_end (gdouble *time, GTimer *timer) { g_timer_stop (timer); - *time += g_timer_elapsed (timer, NULL); + UnlockedAddDouble (time, g_timer_elapsed (timer, NULL)); g_timer_destroy (timer); } -void mono_update_jit_stats (MonoCompile *cfg) +/* + * mono_update_jit_stats: + * + * Only call this function in locked environments to avoid data races. + */ +MONO_NO_SANITIZE_THREAD +void +mono_update_jit_stats (MonoCompile *cfg) { mono_jit_stats.allocate_var += cfg->stat_allocate_var; mono_jit_stats.locals_stack_size += cfg->stat_locals_stack_size; @@ -4127,11 +4045,10 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in MonoJitInfo *jinfo, *info; MonoVTable *vtable; MonoException *ex = NULL; - guint32 prof_options; GTimer *jit_timer; MonoMethod *prof_method, *shared; - mono_error_init (error); + error_init (error); if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) { @@ -4158,7 +4075,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in if (!jinfo) jinfo = mono_jit_info_table_find (mono_domain_get (), (char *)code); if (jinfo) - mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (jit_done, (method, jinfo)); return code; } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) { const char *name = method->name; @@ -4253,7 +4170,9 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in jit_timer = mono_time_track_start (); cfg = mini_method_compile (method, opt, target_domain, JIT_FLAG_RUN_CCTORS, 0, -1); - mono_time_track_end (&mono_jit_stats.jit_time, jit_timer); + gdouble jit_time = 0.0; + mono_time_track_end (&jit_time, jit_timer); + UnlockedAddDouble (&mono_jit_stats.jit_time, jit_time); prof_method = cfg->method; @@ -4297,8 +4216,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in } if (ex) { - if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION) - mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED); + MONO_PROFILER_RAISE (jit_failed, (method)); mono_destroy_compile (cfg); mono_error_set_exception_instance (error, ex); @@ -4321,7 +4239,8 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in /* We can't use a domain specific method in another domain */ if ((target_domain == mono_domain_get ()) || info->domain_neutral) { code = info->code_start; -// printf("Discarding code for method %s\n", method->name); + discarded_code ++; + discarded_jit_time += jit_time; } } if (code == NULL) { @@ -4333,15 +4252,13 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in code = cfg->native_code; if (cfg->gshared && mono_method_is_generic_sharable (method, FALSE)) - mono_stats.generics_shared_methods++; + InterlockedIncrement (&mono_stats.generics_shared_methods); if (cfg->gsharedvt) - mono_stats.gsharedvt_methods++; + InterlockedIncrement (&mono_stats.gsharedvt_methods); } jinfo = cfg->jit_info; - prof_options = cfg->prof_options; - /* * Update global stats while holding a lock, instead of doing many * InterlockedIncrement operations during JITting. @@ -4406,22 +4323,23 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in return NULL; } - if (prof_options & MONO_PROFILE_JIT_COMPILATION) { - if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) { - if (mono_marshal_method_from_wrapper (method)) { - /* Native func wrappers have no method */ - /* The profiler doesn't know about wrappers, so pass the original icall method */ - mono_profiler_method_end_jit (mono_marshal_method_from_wrapper (method), jinfo, MONO_PROFILE_OK); - } - } - mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK); - if (prof_method != method) { - mono_profiler_method_end_jit (prof_method, jinfo, MONO_PROFILE_OK); + if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) { + if (mono_marshal_method_from_wrapper (method)) { + /* Native func wrappers have no method */ + /* The profiler doesn't know about wrappers, so pass the original icall method */ + MONO_PROFILER_RAISE (jit_done, (mono_marshal_method_from_wrapper (method), jinfo)); } } + MONO_PROFILER_RAISE (jit_done, (method, jinfo)); + if (prof_method != method) + MONO_PROFILER_RAISE (jit_done, (prof_method, jinfo)); - if (!mono_runtime_class_init_full (vtable, error)) - return NULL; + if (!(method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE || + method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK || + method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE)) { + if (!mono_runtime_class_init_full (vtable, error)) + return NULL; + } return code; } @@ -4429,7 +4347,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in * mini_get_underlying_type: * * Return the type the JIT will use during compilation. - * Handles: byref, enums, native types, generic sharing. + * Handles: byref, enums, native types, bool/char, ref types, generic sharing. * For gsharedvt types, it will return the original VAR/MVAR. */ MonoType* @@ -4441,6 +4359,9 @@ mini_get_underlying_type (MonoType *type) void mini_jit_init (void) { + mono_counters_register ("Discarded method code", MONO_COUNTER_JIT | MONO_COUNTER_INT, &discarded_code); + mono_counters_register ("Time spent JITting discarded code", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &discarded_jit_time); + mono_os_mutex_init_recursive (&jit_mutex); #ifndef DISABLE_JIT current_backend = g_new0 (MonoBackend, 1);