X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mono%2Fmini%2Fmini.c;h=397fcf0f0dae3d0627991e6fe75fb61a519962b9;hb=101d610a1ce7558d6d3dcac30393d7024fa711d3;hp=8f7772f061c59122749d858f932f804c045f139d;hpb=086141c0bd604eae185495c95a88ee67edb1ed1f;p=mono.git diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 8f7772f061c..397fcf0f0da 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include #include @@ -114,8 +114,7 @@ static int methods_with_llvm, methods_without_llvm; /* * This flag controls whenever the runtime uses LLVM compiled code. * Enabling this causes different/slower code paths to be used, which is why it - * defaults to FALSE if ENABLE_LLVM is not defined, i.e. the runtime is only capable of - * running AOT code compiled by LLVM. + * defaults to FALSE. * Changes when this flag is set include: * - a per method vtable trampoline is used to handle virtual calls, instead of only * one trampoline. @@ -133,8 +132,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; @@ -170,6 +168,12 @@ mono_running_on_valgrind (void) return FALSE; } +typedef struct { + MonoExceptionClause *clause; + MonoBasicBlock *basic_block; + int start_offset; +} TryBlockHole; + typedef struct { void *ip; MonoMethod *method; @@ -397,6 +401,34 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token) { return mono_jump_info_token_new2 (mp, image, token, NULL); } + +/* + * mono_tramp_info_create: + * + * Create a MonoTrampInfo structure from the arguments. This function assumes ownership + * of NAME, JI, and UNWIND_OPS. + */ +MonoTrampInfo* +mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops) +{ + MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1); + + info->name = (char*)name; + info->code = code; + info->code_size = code_size; + info->ji = ji; + info->unwind_ops = unwind_ops; + + return info; +} + +void +mono_tramp_info_free (MonoTrampInfo *info) +{ + g_free (info->name); + + // FIXME: ji + unwind_ops +} #define MONO_INIT_VARINFO(vi,id) do { \ (vi)->range.first_use.pos.bid = 0xffff; \ @@ -471,8 +503,7 @@ mono_bblocks_linked (MonoBasicBlock *bb1, MonoBasicBlock *bb2) static int mono_find_block_region_notry (MonoCompile *cfg, int offset) { - MonoMethod *method = cfg->method; - MonoMethodHeader *header = mono_method_get_header (method); + MonoMethodHeader *header = cfg->header; MonoExceptionClause *clause; int i; @@ -505,7 +536,7 @@ 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); + MonoMethodHeader *header = cfg->header; /* * This can happen if a try clause is nested inside a finally clause. @@ -1219,18 +1250,6 @@ mini_class_is_system_array (MonoClass *klass) return FALSE; } -static MonoJitICallInfo **emul_opcode_map = NULL; - -MonoJitICallInfo * -mono_find_jit_opcode_emulation (int opcode) -{ - g_assert (opcode >= 0 && opcode <= OP_LAST); - if (emul_opcode_map) - return emul_opcode_map [opcode]; - else - return NULL; -} - gboolean mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method) { @@ -1279,15 +1298,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; } } @@ -1439,6 +1462,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))); @@ -1498,6 +1522,10 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s 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: @@ -1520,6 +1548,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: @@ -1544,6 +1574,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: @@ -1663,6 +1695,9 @@ 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 @@ -1730,6 +1765,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); @@ -1773,6 +1809,10 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st 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]; @@ -1798,6 +1838,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: @@ -1822,6 +1864,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: @@ -1880,7 +1924,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) { @@ -1950,21 +1994,50 @@ mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_a return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align); } +#define EMUL_HIT_SHIFT 3 +#define EMUL_HIT_MASK ((1 << EMUL_HIT_SHIFT) - 1) +/* small hit bitmap cache */ +static mono_byte emul_opcode_hit_cache [(OP_LAST>>EMUL_HIT_SHIFT) + 1] = {0}; +static short emul_opcode_num = 0; +static short emul_opcode_alloced = 0; +static short *emul_opcode_opcodes = NULL; +static MonoJitICallInfo **emul_opcode_map = NULL; + +MonoJitICallInfo * +mono_find_jit_opcode_emulation (int opcode) +{ + g_assert (opcode >= 0 && opcode <= OP_LAST); + if (emul_opcode_hit_cache [opcode >> (EMUL_HIT_SHIFT + 3)] & (1 << (opcode & EMUL_HIT_MASK))) { + int i; + for (i = 0; i < emul_opcode_num; ++i) { + if (emul_opcode_opcodes [i] == opcode) + return emul_opcode_map [i]; + } + } + return NULL; +} + void mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw) { MonoJitICallInfo *info; MonoMethodSignature *sig = mono_create_icall_signature (sigstr); - if (!emul_opcode_map) - emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1); - g_assert (!sig->hasthis); g_assert (sig->param_count < 3); info = mono_register_jit_icall (func, name, sig, no_throw); - emul_opcode_map [opcode] = info; + if (emul_opcode_num >= emul_opcode_alloced) { + int incr = emul_opcode_alloced? emul_opcode_alloced/2: 16; + emul_opcode_alloced += incr; + emul_opcode_map = g_realloc (emul_opcode_map, sizeof (emul_opcode_map [0]) * emul_opcode_alloced); + emul_opcode_opcodes = g_realloc (emul_opcode_opcodes, sizeof (emul_opcode_opcodes [0]) * emul_opcode_alloced); + } + emul_opcode_map [emul_opcode_num] = info; + emul_opcode_opcodes [emul_opcode_num] = opcode; + emul_opcode_num++; + emul_opcode_hit_cache [opcode >> (EMUL_HIT_SHIFT + 3)] |= (1 << (opcode & EMUL_HIT_MASK)); } static void @@ -2128,6 +2201,8 @@ mono_verify_cfg (MonoCompile *cfg) void mono_destroy_compile (MonoCompile *cfg) { + if (cfg->header) + mono_metadata_free_mh (cfg->header); //mono_mempool_stats (cfg->mempool); mono_free_loop_info (cfg); if (cfg->rs) @@ -2346,7 +2421,7 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func) } static void -mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func) +mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func) { MonoInternalThread *thread; void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort); @@ -2368,7 +2443,7 @@ mono_thread_abort_dummy (MonoObject *obj) } static void -mono_thread_attach_cb (gsize tid, gpointer stack_start) +mono_thread_attach_cb (intptr_t tid, gpointer stack_start) { MonoInternalThread *thread; void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy); @@ -2419,18 +2494,19 @@ static MonoInst* mono_create_tls_get (MonoCompile *cfg, int offset) { #ifdef MONO_ARCH_HAVE_TLS_GET - MonoInst* ins; - - 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; -#else - return NULL; + if (MONO_ARCH_HAVE_TLS_GET) { + MonoInst* ins; + + 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; + } #endif + return NULL; } MonoInst* @@ -2445,6 +2521,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) { @@ -2699,6 +2781,17 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, case MONO_PATCH_INFO_SFLDA: { MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent); + if (mono_class_field_is_special_static (patch_info->data.field)) { + gpointer addr = NULL; + + mono_domain_lock (domain); + if (domain->special_static_fields) + addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field); + mono_domain_unlock (domain); + g_assert (addr); + return addr; + } + g_assert (vtable); if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method))) /* Done by the generated code */ @@ -2863,6 +2956,8 @@ mono_add_seq_point (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, int nat bb->last_seq_point = ins; } +#ifndef DISABLE_JIT + static void mono_compile_create_vars (MonoCompile *cfg) { @@ -2870,7 +2965,7 @@ mono_compile_create_vars (MonoCompile *cfg) MonoMethodHeader *header; int i; - header = mono_method_get_header (cfg->method); + header = cfg->header; sig = mono_method_signature (cfg->method); @@ -2923,6 +3018,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) { @@ -3028,10 +3125,29 @@ 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, *in_bb; + MonoBasicBlock *bb; GSList *bb_seq_points, *l; MonoInst *last; MonoDomain *domain = cfg->domain; @@ -3074,32 +3190,37 @@ mono_save_seq_point_info (MonoCompile *cfg) 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 */ - /* - * FIXME: What if the prev bb doesn't have a seq point, but - * one of its predecessors has ? - */ - 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)); - } + 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; + int j, next_index; sp->next_len = g_slist_length (next [i]); sp->next = g_new (int, sp->next_len); j = 0; - for (l = next [i]; l; l = l->next) - sp->next [j ++] = GPOINTER_TO_UINT (l->data); + 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); @@ -3157,6 +3278,7 @@ mono_codegen (MonoCompile *cfg) bb->native_offset = cfg->code_len; //if ((bb == cfg->bb_entry) || !(bb->region == -1 && !bb->dfn)) mono_arch_output_basic_block (cfg, bb); + bb->native_length = cfg->code_len - bb->native_offset; if (bb == cfg->bb_exit) { cfg->epilog_begin = cfg->code_len; @@ -3273,6 +3395,313 @@ compute_reachable (MonoBasicBlock *bb) } } +static MonoJitInfo* +create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) +{ + GSList *tmp; + MonoMethodHeader *header; + MonoJitInfo *jinfo; + int num_clauses; + int generic_info_size; + int holes_size = 0, num_holes = 0; + + g_assert (method_to_compile == cfg->method); + header = cfg->header; + + if (cfg->generic_sharing_context) + generic_info_size = sizeof (MonoGenericJitInfo); + else + generic_info_size = 0; + + if (cfg->try_block_holes) { + for (tmp = cfg->try_block_holes; tmp; tmp = tmp->next) { + TryBlockHole *hole = tmp->data; + MonoExceptionClause *ec = hole->clause; + int hole_end = hole->basic_block->native_offset + hole->basic_block->native_length; + MonoBasicBlock *clause_last_bb = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len]; + g_assert (clause_last_bb); + + /* Holes at the end of a try region can be represented by simply reducing the size of the block itself.*/ + if (clause_last_bb->native_offset != hole_end) + ++num_holes; + } + if (num_holes) + holes_size = sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo); + if (G_UNLIKELY (cfg->verbose_level >= 4)) + printf ("Number of try block holes %d\n", num_holes); + } + + 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 + holes_size); + } else { + jinfo = mono_domain_alloc0 (cfg->domain, MONO_SIZEOF_JIT_INFO + + (num_clauses * sizeof (MonoJitExceptionInfo)) + + generic_info_size + holes_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 (num_holes) { + MonoTryBlockHoleTableJitInfo *table; + int i; + + jinfo->has_try_block_holes = 1; + table = mono_jit_info_get_try_block_hole_table_info (jinfo); + table->num_holes = (guint16)num_holes; + i = 0; + for (tmp = cfg->try_block_holes; tmp; tmp = tmp->next) { + guint32 start_bb_offset; + MonoTryBlockHoleJitInfo *hole; + TryBlockHole *hole_data = tmp->data; + MonoExceptionClause *ec = hole_data->clause; + int hole_end = hole_data->basic_block->native_offset + hole_data->basic_block->native_length; + MonoBasicBlock *clause_last_bb = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len]; + g_assert (clause_last_bb); + + /* Holes at the end of a try region can be represented by simply reducing the size of the block itself.*/ + if (clause_last_bb->native_offset == hole_end) + continue; + + start_bb_offset = hole_data->start_offset - hole_data->basic_block->native_offset; + hole = &table->holes [i++]; + hole->clause = hole_data->clause - &header->clauses [0]; + hole->offset = (guint32)hole_data->start_offset; + hole->length = (guint16)(hole_data->basic_block->native_length - start_bb_offset); + + if (G_UNLIKELY (cfg->verbose_level >= 4)) + printf ("\tTry block hole at eh clause %d offset %x length %x\n", hole->clause, hole->offset, hole->length); + } + g_assert (i == num_holes); + } + + 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; + + for (tmp = cfg->try_block_holes; tmp; tmp = tmp->next) { + TryBlockHole *hole = tmp->data; + gpointer hole_end = cfg->native_code + (hole->basic_block->native_offset + hole->basic_block->native_length); + if (hole->clause == ec && hole_end == ei->try_end) { + if (G_UNLIKELY (cfg->verbose_level >= 4)) + printf ("\tShortening try block %d from %x to %x\n", i, (int)((guint8*)ei->try_end - cfg->native_code), hole->start_offset); + + ei->try_end = cfg->native_code + hole->start_offset; + break; + } + } + + if (ec->flags == MONO_EXCEPTION_CLAUSE_FINALLY) { + int end_offset; + if (ec->handler_offset + ec->handler_len < header->code_size) { + tblock = cfg->cil_offset_to_bb [ec->handler_offset + ec->handler_len]; + g_assert (tblock); + end_offset = tblock->native_offset; + } else { + end_offset = cfg->epilog_begin; + } + ei->data.handler_end = cfg->native_code + end_offset; + } + } + + if (G_UNLIKELY (cfg->verbose_level >= 4)) { + for (i = 0; i < jinfo->num_clauses; i++) { + MonoJitExceptionInfo *ei = &jinfo->clauses [i]; + int start = (guint8*)ei->try_start - cfg->native_code; + int end = (guint8*)ei->try_end - cfg->native_code; + int handler = (guint8*)ei->handler_start - cfg->native_code; + + printf ("JitInfo EH clause %d flags %x try %x-%x handler %x\n", i, ei->flags, start, end, handler); + } + } + + } + + /* + * 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; +} +#endif + +/* + * mini_get_shared_method: + * + * Return the method which is actually compiled/registered when doing generic sharing. + */ +MonoMethod* +mini_get_shared_method (MonoMethod *method) +{ + MonoGenericContext shared_context; + MonoMethod *declaring_method, *res; + int i; + gboolean partial = FALSE; + + if (method->is_generic || method->klass->generic_container) + declaring_method = method; + else + declaring_method = mono_method_get_declaring_generic_method (method); + + if (declaring_method->is_generic) + shared_context = mono_method_get_generic_container (declaring_method)->context; + else + shared_context = declaring_method->klass->generic_container->context; + + /* Handle partial sharing */ + if (method != declaring_method && method->is_inflated && !mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE)) { + MonoGenericContext *context = mono_method_get_context (method); + MonoGenericInst *inst; + MonoType **type_argv; + + /* + * Create the shared context by replacing the ref type arguments with + * type parameters, and keeping the rest. + */ + partial = TRUE; + inst = context->class_inst; + if (inst) { + type_argv = g_new0 (MonoType*, inst->type_argc); + for (i = 0; i < inst->type_argc; ++i) { + if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR) + type_argv [i] = shared_context.class_inst->type_argv [i]; + else + type_argv [i] = inst->type_argv [i]; + } + + shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv); + g_free (type_argv); + } + + inst = context->method_inst; + if (inst) { + type_argv = g_new0 (MonoType*, inst->type_argc); + for (i = 0; i < inst->type_argc; ++i) { + if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR) + type_argv [i] = shared_context.method_inst->type_argv [i]; + else + type_argv [i] = inst->type_argv [i]; + } + + shared_context.method_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv); + g_free (type_argv); + } + } + + res = mono_class_inflate_generic_method (declaring_method, &shared_context); + if (!partial) { + /* The result should be an inflated method whose parent is not inflated */ + g_assert (!res->klass->is_inflated); + } + return res; +} + +#ifndef DISABLE_JIT /* * mini_method_compile: * @method: the method to compile @@ -3289,14 +3718,14 @@ MonoCompile* mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts) { MonoMethodHeader *header; + MonoMethodSignature *sig; + MonoError err; 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) @@ -3305,9 +3734,13 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool MONO_PROBE_METHOD_COMPILE_BEGIN (method); if (compile_aot) - /* We are passed the original generic method definition */ + /* + * We might get passed the original generic method definition or + * instances with type parameters. + * FIXME: Remove the method->klass->generic_class limitation. + */ try_generic_shared = mono_class_generic_sharing_enabled (method->klass) && - (opts & MONO_OPT_GSHARED) && (method->is_generic || method->klass->generic_container); + (opts & MONO_OPT_GSHARED) && ((method->is_generic || method->klass->generic_container) || (!method->klass->generic_class && mono_method_is_generic_sharable_impl (method, TRUE))); else try_generic_shared = mono_class_generic_sharing_enabled (method->klass) && (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method, FALSE); @@ -3327,25 +3760,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool restart_compile: if (try_generic_shared) { - MonoMethod *declaring_method; - MonoGenericContext *shared_context; - - if (compile_aot) { - declaring_method = method; - } else { - declaring_method = mono_method_get_declaring_generic_method (method); - if (method->klass->generic_class) - g_assert (method->klass->generic_class->container_class == declaring_method->klass); - else - g_assert (method->klass == declaring_method->klass); - } - - if (declaring_method->is_generic) - shared_context = &(mono_method_get_generic_container (declaring_method)->context); - else - shared_context = &declaring_method->klass->generic_container->context; - - method_to_compile = mono_class_inflate_generic_method (declaring_method, shared_context); + method_to_compile = mini_get_shared_method (method); g_assert (method_to_compile); } else { method_to_compile = method; @@ -3353,6 +3768,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool cfg = g_new0 (MonoCompile, 1); cfg->method = method_to_compile; + cfg->header = mono_method_get_header (cfg->method); cfg->mempool = mono_mempool_new (); cfg->opt = opts; cfg->prof_options = mono_profiler_get_events (); @@ -3378,9 +3794,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool } if (cfg->generic_sharing_context) { - MonoGenericContext object_context = mono_method_construct_object_context (method_to_compile); - - method_to_register = mono_class_inflate_generic_method (method_to_compile, &object_context); + method_to_register = method_to_compile; } else { g_assert (method == method_to_compile); method_to_register = method; @@ -3406,7 +3820,18 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool } } - header = mono_method_get_header (method_to_compile); + mono_error_init (&err); + sig = mono_method_signature_checked (cfg->method, &err); + if (!sig) { + cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD; + cfg->exception_message = g_strdup (mono_error_get_message (&err)); + mono_error_cleanup (&err); + if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ()) + MONO_PROBE_METHOD_COMPILE_END (method, FALSE); + return cfg; + } + + header = cfg->header; if (!header) { MonoLoaderError *error; @@ -3422,10 +3847,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool } if (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. + /* + * FIXME: LLLVM 2.6/SVN no longer seems to generate correct exception info + * for JITted code. */ cfg->exception_message = g_strdup ("clauses"); cfg->disable_llvm = TRUE; @@ -3488,6 +3912,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) { @@ -3499,15 +3926,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; } if (getenv ("MONO_VERBOSE_METHOD")) { - if (strcmp (cfg->method->name, getenv ("MONO_VERBOSE_METHOD")) == 0) - cfg->verbose_level = 4; + char *name = getenv ("MONO_VERBOSE_METHOD"); + + if ((strchr (name, '.') > 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 { + if (strcmp (cfg->method->name, getenv ("MONO_VERBOSE_METHOD")) == 0) + cfg->verbose_level = 4; + } } ip = (guint8 *)header->code; @@ -3518,7 +3960,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool if (COMPILE_LLVM (cfg)) g_print ("converting llvm method %s\n", mono_method_full_name (method, TRUE)); else if (cfg->generic_sharing_context) - g_print ("converting shared method %s\n", mono_method_full_name (method, TRUE)); + g_print ("converting shared method %s\n", mono_method_full_name (method_to_compile, TRUE)); else g_print ("converting method %s\n", mono_method_full_name (method, TRUE)); } @@ -3855,7 +4297,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool mono_decompose_array_access_opts (cfg); if (cfg->got_var) { +#ifndef MONO_ARCH_GOT_REG GList *regs; +#endif + int got_reg; g_assert (cfg->got_var_allocated); @@ -3866,13 +4311,17 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool * branches problem. Testcase: mcs crash in * System.MonoCustomAttrs:GetCustomAttributes. */ +#ifdef MONO_ARCH_GOT_REG + got_reg = MONO_ARCH_GOT_REG; +#else regs = mono_arch_get_global_int_regs (cfg); g_assert (regs); + got_reg = GPOINTER_TO_INT (regs->data); + g_list_free (regs); +#endif cfg->got_var->opcode = OP_REGVAR; - cfg->got_var->dreg = GPOINTER_TO_INT (regs->data); + cfg->got_var->dreg = got_reg; cfg->used_int_regs |= 1LL << cfg->got_var->dreg; - - g_list_free (regs); } /* @@ -3891,7 +4340,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool } if ((cfg->opt & MONO_OPT_LINEARS) && !cfg->globalra) { - GList *vars, *regs; + GList *vars, *regs, *l; /* fixme: maybe we can avoid to compute livenesss here if already computed ? */ cfg->comp_done &= ~MONO_COMP_LIVENESS; @@ -3900,8 +4349,15 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool if ((vars = mono_arch_get_allocatable_int_vars (cfg))) { regs = mono_arch_get_global_int_regs (cfg); - if (cfg->got_var) - regs = g_list_delete_link (regs, regs); + /* Remove the reg reserved for holding the GOT address */ + if (cfg->got_var) { + for (l = regs; l; l = l->next) { + if (GPOINTER_TO_UINT (l->data) == cfg->got_var->dreg) { + regs = g_list_delete_link (regs, l); + break; + } + } + } mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs); } } @@ -3987,10 +4443,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool if (!cfg->disable_llvm) mono_llvm_emit_method (cfg); - if (!cfg->disable_llvm && header->num_clauses && !cfg->compile_aot && cfg->llvm_ex_info_len != header->num_clauses) { - cfg->exception_message = g_strdup ("clause num mismatch."); - cfg->disable_llvm = TRUE; - } if (cfg->disable_llvm) { if (cfg->verbose_level >= 1) { //nm = mono_method_full_name (cfg->method, TRUE); @@ -4023,139 +4475,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; - } - - if (COMPILE_LLVM (cfg)) { - if (!cfg->compile_aot) { - g_assert (cfg->llvm_ex_info && i < cfg->llvm_ex_info_len); - ei->try_start = cfg->llvm_ex_info [i].try_start; - ei->try_end = cfg->llvm_ex_info [i].try_end; - ei->handler_start = cfg->llvm_ex_info [i].handler_start; - } - } else { - 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) { @@ -4173,10 +4493,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool 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); } @@ -4190,7 +4510,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool 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) / mono_method_get_header (method)->code_size; + 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); @@ -4215,17 +4535,29 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool #endif /* DISABLE_JIT */ -static MonoJitInfo* -lookup_generic_method (MonoDomain *domain, MonoMethod *method) +MonoJitInfo* +mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *method) { - MonoMethod *open_method; + static gboolean inited = FALSE; + static int lookups = 0; + static int failed_lookups = 0; + MonoJitInfo *ji; - if (!mono_method_is_generic_sharable_impl (method, FALSE)) - return NULL; + ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, mini_get_shared_method (method)); + if (ji && !ji->has_generic_jit_info) + ji = NULL; + + if (!inited) { + mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups); + mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups); + inited = TRUE; + } - open_method = mono_method_get_declaring_generic_method (method); + ++lookups; + if (!ji) + ++failed_lookups; - return mono_domain_lookup_shared_generic (domain, open_method); + return ji; } /* @@ -4239,7 +4571,9 @@ lookup_method_inner (MonoDomain *domain, MonoMethod *method) if (ji) return ji; - return lookup_generic_method (domain, method); + if (!mono_method_is_generic_sharable_impl (method, FALSE)) + return NULL; + return mono_domain_lookup_shared_generic (domain, method); } static MonoJitInfo* @@ -4256,6 +4590,38 @@ lookup_method (MonoDomain *domain, MonoMethod *method) return info; } +#if ENABLE_JIT_MAP +static FILE* perf_map_file = NULL; + +void +mono_enable_jit_map (void) +{ + if (!perf_map_file) { + char name [64]; + g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ()); + unlink (name); + perf_map_file = fopen (name, "w"); + } +} + +void +mono_emit_jit_tramp (void *start, int size, const char *desc) +{ + if (perf_map_file) + fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc); +} + +void +mono_emit_jit_map (MonoJitInfo *jinfo) +{ + if (perf_map_file) { + char *name = mono_method_full_name (jinfo->method, TRUE); + mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name); + g_free (name); + } +} +#endif + static gpointer mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt, MonoException **jit_ex) { @@ -4282,6 +4648,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in } #endif +#ifndef DISABLE_JIT if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) { MonoMethod *nm; @@ -4340,6 +4707,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in } return NULL; } +#endif if (mono_aot_only) { char *fullname = mono_method_full_name (method, TRUE); @@ -4424,12 +4792,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; } @@ -4467,6 +4835,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in mono_destroy_compile (cfg); +#ifndef DISABLE_JIT if (domain_jit_info (target_domain)->jump_target_hash) { MonoJumpInfo patch_info; GSList *list, *tmp; @@ -4483,6 +4852,8 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in g_slist_free (list); } + mono_emit_jit_map (jinfo); +#endif mono_domain_unlock (target_domain); mono_loader_unlock (); @@ -4494,8 +4865,17 @@ 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) { + 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); + } + } else { + mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK); + } + } mono_runtime_class_init (vtable); return code; @@ -4942,18 +5322,19 @@ SIG_HANDLER_SIGNATURE (mono_sigill_signal_handler) mono_arch_handle_exception (ctx, exc, FALSE); } +#if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32) +#define HAVE_SIG_INFO +#endif + void SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler) { -#ifndef MONO_ARCH_SIGSEGV_ON_ALTSTACK - MonoException *exc = NULL; -#endif MonoJitInfo *ji; MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); GET_CONTEXT; -#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED +#if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO) if (mono_arch_is_single_step_event (info, ctx)) { mono_debugger_agent_single_step_event (ctx); return; @@ -4963,6 +5344,13 @@ SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler) } #endif +#if !defined(HOST_WIN32) && defined(HAVE_SIG_INFO) + 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)) @@ -5006,7 +5394,7 @@ SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler) mono_handle_native_sigsegv (SIGSEGV, ctx); } - mono_arch_handle_exception (ctx, exc, FALSE); + mono_arch_handle_exception (ctx, NULL, FALSE); #endif } @@ -5036,7 +5424,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); } @@ -5062,9 +5450,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; @@ -5106,9 +5495,11 @@ mini_parse_debug_options (void) 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); } } @@ -5268,7 +5659,7 @@ mini_init (const char *filename, const char *runtime_version) #endif #ifdef MONO_ARCH_HAVE_TLS_GET - mono_runtime_set_has_tls_get (TRUE); + mono_runtime_set_has_tls_get (MONO_ARCH_HAVE_TLS_GET); #else mono_runtime_set_has_tls_get (FALSE); #endif @@ -5282,6 +5673,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 (); @@ -5316,8 +5716,6 @@ mini_init (const char *filename, const char *runtime_version) if (!g_thread_supported ()) g_thread_init (NULL); - mono_gc_base_init (); - mono_jit_tls_id = TlsAlloc (); setup_jit_tls_data ((gpointer)-1, mono_thread_abort); @@ -5373,6 +5771,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 @@ -5390,8 +5792,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. @@ -5439,7 +5839,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); @@ -5565,6 +5967,10 @@ mini_init (const char *filename, const char *runtime_version) register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE); #endif +#ifdef COMPRESSED_INTERFACE_BITMAP + register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE); +#endif + #if SIZEOF_REGISTER == 4 mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE); #endif @@ -5599,6 +6005,7 @@ 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 @@ -5768,6 +6175,7 @@ mini_cleanup (MonoDomain *domain) mono_code_manager_destroy (global_codeman); g_hash_table_destroy (jit_icall_name_hash); g_free (emul_opcode_map); + g_free (emul_opcode_opcodes); mono_arch_cleanup (); @@ -5871,7 +6279,22 @@ 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); } + +void +mono_cfg_add_try_hole (MonoCompile *cfg, MonoExceptionClause *clause, guint8 *start, MonoBasicBlock *bb) +{ + TryBlockHole *hole = mono_mempool_alloc (cfg->mempool, sizeof (TryBlockHole)); + hole->clause = clause; + hole->start_offset = start - cfg->native_code; + hole->basic_block = bb; + + cfg->try_block_holes = g_slist_append_mempool (cfg->mempool, cfg->try_block_holes, hole); +} + +#endif