X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmethod-to-ir.c;h=3143431b6c48b11fab721ee8d1d0f6739519716b;hb=4c960e1dd530396fdd9400c87729a6ce3101e5c1;hp=c7ca275b134fe12dccc3803d1958b81a1bad99b7;hpb=89e9e78ee8904181bd8f22f525cd6cfd649f7e57;p=mono.git diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index c7ca275b134..3143431b6c4 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -154,8 +154,7 @@ emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig /* helper methods signatures */ static MonoMethodSignature *helper_sig_domain_get; static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline; -static MonoMethodSignature *helper_sig_llvmonly_imt_thunk; - +static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline; /* type loading helpers */ static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers) @@ -364,7 +363,7 @@ mono_create_helper_signatures (void) { helper_sig_domain_get = mono_create_icall_signature ("ptr"); helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr"); - helper_sig_llvmonly_imt_thunk = mono_create_icall_signature ("ptr ptr ptr"); + helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr"); } static MONO_NEVER_INLINE void @@ -1658,7 +1657,7 @@ mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *kla { int max_iid_reg = alloc_preg (cfg); - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id)); + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id)); mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target); } @@ -1669,7 +1668,7 @@ mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass { int max_iid_reg = alloc_preg (cfg); - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id)); + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id)); mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target); } @@ -1795,7 +1794,7 @@ mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClas mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class); } else if (klass->cast_class == mono_defaults.enum_class) { mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class); - } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) { + } else if (mono_class_is_interface (klass->cast_class)) { mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL); } else { // Pass -1 as obj_reg to skip the check below for arrays of arrays @@ -2551,7 +2550,7 @@ check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_ gboolean pass_mrgctx = FALSE; if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) && - (cmethod->klass->generic_class || cmethod->klass->generic_container)) { + (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) { gboolean sharable = FALSE; if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) @@ -2792,7 +2791,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign if (!sig) sig = mono_method_signature (method); - if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) + if (cfg->llvm_only && (mono_class_is_interface (method->klass))) g_assert_not_reached (); if (rgctx_arg) { @@ -2830,7 +2829,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) return emit_llvmonly_virtual_call (cfg, method, sig, 0, args); - need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE); + need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass); call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline); @@ -2919,7 +2918,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign } else { vtable_reg = alloc_preg (cfg); MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable)); - if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (method->klass)) { guint32 imt_slot = mono_method_get_imt_slot (method); emit_imt_argument (cfg, call, call->method, imt_arg); slot_reg = vtable_reg; @@ -4259,7 +4258,7 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_ EMIT_NEW_CLASSCONST (cfg, iargs [1], klass); alloc_ftn = ves_icall_object_new; - } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) { + } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) { /* This happens often in argument checking code, eg. throw new FooException... */ /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */ EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token)); @@ -4433,11 +4432,11 @@ mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass * 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; + if (mono_class_is_ginst (klass)) { + container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class); + ginst = mono_class_get_generic_class (klass)->context.class_inst; + } else if (mono_class_is_gtd (klass) && context_used) { + container = mono_class_get_generic_container (klass); ginst = container->context.class_inst; } else { return FALSE; @@ -4486,7 +4485,17 @@ icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod) return FALSE; } -#define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) +static gboolean +method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod) +{ + if (cmethod->klass == mono_defaults.systemtype_class) { + if (!strcmp (cmethod->name, "GetType")) + return TRUE; + } + return FALSE; +} + +#define is_complex_isinst(klass) (mono_class_is_interface (klass) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || mono_class_is_sealed (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) static MonoInst* emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args) @@ -4563,7 +4572,7 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context int vtable_reg = alloc_preg (cfg); MonoInst *klass_inst = NULL; - if (src->opcode == OP_PCONST && src->inst_p0 == 0) + if (MONO_INS_IS_PCONST_NULL (src)) return src; if (context_used) { @@ -4596,7 +4605,7 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context save_cast_details (cfg, klass, obj_reg, FALSE); - if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (klass)) { MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable)); mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL); } else { @@ -4604,7 +4613,7 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable)); - if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) { + if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) { /* the remoting code is broken, access the class for now */ 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); @@ -4677,7 +4686,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable)); - if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (klass)) { g_assert (!context_used); /* the is_null_bb target simply copies the input register to the output */ mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb); @@ -4707,7 +4716,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us } else if (klass->cast_class == mono_defaults.enum_class) { mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb); - } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) { + } else if (mono_class_is_interface (klass->cast_class)) { mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb); } else { if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) { @@ -4727,7 +4736,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us /* the is_null_bb target simply copies the input register to the output */ mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb); } else { - if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) { + if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) { g_assert (!context_used); /* the remoting code is broken, access the class for now */ if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/ @@ -4796,7 +4805,7 @@ handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src) MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb); - if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (klass)) { #ifndef DISABLE_REMOTING NEW_BBLOCK (cfg, interface_fail_bb); #endif @@ -4900,7 +4909,7 @@ handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src) save_cast_details (cfg, klass, obj_reg, FALSE); - if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (klass)) { #ifndef DISABLE_REMOTING NEW_BBLOCK (cfg, interface_fail_bb); @@ -5047,7 +5056,7 @@ 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 (!MONO_INS_IS_PCONST_NULL (target)) { MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg); if (cfg->gen_write_barriers) { dreg = alloc_preg (cfg); @@ -5177,7 +5186,7 @@ handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMe * This is hard to do with the current call code, since we would have to emit a branch and two different calls. So instead, we * pack the arguments into an array, and do the rest of the work in in an icall. */ - if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) && + if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) && (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mini_is_gsharedvt_type (fsig->ret)) && (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || fsig->params [0]->byref || mini_is_gsharedvt_type (fsig->params [0]))))) { MonoInst *args [16]; @@ -5350,7 +5359,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method) return FALSE; } } - } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) { + } else if (mono_class_is_before_field_init (method->klass)) { if (cfg->run_cctors && method->klass->has_cctor) { /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */ if (!method->klass->runtime_info) @@ -5386,7 +5395,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method) * the cctor will need to be run at aot method load time, for example, * or at the end of the compilation of the inlining method. */ - if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT))) + if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass)) return FALSE; } @@ -5416,7 +5425,7 @@ mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoCla return FALSE; } - if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) { + if (mono_class_is_before_field_init (klass)) { if (cfg->method == method) return FALSE; } @@ -5669,7 +5678,7 @@ emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst if (is_set) { EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0); EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg); - if (mini_type_is_reference (fsig->params [2])) + if (mini_type_is_reference (&eklass->byval_arg)) emit_write_barrier (cfg, addr, load); } else { EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0); @@ -5689,7 +5698,7 @@ static MonoInst* emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks) { if (safety_checks && generic_class_is_reference_type (cfg, klass) && - !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) { + !(MONO_INS_IS_PCONST_NULL (sp [2]))) { 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]; @@ -6116,8 +6125,13 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign return NULL; } else if (cmethod->klass == mono_defaults.monitor_class) { gboolean is_enter = FALSE; + gboolean is_v4 = FALSE; - if (!strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) + if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) { + is_enter = TRUE; + is_v4 = TRUE; + } + if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1) is_enter = TRUE; if (is_enter) { @@ -6129,10 +6143,10 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign NEW_BBLOCK (cfg, end_bb); - ins = mono_emit_jit_icall (cfg, (gpointer)mono_monitor_enter_fast, args); + ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args); MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb); - ins = mono_emit_jit_icall (cfg, (gpointer)mono_monitor_enter, args); + ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args); MONO_START_BB (cfg, end_bb); return ins; } @@ -7062,11 +7076,11 @@ emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init) /* * inline_method: * - * Return the cost of inlining CMETHOD. + * Return the cost of inlining CMETHOD, or zero if it should not be inlined. */ static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, - guchar *ip, guint real_offset, gboolean inline_always) + guchar *ip, guint real_offset, gboolean inline_always) { MonoError error; MonoInst *ins, *rvar = NULL; @@ -7702,7 +7716,7 @@ emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig MonoInst *icall_args [16]; MonoInst *call_target, *ins, *vtable_ins; int arg_reg, this_reg, vtable_reg; - gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE; + gboolean is_iface = mono_class_is_interface (cmethod->klass); gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig); gboolean variant_iface = FALSE; guint32 slot; @@ -7799,7 +7813,7 @@ emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig icall_args [0] = thunk_arg_ins; icall_args [1] = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD); - ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL); + ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL); return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins); } @@ -7842,7 +7856,7 @@ emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig icall_args [0] = thunk_arg_ins; icall_args [1] = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD); - ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL); + ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL); ftndesc_ins->dreg = ftndesc_reg; /* * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation @@ -7938,7 +7952,7 @@ is_jit_optimizer_disabled (MonoMethod *m) return FALSE; } - attrs = mono_custom_attrs_from_assembly_checked (ass, &error); + attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error); mono_error_cleanup (&error); /* FIXME don't swallow the error */ if (attrs) { for (i = 0; i < attrs->num_attrs; ++i) { @@ -8137,7 +8151,22 @@ emit_setret (MonoCompile *cfg, MonoInst *val) /* * mono_method_to_ir: * - * Translate the .net IL into linear IR. + * Translate the .net IL into linear IR. + * + * @start_bblock: if not NULL, the starting basic block, used during inlining. + * @end_bblock: if not NULL, the ending basic block, used during inlining. + * @return_var: if not NULL, the place where the return value is stored, used during inlining. + * @inline_args: if not NULL, contains the arguments to the inline call + * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise. + * @is_virtual_call: whether this method is being called as a result of a call to callvirt + * + * This method is used to turn ECMA IL into Mono's internal Linear IR + * reprensetation. It is used both for entire methods, as well as + * inlining existing methods. In the former case, the @start_bblock, + * @end_bblock, @return_var, @inline_args are all set to NULL, and the + * inline_offset is set to zero. + * + * Returns: the inline cost, or -1 if there was an error processing this method. */ int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, @@ -8465,7 +8494,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* we use a separate basic block for the initialization code */ NEW_BBLOCK (cfg, init_localsbb); - cfg->bb_init = init_localsbb; + if (cfg->method == method) + cfg->bb_init = init_localsbb; init_localsbb->real_offset = cfg->real_offset; start_bblock->next_bb = init_localsbb; init_localsbb->next_bb = cfg->cbb; @@ -9351,7 +9381,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b n = fsig->param_count + fsig->hasthis; - if (!cfg->gshared && cmethod->klass->generic_container) + if (!cfg->gshared && mono_class_is_gtd (cmethod->klass)) UNVERIFIED; if (!cfg->gshared) @@ -9370,7 +9400,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (mini_is_gsharedvt_klass (constrained_class)) { if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) { /* The 'Own method' case below */ - } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) { + } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) { /* 'The type parameter is instantiated as a reference type' case below. */ } else { ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen); @@ -9391,7 +9421,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b * A simple solution would be to box always and make a normal virtual call, but that would * be bad performance wise. */ - if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) { + if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) { /* * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary. */ @@ -9444,7 +9474,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b nonbox_call->dreg = ins->dreg; goto call_end; } else { - g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE); + g_assert (mono_class_is_interface (cmethod->klass)); addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE); ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL); goto call_end; @@ -9519,7 +9549,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b * If the callee is a shared method, then its static cctor * might not get called after the call was patched. */ - if (cfg->gshared && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) { + if (cfg->gshared && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) { emit_class_init (cfg, cmethod->klass); CHECK_TYPELOAD (cmethod->klass); } @@ -9531,7 +9561,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b context_used = mini_method_check_context_used (cfg, cmethod); - if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) { + if (context_used && mono_class_is_interface (cmethod->klass)) { /* Generic method interface calls are resolved via a helper function and don't @@ -9619,7 +9649,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) GSHAREDVT_FAILURE (*ip); - if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) { + if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) { g_assert (!imt_arg); if (!context_used) g_assert (cmethod->is_inflated); @@ -9732,6 +9762,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } if (!has_vtargs) { + if (need_seq_point) { + emit_seq_point (cfg, method, ip, FALSE, TRUE); + need_seq_point = FALSE; + } for (i = 0; i < n; ++i) EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]); MONO_INST_NEW (cfg, ins, OP_BR); @@ -9770,13 +9804,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid * patching gshared method addresses into a gsharedvt method. */ - if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) && + if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) && !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) && (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) { MonoRgctxInfoType info_type; if (virtual_) { - //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) + //if (mono_class_is_interface (cmethod->klass)) //GSHAREDVT_FAILURE (*ip); // disable for possible remoting calls if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)) @@ -9789,7 +9823,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b cmethod, MONO_RGCTX_INFO_METHOD); /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */ vtable_arg = NULL; - } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) { + } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) { /* This can happen when we call a fully instantiated iface method */ imt_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD); @@ -9897,7 +9931,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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, val->dreg); - if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0)) + if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val)) emit_write_barrier (cfg, addr, val); if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass)) GSHAREDVT_FAILURE (*ip); @@ -10032,6 +10066,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive); } + if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) { + /* + * Clang can convert these calls to tail calls which screw up the stack + * walk. This happens even when the -fno-optimize-sibling-calls + * option is passed to clang. + * Work around this by emitting a dummy call. + */ + mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL); + } + CHECK_CFG_EXCEPTION; ip += 5; @@ -10431,7 +10475,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_ADD_INS (cfg->cbb, ins); - if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0))) + if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1])) emit_write_barrier (cfg, sp [0], sp [1]); inline_costs += 1; @@ -10814,7 +10858,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (mono_security_core_clr_enabled ()) ensure_method_is_allowed_to_call_method (cfg, method, cmethod); - if (cfg->gshared && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) { + if (cfg->gshared && cmethod && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) { emit_class_init (cfg, cmethod->klass); CHECK_TYPELOAD (cmethod->klass); } @@ -11006,13 +11050,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b res = handle_unbox_gsharedvt (cfg, klass, *sp); inline_costs += 2; } else if (generic_class_is_reference_type (cfg, klass)) { - MONO_INST_NEW (cfg, res, OP_CASTCLASS); - res->dreg = alloc_preg (cfg); - res->sreg1 = (*sp)->dreg; - res->klass = klass; - res->type = STACK_OBJ; - MONO_ADD_INS (cfg->cbb, res); - cfg->flags |= MONO_CFG_HAS_TYPE_CHECK; + if (MONO_INS_IS_PCONST_NULL (*sp)) { + EMIT_NEW_PCONST (cfg, res, NULL); + res->type = STACK_OBJ; + } else { + MONO_INST_NEW (cfg, res, OP_CASTCLASS); + res->dreg = alloc_preg (cfg); + res->sreg1 = (*sp)->dreg; + res->klass = klass; + res->type = STACK_OBJ; + MONO_ADD_INS (cfg->cbb, res); + cfg->flags |= MONO_CFG_HAS_TYPE_CHECK; + } } else if (mono_class_is_nullable (klass)) { res = handle_unbox_nullable (cfg, *sp, klass, context_used); } else { @@ -11360,7 +11409,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (sp [0]->opcode != OP_LDADDR) store->flags |= MONO_INST_FAULT; - if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) { + if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) { if (mini_is_gsharedvt_klass (klass)) { g_assert (wbarrier_ptr_ins); emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]); @@ -11783,7 +11832,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg); ins->flags |= ins_flag; if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && - generic_class_is_reference_type (cfg, klass)) { + generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) { /* insert call to write barrier */ emit_write_barrier (cfg, sp [0], sp [1]); } @@ -12126,7 +12175,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg); MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg)); MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg); - } else if (cfg->compile_aot) { + } else { int const_reg = alloc_preg (cfg); int type_reg = alloc_preg (cfg); @@ -12134,9 +12183,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg); MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg)); MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg); - } else { - MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg); - MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass); } MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg); @@ -12283,6 +12329,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } case CEE_THROW: CHECK_STACK (1); + if (sp [-1]->type != STACK_OBJ) + UNVERIFIED; + MONO_INST_NEW (cfg, ins, OP_THROW); --sp; ins->sreg1 = sp [0]->dreg; @@ -13654,7 +13703,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (cfg->method == method) { MonoBasicBlock *bb; for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { - bb->region = mono_find_block_region (cfg, bb->real_offset); + if (bb == cfg->bb_init) + bb->region = -1; + else + bb->region = mono_find_block_region (cfg, bb->real_offset); if (cfg->spvars) mono_create_spvar_for_region (cfg, bb->region); if (cfg->verbose_level > 2) @@ -15073,7 +15125,7 @@ mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins) ret = emit_isinst_with_cache_nonshared (cfg, source, klass); else ret = emit_castclass_with_cache_nonshared (cfg, source, klass); - } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) { + } else if (!context_used && (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass))) { MonoInst *iargs [1]; int costs;