[jit] Fix the saving of the 'cfg->ret_var_set' flag when inlining, it was set to...
[mono.git] / mono / mini / method-to-ir.c
index c802e82394c49be55a0eea08c4524452dec134b2..ce326f3c2d3443d3461073d826215663523955e4 100644 (file)
@@ -1264,7 +1264,7 @@ mono_get_domainvar (MonoCompile *cfg)
 MonoInst *
 mono_get_got_var (MonoCompile *cfg)
 {
-       if (!cfg->compile_aot || !cfg->backend->need_got_var)
+       if (!cfg->compile_aot || !cfg->backend->need_got_var || cfg->llvm_only)
                return NULL;
        if (!cfg->got_var) {
                cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
@@ -1764,24 +1764,6 @@ emit_pop_lmf (MonoCompile *cfg)
        EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
 }
 
-static void
-emit_instrumentation_call (MonoCompile *cfg, void *func)
-{
-       MonoInst *iargs [1];
-
-       /*
-        * Avoid instrumenting inlined methods since it can
-        * distort profiling results.
-        */
-       if (cfg->method != cfg->current_method)
-               return;
-
-       if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
-               EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
-               mono_emit_jit_icall (cfg, func, iargs);
-       }
-}
-
 static int
 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
 {
@@ -2235,7 +2217,7 @@ check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_
 
 inline static MonoCallInst *
 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
-                                        MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
+                                        MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline, MonoMethod *target)
 {
        MonoType *sig_ret;
        MonoCallInst *call;
@@ -2247,7 +2229,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
                tail = FALSE;
 
        if (tail) {
-               emit_instrumentation_call (cfg, mono_profiler_method_leave);
+               mini_profiler_emit_tail_call (cfg, target);
 
                MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
        } else
@@ -2380,7 +2362,7 @@ mini_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, Mo
                MONO_ADD_INS (cfg->cbb, ins);
        }
 
-       call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
+       call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE, NULL);
 
        call->inst.sreg1 = addr->dreg;
 
@@ -2474,7 +2456,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
 
        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);
+       call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline, method);
 
 #ifndef DISABLE_REMOTING
        if (might_be_remote)
@@ -2604,7 +2586,7 @@ mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature
 
        g_assert (sig);
 
-       call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
+       call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE, NULL);
        call->fptr = func;
 
        MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
@@ -3719,11 +3701,10 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_
                /* 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));
-               return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
+               alloc_ftn = mono_helper_newobj_mscorlib;
        } else {
                MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
                MonoMethod *managed_alloc = NULL;
-               gboolean pass_lw;
 
                if (!vtable) {
                        mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
@@ -3742,16 +3723,8 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_
                        EMIT_NEW_ICONST (cfg, iargs [1], size);
                        return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
                }
-               alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
-               if (pass_lw) {
-                       guint32 lw = vtable->klass->instance_size;
-                       lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
-                       EMIT_NEW_ICONST (cfg, iargs [0], lw);
-                       EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
-               }
-               else {
-                       EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
-               }
+               alloc_ftn = ves_icall_object_new_specific;
+               EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
        }
 
        return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
@@ -3999,6 +3972,8 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
        /* Set target field */
        /* Optimize away setting of NULL target */
        if (!MONO_INS_IS_PCONST_NULL (target)) {
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target->dreg, 0);
+               MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
                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);
@@ -4362,6 +4337,9 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
        if (g_list_find (cfg->dont_inline, method))
                return FALSE;
 
+       if (mono_profiler_get_call_instrumentation_flags (method))
+               return FALSE;
+
        return TRUE;
 }
 
@@ -5055,11 +5033,15 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        g_assert (ctx);
                        g_assert (ctx->method_inst);
                        g_assert (ctx->method_inst->type_argc == 1);
-                       MonoType *t = mini_get_underlying_type (ctx->method_inst->type_argv [0]);
-                       MonoClass *klass = mono_class_from_mono_type (t);
+                       MonoType *arg_type = ctx->method_inst->type_argv [0];
+                       MonoType *t;
+                       MonoClass *klass;
 
                        ins = NULL;
 
+                       /* Resolve the argument class as possible so we can handle common cases fast */
+                       t = mini_get_underlying_type (arg_type);
+                       klass = mono_class_from_mono_type (t);
                        mono_class_init (klass);
                        if (MONO_TYPE_IS_REFERENCE (t))
                                EMIT_NEW_ICONST (cfg, ins, 1);
@@ -5072,10 +5054,12 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        else {
                                g_assert (cfg->gshared);
 
-                               int context_used = mini_class_check_context_used (cfg, klass);
+                               /* Have to use the original argument class here */
+                               MonoClass *arg_class = mono_class_from_mono_type (arg_type);
+                               int context_used = mini_class_check_context_used (cfg, arg_class);
 
                                /* This returns 1 or 2 */
-                               MonoInst *info = mini_emit_get_rgctx_klass (cfg, context_used, klass,   MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS);
+                               MonoInst *info = mini_emit_get_rgctx_klass (cfg, context_used, arg_class, MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS);
                                int dreg = alloc_ireg (cfg);
                                EMIT_NEW_BIALU_IMM (cfg, ins, OP_ISUB_IMM, dreg, info->dreg, 1);
                        }
@@ -5861,7 +5845,7 @@ mini_redirect_call (MonoCompile *cfg, MonoMethod *method,
 {
        if (method->klass == mono_defaults.string_class) {
                /* managed string allocation support */
-               if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
+               if (strcmp (method->name, "InternalAllocateStr") == 0 && !(cfg->opt & MONO_OPT_SHARED)) {
                        MonoInst *iargs [2];
                        MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
                        MonoMethod *managed_alloc = NULL;
@@ -6150,9 +6134,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        prev_args = cfg->args;
        prev_arg_types = cfg->arg_types;
        prev_inlined_method = cfg->inlined_method;
-       cfg->inlined_method = cmethod;
-       cfg->ret_var_set = FALSE;
-       cfg->inline_depth ++;
+       prev_ret_var_set = cfg->ret_var_set;
        prev_real_offset = cfg->real_offset;
        prev_cbb_hash = cfg->cbb_hash;
        prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
@@ -6162,9 +6144,12 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        prev_cbb = cfg->cbb;
        prev_current_method = cfg->current_method;
        prev_generic_context = cfg->generic_context;
-       prev_ret_var_set = cfg->ret_var_set;
        prev_disable_inline = cfg->disable_inline;
 
+       cfg->inlined_method = cmethod;
+       cfg->ret_var_set = FALSE;
+       cfg->inline_depth ++;
+
        if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
                virtual_ = TRUE;
 
@@ -6625,10 +6610,78 @@ set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsign
        cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
 }
 
+static guint32
+mono_type_to_stloc_coerce (MonoType *type)
+{
+       if (type->byref)
+               return 0;
+
+       type = mini_get_underlying_type (type);
+handle_enum:
+       switch (type->type) {
+       case MONO_TYPE_I1:
+               return OP_ICONV_TO_I1;
+       case MONO_TYPE_U1:
+               return OP_ICONV_TO_U1;
+       case MONO_TYPE_I2:
+               return OP_ICONV_TO_I2;
+       case MONO_TYPE_U2:
+               return OP_ICONV_TO_U2;
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+       case MONO_TYPE_I:
+       case MONO_TYPE_U:
+       case MONO_TYPE_PTR:
+       case MONO_TYPE_FNPTR:
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_STRING:
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_SZARRAY:
+       case MONO_TYPE_ARRAY:
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+       case MONO_TYPE_R4:
+       case MONO_TYPE_R8:
+       case MONO_TYPE_TYPEDBYREF:
+       case MONO_TYPE_GENERICINST:
+               return 0;
+       case MONO_TYPE_VALUETYPE:
+               if (type->data.klass->enumtype) {
+                       type = mono_class_enum_basetype (type->data.klass);
+                       goto handle_enum;
+               }
+               return 0;
+       case MONO_TYPE_VAR:
+       case MONO_TYPE_MVAR: //TODO I believe we don't need to handle gsharedvt as there won't be match and, for example, u1 is not covariant to u32
+               return 0;
+       default:
+               g_error ("unknown type 0x%02x in mono_type_to_stloc_coerce", type->type);
+       }
+       return -1;
+}
+
 static void
 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
 {
        MonoInst *ins;
+       guint32 coerce_op = mono_type_to_stloc_coerce (header->locals [n]);
+
+       if (coerce_op) {
+               if (cfg->cbb->last_ins == sp [0] && sp [0]->opcode == coerce_op) {
+                       if (cfg->verbose_level > 2)
+                               printf ("Found existing coercing is enough for stloc\n");
+               } else {
+                       MONO_INST_NEW (cfg, ins, coerce_op);
+                       ins->dreg = alloc_ireg (cfg);
+                       ins->sreg1 = sp [0]->dreg;
+                       ins->type = STACK_I4;
+                       ins->klass = mono_class_from_mono_type (header->locals [n]);
+                       MONO_ADD_INS (cfg->cbb, ins);
+                       *sp = mono_decompose_opcode (cfg, ins);
+               }
+       }
+
+
        guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
        if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
                        ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
@@ -6643,6 +6696,30 @@ emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
        }
 }
 
+static void
+emit_starg_ir (MonoCompile *cfg, MonoInst **sp, int n)
+{
+       MonoInst *ins;
+       guint32 coerce_op = mono_type_to_stloc_coerce (cfg->arg_types [n]);
+
+       if (coerce_op) {
+               if (cfg->cbb->last_ins == sp [0] && sp [0]->opcode == coerce_op) {
+                       if (cfg->verbose_level > 2)
+                               printf ("Found existing coercing is enough for starg\n");
+               } else {
+                       MONO_INST_NEW (cfg, ins, coerce_op);
+                       ins->dreg = alloc_ireg (cfg);
+                       ins->sreg1 = sp [0]->dreg;
+                       ins->type = STACK_I4;
+                       ins->klass = mono_class_from_mono_type (cfg->arg_types [n]);
+                       MONO_ADD_INS (cfg->cbb, ins);
+                       *sp = mono_decompose_opcode (cfg, ins);
+               }
+       }
+
+       EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
+}
+
 /*
  * ldloca inhibits many optimizations so try to get rid of it in common
  * cases.
@@ -7304,8 +7381,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
        if (cfg->method == method) {
 
-               if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
-                       cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
+               cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
 
                /* ENTRY BLOCK */
                NEW_BBLOCK (cfg, start_bblock);
@@ -7340,6 +7416,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        tblock->real_offset = clause->handler_offset;
                        tblock->flags |= BB_EXCEPTION_HANDLER;
 
+                       if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
+                               mono_create_exvar_for_offset (cfg, clause->handler_offset);
                        /*
                         * Linking the try block with the EH block hinders inlining as we won't be able to 
                         * merge the bblocks from inlining and produce an artificial hole for no good reason.
@@ -7701,18 +7779,25 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                if ((cfg->method == method) && cfg->coverage_info) {
                        guint32 cil_offset = ip - header->code;
+                       gpointer counter = &cfg->coverage_info->data [cil_offset].count;
                        cfg->coverage_info->data [cil_offset].cil_code = ip;
 
-                       /* TODO: Use an increment here */
-#if defined(TARGET_X86)
-                       MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
-                       ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
-                       ins->inst_imm = 1;
-                       MONO_ADD_INS (cfg->cbb, ins);
-#else
-                       EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
-                       MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
-#endif
+                       if (mono_arch_opcode_supported (OP_ATOMIC_ADD_I4)) {
+                               MonoInst *one_ins, *load_ins;
+
+                               EMIT_NEW_PCONST (cfg, load_ins, counter);
+                               EMIT_NEW_ICONST (cfg, one_ins, 1);
+                               MONO_INST_NEW (cfg, ins, OP_ATOMIC_ADD_I4);
+                               ins->dreg = mono_alloc_ireg (cfg);
+                               ins->inst_basereg = load_ins->dreg;
+                               ins->inst_offset = 0;
+                               ins->sreg2 = one_ins->dreg;
+                               ins->type = STACK_I4;
+                               MONO_ADD_INS (cfg->cbb, ins);
+                       } else {
+                               EMIT_NEW_PCONST (cfg, ins, counter);
+                               MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
+                       }
                }
 
                if (cfg->verbose_level > 3)
@@ -7808,7 +7893,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_ARG (n);
                        if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
                                UNVERIFIED;
-                       EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
+                       emit_starg_ir (cfg, sp, n);
                        ip += 2;
                        break;
                case CEE_LDLOC_S:
@@ -7816,7 +7901,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK_OVF (1);
                        n = ip [1];
                        CHECK_LOCAL (n);
-                       EMIT_NEW_LOCLOAD (cfg, ins, n);
+                       if ((ip [2] == CEE_LDFLD) && ip_in_bb (cfg, cfg->cbb, ip + 2) && MONO_TYPE_ISSTRUCT (header->locals [n])) {
+                               /* Avoid loading a struct just to load one of its fields */
+                               EMIT_NEW_LOCLOADA (cfg, ins, n);
+                       } else {
+                               EMIT_NEW_LOCLOAD (cfg, ins, n);
+                       }
                        *sp++ = ins;
                        ip += 2;
                        break;
@@ -8026,7 +8116,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (cfg->gshared && mono_method_check_context_used (cmethod))
                                GENERIC_SHARING_FAILURE (CEE_JMP);
 
-                       emit_instrumentation_call (cfg, mono_profiler_method_leave);
+                       mini_profiler_emit_tail_call (cfg, cmethod);
 
                        fsig = mono_method_signature (cmethod);
                        n = fsig->param_count + fsig->hasthis;
@@ -8756,6 +8846,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        }
                                        for (i = 0; i < n; ++i)
                                                EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
+
+                                       mini_profiler_emit_tail_call (cfg, cmethod);
+
                                        MONO_INST_NEW (cfg, ins, OP_BR);
                                        MONO_ADD_INS (cfg->cbb, ins);
                                        tblock = start_bblock->out_bb [0];
@@ -8968,7 +9061,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        /* Handle tail calls similarly to normal calls */
                                        tail_call = TRUE;
                                } else {
-                                       emit_instrumentation_call (cfg, mono_profiler_method_leave);
+                                       mini_profiler_emit_tail_call (cfg, cmethod);
 
                                        MONO_INST_NEW_CALL (cfg, call, OP_JMP);
                                        call->tail_call = TRUE;
@@ -9079,6 +9172,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                }
                case CEE_RET:
+                       mini_profiler_emit_leave (cfg, sig->ret->type != MONO_TYPE_VOID ? sp [-1] : NULL);
+
                        if (cfg->method != method) {
                                /* return from inlined method */
                                /* 
@@ -9102,8 +9197,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        cfg->ret_var_set = TRUE;
                                } 
                        } else {
-                               emit_instrumentation_call (cfg, mono_profiler_method_leave);
-
                                if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
                                        emit_pop_lmf (cfg);
 
@@ -11391,18 +11484,35 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
                                GList *tmp;
-                               MonoExceptionClause *clause;
 
                                for (tmp = handlers; tmp; tmp = tmp->next) {
-                                       clause = (MonoExceptionClause *)tmp->data;
+                                       MonoExceptionClause *clause = (MonoExceptionClause *)tmp->data;
+                                       MonoInst *abort_exc = (MonoInst *)mono_find_exvar_for_offset (cfg, clause->handler_offset);
+                                       MonoBasicBlock *dont_throw;
+
                                        tblock = cfg->cil_offset_to_bb [clause->handler_offset];
                                        g_assert (tblock);
                                        link_bblock (cfg, cfg->cbb, tblock);
+
+                                       MONO_EMIT_NEW_PCONST (cfg, abort_exc->dreg, 0);
+
                                        MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
                                        ins->inst_target_bb = tblock;
                                        ins->inst_eh_block = clause;
                                        MONO_ADD_INS (cfg->cbb, ins);
                                        cfg->cbb->has_call_handler = 1;
+
+                                       /* Throw exception if exvar is set */
+                                       /* FIXME Do we need this for calls from catch/filter ? */
+                                       NEW_BBLOCK (cfg, dont_throw);
+                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, abort_exc->dreg, 0);
+                                       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
+                                       mono_emit_jit_icall (cfg, mono_thread_self_abort, NULL);
+                                       cfg->cbb->clause_hole = clause;
+
+                                       MONO_START_BB (cfg, dont_throw);
+                                       cfg->cbb->clause_hole = clause;
+
                                        if (COMPILE_LLVM (cfg)) {
                                                MonoBasicBlock *target_bb;
 
@@ -11482,7 +11592,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        case CEE_MONO_LDPTR_CARD_TABLE:
                        case CEE_MONO_LDPTR_NURSERY_START:
                        case CEE_MONO_LDPTR_NURSERY_BITS:
-                       case CEE_MONO_LDPTR_INT_REQ_FLAG: {
+                       case CEE_MONO_LDPTR_INT_REQ_FLAG:
+                       case CEE_MONO_LDPTR_PROFILER_ALLOCATION_COUNT: {
                                CHECK_STACK_OVF (1);
 
                                switch (ip [1]) {
@@ -11498,6 +11609,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                case CEE_MONO_LDPTR_INT_REQ_FLAG:
                                        ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
                                        break;
+                               case CEE_MONO_LDPTR_PROFILER_ALLOCATION_COUNT:
+                                       ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT, NULL);
+                                       break;
                                default:
                                        g_assert_not_reached ();
                                        break;
@@ -11669,6 +11783,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (sp != stack_start)
                                        UNVERIFIED;
                                
+                               mini_profiler_emit_leave (cfg, sp [0]);
+
                                MONO_INST_NEW (cfg, ins, OP_BR);
                                ins->inst_target_bb = end_bblock;
                                MONO_ADD_INS (cfg->cbb, ins);
@@ -11723,7 +11839,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
                                }
 
-                               /* Has to use a call inst since it local regalloc expects it */
+                               /* Has to use a call inst since local regalloc expects it */
                                MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
                                ins = (MonoInst*)call;
                                sp -= 2;
@@ -11732,6 +11848,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_ADD_INS (cfg->cbb, ins);
 
                                cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
+                               /* OP_DYN_CALL might need to allocate a dynamically sized param area */
+                               cfg->flags |= MONO_CFG_HAS_ALLOCA;
 
                                ip += 2;
                                inline_costs += 10 * num_calls++;
@@ -11765,7 +11883,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoInst *ad_ins, *jit_tls_ins;
                                MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
 
-                               g_assert (!mono_threads_is_coop_enabled ());
+                               g_assert (!mono_threads_is_blocking_transition_enabled ());
 
                                cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
 
@@ -12263,7 +12381,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_ARG (n);
                                if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
                                        UNVERIFIED;
-                               EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
+                               emit_starg_ir (cfg, sp, n);
                                ip += 4;
                                break;
                        case CEE_LDLOC:
@@ -12271,7 +12389,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_OPSIZE (4);
                                n = read16 (ip + 2);
                                CHECK_LOCAL (n);
-                               EMIT_NEW_LOCLOAD (cfg, ins, n);
+                               if ((ip [4] == CEE_LDFLD) && ip_in_bb (cfg, cfg->cbb, ip + 4) && header->locals [n]->type == MONO_TYPE_VALUETYPE) {
+                                       /* Avoid loading a struct just to load one of its fields */
+                                       EMIT_NEW_LOCLOADA (cfg, ins, n);
+                               } else {
+                                       EMIT_NEW_LOCLOAD (cfg, ins, n);
+                               }
                                *sp++ = ins;
                                ip += 4;
                                break;
@@ -12605,7 +12728,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        }
 
        cfg->cbb = init_localsbb;
-       emit_instrumentation_call (cfg, mono_profiler_method_enter);
+       mini_profiler_emit_enter (cfg);
 
        if (seq_points) {
                MonoBasicBlock *bb;