Merge pull request #4045 from lambdageek/bug-47867
[mono.git] / mono / mini / method-to-ir.c
index 1b55991ff0290da9607e57336770694cab92c4db..87a0974d0d62ea8ecff10fe43232a56e980cf247 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <config.h>
+#include <mono/utils/mono-compiler.h>
 
 #ifndef DISABLE_JIT
 
@@ -155,6 +156,7 @@ emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig
 static MonoMethodSignature *helper_sig_domain_get;
 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
 static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
+static MonoMethodSignature *helper_sig_jit_thread_attach;
 
 /* type loading helpers */
 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
@@ -326,6 +328,8 @@ handle_enum:
        case MONO_TYPE_TYPEDBYREF:
                return OP_VMOVE;
        case MONO_TYPE_GENERICINST:
+               if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
+                       return OP_XMOVE;
                type = &type->data.generic_class->container_class->byval_arg;
                goto handle_enum;
        case MONO_TYPE_VAR:
@@ -364,6 +368,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_trampoline = mono_create_icall_signature ("ptr ptr ptr");
+       helper_sig_jit_thread_attach = mono_create_icall_signature ("ptr ptr");
 }
 
 static MONO_NEVER_INLINE void
@@ -1657,7 +1662,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);
 }
 
@@ -1668,7 +1673,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);
 }
 
@@ -1794,7 +1799,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
@@ -2550,7 +2555,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))
@@ -2791,7 +2796,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) {
@@ -2829,7 +2834,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);
 
@@ -2918,7 +2923,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;
@@ -3496,8 +3501,8 @@ emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
 
        if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
                        !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
-                       !method->klass->valuetype)
-               EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
+               !method->klass->valuetype)
+               EMIT_NEW_VARLOAD (cfg, this_ins, cfg->this_arg, &mono_defaults.object_class->byval_arg);
 
        if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
                MonoInst *mrgctx_loc, *mrgctx_var;
@@ -3678,8 +3683,8 @@ static MonoInst*
 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
                                          MonoClass *klass, MonoRgctxInfoType rgctx_type)
 {
-       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_CLASS, klass, rgctx_type);
-       MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_CLASS, klass, rgctx_type);
+       MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
 
        return emit_rgctx_fetch (cfg, rgctx, entry);
 }
@@ -3688,8 +3693,8 @@ static MonoInst*
 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
                                        MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
 {
-       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_SIGNATURE, sig, rgctx_type);
-       MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_SIGNATURE, sig, rgctx_type);
+       MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
 
        return emit_rgctx_fetch (cfg, rgctx, entry);
 }
@@ -3706,8 +3711,8 @@ emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
        call_info->sig = sig;
        call_info->method = cmethod;
 
-       entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_CALL, call_info, rgctx_type);
-       rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+       entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_CALL, call_info, rgctx_type);
+       rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
 
        return emit_rgctx_fetch (cfg, rgctx, entry);
 }
@@ -3729,8 +3734,8 @@ emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
        info->klass = klass;
        info->method = virt_method;
 
-       entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_VIRT_METHOD, info, rgctx_type);
-       rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+       entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_VIRT_METHOD, info, rgctx_type);
+       rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
 
        return emit_rgctx_fetch (cfg, rgctx, entry);
 }
@@ -3742,8 +3747,8 @@ emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
        MonoJumpInfoRgctxEntry *entry;
        MonoInst *rgctx;
 
-       entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_METHOD, info, MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO);
-       rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+       entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_METHOD, info, MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO);
+       rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
 
        return emit_rgctx_fetch (cfg, rgctx, entry);
 }
@@ -3772,8 +3777,8 @@ emit_get_rgctx_method (MonoCompile *cfg, int context_used,
                        g_assert_not_reached ();
                }
        } else {
-               MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
-               MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+               MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
+               MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
 
                return emit_rgctx_fetch (cfg, rgctx, entry);
        }
@@ -3783,8 +3788,8 @@ static MonoInst*
 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
                                          MonoClassField *field, MonoRgctxInfoType rgctx_type)
 {
-       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_FIELD, field, rgctx_type);
-       MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_FIELD, field, rgctx_type);
+       MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
 
        return emit_rgctx_fetch (cfg, rgctx, entry);
 }
@@ -4054,7 +4059,7 @@ handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int co
                        cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
                        return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
                } else {
-                       rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+                       rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
 
                        return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
                }
@@ -4258,7 +4263,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));
@@ -4321,7 +4326,7 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
                                   have to get the method address from the RGCTX. */
                                MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
                                                                                                                MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
-                               MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+                               MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
 
                                return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
                        }
@@ -4432,11 +4437,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;
@@ -4495,7 +4500,7 @@ method_needs_stack_walk (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)
+#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)
@@ -4572,7 +4577,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) {
@@ -4605,7 +4610,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 {
@@ -4613,7 +4618,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);
@@ -4686,7 +4691,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);
@@ -4716,7 +4721,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)) {
@@ -4736,7 +4741,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.*/
@@ -4805,7 +4810,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
@@ -4909,7 +4914,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);
        
@@ -5056,7 +5061,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);
@@ -5186,7 +5191,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];
@@ -5312,7 +5317,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
 
        if (cfg->disable_inline)
                return FALSE;
-       if (cfg->gshared)
+       if (cfg->gsharedvt)
                return FALSE;
 
        if (cfg->inline_depth > 10)
@@ -5346,20 +5351,25 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
         * since it would mean inserting a call to mono_runtime_class_init()
         * inside the inlined code
         */
+       if (cfg->gshared && method->klass->has_cctor && mini_class_check_context_used (cfg, method->klass))
+               return FALSE;
+
        if (!(cfg->opt & MONO_OPT_SHARED)) {
                /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
                if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
-                       vtable = mono_class_vtable (cfg->domain, method->klass);
-                       if (!vtable)
-                               return FALSE;
-                       if (!cfg->compile_aot) {
-                               MonoError error;
-                               if (!mono_runtime_class_init_full (vtable, &error)) {
-                                       mono_error_cleanup (&error);
+                       if (method->klass->has_cctor) {
+                               vtable = mono_class_vtable (cfg->domain, method->klass);
+                               if (!vtable)
                                        return FALSE;
+                               if (!cfg->compile_aot) {
+                                       MonoError error;
+                                       if (!mono_runtime_class_init_full (vtable, &error)) {
+                                               mono_error_cleanup (&error);
+                                               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)
@@ -5395,7 +5405,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;
        }
 
@@ -5425,7 +5435,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;
        }
@@ -5440,7 +5450,7 @@ mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoCla
        return TRUE;
 }
 
-static MonoInst*
+MonoInst*
 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
 {
        MonoInst *ins;
@@ -5698,7 +5708,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];
@@ -6125,8 +6135,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) {
@@ -6138,10 +6153,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;
                }
@@ -6803,6 +6818,13 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                 * all inputs:
                 * http://everything2.com/?node_id=1051618
                 */
+       } else if (cmethod->klass == mono_defaults.systemtype_class && !strcmp (cmethod->name, "op_Equality")) {
+               EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg);
+               MONO_INST_NEW (cfg, ins, OP_PCEQ);
+               ins->dreg = alloc_preg (cfg);
+               ins->type = STACK_I4;
+               MONO_ADD_INS (cfg->cbb, ins);
+               return ins;
        } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
                    !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
                                !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
@@ -7071,11 +7093,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;
@@ -7199,7 +7221,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
                if (cfg->verbose_level > 2)
                        printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
-               
+
                cfg->stat_inlined_methods++;
 
                /* always add some code to avoid block split failures */
@@ -7711,7 +7733,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;
@@ -7947,7 +7969,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) {
@@ -8146,7 +8168,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, 
@@ -8474,7 +8511,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;
@@ -9360,7 +9398,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)
@@ -9379,7 +9417,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);
@@ -9400,7 +9438,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.
                                                 */
@@ -9453,7 +9491,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;
@@ -9528,7 +9566,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);
                        }
@@ -9540,7 +9578,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
@@ -9783,13 +9821,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))
@@ -9802,7 +9840,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);
@@ -9910,7 +9948,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);
@@ -10006,7 +10044,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        /* Common call */
-                       INLINE_FAILURE ("call");
+                       if (!(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
+                               INLINE_FAILURE ("call");
                        ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
                                                                                          imt_arg, vtable_arg);
 
@@ -10454,7 +10493,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;
@@ -10837,7 +10876,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);
                        }
@@ -11029,13 +11068,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 {
@@ -11383,7 +11427,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]);
@@ -11475,6 +11519,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
 
+                                       if (sp [0]->opcode == OP_LDADDR && klass->simd_type && cfg->opt & MONO_OPT_SIMD) {
+                                               ins = mono_emit_simd_field_load (cfg, field, sp [0]);
+                                               if (ins) {
+                                                       *sp++ = ins;
+                                                       ins_flag = 0;
+                                                       ip += 5;
+                                                       break;
+                                               }
+                                       }
+
                                        if (mini_is_gsharedvt_klass (klass)) {
                                                MonoInst *offset_ins;
 
@@ -11806,7 +11860,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]);
                        }
@@ -12149,7 +12203,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);
 
@@ -12157,9 +12211,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);
 
@@ -12555,7 +12606,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
 
                                if (cfg->compile_aot) {
-                                       EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
+                                       if (cfg->direct_pinvoke && ip + 6 < end && (ip [6] == CEE_POP)) {
+                                               /*
+                                                * This is generated by emit_native_wrapper () to resolve the pinvoke address
+                                                * before the call, its not needed when using direct pinvoke.
+                                                * This is not an optimization, but its used to avoid looking up pinvokes
+                                                * on platforms which don't support dlopen ().
+                                                */
+                                               EMIT_NEW_PCONST (cfg, ins, NULL);
+                                       } else {
+                                               EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
+                                       }
                                } else {
                                        ptr = mono_lookup_internal_call (cmethod);
                                        g_assert (ptr);
@@ -12818,13 +12879,24 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                /* AOT code is only used in the root domain */
                                EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
-                               ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
+                               if (cfg->compile_aot) {
+                                       MonoInst *addr;
+
+                                       /*
+                                        * This is called on unattached threads, so it cannot go through the trampoline
+                                        * infrastructure. Use an indirect call through a got slot initialized at load time
+                                        * instead.
+                                        */
+                                       EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_JIT_THREAD_ATTACH, NULL);
+                                       ins = mono_emit_calli (cfg, helper_sig_jit_thread_attach, args, addr, NULL, NULL);
+                               } else {
+                                       ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
+                               }
                                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
 
                                if (next_bb)
                                        MONO_START_BB (cfg, next_bb);
 
-
                                ip += 2;
                                break;
                        }
@@ -13680,7 +13752,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)
@@ -14310,6 +14385,7 @@ mono_handle_global_vregs (MonoCompile *cfg)
                                                        mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
                                                        break;
                                                case 'v':
+                                               case 'x':
                                                        mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
                                                        break;
                                                default:
@@ -15094,12 +15170,12 @@ mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
        NEW_BBLOCK (cfg, first_bb);
        cfg->cbb = first_bb;
 
-       if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
+       if (!context_used && (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || klass->is_array_special_interface)) {
                if (is_isinst)
                        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;
 
@@ -15269,4 +15345,8 @@ NOTES
   the values on the stack before emitting the last instruction of the bb.
 */
 
-#endif /* DISABLE_JIT */
+#else /* !DISABLE_JIT */
+
+MONO_EMPTY_SOURCE_FILE (method_to_ir);
+
+#endif /* !DISABLE_JIT */