X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmethod-to-ir.c;h=a34d674696d4845b391a8766669a311992625dfd;hb=5b558abeeb255a3179d4ca6a85617e051c6abd38;hp=8a4ba0eb880d7a0006e53448b44fa5985bee451c;hpb=0c29256779c407bccafb2cf17a67e2a37d3681ce;p=mono.git diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index 8a4ba0eb880..a34d674696d 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -98,7 +98,10 @@ goto exception_exit; \ } \ } while (0) - +#define OUT_OF_MEMORY_FAILURE do { \ + mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY); \ + goto exception_exit; \ + } while (0) /* Determine whenever 'ins' represents a load of the 'this' argument */ #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg)) @@ -112,14 +115,14 @@ MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMetho void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native); void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass); -/* helper methods signature */ -extern MonoMethodSignature *helper_sig_class_init_trampoline; -extern MonoMethodSignature *helper_sig_domain_get; -extern MonoMethodSignature *helper_sig_generic_class_init_trampoline; -extern MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm; -extern MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline; -extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline; -extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm; +/* helper methods signatures */ +static MonoMethodSignature *helper_sig_class_init_trampoline = NULL; +static MonoMethodSignature *helper_sig_domain_get = NULL; +static MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL; +static MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm = NULL; +static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL; +static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL; +static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL; /* * Instruction metadata @@ -200,6 +203,44 @@ mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type) return alloc_dreg (cfg, stack_type); } +/* + * mono_alloc_ireg_ref: + * + * Allocate an IREG, and mark it as holding a GC ref. + */ +guint32 +mono_alloc_ireg_ref (MonoCompile *cfg) +{ + return alloc_ireg_ref (cfg); +} + +/* + * mono_alloc_ireg_mp: + * + * Allocate an IREG, and mark it as holding a managed pointer. + */ +guint32 +mono_alloc_ireg_mp (MonoCompile *cfg) +{ + return alloc_ireg_mp (cfg); +} + +/* + * mono_alloc_ireg_copy: + * + * Allocate an IREG with the same GC type as VREG. + */ +guint32 +mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg) +{ + if (vreg_is_ref (cfg, vreg)) + return alloc_ireg_ref (cfg); + else if (vreg_is_mp (cfg, vreg)) + return alloc_ireg_mp (cfg); + else + return alloc_ireg (cfg); +} + guint mono_type_to_regmove (MonoCompile *cfg, MonoType *type) { @@ -281,6 +322,18 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg) mono_print_ins_index (-1, tree); } +void +mono_create_helper_signatures (void) +{ + helper_sig_domain_get = mono_create_icall_signature ("ptr"); + helper_sig_class_init_trampoline = mono_create_icall_signature ("void"); + helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void"); + helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr"); + 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"); +} + /* * Can't put this at the beginning, since other files reference stuff from this * file. @@ -304,7 +357,7 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg) #if defined(TARGET_X86) || defined(TARGET_AMD64) #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \ MONO_INST_NEW (cfg, dest, OP_X86_LEA); \ - (dest)->dreg = alloc_preg ((cfg)); \ + (dest)->dreg = alloc_ireg_mp ((cfg)); \ (dest)->sreg1 = (sr1); \ (dest)->sreg2 = (sr2); \ (dest)->inst_imm = (imm); \ @@ -779,7 +832,7 @@ type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) { case OP_LCOMPARE: case OP_ICOMPARE: ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV; - if ((src1->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP)))) + if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP)))) ins->opcode = OP_LCOMPARE; else if (src1->type == STACK_R8) ins->opcode = OP_FCOMPARE; @@ -788,7 +841,7 @@ type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) { break; case OP_ICOMPARE_IMM: ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV; - if ((src1->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP)))) + if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP)))) ins->opcode = OP_LCOMPARE_IMM; break; case CEE_BEQ: @@ -876,7 +929,7 @@ type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) { break; case STACK_PTR: case STACK_MP: -#if SIZEOF_REGISTER == 8 +#if SIZEOF_VOID_P == 8 ins->opcode = OP_LCONV_TO_U; #else ins->opcode = OP_MOVE; @@ -2152,7 +2205,7 @@ mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpoint inline static MonoCallInst * mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, - MonoInst **args, int calli, int virtual, int tail) + MonoInst **args, int calli, int virtual, int tail, int rgctx) { MonoCallInst *call; #ifdef MONO_ARCH_SOFT_FLOAT @@ -2166,6 +2219,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, call->args = args; call->signature = sig; + call->rgctx_reg = rgctx; type_to_eval_stack_type ((cfg), sig->ret, &call->inst); @@ -2247,18 +2301,6 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, return call; } -inline static MonoInst* -mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr) -{ - MonoCallInst *call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE); - - call->inst.sreg1 = addr->dreg; - - MONO_ADD_INS (cfg->cbb, (MonoInst*)call); - - return (MonoInst*)call; -} - static void set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg) { @@ -2275,7 +2317,7 @@ set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rg } inline static MonoInst* -mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg) +mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg) { MonoCallInst *call; int rgctx_reg = -1; @@ -2284,9 +2326,19 @@ mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **ar rgctx_reg = mono_alloc_preg (cfg); MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg); } - call = (MonoCallInst*)mono_emit_calli (cfg, sig, args, addr); + + if (rgctx_arg) + printf ("MOO!\n"); + + call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE); + + call->inst.sreg1 = addr->dreg; + + MONO_ADD_INS (cfg->cbb, (MonoInst*)call); + if (rgctx_arg) set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg); + return (MonoInst*)call; } @@ -2297,13 +2349,19 @@ emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, int static MonoInst* mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, - MonoInst **args, MonoInst *this, MonoInst *imt_arg) + MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg) { gboolean might_be_remote; gboolean virtual = this != NULL; gboolean enable_for_aot = TRUE; int context_used; MonoCallInst *call; + int rgctx_reg = 0; + + if (rgctx_arg) { + rgctx_reg = mono_alloc_preg (cfg); + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg); + } if (method->string_ctor) { /* Create the real signature */ @@ -2326,10 +2384,10 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK); - return mono_emit_calli (cfg, sig, args, addr); + return mono_emit_calli (cfg, sig, args, addr, NULL); } - call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, FALSE); + call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, FALSE, rgctx_arg ? TRUE : FALSE); if (might_be_remote) call->method = mono_marshal_get_remoting_invoke_with_check (method); @@ -2435,34 +2493,16 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign MONO_ADD_INS (cfg->cbb, (MonoInst*)call); - return (MonoInst*)call; -} - -static MonoInst* -mono_emit_rgctx_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, - MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *vtable_arg) -{ - int rgctx_reg = 0; - MonoInst *ins; - MonoCallInst *call; - - if (vtable_arg) { - rgctx_reg = mono_alloc_preg (cfg); - MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg); - } - ins = mono_emit_method_call_full (cfg, method, sig, args, this, imt_arg); - - call = (MonoCallInst*)ins; - if (vtable_arg) - set_rgctx_arg (cfg, call, rgctx_reg, vtable_arg); + if (rgctx_arg) + set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg); - return ins; + return (MonoInst*)call; } MonoInst* mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this) { - return mono_emit_method_call_full (cfg, method, mono_method_signature (method), args, this, NULL); + return mono_emit_method_call_full (cfg, method, mono_method_signature (method), args, this, NULL, NULL); } MonoInst* @@ -2473,7 +2513,7 @@ mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature g_assert (sig); - call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE); + call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE); call->fptr = func; MONO_ADD_INS (cfg->cbb, (MonoInst*)call); @@ -2596,19 +2636,26 @@ create_write_barrier_bitmap (MonoClass *klass, unsigned *wb_bitmap, int offset) static void emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value, int value_reg) { -#ifdef HAVE_SGEN_GC int card_table_shift_bits; gpointer card_table_mask; - guint8 *card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask); + guint8 *card_table; MonoInst *dummy_use; - -#ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER int nursery_shift_bits; size_t nursery_size; + gboolean has_card_table_wb = FALSE; + + if (!cfg->gen_write_barriers) + return; + + card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask); mono_gc_get_nursery (&nursery_shift_bits, &nursery_size); - if (!cfg->compile_aot && card_table && nursery_shift_bits > 0) { +#ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER + has_card_table_wb = TRUE; +#endif + + if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0) { MonoInst *wbarrier; MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER); @@ -2618,9 +2665,7 @@ emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value, int value_ else wbarrier->sreg2 = value_reg; MONO_ADD_INS (cfg->cbb, wbarrier); - } else -#endif - if (card_table) { + } else if (card_table) { int offset_reg = alloc_preg (cfg); int card_reg = alloc_preg (cfg); MonoInst *ins; @@ -2655,7 +2700,6 @@ emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value, int value_ dummy_use->sreg1 = value_reg; MONO_ADD_INS (cfg->cbb, dummy_use); } -#endif } static gboolean @@ -2889,10 +2933,9 @@ emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used) return vtable_var; } else { MonoInst *ins; - int vtable_reg, res_reg; + int vtable_reg; vtable_reg = alloc_preg (cfg); - res_reg = alloc_preg (cfg); EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, G_STRUCT_OFFSET (MonoObject, vtable)); return ins; } @@ -3116,7 +3159,7 @@ handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int co rgctx = emit_get_rgctx (cfg, method, context_used); - return mono_emit_rgctx_calli (cfg, mono_method_signature (method), &val, addr, rgctx); + return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, rgctx); } else { return mono_emit_method_call (cfg, method, &val, NULL); } @@ -3163,7 +3206,7 @@ handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_use reset_cast_details (cfg); } - NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_PTR), obj_reg, sizeof (MonoObject)); + NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject)); MONO_ADD_INS (cfg->cbb, add); add->type = STACK_MP; add->klass = klass; @@ -3273,7 +3316,7 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used) MONO_RGCTX_INFO_GENERIC_METHOD_CODE); MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used); - return mono_emit_rgctx_calli (cfg, mono_method_signature (method), &val, addr, rgctx); + return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, rgctx); } else { return mono_emit_method_call (cfg, method, &val, NULL); } @@ -3425,7 +3468,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us MonoBasicBlock *is_null_bb, *false_bb, *end_bb; int obj_reg = src->dreg; int vtable_reg = alloc_preg (cfg); - int res_reg = alloc_preg (cfg); + int res_reg = alloc_ireg_ref (cfg); MonoInst *klass_inst = NULL; if (context_used) { @@ -4038,18 +4081,20 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 }; EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], G_STRUCT_OFFSET (MonoArray, vector)); - ins->type = STACK_PTR; + ins->klass = mono_class_get_element_class (klass); + ins->type = STACK_MP; return ins; } #endif - add_reg = alloc_preg (cfg); + add_reg = alloc_ireg_mp (cfg); MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size); MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg); NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector)); - ins->type = STACK_PTR; + ins->klass = mono_class_get_element_class (klass); + ins->type = STACK_MP; MONO_ADD_INS (cfg->cbb, ins); return ins; @@ -4060,7 +4105,7 @@ static MonoInst* mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2) { int bounds_reg = alloc_preg (cfg); - int add_reg = alloc_preg (cfg); + int add_reg = alloc_ireg_mp (cfg); int mult_reg = alloc_preg (cfg); int mult2_reg = alloc_preg (cfg); int low1_reg = alloc_preg (cfg); @@ -4286,7 +4331,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } else if (cmethod->klass == mono_defaults.object_class) { if (strcmp (cmethod->name, "GetType") == 0) { - int dreg = alloc_preg (cfg); + int dreg = alloc_ireg_ref (cfg); int vt_reg = alloc_preg (cfg); MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable)); EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type)); @@ -4321,7 +4366,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign */ if ((strcmp (cmethod->name, "GetLength") == 0 || strcmp (cmethod->name, "GetLowerBound") == 0) && args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) { int dreg = alloc_ireg (cfg); - int bounds_reg = alloc_ireg (cfg); + int bounds_reg = alloc_ireg_mp (cfg); MonoBasicBlock *end_bb, *szarray_bb; gboolean get_length = strcmp (cmethod->name, "GetLength") == 0; @@ -4552,7 +4597,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign return NULL; MONO_INST_NEW (cfg, ins, opcode); - ins->dreg = mono_alloc_ireg (cfg); + ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg); ins->inst_basereg = args [0]->dreg; ins->inst_offset = 0; ins->sreg2 = args [1]->dreg; @@ -4590,7 +4635,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign size = 8; if (size == 4) { MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4); - ins->dreg = alloc_ireg (cfg); + ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg); ins->sreg1 = args [0]->dreg; ins->sreg2 = args [1]->dreg; ins->sreg3 = args [2]->dreg; @@ -4598,7 +4643,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign MONO_ADD_INS (cfg->cbb, ins); } else if (size == 8) { MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8); - ins->dreg = alloc_ireg (cfg); + ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg); ins->sreg1 = args [0]->dreg; ins->sreg2 = args [1]->dreg; ins->sreg3 = args [2]->dreg; @@ -4772,7 +4817,7 @@ check_inline_caller_method_name_limit (MonoMethod *caller_method) static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, - guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_allways) + guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_always) { MonoInst *ins, *rvar = NULL; MonoMethodHeader *cheader; @@ -4794,11 +4839,11 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, g_assert (cfg->exception_type == MONO_EXCEPTION_NONE); #if (MONO_INLINE_CALLED_LIMITED_METHODS) - if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod)) + if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod)) return 0; #endif #if (MONO_INLINE_CALLER_LIMITED_METHODS) - if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method)) + if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method)) return 0; #endif @@ -4814,8 +4859,13 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, cheader = mono_method_get_header (cmethod); if (cheader == NULL || mono_loader_get_last_error ()) { + MonoLoaderError *error = mono_loader_get_last_error (); + if (cheader) mono_metadata_free_mh (cheader); + if (inline_always && error) + mono_cfg_set_exception (cfg, error->exception_type); + mono_loader_clear_error (); return 0; } @@ -4880,7 +4930,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, cfg->ret_var_set = prev_ret_var_set; cfg->inline_depth --; - if ((costs >= 0 && costs < 60) || inline_allways) { + if ((costs >= 0 && costs < 60) || inline_always) { if (cfg->verbose_level > 2) printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE)); @@ -5430,6 +5480,105 @@ is_exception_class (MonoClass *class) return FALSE; } +/* + * is_jit_optimizer_disabled: + * + * Determine whenever M's assembly has a DebuggableAttribute with the + * IsJITOptimizerDisabled flag set. + */ +static gboolean +is_jit_optimizer_disabled (MonoMethod *m) +{ + MonoAssembly *ass = m->klass->image->assembly; + MonoCustomAttrInfo* attrs; + static MonoClass *klass; + int i; + gboolean val = FALSE; + + g_assert (ass); + if (ass->jit_optimizer_disabled_inited) + return ass->jit_optimizer_disabled; + + klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute"); + + attrs = mono_custom_attrs_from_assembly (ass); + if (attrs) { + for (i = 0; i < attrs->num_attrs; ++i) { + MonoCustomAttrEntry *attr = &attrs->attrs [i]; + const gchar *p; + int len; + MonoMethodSignature *sig; + + if (!attr->ctor || attr->ctor->klass != klass) + continue; + /* Decode the attribute. See reflection.c */ + len = attr->data_size; + p = (const char*)attr->data; + g_assert (read16 (p) == 0x0001); + p += 2; + + // FIXME: Support named parameters + sig = mono_method_signature (attr->ctor); + if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN) + continue; + /* Two boolean arguments */ + p ++; + val = *p; + } + mono_custom_attrs_free (attrs); + } + + ass->jit_optimizer_disabled = val; + mono_memory_barrier (); + ass->jit_optimizer_disabled_inited = TRUE; + + return val; +} + +static gboolean +is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig) +{ + gboolean supported_tail_call; + int i; + +#ifdef MONO_ARCH_USE_OP_TAIL_CALL + supported_tail_call = MONO_ARCH_USE_OP_TAIL_CALL (mono_method_signature (method), mono_method_signature (cmethod)); +#else + supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret); +#endif + + for (i = 0; i < fsig->param_count; ++i) { + if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR) + /* These can point to the current method's stack */ + supported_tail_call = FALSE; + } + if (fsig->hasthis && cmethod->klass->valuetype) + /* this might point to the current method's stack */ + supported_tail_call = FALSE; + if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) + supported_tail_call = FALSE; + if (cfg->method->save_lmf) + supported_tail_call = FALSE; + if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD) + supported_tail_call = FALSE; + + /* Debugging support */ +#if 0 + if (supported_tail_call) { + static int count = 0; + count ++; + if (getenv ("COUNT")) { + if (count == atoi (getenv ("COUNT"))) + printf ("LAST: %s\n", mono_method_full_name (cmethod, TRUE)); + if (count > atoi (getenv ("COUNT"))) + supported_tail_call = FALSE; + } + } +#endif + + return supported_tail_call; +} + /* * mono_method_to_ir: * @@ -5468,6 +5617,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b gboolean dont_verify, dont_verify_stloc, readonly = FALSE; int context_used; gboolean init_locals, seq_points, skip_dead_blocks; + gboolean disable_inline; + + disable_inline = is_jit_optimizer_disabled (method); /* serialization and xdomain stuff may need access to private fields and methods */ dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE; @@ -5483,6 +5635,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN; dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED; + dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF; image = method->klass->image; header = mono_method_get_header (method); @@ -5577,6 +5730,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b cfg->bb_entry = start_bblock; start_bblock->cil_code = NULL; start_bblock->cil_length = 0; +#if defined(__native_client_codegen__) + MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT); + ins->dreg = alloc_dreg (cfg, STACK_I4); + MONO_ADD_INS (start_bblock, ins); +#endif /* EXIT BLOCK */ NEW_BBLOCK (cfg, end_bblock); @@ -5598,6 +5756,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoExceptionClause *clause = &header->clauses [i]; GET_BBLOCK (cfg, try_bb, ip + clause->try_offset); try_bb->real_offset = clause->try_offset; + try_bb->try_start = TRUE; + try_bb->region = ((i + 1) << 8) | clause->flags; GET_BBLOCK (cfg, tblock, ip + clause->handler_offset); tblock->real_offset = clause->handler_offset; tblock->flags |= BB_EXCEPTION_HANDLER; @@ -5613,6 +5773,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_INST_NEW (cfg, ins, OP_START_HANDLER); MONO_ADD_INS (tblock, ins); + if (seq_points) { + NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE); + MONO_ADD_INS (tblock, ins); + } + /* todo: is a fault block unsafe to optimize? */ if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) tblock->flags |= BB_EXCEPTION_UNSAFE; @@ -6480,7 +6645,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call)); CHECK_CFG_EXCEPTION; } else if (!constrained_call->valuetype) { - int dreg = alloc_preg (cfg); + int dreg = alloc_ireg_ref (cfg); /* * The type parameter is instantiated as a reference @@ -6634,7 +6799,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b g_assert (cmethod->is_inflated); imt_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD); - ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, sp [0], imt_arg); + ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, sp [0], imt_arg, NULL); } else #endif { @@ -6654,7 +6819,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0); - ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr); + ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL); } if (!MONO_TYPE_IS_VOID (fsig->ret)) @@ -6667,54 +6832,31 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b break; } -#ifdef MONO_ARCH_USE_OP_TAIL_CALL - supported_tail_call = cmethod && MONO_ARCH_USE_OP_TAIL_CALL (mono_method_signature (method), mono_method_signature (cmethod)); -#else - supported_tail_call = cmethod && mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret); -#endif - - /* Tail prefix */ - /* FIXME: runtime generic context pointer for jumps? */ - /* FIXME: handle this for generic sharing eventually */ - if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) && supported_tail_call) { - MonoCallInst *call; - - /* Prevent inlining of methods with tail calls (the call stack would be altered) */ - INLINE_FAILURE; - -#ifdef MONO_ARCH_USE_OP_TAIL_CALL - /* Handle tail calls similarly to calls */ - call = mono_emit_call_args (cfg, mono_method_signature (cmethod), sp, FALSE, FALSE, TRUE); -#else - MONO_INST_NEW_CALL (cfg, call, OP_JMP); - call->tail_call = TRUE; - call->method = cmethod; - call->signature = mono_method_signature (cmethod); + /* + * Implement a workaround for the inherent races involved in locking: + * Monitor.Enter () + * try { + * } finally { + * Monitor.Exit () + * } + * If a thread abort happens between the call to Monitor.Enter () and the start of the + * try block, the Exit () won't be executed, see: + * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx + * To work around this, we extend such try blocks to include the last x bytes + * of the Monitor.Enter () call. + */ + if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) { + MonoBasicBlock *tbb; - /* - * We implement tail calls by storing the actual arguments into the - * argument variables, then emitting a CEE_JMP. + GET_BBLOCK (cfg, tbb, ip + 5); + /* + * Only extend try blocks with a finally, to avoid catching exceptions thrown + * from Monitor.Enter like ArgumentNullException. */ - for (i = 0; i < n; ++i) { - /* Prevent argument from being register allocated */ - arg_array [i]->flags |= MONO_INST_VOLATILE; - EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]); + if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) { + /* Mark this bblock as needing to be extended */ + tbb->extend_try_block = TRUE; } -#endif - - ins = (MonoInst*)call; - ins->inst_p0 = cmethod; - ins->inst_p1 = arg_array [0]; - MONO_ADD_INS (bblock, ins); - link_bblock (cfg, bblock, end_bblock); - start_new_bblock = 1; - - CHECK_CFG_EXCEPTION; - - /* skip CEE_RET as well */ - ip += 6; - ins_flag = 0; - break; } /* Conversion to a JIT intrinsic */ @@ -6736,20 +6878,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* Inlining */ if ((cfg->opt & MONO_OPT_INLINE) && cmethod && (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) && - mono_method_check_inlining (cfg, cmethod) && + !disable_inline && mono_method_check_inlining (cfg, cmethod) && !g_list_find (dont_inline, cmethod)) { int costs; - gboolean allways = FALSE; + gboolean always = FALSE; if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) { /* Prevent inlining of methods that call wrappers */ INLINE_FAILURE; cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE); - allways = TRUE; + always = TRUE; } - if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, allways))) { + if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always))) { ip += 5; cfg->real_offset += 5; bblock = cfg->cbb; @@ -6842,12 +6984,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (vtable_arg) { MonoCallInst *call; - int rgctx_reg = mono_alloc_preg (cfg); - MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg); - ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr); + ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, vtable_arg); call = (MonoCallInst*)ins; - set_rgctx_arg (cfg, call, rgctx_reg, vtable_arg); } else { if (addr->opcode == OP_AOTCONST && addr->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) { /* @@ -6860,7 +6999,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_right->inst_left, fsig, sp); NULLIFY_INS (addr); } else { - ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr); + ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL); } } if (!MONO_TYPE_IS_VOID (fsig->ret)) @@ -6878,17 +7017,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoInst *addr; if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ - if (sp [fsig->param_count]->type == STACK_OBJ) { + MonoInst *val = sp [fsig->param_count]; + + if (val->type == STACK_OBJ) { MonoInst *iargs [2]; iargs [0] = sp [0]; - iargs [1] = sp [fsig->param_count]; + iargs [1] = val; mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs); } addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE); - EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, sp [fsig->param_count]->dreg); + EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg); + if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0)) + emit_write_barrier (cfg, addr, val, 0); } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */ addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE); @@ -6926,16 +7069,72 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b break; } + /* Tail prefix / tail call optimization */ + + /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */ + /* FIXME: runtime generic context pointer for jumps? */ + /* FIXME: handle this for generic sharing eventually */ + supported_tail_call = cmethod && + ((((ins_flag & MONO_INST_TAILCALL) && (*ip == CEE_CALL)) + ))//|| ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && ip [5] == CEE_RET)) + && !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig); + + if (supported_tail_call) { + MonoCallInst *call; + + /* Prevent inlining of methods with tail calls (the call stack would be altered) */ + INLINE_FAILURE; + + //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE)); + +#ifdef MONO_ARCH_USE_OP_TAIL_CALL + /* Handle tail calls similarly to calls */ + call = mono_emit_call_args (cfg, mono_method_signature (cmethod), sp, FALSE, FALSE, TRUE, FALSE); +#else + MONO_INST_NEW_CALL (cfg, call, OP_JMP); + call->tail_call = TRUE; + call->method = cmethod; + call->signature = mono_method_signature (cmethod); + + /* + * We implement tail calls by storing the actual arguments into the + * argument variables, then emitting a CEE_JMP. + */ + for (i = 0; i < n; ++i) { + /* Prevent argument from being register allocated */ + arg_array [i]->flags |= MONO_INST_VOLATILE; + EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]); + } +#endif + + ins = (MonoInst*)call; + ins->inst_p0 = cmethod; + ins->inst_p1 = arg_array [0]; + MONO_ADD_INS (bblock, ins); + link_bblock (cfg, bblock, end_bblock); + start_new_bblock = 1; + + CHECK_CFG_EXCEPTION; + + ip += 5; + ins_flag = 0; + + // FIXME: Eliminate unreachable epilogs + + /* + * OP_TAILCALL has no return value, so skip the CEE_RET if it is + * only reachable from this call. + */ + GET_BBLOCK (cfg, tblock, ip); + if (tblock == bblock || tblock->in_count == 0) + ip += 1; + break; + } + /* Common call */ INLINE_FAILURE; - if (vtable_arg) { - ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, - NULL, vtable_arg); - } else if (imt_arg) { - ins = (MonoInst*)mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, imt_arg); - } else { - ins = (MonoInst*)mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, NULL); - } + ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, + imt_arg, vtable_arg); if (!MONO_TYPE_IS_VOID (fsig->ret)) *sp++ = mono_emit_widen_call_res (cfg, ins, fsig); @@ -6982,6 +7181,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b g_assert (!return_var); CHECK_STACK (1); --sp; + + if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp)) + UNVERIFIED; + if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) { MonoInst *ret_addr; @@ -7298,6 +7501,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b case CEE_LDIND_I8: dreg = alloc_lreg (cfg); break; + case CEE_LDIND_REF: + dreg = alloc_ireg_ref (cfg); + break; default: dreg = alloc_preg (cfg); } @@ -7520,7 +7726,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b sp -= 2; if (generic_class_is_reference_type (cfg, klass)) { MonoInst *store, *load; - int dreg = alloc_preg (cfg); + int dreg = alloc_ireg_ref (cfg); NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0); load->flags |= ins_flag; @@ -7653,6 +7859,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b NEW_PCONST (cfg, ins, NULL); ins->type = STACK_OBJ; ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n)); + if (!ins->inst_p0) + OUT_OF_MEMORY_FAILURE; + *sp = ins; MONO_ADD_INS (bblock, ins); } @@ -7795,7 +8004,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* we simply pass a null pointer */ EMIT_NEW_PCONST (cfg, *sp, NULL); /* now call the string ctor */ - alloc = mono_emit_method_call_full (cfg, cmethod, fsig, sp, NULL, NULL); + alloc = mono_emit_method_call_full (cfg, cmethod, fsig, sp, NULL, NULL, NULL); } else { MonoInst* callvirt_this_arg = NULL; @@ -7853,12 +8062,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } CHECK_CFG_EXCEPTION; - } else - - - - if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg && - mono_method_check_inlining (cfg, cmethod) && + } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg && + !disable_inline && mono_method_check_inlining (cfg, cmethod) && !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) && !g_list_find (dont_inline, cmethod)) { int costs; @@ -7870,7 +8075,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b inline_costs += costs - 5; } else { INLINE_FAILURE; - mono_emit_method_call_full (cfg, cmethod, fsig, sp, callvirt_this_arg, NULL); + mono_emit_method_call_full (cfg, cmethod, fsig, sp, callvirt_this_arg, NULL, NULL); } } else if (context_used && (!mono_method_is_generic_sharable_impl (cmethod, TRUE) || @@ -7880,11 +8085,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b cmethod_addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE); - mono_emit_rgctx_calli (cfg, fsig, sp, cmethod_addr, vtable_arg); + mono_emit_calli (cfg, fsig, sp, cmethod_addr, vtable_arg); } else { INLINE_FAILURE; - ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp, - callvirt_this_arg, NULL, vtable_arg); + ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, + callvirt_this_arg, NULL, vtable_arg); } } @@ -7941,7 +8146,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b iargs [0] = sp [0]; costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), - iargs, ip, cfg->real_offset, dont_inline, TRUE); + iargs, ip, cfg->real_offset, dont_inline, TRUE); + CHECK_CFG_EXCEPTION; g_assert (costs > 0); ip += 5; @@ -7999,7 +8205,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b iargs [0] = sp [0]; costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), - iargs, ip, cfg->real_offset, dont_inline, TRUE); + iargs, ip, cfg->real_offset, dont_inline, TRUE); + CHECK_CFG_EXCEPTION; g_assert (costs > 0); ip += 5; @@ -8062,7 +8269,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), iargs, ip, cfg->real_offset, dont_inline, TRUE); - + CHECK_CFG_EXCEPTION; g_assert (costs > 0); ip += 5; @@ -8293,6 +8500,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) { costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, cfg->real_offset, dont_inline, TRUE); + CHECK_CFG_EXCEPTION; g_assert (costs > 0); cfg->real_offset += 5; @@ -8316,7 +8524,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoInst *ptr; int dreg; - dreg = alloc_preg (cfg); + dreg = alloc_ireg_mp (cfg); EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset); emit_write_barrier (cfg, ptr, sp [1], -1); } @@ -8339,6 +8547,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) { costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, ip, cfg->real_offset, dont_inline, TRUE); + CHECK_CFG_EXCEPTION; bblock = cfg->cbb; g_assert (costs > 0); @@ -8373,7 +8582,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException"); } - dreg = alloc_preg (cfg); + dreg = alloc_ireg_mp (cfg); EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset); ins->klass = mono_class_from_mono_type (field->type); @@ -8401,6 +8610,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoClassField *field; gpointer addr = NULL; gboolean is_special_static; + MonoType *ftype; CHECK_OPSIZE (5); token = read32 (ip + 1); @@ -8434,7 +8644,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (cfg->generic_sharing_context) context_used = mono_class_check_context_used (klass); - g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)); + ftype = mono_field_get_type (field); + + g_assert (!(ftype->attrs & FIELD_ATTRIBUTE_LITERAL)); /* The special_static_fields field is init'd in mono_class_vtable, so it needs * to be called here. @@ -8585,7 +8797,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* Generate IR to do the actual load/store operation */ if (*ip == CEE_LDSFLDA) { - ins->klass = mono_class_from_mono_type (field->type); + ins->klass = mono_class_from_mono_type (ftype); ins->type = STACK_PTR; *sp++ = ins; } else if (*ip == CEE_STSFLD) { @@ -8593,7 +8805,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b CHECK_STACK (1); sp--; - EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, ins->dreg, 0, sp [0]->dreg); + EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, sp [0]->dreg); store->flags |= ins_flag; } else { gboolean is_const = FALSE; @@ -8604,11 +8816,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b CHECK_TYPELOAD (klass); } if (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && - vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) { + vtable->initialized && (ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) { gpointer addr = (char*)vtable->data + field->offset; - int ro_type = field->type->type; - if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) { - ro_type = mono_class_enum_basetype (field->type->data.klass)->type; + int ro_type = ftype->type; + if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) { + ro_type = mono_class_enum_basetype (ftype->data.klass)->type; } /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/ is_const = TRUE; @@ -8785,7 +8997,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b CHECK_TYPELOAD (array_type); MONO_INST_NEW (cfg, ins, OP_NEWARR); - ins->dreg = alloc_preg (cfg); + ins->dreg = alloc_ireg_ref (cfg); ins->sreg1 = sp [0]->dreg; ins->inst_newa_class = klass; ins->type = STACK_OBJ; @@ -8813,7 +9025,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, bblock, ip + 6) && (len_ins->opcode == OP_ICONST) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, klass, len_ins->inst_c0, &data_size, &field_token))) { MonoMethod *memcpy_method = get_memcpy_method (); MonoInst *iargs [3]; - int add_reg = alloc_preg (cfg); + int add_reg = alloc_ireg_mp (cfg); EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector)); if (cfg->compile_aot) { @@ -8834,7 +9046,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (sp [0]->type != STACK_OBJ) UNVERIFIED; - dreg = alloc_preg (cfg); MONO_INST_NEW (cfg, ins, OP_LDLEN); ins->dreg = alloc_preg (cfg); ins->sreg1 = sp [0]->dreg; @@ -9312,7 +9523,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b NEW_BBLOCK (cfg, dont_throw); /* - * Currently, we allways rethrow the abort exception, despite the + * Currently, we always rethrow the abort exception, despite the * fact that this is not correct. See thread6.cs for an example. * But propagating the abort exception is more important than * getting the sematics right. @@ -9495,7 +9706,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b CHECK_STACK (1); --sp; MONO_INST_NEW (cfg, ins, OP_MOVE); - ins->dreg = alloc_preg (cfg); + ins->dreg = alloc_ireg_mp (cfg); ins->sreg1 = sp [0]->dreg; ins->type = STACK_MP; MONO_ADD_INS (cfg->cbb, ins); @@ -9696,7 +9907,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b cmp->sreg2 = sp [1]->dreg; type_from_op (cmp, sp [0], sp [1]); CHECK_TYPE (cmp); - if ((sp [0]->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP)))) + if ((sp [0]->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP)))) cmp->opcode = OP_LCOMPARE; else if (sp [0]->type == STACK_R8) cmp->opcode = OP_FCOMPARE; @@ -10629,7 +10840,11 @@ op_to_op_src1_membase (int load_opcode, int opcode) switch (opcode) { case OP_X86_PUSH: +#ifdef __mono_ilp32__ + if (load_opcode == OP_LOADI8_MEMBASE) +#else if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE)) +#endif return OP_X86_PUSH_MEMBASE; break; /* FIXME: This only works for 32 bit immediates @@ -10644,7 +10859,13 @@ op_to_op_src1_membase (int load_opcode, int opcode) break; case OP_COMPARE: case OP_LCOMPARE: +#ifdef __mono_ilp32__ + if (load_opcode == OP_LOAD_MEMBASE) + return OP_AMD64_ICOMPARE_MEMBASE_REG; + if (load_opcode == OP_LOADI8_MEMBASE) +#else if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE)) +#endif return OP_AMD64_COMPARE_MEMBASE_REG; break; case OP_ICOMPARE: @@ -10682,7 +10903,11 @@ op_to_op_src2_membase (int load_opcode, int opcode) #endif #ifdef TARGET_AMD64 +#ifdef __mono_ilp32__ + if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) { +#else if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) { +#endif switch (opcode) { case OP_ICOMPARE: return OP_AMD64_ICOMPARE_REG_MEMBASE; @@ -10697,7 +10922,11 @@ op_to_op_src2_membase (int load_opcode, int opcode) case OP_IXOR: return OP_X86_XOR_REG_MEMBASE; } +#ifdef __mono_ilp32__ + } else if (load_opcode == OP_LOADI8_MEMBASE) { +#else } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) { +#endif switch (opcode) { case OP_COMPARE: case OP_LCOMPARE: @@ -10847,7 +11076,10 @@ mono_handle_global_vregs (MonoCompile *cfg) switch (regtype) { case 'i': - mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg); + if (vreg_is_ref (cfg, vreg)) + mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg); + else + mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg); break; case 'l': mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg); @@ -11044,6 +11276,16 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) } #endif + if (cfg->compute_gc_maps) { + /* registers need liveness info even for !non refs */ + for (i = 0; i < cfg->num_varinfo; i++) { + MonoInst *ins = cfg->varinfo [i]; + + if (ins->opcode == OP_REGVAR) + ins->flags |= MONO_INST_GC_TRACK; + } + } + /* FIXME: widening and truncation */ /* @@ -11285,6 +11527,14 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) live_range_start [dreg] = def_ins; live_range_start_bb [dreg] = bb; } + + if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) { + MonoInst *tmp; + + MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF); + tmp->inst_c1 = dreg; + mono_bblock_insert_after_ins (bb, def_ins, tmp); + } } /************/ @@ -11307,6 +11557,16 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) //mono_inst_set_src_registers (ins, sregs); live_range_end [sreg] = use_ins; live_range_end_bb [sreg] = bb; + + if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) { + MonoInst *tmp; + + MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE); + /* var->dreg is a hreg */ + tmp->inst_c1 = sreg; + mono_bblock_insert_after_ins (bb, ins, tmp); + } + continue; } @@ -11387,6 +11647,14 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) live_range_end [var->dreg] = use_ins; live_range_end_bb [var->dreg] = bb; } + + if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) { + MonoInst *tmp; + + MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE); + tmp->inst_c1 = var->dreg; + mono_bblock_insert_after_ins (bb, ins, tmp); + } } } mono_inst_set_src_registers (ins, sregs);