X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmethod-to-ir.c;h=a34d674696d4845b391a8766669a311992625dfd;hb=5b558abeeb255a3179d4ca6a85617e051c6abd38;hp=5705cd7cc8d4d7a0d85cb4a029be9779f023ad33;hpb=9f96b7fad1135548019340be1264068d4094a81e;p=mono.git diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index 5705cd7cc8d..a34d674696d 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -74,7 +75,7 @@ #define METHOD_ACCESS_FAILURE do { \ char *method_fname = mono_method_full_name (method, TRUE); \ char *cil_method_fname = mono_method_full_name (cil_method, TRUE); \ - cfg->exception_type = MONO_EXCEPTION_METHOD_ACCESS; \ + mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS); \ cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname); \ g_free (method_fname); \ g_free (cil_method_fname); \ @@ -83,7 +84,7 @@ #define FIELD_ACCESS_FAILURE do { \ char *method_fname = mono_method_full_name (method, TRUE); \ char *field_fname = mono_field_full_name (field); \ - cfg->exception_type = MONO_EXCEPTION_FIELD_ACCESS; \ + mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS); \ cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname); \ g_free (method_fname); \ g_free (field_fname); \ @@ -93,11 +94,14 @@ if (cfg->generic_sharing_context) { \ if (cfg->verbose_level > 2) \ printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__); \ - cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED; \ + mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \ 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)) @@ -111,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 @@ -199,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) { @@ -280,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. @@ -288,6 +342,8 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg) #define UNVERIFIED do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0) +#define LOAD_ERROR do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto load_error; } while (0) + #define GET_BBLOCK(cfg,tblock,ip) do { \ (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \ if (!(tblock)) { \ @@ -301,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); \ @@ -776,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; @@ -785,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: @@ -873,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; @@ -2149,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 @@ -2163,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); @@ -2244,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) { @@ -2272,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; @@ -2281,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; } @@ -2294,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 */ @@ -2323,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); @@ -2432,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* @@ -2470,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); @@ -2593,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); @@ -2615,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; @@ -2652,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 @@ -2886,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; } @@ -3002,6 +3048,43 @@ emit_generic_class_init (MonoCompile *cfg, MonoClass *klass) #endif } +static void +save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg) +{ + if (mini_get_debug_options ()->better_cast_details) { + int to_klass_reg = alloc_preg (cfg); + int vtable_reg = alloc_preg (cfg); + int klass_reg = alloc_preg (cfg); + MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg); + + if (!tls_get) { + fprintf (stderr, "error: --debug=casts not supported on this platform.\n."); + exit (1); + } + + MONO_ADD_INS (cfg->cbb, tls_get); + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable)); + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass)); + + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg); + MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg); + } +} + +static void +reset_cast_details (MonoCompile *cfg) +{ + /* Reset the variables holding the cast details */ + if (mini_get_debug_options ()->better_cast_details) { + MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg); + + MONO_ADD_INS (cfg->cbb, tls_get); + /* It is enough to reset the from field */ + MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0); + } +} + /* * On return the caller must check @array_class for load errors */ @@ -3014,8 +3097,10 @@ mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_cl if (cfg->generic_sharing_context) context_used = mono_class_check_context_used (array_class); + save_cast_details (cfg, array_class, obj->dreg); + MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable)); - + if (cfg->opt & MONO_OPT_SHARED) { int class_reg = alloc_preg (cfg); MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass)); @@ -3050,43 +3135,8 @@ mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_cl } MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException"); -} - -static void -save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg) -{ - if (mini_get_debug_options ()->better_cast_details) { - int to_klass_reg = alloc_preg (cfg); - int vtable_reg = alloc_preg (cfg); - int klass_reg = alloc_preg (cfg); - MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg); - - if (!tls_get) { - fprintf (stderr, "error: --debug=casts not supported on this platform.\n."); - exit (1); - } - - MONO_ADD_INS (cfg->cbb, tls_get); - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable)); - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass)); - - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg); - MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass); - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg); - } -} - -static void -reset_cast_details (MonoCompile *cfg) -{ - /* Reset the variables holding the cast details */ - if (mini_get_debug_options ()->better_cast_details) { - MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg); - MONO_ADD_INS (cfg->cbb, tls_get); - /* It is enough to reset the from field */ - MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0); - } + reset_cast_details (cfg); } /** @@ -3109,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); } @@ -3156,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; @@ -3220,7 +3270,7 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_ gboolean pass_lw; if (!vtable) { - cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD; + mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); cfg->exception_ptr = klass; return NULL; } @@ -3266,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); } @@ -3281,8 +3331,40 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used) return alloc; } + +static gboolean +mini_class_has_reference_variant_generic_argument (MonoClass *klass, int context_used) +{ + int i; + MonoGenericContainer *container; + MonoGenericInst *ginst; + + if (klass->generic_class) { + container = klass->generic_class->container_class->generic_container; + ginst = klass->generic_class->context.class_inst; + } else if (klass->generic_container && context_used) { + container = klass->generic_container; + ginst = container->context.class_inst; + } else { + return FALSE; + } + + for (i = 0; i < container->type_argc; ++i) { + MonoType *type; + if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))) + continue; + type = ginst->type_argv [i]; + if (MONO_TYPE_IS_REFERENCE (type)) + return TRUE; + + if (context_used && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) + return TRUE; + } + return FALSE; +} + // FIXME: This doesn't work yet (class libs tests fail?) -#define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_SEALED) || mono_class_has_variant_generic_params (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) +#define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) /* * Returns NULL and set the cfg exception on error. @@ -3296,10 +3378,27 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context MonoInst *klass_inst = NULL; if (context_used) { - MonoInst *args [2]; + MonoInst *args [3]; + + if(mini_class_has_reference_variant_generic_argument (klass, context_used)) { + MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache (); + MonoInst *cache_ins; - klass_inst = emit_get_rgctx_klass (cfg, context_used, - klass, MONO_RGCTX_INFO_KLASS); + cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE); + + /* obj */ + args [0] = src; + + /* klass - it's the second element of the cache entry*/ + EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer)); + + /* cache */ + args [2] = cache_ins; + + return mono_emit_method_call (cfg, mono_castclass, args, NULL); + } + + klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS); if (is_complex_isinst (klass)) { /* Complex case, handle by an icall */ @@ -3336,7 +3435,7 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/ MonoVTable *vt = mono_class_vtable (cfg->domain, klass); if (!vt) { - cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD; + mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); cfg->exception_ptr = klass; return NULL; } @@ -3369,15 +3468,33 @@ 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) { + MonoInst *args [3]; + + if(mini_class_has_reference_variant_generic_argument (klass, context_used)) { + MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache (); + MonoInst *cache_ins; + + cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE); + + /* obj */ + args [0] = src; + + /* klass - it's the second element of the cache entry*/ + EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer)); + + /* cache */ + args [2] = cache_ins; + + return mono_emit_method_call (cfg, mono_isinst, args, NULL); + } + klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS); if (is_complex_isinst (klass)) { - MonoInst *args [2]; - /* Complex case, handle by an icall */ /* obj */ @@ -3462,7 +3579,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/ MonoVTable *vt = mono_class_vtable (cfg->domain, klass); if (!vt) { - cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD; + mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); cfg->exception_ptr = klass; return NULL; } @@ -3670,6 +3787,8 @@ handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src) static G_GNUC_UNUSED MonoInst* handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used) { + MonoInst *ptr; + int dreg; gpointer *trampoline; MonoInst *obj, *method_ins, *tramp_ins; MonoDomain *domain; @@ -3683,13 +3802,23 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono /* Set target field */ /* Optimize away setting of NULL target */ - if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) + if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) { MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg); + if (cfg->gen_write_barriers) { + dreg = alloc_preg (cfg); + EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target)); + emit_write_barrier (cfg, ptr, target, 0); + } + } /* Set method field */ method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD); MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg); - + if (cfg->gen_write_barriers) { + dreg = alloc_preg (cfg); + EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method)); + emit_write_barrier (cfg, ptr, method_ins, 0); + } /* * To avoid looking up the compiled code belonging to the target method * in mono_delegate_trampoline (), we allocate a per-domain memory slot to @@ -3952,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; @@ -3974,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); @@ -4200,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)); @@ -4235,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; @@ -4312,10 +4443,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } } else if (cmethod->klass == mono_defaults.monitor_class) { #if defined(MONO_ARCH_MONITOR_OBJECT_REG) - /* The trampolines don't work under SGEN */ - gboolean is_moving_gc = mono_gc_is_moving (); - - if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1 && !is_moving_gc) { + if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) { MonoCallInst *call; if (COMPILE_LLVM (cfg)) { @@ -4332,7 +4460,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } return (MonoInst*)call; - } else if (strcmp (cmethod->name, "Exit") == 0 && !is_moving_gc) { + } else if (strcmp (cmethod->name, "Exit") == 0) { MonoCallInst *call; if (COMPILE_LLVM (cfg)) { @@ -4469,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; @@ -4507,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; @@ -4515,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; @@ -4689,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; @@ -4711,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 @@ -4731,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; } @@ -4797,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)); @@ -4914,7 +5047,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED -#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;} +#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; LOAD_ERROR;} /* offset from br.s -> br like opcodes */ #define BIG_BRANCH_OFFSET 13 @@ -5085,7 +5218,7 @@ gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *cal mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL); } else if (cfg->exception_type == MONO_EXCEPTION_NONE) { /* don't hide previous results */ - cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND; + mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND); cfg->exception_data = result; return TRUE; } @@ -5249,7 +5382,7 @@ set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsign method_code = g_strdup ("method body is empty."); else method_code = mono_disasm_code_one (NULL, method, ip, NULL); - cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM; + mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM); cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code); g_free (method_fname); g_free (method_code); @@ -5259,7 +5392,7 @@ set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsign static void set_exception_object (MonoCompile *cfg, MonoException *exception) { - cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED; + mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED); MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr); cfg->exception_ptr = exception; } @@ -5347,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: * @@ -5385,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; @@ -5400,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); @@ -5407,9 +5643,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoLoaderError *error; if ((error = mono_loader_get_last_error ())) { - cfg->exception_type = error->exception_type; + mono_cfg_set_exception (cfg, error->exception_type); } else { - cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM; + mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM); cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name); } goto exception_exit; @@ -5494,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); @@ -5515,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; @@ -5530,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; @@ -6186,7 +6434,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b cmethod = mini_get_method (cfg, method, token, NULL, generic_context); if (!cmethod || mono_loader_get_last_error ()) - goto load_error; + LOAD_ERROR; if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod)) GENERIC_SHARING_FAILURE (CEE_JMP); @@ -6300,7 +6548,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } if (!cmethod || mono_loader_get_last_error ()) - goto load_error; + LOAD_ERROR; if (!dont_verify && !cfg->skip_visibility) { MonoMethod *target_method = cil_method; if (method->is_inflated) { @@ -6333,7 +6581,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (!cmethod->klass->inited) if (!mono_class_init (cmethod->klass)) - goto load_error; + LOAD_ERROR; if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL && mini_class_is_system_array (cmethod->klass)) { @@ -6343,7 +6591,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b fsig = mono_method_signature (cmethod); if (!fsig) - goto load_error; + LOAD_ERROR; if (fsig->pinvoke) { MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, @@ -6397,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 @@ -6551,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 { @@ -6571,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)) @@ -6584,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 */ @@ -6653,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; @@ -6759,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) { /* @@ -6777,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)) @@ -6795,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); @@ -6843,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); @@ -6899,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; @@ -7215,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); } @@ -7437,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; @@ -7570,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); } @@ -7590,15 +7882,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b token = read32 (ip + 1); cmethod = mini_get_method (cfg, method, token, NULL, generic_context); if (!cmethod || mono_loader_get_last_error ()) - goto load_error; + LOAD_ERROR; fsig = mono_method_get_signature (cmethod, image, token); if (!fsig) - goto load_error; + LOAD_ERROR; mono_save_token_info (cfg, image, token, cmethod); if (!mono_class_init (cmethod->klass)) - goto load_error; + LOAD_ERROR; if (cfg->generic_sharing_context) context_used = mono_method_check_context_used (cmethod); @@ -7712,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; @@ -7770,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; @@ -7787,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) || @@ -7797,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); } } @@ -7831,8 +8119,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); - if (!context_used && mono_class_has_variant_generic_params (klass)) { - MonoInst *args [2]; + if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) { + MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache (); + MonoInst *args [3]; /* obj */ args [0] = *sp; @@ -7840,8 +8129,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* klass */ EMIT_NEW_CLASSCONST (cfg, args [1], klass); - ins = mono_emit_jit_icall (cfg, mono_object_castclass, args); - *sp ++ = ins; + /* inline cache*/ + /*FIXME AOT support*/ + EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer))); + + /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/ + *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL); ip += 5; inline_costs += 2; } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) { @@ -7853,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; @@ -7885,8 +8179,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); - if (!context_used && mono_class_has_variant_generic_params (klass)) { - MonoInst *args [2]; + if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) { + MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache (); + MonoInst *args [3]; /* obj */ args [0] = *sp; @@ -7894,8 +8189,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* klass */ EMIT_NEW_CLASSCONST (cfg, args [1], klass); - *sp = mono_emit_jit_icall (cfg, mono_object_isinst, args); - sp++; + /* inline cache*/ + /*FIXME AOT support*/ + EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer))); + + *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL); ip += 5; inline_costs += 2; } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) { @@ -7907,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; @@ -7942,7 +8241,25 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (generic_class_is_reference_type (cfg, klass)) { /* CASTCLASS FIXME kill this huge slice of duplicated code*/ - if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) { + if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) { + MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache (); + MonoInst *args [3]; + + /* obj */ + args [0] = *sp; + + /* klass */ + EMIT_NEW_CLASSCONST (cfg, args [1], klass); + + /* inline cache*/ + /*FIXME AOT support*/ + EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer))); + + /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/ + *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL); + ip += 5; + inline_costs += 2; + } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) { MonoMethod *mono_castclass; MonoInst *iargs [1]; int costs; @@ -7952,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; @@ -8154,7 +8471,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b field = mono_field_from_token (image, token, &klass, generic_context); } if (!field) - goto load_error; + LOAD_ERROR; if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field)) FIELD_ACCESS_FAILURE; mono_class_init (klass); @@ -8183,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; @@ -8206,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); } @@ -8229,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); @@ -8263,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); @@ -8291,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); @@ -8302,7 +8622,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b else field = mono_field_from_token (image, token, &klass, generic_context); if (!field) - goto load_error; + LOAD_ERROR; mono_class_init (klass); if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field)) FIELD_ACCESS_FAILURE; @@ -8324,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. @@ -8475,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) { @@ -8483,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; @@ -8494,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; @@ -8675,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; @@ -8703,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) { @@ -8724,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; @@ -8845,9 +9166,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* storing a NULL doesn't need any of the complex checks in stelemref */ if (generic_class_is_reference_type (cfg, klass) && !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) { - MonoMethod* helper = mono_marshal_get_stelemref (); + MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1); + MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array); MonoInst *iargs [3]; + if (!helper->slot) + mono_class_setup_vtable (obj_array); + g_assert (helper->slot); + if (sp [0]->type != STACK_OBJ) UNVERIFIED; if (sp [2]->type != STACK_OBJ) @@ -8856,8 +9182,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b iargs [2] = sp [2]; iargs [1] = sp [1]; iargs [0] = sp [0]; - - mono_emit_method_call (cfg, helper, iargs, NULL); + + mono_emit_method_call (cfg, helper, iargs, sp [0]); } else { if (sp [1]->opcode == OP_ICONST) { int array_reg = sp [0]->dreg; @@ -9002,7 +9328,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b handle = mono_ldtoken (image, n, &handle_class, generic_context); } if (!handle) - goto load_error; + LOAD_ERROR; mono_class_init (handle_class); if (cfg->generic_sharing_context) { if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF || @@ -9197,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. @@ -9380,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); @@ -9581,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; @@ -9616,7 +9942,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b n = read32 (ip + 2); cmethod = mini_get_method (cfg, method, n, NULL, generic_context); if (!cmethod || mono_loader_get_last_error ()) - goto load_error; + LOAD_ERROR; mono_class_init (cmethod->klass); mono_save_token_info (cfg, image, n, cmethod); @@ -9644,25 +9970,33 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) { MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context); if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) { + MonoInst *target_ins; MonoMethod *invoke; int invoke_context_used = 0; invoke = mono_get_delegate_invoke (ctor_method->klass); if (!invoke || !mono_method_signature (invoke)) - goto load_error; + LOAD_ERROR; if (cfg->generic_sharing_context) invoke_context_used = mono_method_check_context_used (invoke); + target_ins = sp [-1]; + + if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) { + /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/ + if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) { + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0); + MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException"); + } + } + #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) /* FIXME: SGEN support */ - if (!cfg->gen_write_barriers && invoke_context_used == 0) { - MonoInst *target_ins; - + if (invoke_context_used == 0) { ip += 6; if (cfg->verbose_level > 3) g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL)); - target_ins = sp [-1]; sp --; *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used); CHECK_CFG_EXCEPTION; @@ -9690,7 +10024,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b n = read32 (ip + 2); cmethod = mini_get_method (cfg, method, n, NULL, generic_context); if (!cmethod || mono_loader_get_last_error ()) - goto load_error; + LOAD_ERROR; mono_class_init (cmethod->klass); if (cfg->generic_sharing_context) @@ -10124,7 +10458,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* Method is too large */ mname = mono_method_full_name (method, TRUE); - cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM; + mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM); cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname); g_free (mname); cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header); @@ -10147,7 +10481,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b goto cleanup; load_error: - cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD; + mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); goto cleanup; unverified: @@ -10506,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 @@ -10521,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: @@ -10559,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; @@ -10574,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: @@ -10724,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); @@ -10921,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 */ /* @@ -11162,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); + } } /************/ @@ -11184,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; } @@ -11264,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);