X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini.c;h=f977b3a66c49caba9ae20bb4d015f0327c9b0121;hb=e4abb3281f6abfa1effcbfc174884a3bb63865a4;hp=fcab1ffcb8e1ce562643b06e1dded26ba4a7dcd3;hpb=9be6e6df996102f0e76e7ba67166dd35c6620d04;p=mono.git diff --git a/mono/mini/mini.c b/mono/mini/mini.c index fcab1ffcb8e..f977b3a66c4 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -21,9 +21,7 @@ #include #endif -#ifdef HAVE_VALGRIND_MEMCHECK_H -#include -#endif +#include #include #include @@ -76,6 +74,7 @@ MonoMethodSignature *helper_sig_domain_get = NULL; MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL; MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL; MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL; +MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL; static guint32 default_opt = 0; static gboolean default_opt_set = FALSE; @@ -134,8 +133,7 @@ static CRITICAL_SECTION jit_mutex; static MonoCodeManager *global_codeman = NULL; -/* FIXME: Make this static again */ -GHashTable *jit_icall_name_hash = NULL; +static GHashTable *jit_icall_name_hash = NULL; static MonoDebugOptions debug_options; @@ -162,17 +160,13 @@ gboolean mono_dont_free_global_codeman; gboolean mono_running_on_valgrind (void) { -#ifdef HAVE_VALGRIND_MEMCHECK_H - if (RUNNING_ON_VALGRIND){ + if (RUNNING_ON_VALGRIND){ #ifdef VALGRIND_JIT_REGISTER_MAP - valgrind_register = TRUE; + valgrind_register = TRUE; #endif - return TRUE; - } else - return FALSE; -#else + return TRUE; + } else return FALSE; -#endif } typedef struct { @@ -264,9 +258,10 @@ mono_print_method_from_ip (void *ip) char *method; MonoDebugSourceLocation *source; MonoDomain *domain = mono_domain_get (); + MonoDomain *target_domain = mono_domain_get (); FindTrampUserData user_data; - ji = mini_jit_info_table_find (domain, ip, &domain); + ji = mini_jit_info_table_find (domain, ip, &target_domain); if (!ji) { user_data.ip = ip; user_data.method = NULL; @@ -283,9 +278,9 @@ mono_print_method_from_ip (void *ip) return; } method = mono_method_full_name (ji->method, TRUE); - source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain); + source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain); - g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), method, ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name); + g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name); if (source) g_print ("%s:%d\n", source->source_file, source->row); @@ -499,8 +494,14 @@ mono_find_block_region_notry (MonoCompile *cfg, int offset) return -1; } -MonoInst * -mono_find_spvar_for_region (MonoCompile *cfg, int region) +/* + * mono_get_block_region_notry: + * + * Return the region corresponding to REGION, ignoring try clauses nested inside + * finally clauses. + */ +int +mono_get_block_region_notry (MonoCompile *cfg, int region) { if ((region & (0xf << 4)) == MONO_REGION_TRY) { MonoMethodHeader *header = mono_method_get_header (cfg->method); @@ -514,13 +515,15 @@ mono_find_spvar_for_region (MonoCompile *cfg, int region) region = mono_find_block_region_notry (cfg, header->clauses [clause_index].try_offset); } - return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region)); + return region; } -static MonoInst * -mono_find_exvar_for_offset (MonoCompile *cfg, int offset) +MonoInst * +mono_find_spvar_for_region (MonoCompile *cfg, int region) { - return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset)); + region = mono_get_block_region_notry (cfg, region); + + return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region)); } static void @@ -645,7 +648,9 @@ mono_type_to_load_membase (MonoCompile *cfg, MonoType *type) if (type->byref) return OP_LOAD_MEMBASE; - switch (mono_type_get_underlying_type (type)->type) { + type = mono_type_get_underlying_type (type); + + switch (type->type) { case MONO_TYPE_I1: return OP_LOADI1_MEMBASE; case MONO_TYPE_U1: @@ -1273,15 +1278,19 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method) for (tmp = res; tmp; tmp = tmp->next) { MonoVerifyInfoExtended *info = (MonoVerifyInfoExtended *)tmp->data; if (info->info.status == MONO_VERIFY_ERROR) { + char *method_name = mono_method_full_name (method, TRUE); cfg->exception_type = info->exception_type; - cfg->exception_message = g_strdup (info->info.message); + cfg->exception_message = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message); mono_free_verify_list (res); + g_free (method_name); return TRUE; } if (info->info.status == MONO_VERIFY_NOT_VERIFIABLE && (!is_fulltrust || info->exception_type == MONO_EXCEPTION_METHOD_ACCESS || info->exception_type == MONO_EXCEPTION_FIELD_ACCESS)) { + char *method_name = mono_method_full_name (method, TRUE); cfg->exception_type = info->exception_type; - cfg->exception_message = g_strdup (info->info.message); + cfg->exception_message = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message); mono_free_verify_list (res); + g_free (method_name); return TRUE; } } @@ -1291,6 +1300,23 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method) return FALSE; } +/*Returns true is something went wrong*/ +static gboolean +mono_compile_is_broken (MonoCompile *cfg) +{ + MonoMethod *method = cfg->method; + MonoMethod *method_definition = method; + gboolean dont_verify = mini_assembly_can_skip_verification (cfg->domain, method); + dont_verify |= method->klass->image->assembly->corlib_internal; + + while (method_definition->is_inflated) { + MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition; + method_definition = imethod->declaring; + } + + return !dont_verify && mini_method_verify (cfg, method_definition); +} + static void create_helper_signature (void) { @@ -1299,6 +1325,7 @@ create_helper_signature (void) helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void"); helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr"); helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void"); + helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object"); } static gconstpointer @@ -1415,6 +1442,7 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info; MonoType *t; int nvtypes; + gboolean reuse_slot; LSCAN_DEBUG (printf ("Allocate Stack Slots 2 for %s:\n", mono_method_full_name (cfg->method, TRUE))); @@ -1469,8 +1497,15 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s size = mono_type_size (inst->inst_vtype, &ialign); align = ialign; + + if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (inst->inst_vtype))) + align = 16; } + reuse_slot = TRUE; + if (cfg->disable_reuse_stack_slots) + reuse_slot = FALSE; + t = mono_type_get_underlying_type (inst->inst_vtype); switch (t->type) { case MONO_TYPE_GENERICINST: @@ -1493,6 +1528,8 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s slot_info = &vtype_stack_slots [nvtypes]; nvtypes ++; } + if (cfg->disable_reuse_ref_stack_slots) + reuse_slot = FALSE; break; case MONO_TYPE_PTR: @@ -1517,6 +1554,8 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s case MONO_TYPE_STRING: /* Share non-float stack slots of the same size */ slot_info = &scalar_stack_slots [MONO_TYPE_CLASS]; + if (cfg->disable_reuse_ref_stack_slots) + reuse_slot = FALSE; break; default: @@ -1636,14 +1675,19 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s LSCAN_DEBUG (printf ("R%d %s -> 0x%x\n", inst->dreg, mono_type_full_name (t), slot)); + if (!reuse_slot) + slot = 0xffffff; + if (slot == 0xffffff) { /* * Allways allocate valuetypes to sizeof (gpointer) to allow more * efficient copying (and to work around the fact that OP_MEMCPY * and OP_MEMSET ignores alignment). */ - if (MONO_TYPE_ISSTRUCT (t)) - align = MAX (sizeof (gpointer), mono_class_min_align (mono_class_from_mono_type (t))); + if (MONO_TYPE_ISSTRUCT (t)) { + align = MAX (align, sizeof (gpointer)); + align = MAX (align, mono_class_min_align (mono_class_from_mono_type (t))); + } if (backward) { offset += size; @@ -1701,6 +1745,7 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info; MonoType *t; int nvtypes; + gboolean reuse_slot; if ((cfg->num_varinfo > 0) && MONO_VARINFO (cfg, 0)->interval) return mono_allocate_stack_slots_full2 (cfg, backward, stack_size, stack_align); @@ -1739,8 +1784,15 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st size = mono_type_size (inst->inst_vtype, &ialign); align = ialign; + + if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (inst->inst_vtype))) + align = 16; } + reuse_slot = TRUE; + if (cfg->disable_reuse_stack_slots) + reuse_slot = FALSE; + t = mono_type_get_underlying_type (inst->inst_vtype); if (t->byref) { slot_info = &scalar_stack_slots [MONO_TYPE_I]; @@ -1766,6 +1818,8 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st slot_info = &vtype_stack_slots [nvtypes]; nvtypes ++; } + if (cfg->disable_reuse_ref_stack_slots) + reuse_slot = FALSE; break; case MONO_TYPE_PTR: @@ -1790,6 +1844,8 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st case MONO_TYPE_STRING: /* Share non-float stack slots of the same size */ slot_info = &scalar_stack_slots [MONO_TYPE_CLASS]; + if (cfg->disable_reuse_ref_stack_slots) + reuse_slot = FALSE; break; default: @@ -1848,7 +1904,7 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st */ } - if (cfg->disable_reuse_stack_slots) + if (!reuse_slot) slot = 0xffffff; if (slot == 0xffffff) { @@ -1858,7 +1914,8 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st * and OP_MEMSET ignores alignment). */ if (MONO_TYPE_ISSTRUCT (t)) { - align = MAX (sizeof (gpointer), mono_class_min_align (mono_class_from_mono_type (t))); + align = MAX (align, sizeof (gpointer)); + align = MAX (align, mono_class_min_align (mono_class_from_mono_type (t))); /* * Align the size too so the code generated for passing vtypes in * registers doesn't overwrite random locals. @@ -2412,6 +2469,12 @@ mono_get_domain_intrinsic (MonoCompile* cfg) return mono_create_tls_get (cfg, mono_domain_get_tls_offset ()); } +MonoInst* +mono_get_thread_intrinsic (MonoCompile* cfg) +{ + return mono_create_tls_get (cfg, mono_thread_get_tls_offset ()); +} + void mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target) { @@ -2577,7 +2640,11 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, switch (patch_info->type) { case MONO_PATCH_INFO_BB: - g_assert (patch_info->data.bb->native_offset); + /* + * FIXME: This could be hit for methods without a prolog. Should use -1 + * but too much code depends on a 0 initial value. + */ + //g_assert (patch_info->data.bb->native_offset); target = patch_info->data.bb->native_offset + code; break; case MONO_PATCH_INFO_ABS: @@ -2817,6 +2884,17 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, return (gpointer)target; } +void +mono_add_seq_point (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, int native_offset) +{ + ins->inst_offset = native_offset; + g_ptr_array_add (cfg->seq_points, ins); + bb->seq_points = g_slist_prepend_mempool (cfg->mempool, bb->seq_points, ins); + bb->last_seq_point = ins; +} + +#ifndef DISABLE_JIT + static void mono_compile_create_vars (MonoCompile *cfg) { @@ -2877,6 +2955,8 @@ mono_compile_create_vars (MonoCompile *cfg) mono_arch_create_vars (cfg); } +#endif /* #ifndef DISABLE_JIT */ + void mono_print_code (MonoCompile *cfg, const char* msg) { @@ -2982,6 +3062,117 @@ mono_postprocess_patches (MonoCompile *cfg) } } +static void +collect_pred_seq_points (MonoBasicBlock *bb, MonoInst *ins, GSList **next, int depth) +{ + int i; + MonoBasicBlock *in_bb; + + for (i = 0; i < bb->in_count; ++i) { + in_bb = bb->in_bb [i]; + + if (in_bb->last_seq_point) { + next [in_bb->last_seq_point->backend.size] = g_slist_append (next [in_bb->last_seq_point->backend.size], GUINT_TO_POINTER (ins->backend.size)); + } else { + /* Have to look at its predecessors */ + if (depth < 5) + collect_pred_seq_points (in_bb, ins, next, depth + 1); + } + } +} + +static void +mono_save_seq_point_info (MonoCompile *cfg) +{ + MonoBasicBlock *bb; + GSList *bb_seq_points, *l; + MonoInst *last; + MonoDomain *domain = cfg->domain; + int i; + MonoSeqPointInfo *info; + GSList **next; + + if (!cfg->seq_points) + return; + + info = g_malloc0 (sizeof (MonoSeqPointInfo) + (cfg->seq_points->len - MONO_ZERO_LEN_ARRAY) * sizeof (SeqPoint)); + info->len = cfg->seq_points->len; + for (i = 0; i < cfg->seq_points->len; ++i) { + SeqPoint *sp = &info->seq_points [i]; + MonoInst *ins = g_ptr_array_index (cfg->seq_points, i); + + sp->il_offset = ins->inst_imm; + sp->native_offset = ins->inst_offset; + + /* Used below */ + ins->backend.size = i; + } + + /* + * For each sequence point, compute the list of sequence points immediately + * following it, this is needed to implement 'step over' in the debugger agent. + */ + next = g_new0 (GSList*, cfg->seq_points->len); + for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { + bb_seq_points = g_slist_reverse (bb->seq_points); + last = NULL; + for (l = bb_seq_points; l; l = l->next) { + MonoInst *ins = l->data; + + if (!(ins->flags & MONO_INST_SINGLE_STEP_LOC)) + continue; + + if (last != NULL) { + /* Link with the previous seq point in the same bb */ + next [last->backend.size] = g_slist_append (next [last->backend.size], GUINT_TO_POINTER (ins->backend.size)); + } else { + /* Link with the last bb in the previous bblocks */ + collect_pred_seq_points (bb, ins, next, 0); + } + + last = ins; + } + } + + if (cfg->verbose_level > 2) { + printf ("\nSEQ POINT MAP: \n"); + } + + for (i = 0; i < cfg->seq_points->len; ++i) { + SeqPoint *sp = &info->seq_points [i]; + GSList *l; + int j, next_index; + + sp->next_len = g_slist_length (next [i]); + sp->next = g_new (int, sp->next_len); + j = 0; + if (cfg->verbose_level > 2 && next [i]) { + printf ("\t0x%x ->", sp->il_offset); + for (l = next [i]; l; l = l->next) { + next_index = GPOINTER_TO_UINT (l->data); + printf (" 0x%x", info->seq_points [next_index].il_offset); + } + printf ("\n"); + } + for (l = next [i]; l; l = l->next) { + next_index = GPOINTER_TO_UINT (l->data); + sp->next [j ++] = next_index; + } + g_slist_free (next [i]); + } + g_free (next); + + cfg->seq_point_info = info; + + // FIXME: dynamic methods + mono_domain_lock (domain); + g_hash_table_insert (domain_jit_info (domain)->seq_points, cfg->method_to_register, info); + mono_domain_unlock (domain); + + g_ptr_array_free (cfg->seq_points, TRUE); + cfg->seq_points = NULL; +} + void mono_codegen (MonoCompile *cfg) { @@ -3140,6 +3331,150 @@ compute_reachable (MonoBasicBlock *bb) } } +static MonoJitInfo* +create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) +{ + MonoMethodHeader *header; + MonoJitInfo *jinfo; + int num_clauses; + int generic_info_size; + + header = mono_method_get_header (method_to_compile); + + if (cfg->generic_sharing_context) + generic_info_size = sizeof (MonoGenericJitInfo); + else + generic_info_size = 0; + + if (COMPILE_LLVM (cfg)) + num_clauses = cfg->llvm_ex_info_len; + else + num_clauses = header->num_clauses; + + if (cfg->method->dynamic) { + jinfo = g_malloc0 (MONO_SIZEOF_JIT_INFO + (num_clauses * sizeof (MonoJitExceptionInfo)) + + generic_info_size); + } else { + jinfo = mono_domain_alloc0 (cfg->domain, MONO_SIZEOF_JIT_INFO + + (num_clauses * sizeof (MonoJitExceptionInfo)) + + generic_info_size); + } + + jinfo->method = cfg->method_to_register; + jinfo->code_start = cfg->native_code; + jinfo->code_size = cfg->code_len; + jinfo->used_regs = cfg->used_int_regs; + jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0; + jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */ + jinfo->num_clauses = num_clauses; + if (COMPILE_LLVM (cfg)) + jinfo->from_llvm = TRUE; + + if (cfg->generic_sharing_context) { + MonoInst *inst; + MonoGenericJitInfo *gi; + + jinfo->has_generic_jit_info = 1; + + gi = mono_jit_info_get_generic_jit_info (jinfo); + g_assert (gi); + + gi->generic_sharing_context = cfg->generic_sharing_context; + + if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) || + mini_method_get_context (method_to_compile)->method_inst || + method_to_compile->klass->valuetype) { + g_assert (cfg->rgctx_var); + } + + gi->has_this = 1; + + if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) || + mini_method_get_context (method_to_compile)->method_inst || + method_to_compile->klass->valuetype) { + inst = cfg->rgctx_var; + g_assert (inst->opcode == OP_REGOFFSET); + } else { + inst = cfg->args [0]; + } + + if (inst->opcode == OP_REGVAR) { + gi->this_in_reg = 1; + gi->this_reg = inst->dreg; + } else { + g_assert (inst->opcode == OP_REGOFFSET); +#ifdef TARGET_X86 + g_assert (inst->inst_basereg == X86_EBP); +#elif defined(TARGET_AMD64) + g_assert (inst->inst_basereg == X86_EBP || inst->inst_basereg == X86_ESP); +#endif + g_assert (inst->inst_offset >= G_MININT32 && inst->inst_offset <= G_MAXINT32); + + gi->this_in_reg = 0; + gi->this_reg = inst->inst_basereg; + gi->this_offset = inst->inst_offset; + } + } + + if (COMPILE_LLVM (cfg)) { + if (num_clauses) + memcpy (&jinfo->clauses [0], &cfg->llvm_ex_info [0], num_clauses * sizeof (MonoJitExceptionInfo)); + } else if (header->num_clauses) { + int i; + + for (i = 0; i < header->num_clauses; i++) { + MonoExceptionClause *ec = &header->clauses [i]; + MonoJitExceptionInfo *ei = &jinfo->clauses [i]; + MonoBasicBlock *tblock; + MonoInst *exvar; + + ei->flags = ec->flags; + + 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]; + g_assert (tblock); + ei->data.filter = cfg->native_code + tblock->native_offset; + } else { + ei->data.catch_class = ec->data.catch_class; + } + + tblock = cfg->cil_offset_to_bb [ec->try_offset]; + g_assert (tblock); + ei->try_start = cfg->native_code + tblock->native_offset; + g_assert (tblock->native_offset); + tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len]; + g_assert (tblock); + ei->try_end = cfg->native_code + tblock->native_offset; + g_assert (tblock->native_offset); + tblock = cfg->cil_offset_to_bb [ec->handler_offset]; + g_assert (tblock); + ei->handler_start = cfg->native_code + tblock->native_offset; + } + } + + /* + * Its possible to generate dwarf unwind info for xdebug etc, but not actually + * using it during runtime, hence the define. + */ +#ifdef MONO_ARCH_HAVE_XP_UNWIND + if (cfg->encoded_unwind_ops) { + jinfo->used_regs = mono_cache_unwind_info (cfg->encoded_unwind_ops, cfg->encoded_unwind_ops_len); + g_free (cfg->encoded_unwind_ops); + } else if (cfg->unwind_ops) { + guint32 info_len; + guint8 *unwind_info = mono_unwind_ops_encode (cfg->unwind_ops, &info_len); + + jinfo->used_regs = mono_cache_unwind_info (unwind_info, info_len); + g_free (unwind_info); + } +#endif + + return jinfo; +} + /* * mini_method_compile: * @method: the method to compile @@ -3158,12 +3493,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool MonoMethodHeader *header; guint8 *ip; MonoCompile *cfg; - MonoJitInfo *jinfo; int dfn, i, code_size_ratio; gboolean deadce_has_run = FALSE; gboolean try_generic_shared, try_llvm; MonoMethod *method_to_compile, *method_to_register; - int generic_info_size; mono_jit_stats.methods_compiled++; if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION) @@ -3236,6 +3569,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool cfg->compile_llvm = try_llvm; cfg->token_info_hash = g_hash_table_new (NULL, NULL); + if (cfg->gen_seq_points) + cfg->seq_points = g_ptr_array_new (); + if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container)) { cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED; return cfg; @@ -3251,17 +3587,78 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool } cfg->method_to_register = method_to_register; - /* No way to obtain the location info for 'this' */ - if (try_generic_shared) { - cfg->exception_message = g_strdup ("gshared"); - cfg->disable_llvm = TRUE; + if (cfg->compile_llvm) { + /* No way to obtain the location info for 'this' */ + if (try_generic_shared) { + cfg->exception_message = g_strdup ("gshared"); + cfg->disable_llvm = TRUE; + } + + if (cfg->method->save_lmf) { + cfg->exception_message = g_strdup ("lmf"); + cfg->disable_llvm = TRUE; + } + + /* FIXME: */ + if (cfg->method->dynamic) { + cfg->exception_message = g_strdup ("dynamic."); + cfg->disable_llvm = TRUE; + } + } + + header = mono_method_get_header (method_to_compile); + if (!header) { + MonoLoaderError *error; + + if ((error = mono_loader_get_last_error ())) { + cfg->exception_type = error->exception_type; + } else { + cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM; + cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name); + } + if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ()) + MONO_PROBE_METHOD_COMPILE_END (method, FALSE); + return cfg; } - if (cfg->method->save_lmf) { - cfg->exception_message = g_strdup ("lmf"); + if (FALSE && header->clauses) { + /* + * Cannot be enabled until LLVM supports implicit exceptions, or we use + * explicit checks, or we disable this for methods which might throw implicit + * exceptions inside clauses. + */ + cfg->exception_message = g_strdup ("clauses"); cfg->disable_llvm = TRUE; } +#ifdef ENABLE_LLVM + { + static gboolean inited; + + if (!inited) { + mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &methods_with_llvm); + mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &methods_without_llvm); + inited = TRUE; + } + + /* + * Check for methods which cannot be compiled by LLVM early, to avoid + * the extra compilation pass. + */ + if (COMPILE_LLVM (cfg) && cfg->disable_llvm) { + if (cfg->verbose_level >= 1) { + //nm = mono_method_full_name (cfg->method, TRUE); + printf ("LLVM failed for '%s': %s\n", method->name, cfg->exception_message); + //g_free (nm); + } + InterlockedIncrement (&methods_without_llvm); + mono_destroy_compile (cfg); + try_llvm = FALSE; + goto restart_compile; + } + } +#endif + /* The debugger has no liveness information, so avoid sharing registers/stack slots */ if (mono_debug_using_mono_debugger () || debug_options.mdb_optimizations) { cfg->disable_reuse_registers = TRUE; @@ -3291,6 +3688,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool cfg->opt &= ~MONO_OPT_COPYPROP; cfg->opt &= ~MONO_OPT_CONSPROP; cfg->opt &= ~MONO_OPT_GSHARED; + + /* This is needed for the soft debugger, which doesn't like code after the epilog */ + cfg->disable_out_of_line_bblocks = TRUE; } if (mono_using_xdebug) { @@ -3302,30 +3702,30 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool cfg->disable_reuse_registers = TRUE; cfg->disable_reuse_stack_slots = TRUE; cfg->extend_live_ranges = TRUE; + cfg->compute_precise_live_ranges = TRUE; } + mini_gc_init_gc_map (cfg); + if (COMPILE_LLVM (cfg)) { cfg->opt |= MONO_OPT_ABCREM; } - header = mono_method_get_header (method_to_compile); - if (!header) { - MonoLoaderError *error; + if (getenv ("MONO_VERBOSE_METHOD")) { + char *name = getenv ("MONO_VERBOSE_METHOD"); - if ((error = mono_loader_get_last_error ())) { - cfg->exception_type = error->exception_type; + if (strchr (name, '.') || strchr (name, ':')) { + MonoMethodDesc *desc; + + desc = mono_method_desc_new (name, TRUE); + if (mono_method_desc_full_match (desc, cfg->method)) { + cfg->verbose_level = 4; + } + mono_method_desc_free (desc); } else { - cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM; - cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name); + if (strcmp (cfg->method->name, getenv ("MONO_VERBOSE_METHOD")) == 0) + cfg->verbose_level = 4; } - if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ()) - MONO_PROBE_METHOD_COMPILE_END (method, FALSE); - return cfg; - } - - if (getenv ("MONO_VERBOSE_METHOD")) { - if (strcmp (cfg->method->name, getenv ("MONO_VERBOSE_METHOD")) == 0) - cfg->verbose_level = 4; } ip = (guint8 *)header->code; @@ -3406,6 +3806,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool */ //cfg->enable_extended_bblocks = TRUE; + /*We must verify the method before doing any IR generation as mono_compile_create_vars can assert.*/ + if (mono_compile_is_broken (cfg)) + return cfg; + /* * create MonoInst* which represents arguments and local variables */ @@ -3473,6 +3877,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool * r1 <- 1 * * r1 <- 2 + * This also allows SSA to be run on methods containing exception clauses, since + * SSA will ignore variables marked VOLATILE. */ mono_liveness_handle_exception_clauses (cfg); @@ -3524,6 +3930,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool if (cfg->verbose_level > 1) g_print ("found unreachable code in BB%d\n", bb->block_num); bb->code = bb->last_ins = NULL; + while (bb->out_count) + mono_unlink_bblock (cfg, bb, bb->out_bb [0]); } } for (bb = cfg->bb_entry; bb; bb = bb->next_bb) @@ -3552,11 +3960,16 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool return cfg; } + /* + if (header->num_clauses) + cfg->disable_ssa = TRUE; + */ + //#define DEBUGSSA "logic_run" #define DEBUGSSA_CLASS "Tests" #ifdef DEBUGSSA - if (!header->num_clauses && !cfg->disable_ssa) { + if (!cfg->disable_ssa) { mono_local_cprop (cfg); #ifndef DISABLE_SSA @@ -3565,7 +3978,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool } #else if (cfg->opt & MONO_OPT_SSA) { - if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) { + if (!(cfg->comp_done & MONO_COMP_SSA) && !cfg->disable_ssa) { #ifndef DISABLE_SSA mono_ssa_compute (cfg); #endif @@ -3716,8 +4129,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool //print_dfn (cfg); /* variables are allocated after decompose, since decompose could create temps */ - if (!cfg->globalra && !COMPILE_LLVM (cfg)) + if (!cfg->globalra && !COMPILE_LLVM (cfg)) { mono_arch_allocate_vars (cfg); + if (cfg->exception_type) + return cfg; + } { MonoBasicBlock *bb; @@ -3777,13 +4193,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool if (COMPILE_LLVM (cfg)) { #ifdef ENABLE_LLVM char *nm; - static gboolean inited; - - if (!inited) { - mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &methods_with_llvm); - mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &methods_without_llvm); - inited = TRUE; - } /* The IR has to be in SSA form for LLVM */ if (!(cfg->comp_done & MONO_COMP_SSA)) { @@ -3791,12 +4200,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool cfg->disable_llvm = TRUE; } - /* FIXME: */ - if (cfg->method->dynamic) { - cfg->exception_message = g_strdup ("dynamic."); - cfg->disable_llvm = TRUE; - } - if (cfg->flags & MONO_CFG_HAS_ARRAY_ACCESS) mono_decompose_array_access_opts (cfg); @@ -3834,130 +4237,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool g_free (id); } - if (cfg->generic_sharing_context) - generic_info_size = sizeof (MonoGenericJitInfo); - else - generic_info_size = 0; - - if (cfg->method->dynamic) { - jinfo = g_malloc0 (MONO_SIZEOF_JIT_INFO + (header->num_clauses * sizeof (MonoJitExceptionInfo)) + - generic_info_size); - } else { - jinfo = mono_domain_alloc0 (cfg->domain, MONO_SIZEOF_JIT_INFO + - (header->num_clauses * sizeof (MonoJitExceptionInfo)) + - generic_info_size); - } - - jinfo->method = method_to_register; - jinfo->code_start = cfg->native_code; - jinfo->code_size = cfg->code_len; - jinfo->used_regs = cfg->used_int_regs; - jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0; - jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */ - jinfo->num_clauses = header->num_clauses; - if (COMPILE_LLVM (cfg)) - jinfo->from_llvm = TRUE; - - if (cfg->generic_sharing_context) { - MonoInst *inst; - MonoGenericJitInfo *gi; - - jinfo->has_generic_jit_info = 1; - - gi = mono_jit_info_get_generic_jit_info (jinfo); - g_assert (gi); - - gi->generic_sharing_context = cfg->generic_sharing_context; - - if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) || - mini_method_get_context (method_to_compile)->method_inst || - method_to_compile->klass->valuetype) { - g_assert (cfg->rgctx_var); - } - - gi->has_this = 1; - - if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) || - mini_method_get_context (method_to_compile)->method_inst || - method_to_compile->klass->valuetype) { - inst = cfg->rgctx_var; - g_assert (inst->opcode == OP_REGOFFSET); - } else { - inst = cfg->args [0]; - } - - if (inst->opcode == OP_REGVAR) { - gi->this_in_reg = 1; - gi->this_reg = inst->dreg; - } else { - g_assert (inst->opcode == OP_REGOFFSET); -#ifdef TARGET_X86 - g_assert (inst->inst_basereg == X86_EBP); -#elif defined(TARGET_AMD64) - g_assert (inst->inst_basereg == X86_EBP || inst->inst_basereg == X86_ESP); -#endif - g_assert (inst->inst_offset >= G_MININT32 && inst->inst_offset <= G_MAXINT32); - - gi->this_in_reg = 0; - gi->this_reg = inst->inst_basereg; - gi->this_offset = inst->inst_offset; - } - } - - if (header->num_clauses) { - int i; - - for (i = 0; i < header->num_clauses; i++) { - MonoExceptionClause *ec = &header->clauses [i]; - MonoJitExceptionInfo *ei = &jinfo->clauses [i]; - MonoBasicBlock *tblock; - MonoInst *exvar; - - ei->flags = ec->flags; - - 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]; - g_assert (tblock); - ei->data.filter = cfg->native_code + tblock->native_offset; - } else { - ei->data.catch_class = ec->data.catch_class; - } - - tblock = cfg->cil_offset_to_bb [ec->try_offset]; - g_assert (tblock); - ei->try_start = cfg->native_code + tblock->native_offset; - g_assert (tblock->native_offset); - tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len]; - g_assert (tblock); - ei->try_end = cfg->native_code + tblock->native_offset; - g_assert (tblock->native_offset); - tblock = cfg->cil_offset_to_bb [ec->handler_offset]; - g_assert (tblock); - ei->handler_start = cfg->native_code + tblock->native_offset; - } - } - - /* - * Its possible to generate dwarf unwind info for xdebug etc, but not actually - * using it during runtime, hence the define. - */ -#ifdef MONO_ARCH_HAVE_XP_UNWIND - if (cfg->encoded_unwind_ops) { - jinfo->used_regs = mono_cache_unwind_info (cfg->encoded_unwind_ops, cfg->encoded_unwind_ops_len); - g_free (cfg->encoded_unwind_ops); - } else if (cfg->unwind_ops) { - guint32 info_len; - guint8 *unwind_info = mono_unwind_ops_encode (cfg->unwind_ops, &info_len); - - jinfo->used_regs = mono_cache_unwind_info (unwind_info, info_len); - g_free (unwind_info); - } -#endif - - cfg->jit_info = jinfo; + cfg->jit_info = create_jit_info (cfg, method_to_compile); #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS if (cfg->extend_live_ranges) { @@ -3971,19 +4251,14 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool mini_gc_create_gc_map (cfg); - if (cfg->seq_points) { - // FIXME: dynamic methods - mono_domain_lock (domain); - g_hash_table_insert (domain_jit_info (domain)->seq_points, method_to_register, cfg->seq_points); - mono_domain_unlock (domain); - } + mono_save_seq_point_info (cfg); if (!cfg->compile_aot) { mono_domain_lock (cfg->domain); - mono_jit_info_table_add (cfg->domain, jinfo); + mono_jit_info_table_add (cfg->domain, cfg->jit_info); if (cfg->method->dynamic) - mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo; + mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = cfg->jit_info; mono_domain_unlock (cfg->domain); } @@ -4231,12 +4506,12 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in } if (ex) { - mono_destroy_compile (cfg); - *jit_ex = ex; - if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION) mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED); + mono_destroy_compile (cfg); + *jit_ex = ex; + return NULL; } @@ -4301,8 +4576,13 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in mono_raise_exception (exc); } - if (prof_options & MONO_PROFILE_JIT_COMPILATION) - mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK); + if (prof_options & MONO_PROFILE_JIT_COMPILATION) { + if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) + /* 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); + else + mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK); + } mono_runtime_class_init (vtable); return code; @@ -4770,6 +5050,13 @@ SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler) } #endif +#ifndef HOST_WIN32 + if (mono_aot_is_pagefault (info->si_addr)) { + mono_aot_handle_pagefault (info->si_addr); + return; + } +#endif + /* The thread might no be registered with the runtime */ if (!mono_domain_get () || !jit_tls) { if (mono_chain_signal (SIG_HANDLER_PARAMS)) @@ -4843,7 +5130,7 @@ mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, Mon guint8 *addr = NULL; if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) { - return mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING, + return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING, domain, NULL); } @@ -4869,9 +5156,10 @@ mini_get_imt_trampoline (void) #endif gpointer -mini_get_vtable_trampoline (void) +mini_get_vtable_trampoline (int slot_index) { static gpointer tramp = NULL; + if (!tramp) tramp = mono_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL); return tramp; @@ -4911,9 +5199,13 @@ mini_parse_debug_options (void) debug_options.gdb = TRUE; else if (!strcmp (arg, "explicit-null-checks")) debug_options.explicit_null_checks = TRUE; + else if (!strcmp (arg, "gen-seq-points")) + debug_options.gen_seq_points = TRUE; + else if (!strcmp (arg, "init-stacks")) + debug_options.init_stacks = TRUE; else { fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg); - fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks'\n"); + fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'init-stacks'\n"); exit (1); } } @@ -4975,10 +5267,9 @@ mini_create_jit_domain_info (MonoDomain *domain) info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); info->delegate_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); - info->static_rgctx_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); info->runtime_invoke_hash = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free); - info->seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL); + info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, g_free); info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL); domain->runtime_info = info; @@ -5033,9 +5324,12 @@ mini_free_jit_domain_info (MonoDomain *domain) g_hash_table_destroy (info->jump_trampoline_hash); g_hash_table_destroy (info->jit_trampoline_hash); g_hash_table_destroy (info->delegate_trampoline_hash); - g_hash_table_destroy (info->static_rgctx_trampoline_hash); + if (info->static_rgctx_trampoline_hash) + g_hash_table_destroy (info->static_rgctx_trampoline_hash); g_hash_table_destroy (info->llvm_vcall_trampoline_hash); g_hash_table_destroy (info->runtime_invoke_hash); + g_hash_table_destroy (info->seq_points); + g_hash_table_destroy (info->arch_seq_points); if (info->agent_info) mono_debugger_agent_free_domain_info (domain); @@ -5085,6 +5379,15 @@ mini_init (const char *filename, const char *runtime_version) callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr; callbacks.get_runtime_build_info = mono_get_runtime_build_info; +#ifdef MONO_ARCH_HAVE_IMT + if (mono_use_imt) { + if (!mono_use_llvm) { + /* LLVM needs a per-method vtable trampoline */ + callbacks.get_vtable_trampoline = mini_get_vtable_trampoline; + } + } +#endif + mono_install_callbacks (&callbacks); mono_arch_cpu_init (); @@ -5176,6 +5479,10 @@ mini_init (const char *filename, const char *runtime_version) mono_install_get_class_from_name (mono_aot_get_class_from_name); mono_install_jit_info_find_in_aot (mono_aot_find_jit_info); + if (debug_options.collect_pagefault_stats) { + mono_aot_set_make_unreadable (TRUE); + } + if (runtime_version) domain = mono_init_version (filename, runtime_version); else @@ -5193,8 +5500,6 @@ mini_init (const char *filename, const char *runtime_version) else mono_install_imt_thunk_builder (mono_arch_build_imt_thunk); if (!mono_use_llvm) { - /* LLVM needs a per-method vtable trampoline */ - mono_install_vtable_trampoline (mini_get_vtable_trampoline ()); /* * The imt code in mono_magic_trampoline () can't handle LLVM code. By disabling * this, we force iface calls to go through the llvm vcall trampoline. @@ -5242,7 +5547,9 @@ mini_init (const char *filename, const char *runtime_version) register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE); register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE); +#ifdef MONO_ARCH_HAVE_THROW_EXCEPTION_BY_NAME register_icall (mono_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); +#endif #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE); @@ -5402,6 +5709,8 @@ mini_init (const char *filename, const char *runtime_version) register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE); register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE); register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE); + register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE); + register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE); #endif mono_generic_sharing_init (); @@ -5613,9 +5922,9 @@ char* mono_get_runtime_build_info (void) { if (mono_build_date) - return g_strdup_printf ("%s %s", FULL_VERSION, mono_build_date); + return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date); else - return g_strdup_printf ("%s", FULL_VERSION); + return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION); } static void @@ -5673,7 +5982,11 @@ void mono_precompile_assemblies () g_hash_table_destroy (assemblies); } +#ifndef DISABLE_JIT + void* mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) { return mono_arch_instrument_epilog_full (cfg, func, p, enable_arguments, FALSE); } + +#endif