[jit] Finish support for valuetype based sharing in JIT mode, not enabled yet.
[mono.git] / mono / mini / method-to-ir.c
index f4552d4b942478db91607867aa3808621a9e28fd..dee6f35c7ae21c0816aa00adcba9dd2060573b5e 100755 (executable)
@@ -276,7 +276,7 @@ mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
        if (type->byref)
                return OP_MOVE;
 
-       type = mini_replace_type (type);
+       type = mini_get_underlying_type (cfg, type);
 handle_enum:
        switch (type->type) {
        case MONO_TYPE_I1:
@@ -331,7 +331,7 @@ handle_enum:
                if (mini_type_var_is_vt (cfg, type))
                        return OP_VMOVE;
                else
-                       return OP_MOVE;
+                       return mono_type_to_regmove (cfg, mini_get_underlying_type (cfg, type));
        default:
                g_error ("unknown type 0x%02x in type_to_regstore", type->type);
        }
@@ -513,7 +513,7 @@ add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **a
         add_widen_op (cfg, ins, &sp [0], &sp [1]);              \
         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
         MONO_ADD_INS ((cfg)->cbb, (ins)); \
-        *sp++ = mono_decompose_opcode ((cfg), (ins)); \
+        *sp++ = mono_decompose_opcode ((cfg), (ins), &bblock); \
        } while (0)
 
 #define ADD_UNOP(op) do {      \
@@ -524,7 +524,7 @@ add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **a
                CHECK_TYPE (ins);       \
         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
         MONO_ADD_INS ((cfg)->cbb, (ins)); \
-               *sp++ = mono_decompose_opcode (cfg, ins); \
+               *sp++ = mono_decompose_opcode (cfg, ins, &bblock);      \
        } while (0)
 
 #define ADD_BINCOND(next_block) do {   \
@@ -738,7 +738,7 @@ type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
 {
        MonoClass *klass;
 
-       type = mini_replace_type (type);
+       type = mini_get_underlying_type (cfg, type);
        inst->klass = klass = mono_class_from_mono_type (type);
        if (type->byref) {
                inst->type = STACK_MP;
@@ -806,7 +806,7 @@ handle_enum:
                        g_assert (cfg->gsharedvt);
                        inst->type = STACK_VTYPE;
                } else {
-                       inst->type = STACK_OBJ;
+                       type_to_eval_stack_type (cfg, mini_get_underlying_type (cfg, type), inst);
                }
                return;
        default:
@@ -2140,12 +2140,8 @@ emit_instrumentation_call (MonoCompile *cfg, void *func)
 static int
 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
 {
-       if (type->byref)
-               return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
-
 handle_enum:
-       type = mini_get_basic_type_from_generic (gsctx, type);
-       type = mini_replace_type (type);
+       type = mini_get_underlying_type (cfg, type);
        switch (type->type) {
        case MONO_TYPE_VOID:
                return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
@@ -2217,7 +2213,6 @@ target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
        MonoType *simple_type;
        MonoClass *klass;
 
-       target = mini_replace_type (target);
        if (target->byref) {
                /* FIXME: check that the pointed to types match */
                if (arg->type == STACK_MP)
@@ -2227,7 +2222,7 @@ target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
                return 1;
        }
 
-       simple_type = mono_type_get_underlying_type (target);
+       simple_type = mini_get_underlying_type (cfg, target);
        switch (simple_type->type) {
        case MONO_TYPE_VOID:
                return 1;
@@ -2350,8 +2345,7 @@ check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **arg
                                return 1;
                        continue;
                }
-               simple_type = sig->params [i];
-               simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
+               simple_type = mini_get_underlying_type (cfg, sig->params [i]);
 handle_enum:
                switch (simple_type->type) {
                case MONO_TYPE_VOID:
@@ -2612,7 +2606,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
        call->args = args;
        call->signature = sig;
        call->rgctx_reg = rgctx;
-       sig_ret = mini_replace_type (sig->ret);
+       sig_ret = mini_get_underlying_type (cfg, sig->ret);
 
        type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
 
@@ -3004,6 +2998,58 @@ mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer
        ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
        return ins;
 }
+
+MonoInst*
+mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args, MonoBasicBlock **out_cbb)
+{
+       gboolean no_wrapper = FALSE;
+
+       /*
+        * Call the jit icall without a wrapper if possible.
+        * The wrapper is needed for the following reasons:
+        * - to handle exceptions thrown using mono_raise_exceptions () from the
+        *   icall function. The EH code needs the lmf frame pushed by the
+        *   wrapper to be able to unwind back to managed code.
+        * - to be able to do stack walks for asynchronously suspended
+        *   threads when debugging.
+        */
+       if (info->no_raise) {
+               if (cfg->compile_aot) {
+                       // FIXME: This might be loaded into a runtime during debugging
+                       // even if it is not compiled using 'soft-debug'.
+               } else {
+                       no_wrapper = TRUE;
+                       /* LLVM on amd64 can't handle calls to non-32 bit addresses */
+                       if ((cfg->compile_llvm && SIZEOF_VOID_P == 8) || cfg->gen_seq_points_debug_data)
+                               no_wrapper = FALSE;
+               }
+       }
+
+       if (no_wrapper) {
+               char *name;
+               int costs;
+
+               if (!info->wrapper_method) {
+                       name = g_strdup_printf ("__icall_wrapper_%s", info->name);
+                       info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
+                       g_free (name);
+                       mono_memory_barrier ();
+               }
+
+               /*
+                * Inline the wrapper method, which is basically a call to the C icall, and
+                * an exception check.
+                */
+               costs = inline_method (cfg, info->wrapper_method, NULL,
+                                                          args, NULL, cfg->real_offset, TRUE, out_cbb);
+               g_assert (costs > 0);
+               g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
+
+               return args [0];
+       } else {
+               return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
+       }
+}
  
 static MonoInst*
 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
@@ -3240,13 +3286,16 @@ void
 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
 {
        MonoInst *iargs [4];
-       int context_used, n;
+       int n;
        guint32 align = 0;
        MonoMethod *memcpy_method;
        MonoInst *size_ins = NULL;
        MonoInst *memcpy_ins = NULL;
 
        g_assert (klass);
+       if (cfg->generic_sharing_context)
+               klass = mono_class_from_mono_type (mini_get_underlying_type (cfg, &klass->byval_arg));
+
        /*
         * This check breaks with spilled vars... need to handle it during verification anyway.
         * g_assert (klass && klass == src->klass && klass == dest->klass);
@@ -3254,7 +3303,6 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
 
        if (mini_is_gsharedvt_klass (cfg, klass)) {
                g_assert (!native);
-               context_used = mini_class_check_context_used (cfg, klass);
                size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
                memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
        }
@@ -3333,7 +3381,7 @@ void
 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
 {
        MonoInst *iargs [3];
-       int n, context_used;
+       int n;
        guint32 align;
        MonoMethod *memset_method;
        MonoInst *size_ins = NULL;
@@ -3341,10 +3389,8 @@ mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass
        static MonoMethod *bzero_method;
 
        /* FIXME: Optimize this for the case when dest is an LDADDR */
-
        mono_class_init (klass);
        if (mini_is_gsharedvt_klass (cfg, klass)) {
-               context_used = mini_class_check_context_used (cfg, klass);
                size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
                bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
                if (!bzero_method)
@@ -3828,7 +3874,7 @@ handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_use
                g_assert (klass->rank == 0);
 
                element_class = emit_get_rgctx_klass (cfg, context_used,
-                               klass->element_class, MONO_RGCTX_INFO_KLASS);
+                               klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
 
                MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
                MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
@@ -3902,9 +3948,6 @@ handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj, MonoB
                MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
                MonoInst *unbox_call;
                MonoMethodSignature *unbox_sig;
-               MonoInst *var;
-
-               var = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
 
                unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
                unbox_sig->ret = &klass->byval_arg;
@@ -3942,8 +3985,9 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_
                MonoInst *data;
                int rgctx_info;
                MonoInst *iargs [2];
+               gboolean known_instance_size = !mini_is_gsharedvt_klass (cfg, klass);
 
-               MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
+               MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
 
                if (cfg->opt & MONO_OPT_SHARED)
                        rgctx_info = MONO_RGCTX_INFO_KLASS;
@@ -3960,8 +4004,14 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_
                        alloc_ftn = mono_object_new_specific;
                }
 
-               if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED))
+               if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
+                       if (known_instance_size) {
+                               int size = mono_class_instance_size (klass);
+
+                               EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
+                       }
                        return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
+               }
 
                return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
        }
@@ -3988,11 +4038,14 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_
                }
 
 #ifndef MONO_CROSS_COMPILE
-               managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
+               managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
 #endif
 
                if (managed_alloc) {
+                       int size = mono_class_instance_size (klass);
+
                        EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
+                       EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
                        return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
                }
                alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
@@ -4052,7 +4105,7 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used,
        if (mini_is_gsharedvt_klass (cfg, klass)) {
                MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
                MonoInst *res, *is_ref, *src_var, *addr;
-               int addr_reg, dreg;
+               int dreg;
 
                dreg = alloc_ireg (cfg);
 
@@ -4080,7 +4133,6 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used,
                
                /* Ref case */
                MONO_START_BB (cfg, is_ref_bb);
-               addr_reg = alloc_ireg (cfg);
 
                /* val is a vtype, so has to load the value manually */
                src_var = get_vreg_to_inst (cfg, val->dreg);
@@ -4672,7 +4724,7 @@ handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, M
 {
        MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
        guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
-       gboolean is_i4 = TRUE;
+       gboolean is_i4;
 
        switch (enum_type->type) {
        case MONO_TYPE_I8:
@@ -4683,6 +4735,9 @@ handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, M
 #endif
                is_i4 = FALSE;
                break;
+       default:
+               is_i4 = TRUE;
+               break;
        }
 
        {
@@ -4699,10 +4754,10 @@ handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, M
                ceq->type = STACK_I4;
 
                if (!is_i4) {
-                       load = mono_decompose_opcode (cfg, load);
-                       and = mono_decompose_opcode (cfg, and);
-                       cmp = mono_decompose_opcode (cfg, cmp);
-                       ceq = mono_decompose_opcode (cfg, ceq);
+                       load = mono_decompose_opcode (cfg, load, NULL);
+                       and = mono_decompose_opcode (cfg, and, NULL);
+                       cmp = mono_decompose_opcode (cfg, cmp, NULL);
+                       ceq = mono_decompose_opcode (cfg, ceq, NULL);
                }
 
                return ceq;
@@ -4836,6 +4891,99 @@ handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
        return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
 }
 
+/*
+ * handle_constrained_gsharedvt_call:
+ *
+ *   Handle constrained calls where the receiver is a gsharedvt type.
+ * Return the instruction representing the call. Set the cfg exception on failure.
+ */
+static MonoInst*
+handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
+                                                                  gboolean *ref_emit_widen, MonoBasicBlock **ref_bblock)
+{
+       MonoInst *ins = NULL;
+       MonoBasicBlock *bblock = *ref_bblock;
+       gboolean emit_widen = *ref_emit_widen;
+
+       /*
+        * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
+        * 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)) &&
+               (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 (cfg, 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 (cfg, fsig->params [0]))))) {
+               MonoInst *args [16];
+
+               /*
+                * This case handles calls to
+                * - object:ToString()/Equals()/GetHashCode(),
+                * - System.IComparable<T>:CompareTo()
+                * - System.IEquatable<T>:Equals ()
+                * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
+                */
+
+               args [0] = sp [0];
+               if (mono_method_check_context_used (cmethod))
+                       args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
+               else
+                       EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
+               args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
+
+               /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
+               if (fsig->hasthis && fsig->param_count) {
+                       /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
+                       MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
+                       ins->dreg = alloc_preg (cfg);
+                       ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
+                       MONO_ADD_INS (cfg->cbb, ins);
+                       args [4] = ins;
+
+                       if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
+                               int addr_reg;
+
+                               args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
+
+                               EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
+                               addr_reg = ins->dreg;
+                               EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
+                       } else {
+                               EMIT_NEW_ICONST (cfg, args [3], 0);
+                               EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
+                       }
+               } else {
+                       EMIT_NEW_ICONST (cfg, args [3], 0);
+                       EMIT_NEW_ICONST (cfg, args [4], 0);
+               }
+               ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
+               emit_widen = FALSE;
+
+               if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
+                       ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
+               } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
+                       MonoInst *add;
+
+                       /* Unbox */
+                       NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
+                       MONO_ADD_INS (cfg->cbb, add);
+                       /* Load value */
+                       NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
+                       MONO_ADD_INS (cfg->cbb, ins);
+                       /* ins represents the call result */
+               }
+       } else {
+               GSHAREDVT_FAILURE (CEE_CALLVIRT);
+       }
+
+       *ref_emit_widen = emit_widen;
+       *ref_bblock = bblock;
+
+       return ins;
+
+ exception_exit:
+       return NULL;
+}
+
 static void
 mono_emit_load_got_addr (MonoCompile *cfg)
 {
@@ -5178,20 +5326,24 @@ mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, uns
        MonoInst *addr;
        MonoMethod *addr_method;
        int element_size;
+       MonoClass *eclass = cmethod->klass->element_class;
 
        rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
 
        if (rank == 1)
-               return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
+               return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
 
 #ifndef MONO_ARCH_EMULATE_MUL_DIV
        /* emit_ldelema_2 depends on OP_LMUL */
-       if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
-               return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
+       if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (cfg, eclass)) {
+               return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
        }
 #endif
 
-       element_size = mono_class_array_element_size (cmethod->klass->element_class);
+       if (mini_is_gsharedvt_variable_klass (cfg, eclass))
+               element_size = 0;
+       else
+               element_size = mono_class_array_element_size (eclass);
        addr_method = mono_marshal_get_array_address (rank, element_size);
        addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
 
@@ -5507,7 +5659,6 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count == 2) {
                        int dreg = alloc_ireg (cfg);
                        int index_reg = alloc_preg (cfg);
-                       int mult_reg = alloc_preg (cfg);
                        int add_reg = alloc_preg (cfg);
 
 #if SIZEOF_REGISTER == 8
@@ -5521,11 +5672,10 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
 #if defined(TARGET_X86) || defined(TARGET_AMD64)
                        EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
                        add_reg = ins->dreg;
-                       /* Avoid a warning */
-                       mult_reg = 0;
                        EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
                                                                   add_reg, 0);
 #else
+                       int mult_reg = alloc_preg (cfg);
                        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
                        MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
                        EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
@@ -5736,7 +5886,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                                }
 
                                if (opcode == OP_LOADI8_MEMBASE)
-                                       ins = mono_decompose_opcode (cfg, ins);
+                                       ins = mono_decompose_opcode (cfg, ins, NULL);
 
                                emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
 
@@ -5771,7 +5921,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                                MONO_ADD_INS (cfg->cbb, ins);
 
                                if (opcode == OP_STOREI8_MEMBASE_REG)
-                                       ins = mono_decompose_opcode (cfg, ins);
+                                       ins = mono_decompose_opcode (cfg, ins, NULL);
 
                                return ins;
                        }
@@ -6096,7 +6246,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
                        MONO_ADD_INS (cfg->cbb, ins);
 
-                       switch (fsig->params [0]->type) {
+                       switch (fsig->params [1]->type) {
                        case MONO_TYPE_I4:
                                ins->type = STACK_I4;
                                break;
@@ -6115,7 +6265,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                                ins->type = STACK_R8;
                                break;
                        default:
-                               g_assert (mini_type_is_reference (cfg, fsig->params [0]));
+                               g_assert (mini_type_is_reference (cfg, fsig->params [1]));
                                ins->type = STACK_OBJ;
                                break;
                        }
@@ -6408,7 +6558,7 @@ mini_redirect_call (MonoCompile *cfg, MonoMethod *method,
 
                        g_assert (vtable); /*Should not fail since it System.String*/
 #ifndef MONO_CROSS_COMPILE
-                       managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE);
+                       managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
 #endif
                        if (!managed_alloc)
                                return NULL;
@@ -6517,7 +6667,7 @@ emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
        MonoInst *ins;
        int t;
 
-       rtype = mini_replace_type (rtype);
+       rtype = mini_get_underlying_type (cfg, rtype);
        t = rtype->type;
 
        if (rtype->byref) {
@@ -6553,7 +6703,7 @@ emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
 {
        int t;
 
-       rtype = mini_replace_type (rtype);
+       rtype = mini_get_underlying_type (cfg, rtype);
        t = rtype->type;
 
        if (rtype->byref) {
@@ -6631,6 +6781,9 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                return 0;
 #endif
 
+       if (!fsig)
+               fsig = mono_method_signature (cmethod);
+
        if (cfg->verbose_level > 2)
                printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
 
@@ -6696,7 +6849,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        prev_ret_var_set = cfg->ret_var_set;
        prev_disable_inline = cfg->disable_inline;
 
-       if (*ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
+       if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
                virtual = TRUE;
 
        costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
@@ -6770,7 +6923,8 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                        cfg->cbb = ebblock;
                }
 
-               *out_cbb = cfg->cbb;
+               if (out_cbb)
+                       *out_cbb = cfg->cbb;
 
                if (rvar) {
                        /*
@@ -7252,7 +7406,7 @@ emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *en
                token = read32 (ip + 2);
                klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
                CHECK_TYPELOAD (klass);
-               type = mini_replace_type (&klass->byval_arg);
+               type = mini_get_underlying_type (cfg, &klass->byval_arg);
                emit_init_local (cfg, local, type, TRUE);
                return ip + 6;
        }
@@ -7305,13 +7459,11 @@ is_jit_optimizer_disabled (MonoMethod *m)
                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;
@@ -7557,7 +7709,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        MonoImage *image;
        guint32 token, ins_flag;
        MonoClass *klass;
-       MonoClass *constrained_call = NULL;
+       MonoClass *constrained_class = NULL;
        unsigned char *ip, *end, *target, *err_pos;
        MonoMethodSignature *sig;
        MonoGenericContext *generic_context = NULL;
@@ -8602,31 +8754,41 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
                                cil_method = cmethod;
                                
-                               if (constrained_call) {
+                               if (constrained_class) {
+                                       if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
+                                               if (!mini_is_gsharedvt_klass (cfg, constrained_class)) {
+                                                       g_assert (!cmethod->klass->valuetype);
+                                                       if (!mini_type_is_reference (cfg, &constrained_class->byval_arg)) {
+                                                               /* FIXME: gshared type constrained to a primitive type */
+                                                               GENERIC_SHARING_FAILURE (CEE_CALL);
+                                                       }
+                                               }
+                                       }
+
                                        if (method->wrapper_type != MONO_WRAPPER_NONE) {
                                                if (cfg->verbose_level > 2)
-                                                       printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
-                                               if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
-                                                          constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
+                                                       printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
+                                               if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
+                                                          constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
                                                          cfg->generic_sharing_context)) {
-                                                       cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context, &cfg->error);
+                                                       cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
                                                        CHECK_CFG_ERROR;
                                                }
                                        } else {
                                                if (cfg->verbose_level > 2)
-                                                       printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
+                                                       printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
 
-                                               if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
+                                               if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
                                                        /* 
                                                         * This is needed since get_method_constrained can't find 
                                                         * the method in klass representing a type var.
                                                         * The type var is guaranteed to be a reference type in this
                                                         * case.
                                                         */
-                                                       if (!mini_is_gsharedvt_klass (cfg, constrained_call))
+                                                       if (!mini_is_gsharedvt_klass (cfg, constrained_class))
                                                                g_assert (!cmethod->klass->valuetype);
                                                } else {
-                                                       cmethod = mono_get_method_constrained_checked (image, token, constrained_call, generic_context, &cil_method, &cfg->error);
+                                                       cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
                                                        CHECK_CFG_ERROR;
                                                }
                                        }
@@ -8682,7 +8844,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
                                                        check_for_pending_exc, cfg->compile_aot);
                                                fsig = mono_method_signature (wrapper);
-                                       } else if (constrained_call) {
+                                       } else if (constrained_class) {
                                                fsig = mono_method_signature (cmethod);
                                        } else {
                                                fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
@@ -8727,96 +8889,34 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        sp -= n;
 
-                       if (constrained_call) {
-                               if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
-                                       /*
-                                        * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
-                                        */
-                                       if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
+                       if (constrained_class) {
+                               if (mini_is_gsharedvt_klass (cfg, 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) {
                                                /* 'The type parameter is instantiated as a reference type' case below. */
-                                       } else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!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 (cfg, fsig->ret)) &&
-                                                          (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || mini_is_gsharedvt_type (cfg, fsig->params [0]))))) {
-                                               MonoInst *args [16];
-
-                                               /*
-                                                * This case handles calls to
-                                                * - object:ToString()/Equals()/GetHashCode(),
-                                                * - System.IComparable<T>:CompareTo()
-                                                * - System.IEquatable<T>:Equals ()
-                                                * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
-                                                */
-
-                                               args [0] = sp [0];
-                                               if (mono_method_check_context_used (cmethod))
-                                                       args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
-                                               else
-                                                       EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
-                                               args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
-
-                                               /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
-                                               if (fsig->hasthis && fsig->param_count) {
-                                                       /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
-                                                       MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
-                                                       ins->dreg = alloc_preg (cfg);
-                                                       ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
-                                                       MONO_ADD_INS (cfg->cbb, ins);
-                                                       args [4] = ins;
-
-                                                       if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
-                                                               int addr_reg;
-
-                                                               args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
-
-                                                               EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
-                                                               addr_reg = ins->dreg;
-                                                               EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
-                                                       } else {
-                                                               EMIT_NEW_ICONST (cfg, args [3], 0);
-                                                               EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
-                                                       }
-                                               } else {
-                                                       EMIT_NEW_ICONST (cfg, args [3], 0);
-                                                       EMIT_NEW_ICONST (cfg, args [4], 0);
-                                               }
-                                               ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
-                                               emit_widen = FALSE;
-
-                                               if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
-                                                       ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
-                                               } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
-                                                       MonoInst *add;
-
-                                                       /* Unbox */
-                                                       NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
-                                                       MONO_ADD_INS (cfg->cbb, add);
-                                                       /* Load value */
-                                                       NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
-                                                       MONO_ADD_INS (cfg->cbb, ins);
-                                                       /* ins represents the call result */
-                                               }
-
-                                               goto call_end;
                                        } else {
-                                               GSHAREDVT_FAILURE (*ip);
+                                               ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen, &bblock);
+                                               CHECK_CFG_EXCEPTION;
+                                               g_assert (ins);
+                                               goto call_end;
                                        }
                                }
+
                                /*
                                 * We have the `constrained.' prefix opcode.
                                 */
-                               if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
+                               if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
                                        /*
                                         * The type parameter is instantiated as a valuetype,
                                         * but that type doesn't override the method we're
                                         * calling, so we need to box `this'.
                                         */
-                                       EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
-                                       ins->klass = constrained_call;
-                                       sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
+                                       EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
+                                       ins->klass = constrained_class;
+                                       sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class), &bblock);
                                        CHECK_CFG_EXCEPTION;
-                               } else if (!constrained_call->valuetype) {
+                               } else if (!constrained_class->valuetype) {
                                        int dreg = alloc_ireg_ref (cfg);
 
                                        /*
@@ -8834,27 +8934,27 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                /* Interface method */
                                                int ioffset, slot;
 
-                                               mono_class_setup_vtable (constrained_call);
-                                               CHECK_TYPELOAD (constrained_call);
-                                               ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
+                                               mono_class_setup_vtable (constrained_class);
+                                               CHECK_TYPELOAD (constrained_class);
+                                               ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
                                                if (ioffset == -1)
-                                                       TYPE_LOAD_ERROR (constrained_call);
+                                                       TYPE_LOAD_ERROR (constrained_class);
                                                slot = mono_method_get_vtable_slot (cmethod);
                                                if (slot == -1)
                                                        TYPE_LOAD_ERROR (cmethod->klass);
-                                               cmethod = constrained_call->vtable [ioffset + slot];
+                                               cmethod = constrained_class->vtable [ioffset + slot];
 
                                                if (cmethod->klass == mono_defaults.enum_class) {
                                                        /* Enum implements some interfaces, so treat this as the first case */
-                                                       EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
-                                                       ins->klass = constrained_call;
-                                                       sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
+                                                       EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
+                                                       ins->klass = constrained_class;
+                                                       sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class), &bblock);
                                                        CHECK_CFG_EXCEPTION;
                                                }
                                        }
                                        virtual = 0;
                                }
-                               constrained_call = NULL;
+                               constrained_class = NULL;
                        }
 
                        if (!calli && check_call_signature (cfg, fsig, sp))
@@ -9124,7 +9224,8 @@ 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 (cmethod && cfg->gsharedvt && (mini_is_gsharedvt_signature (cfg, fsig) || cmethod->is_inflated || cmethod->klass->generic_class)) {
+                       if (cmethod && cfg->gsharedvt && (mini_is_gsharedvt_signature (cfg, fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
+                               !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
                                MonoRgctxInfoType info_type;
 
                                if (virtual) {
@@ -9150,10 +9251,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        }
                                }
 
-                               if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
-                                       /* test_0_multi_dim_arrays () in gshared.cs */
-                                       GSHAREDVT_FAILURE (*ip);
-
                                if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
                                        keep_this_alive = sp [0];
 
@@ -9273,6 +9370,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        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);
+                                       if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cfg, cmethod->klass))
+                                               GSHAREDVT_FAILURE (*ip);
                                } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
                                        addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
 
@@ -9418,7 +9517,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 1;
                        }
                        ins_flag = 0;
-                       constrained_call = NULL;
+                       constrained_class = NULL;
                        if (need_seq_point)
                                emit_seq_point (cfg, method, ip, FALSE, TRUE);
                        break;
@@ -9453,7 +9552,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        emit_pop_lmf (cfg);
 
                                if (cfg->ret) {
-                                       MonoType *ret_type = mini_replace_type (mono_method_signature (method)->ret);
+                                       MonoType *ret_type = mini_get_underlying_type (cfg, mono_method_signature (method)->ret);
 
                                        if (seq_points && !sym_seq_points) {
                                                /* 
@@ -9865,7 +9964,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        MONO_ADD_INS ((cfg)->cbb, (ins));
 
-                       *sp++ = mono_decompose_opcode (cfg, ins);
+                       *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
                        ip++;
                        break;
                case CEE_ADD:
@@ -9925,7 +10024,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                        MONO_ADD_INS ((cfg)->cbb, (ins));
 
-                       *sp++ = mono_decompose_opcode (cfg, ins);
+                       *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
                        ip++;
                        break;
                case CEE_NEG:
@@ -10460,7 +10559,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
+
                        mono_save_token_info (cfg, image, token, klass);
 
                        context_used = mini_class_check_context_used (cfg, klass);
@@ -11279,7 +11378,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->type = STACK_I4;
                                ins->dreg = alloc_ireg (cfg);
                                MONO_ADD_INS (cfg->cbb, ins);
-                               *sp = mono_decompose_opcode (cfg, ins);
+                               *sp = mono_decompose_opcode (cfg, ins, &bblock);
                        }
 
                        if (context_used) {
@@ -11504,7 +11603,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->type = STACK_R8;
                        MONO_ADD_INS (bblock, ins);
 
-                       *sp++ = mono_decompose_opcode (cfg, ins);
+                       *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
 
                        ++ip;
                        break;
@@ -12564,7 +12663,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        case CEE_ENDFILTER: {
                                MonoExceptionClause *clause, *nearest;
-                               int cc, nearest_num;
+                               int cc;
 
                                CHECK_STACK (1);
                                --sp;
@@ -12577,15 +12676,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 2;
 
                                nearest = NULL;
-                               nearest_num = 0;
                                for (cc = 0; cc < header->num_clauses; ++cc) {
                                        clause = &header->clauses [cc];
                                        if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
                                                ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
-                                           (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
+                                           (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
                                                nearest = clause;
-                                               nearest_num = cc;
-                                       }
                                }
                                g_assert (nearest);
                                if ((ip - header->code) != nearest->handler_offset)
@@ -12627,8 +12723,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        case CEE_CONSTRAINED_:
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
-                               constrained_call = mini_get_class (method, token, generic_context);
-                               CHECK_TYPELOAD (constrained_call);
+                               constrained_class = mini_get_class (method, token, generic_context);
+                               CHECK_TYPELOAD (constrained_class);
                                ip += 6;
                                break;
                        case CEE_CPBLK: