Merge pull request #4781 from kumpera/unaligned-cleanup-1
[mono.git] / mono / mini / method-to-ir.c
index 3143431b6c48b11fab721ee8d1d0f6739519716b..46ec94350691f39d384d6db6d94021864c6da907 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * method-to-ir.c: Convert CIL to the JIT internal representation
+/**
+ * \file
+ * Convert CIL to the JIT internal representation
  *
  * Author:
  *   Paolo Molaro (lupus@ximian.com)
@@ -12,6 +13,8 @@
  */
 
 #include <config.h>
+#include <mono/utils/mono-compiler.h>
+#include "mini.h"
 
 #ifndef DISABLE_JIT
 
@@ -34,7 +37,6 @@
 #endif
 
 #include <mono/utils/memcheck.h>
-#include "mini.h"
 #include <mono/metadata/abi-details.h>
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/attrdefs.h>
@@ -49,8 +51,7 @@
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/marshal.h>
 #include <mono/metadata/debug-helpers.h>
-#include <mono/metadata/mono-debug.h>
-#include <mono/metadata/mono-debug-debugger.h>
+#include <mono/metadata/debug-internals.h>
 #include <mono/metadata/gc-internals.h>
 #include <mono/metadata/security-manager.h>
 #include <mono/metadata/threads-types.h>
@@ -58,8 +59,6 @@
 #include <mono/metadata/profiler-private.h>
 #include <mono/metadata/profiler.h>
 #include <mono/metadata/monitor.h>
-#include <mono/metadata/debug-mono-symfile.h>
-#include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-memory-model.h>
 #include <mono/utils/mono-error-internals.h>
 #include <mono/metadata/mono-basic-block.h>
@@ -144,8 +143,6 @@ static int stind_to_store_membase (int opcode);
 int mono_op_to_op_imm (int opcode);
 int mono_op_to_op_imm_noemul (int opcode);
 
-MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
-
 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
                                                  guchar *ip, guint real_offset, gboolean inline_always);
 static MonoInst*
@@ -155,10 +152,13 @@ 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;
+static MonoMethodSignature *helper_sig_get_tls_tramp;
+static MonoMethodSignature *helper_sig_set_tls_tramp;
 
 /* type loading helpers */
-static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
-static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, System.Diagnostics, DebuggableAttribute)
+static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, "System.Runtime.CompilerServices", "RuntimeHelpers")
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, "System.Diagnostics", "DebuggableAttribute")
 
 /*
  * Instruction metadata
@@ -201,12 +201,6 @@ const gint8 ins_sreg_counts[] = {
 #undef MINI_OP
 #undef MINI_OP3
 
-#define MONO_INIT_VARINFO(vi,id) do { \
-       (vi)->range.first_use.pos.bid = 0xffff; \
-       (vi)->reg = -1; \
-       (vi)->idx = (id); \
-} while (0)
-
 guint32
 mono_alloc_ireg (MonoCompile *cfg)
 {
@@ -326,6 +320,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:
@@ -346,14 +342,19 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg)
 {
        int i;
        MonoInst *tree;
+       GString *str = g_string_new ("");
 
-       printf ("\n%s %d: [IN: ", msg, bb->block_num);
+       g_string_append_printf (str, "%s %d: [IN: ", msg, bb->block_num);
        for (i = 0; i < bb->in_count; ++i)
-               printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
-       printf (", OUT: ");
+               g_string_append_printf (str, " BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
+       g_string_append_printf (str, ", OUT: ");
        for (i = 0; i < bb->out_count; ++i)
-               printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
-       printf (" ]\n");
+               g_string_append_printf (str, " BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
+       g_string_append_printf (str, " ]\n");
+
+       g_print ("%s", str->str);
+       g_string_free (str, TRUE);
+
        for (tree = bb->code; tree; tree = tree->next)
                mono_print_ins_index (-1, tree);
 }
@@ -364,6 +365,9 @@ 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");
+       helper_sig_get_tls_tramp = mono_create_icall_signature ("ptr");
+       helper_sig_set_tls_tramp = mono_create_icall_signature ("void ptr");
 }
 
 static MONO_NEVER_INLINE void
@@ -1157,10 +1161,24 @@ type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
                ins->klass = mono_defaults.object_class;
 }
 
-static const char 
-ldind_type [] = {
-       STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
-};
+static MonoClass*
+ldind_to_type (int op)
+{
+       switch (op) {
+       case CEE_LDIND_I1: return mono_defaults.sbyte_class;
+       case CEE_LDIND_U1: return mono_defaults.byte_class;
+       case CEE_LDIND_I2: return mono_defaults.int16_class;
+       case CEE_LDIND_U2: return mono_defaults.uint16_class;
+       case CEE_LDIND_I4: return mono_defaults.int32_class;
+       case CEE_LDIND_U4: return mono_defaults.uint32_class;
+       case CEE_LDIND_I8: return mono_defaults.int64_class;
+       case CEE_LDIND_I: return mono_defaults.int_class;
+       case CEE_LDIND_R4: return mono_defaults.single_class;
+       case CEE_LDIND_R8: return mono_defaults.double_class;
+       case CEE_LDIND_REF:return mono_defaults.object_class; //FIXME we should try to return a more specific type
+       default: g_error ("Unknown ldind type %d", op);
+       }
+}
 
 #if 0
 
@@ -1254,16 +1272,22 @@ mono_get_got_var (MonoCompile *cfg)
        return cfg->got_var;
 }
 
-static MonoInst *
-mono_get_vtable_var (MonoCompile *cfg)
+static void
+mono_create_rgctx_var (MonoCompile *cfg)
 {
-       g_assert (cfg->gshared);
-
        if (!cfg->rgctx_var) {
                cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
                /* force the var to be stack allocated */
                cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
        }
+}
+
+static MonoInst *
+mono_get_vtable_var (MonoCompile *cfg)
+{
+       g_assert (cfg->gshared);
+
+       mono_create_rgctx_var (cfg);
 
        return cfg->rgctx_var;
 }
@@ -1547,8 +1571,8 @@ handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
        }
 }
 
-static MonoInst*
-emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
+MonoInst*
+mini_emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
 {
        MonoInst *ins;
 
@@ -1569,421 +1593,91 @@ emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer d
        return ins;
 }
 
-static void
-mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
-{
-       int ibitmap_reg = alloc_preg (cfg);
-#ifdef COMPRESSED_INTERFACE_BITMAP
-       MonoInst *args [2];
-       MonoInst *res, *ins;
-       NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
-       MONO_ADD_INS (cfg->cbb, ins);
-       args [0] = ins;
-       args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
-       res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
-       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
-#else
-       int ibitmap_byte_reg = alloc_preg (cfg);
-
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
-
-       if (cfg->compile_aot) {
-               int iid_reg = alloc_preg (cfg);
-               int shifted_iid_reg = alloc_preg (cfg);
-               int ibitmap_byte_address_reg = alloc_preg (cfg);
-               int masked_iid_reg = alloc_preg (cfg);
-               int iid_one_bit_reg = alloc_preg (cfg);
-               int iid_bit_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
-               MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
-               MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
-               MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
-               MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
-       } else {
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
-       }
-#endif
-}
-
-/* 
- * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
- * stored in "klass_reg" implements the interface "klass".
- */
-static void
-mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
+static MonoInst*
+mono_create_fast_tls_getter (MonoCompile *cfg, MonoTlsKey key)
 {
-       mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
-}
+       int tls_offset = mono_tls_get_tls_offset (key);
 
-/* 
- * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
- * stored in "vtable_reg" implements the interface "klass".
- */
-static void
-mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
-{
-       mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
-}
+       if (cfg->compile_aot)
+               return NULL;
 
-/* 
- * Emit code which checks whenever the interface id of @klass is smaller than
- * than the value given by max_iid_reg.
-*/
-static void
-mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
-                                                MonoBasicBlock *false_target)
-{
-       if (cfg->compile_aot) {
-               int iid_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
-               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
+       if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
+               MonoInst *ins;
+               MONO_INST_NEW (cfg, ins, OP_TLS_GET);
+               ins->dreg = mono_alloc_preg (cfg);
+               ins->inst_offset = tls_offset;
+               return ins;
        }
-       else
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
-       if (false_target)
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
-       else
-               MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
-}
-
-/* Same as above, but obtains max_iid from a vtable */
-static void
-mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
-                                                                MonoBasicBlock *false_target)
-{
-       int max_iid_reg = alloc_preg (cfg);
-               
-       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);
+       return NULL;
 }
 
-/* Same as above, but obtains max_iid from a klass */
-static void
-mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
-                                                                MonoBasicBlock *false_target)
+static MonoInst*
+mono_create_fast_tls_setter (MonoCompile *cfg, MonoInst* value, MonoTlsKey key)
 {
-       int max_iid_reg = alloc_preg (cfg);
+       int tls_offset = mono_tls_get_tls_offset (key);
 
-       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);
-}
+       if (cfg->compile_aot)
+               return NULL;
 
-static void
-mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
-{
-       int idepth_reg = alloc_preg (cfg);
-       int stypes_reg = alloc_preg (cfg);
-       int stype = alloc_preg (cfg);
-
-       mono_class_setup_supertypes (klass);
-
-       if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
-       }
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
-       if (klass_ins) {
-               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
-       } else if (cfg->compile_aot) {
-               int const_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
-               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
-       } else {
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
+       if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
+               MonoInst *ins;
+               MONO_INST_NEW (cfg, ins, OP_TLS_SET);
+               ins->sreg1 = value->dreg;
+               ins->inst_offset = tls_offset;
+               return ins;
        }
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
-}
-
-static void
-mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
-{
-       mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
+       return NULL;
 }
 
-static void
-mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
-{
-       int intf_reg = alloc_preg (cfg);
-
-       mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
-       mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
-       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
-       if (true_target)
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
-       else
-               MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
-}
 
-/*
- * Variant of the above that takes a register to the class, not the vtable.
- */
-static void
-mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
+MonoInst*
+mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
 {
-       int intf_bit_reg = alloc_preg (cfg);
+       MonoInst *fast_tls = NULL;
 
-       mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
-       mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
-       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
-       if (true_target)
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
-       else
-               MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
-}
+       if (!mini_get_debug_options ()->use_fallback_tls)
+               fast_tls = mono_create_fast_tls_getter (cfg, key);
 
-static inline void
-mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
-{
-       if (klass_inst) {
-               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
-       } else {
-               MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
-               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
+       if (fast_tls) {
+               MONO_ADD_INS (cfg->cbb, fast_tls);
+               return fast_tls;
        }
-       MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
-}
-
-static inline void
-mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
-{
-       mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
-}
 
-static inline void
-mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
-{
        if (cfg->compile_aot) {
-               int const_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
-               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
-       } else {
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
-       }
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
-}
-
-static void
-mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
-       
-static void
-mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
-{
-       if (klass->rank) {
-               int rank_reg = alloc_preg (cfg);
-               int eclass_reg = alloc_preg (cfg);
-
-               g_assert (!klass_inst);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
-               MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
-               //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
-               if (klass->cast_class == mono_defaults.object_class) {
-                       int parent_reg = alloc_preg (cfg);
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
-                       mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
-                       mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
-               } else if (klass->cast_class == mono_defaults.enum_class->parent) {
-                       mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
-                       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 (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
-                       mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
-               }
-
-               if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
-                       /* Check that the object is a vector too */
-                       int bounds_reg = alloc_preg (cfg);
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
-                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
-                       MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
-               }
+               MonoInst *addr;
+               /*
+                * tls getters are critical pieces of code and we don't want to resolve them
+                * through the standard plt/tramp mechanism since we might expose ourselves
+                * to crashes and infinite recursions.
+                */
+               EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GET_TLS_TRAMP, (void*)key);
+               return mini_emit_calli (cfg, helper_sig_get_tls_tramp, NULL, addr, NULL, NULL);
        } else {
-               int idepth_reg = alloc_preg (cfg);
-               int stypes_reg = alloc_preg (cfg);
-               int stype = alloc_preg (cfg);
-
-               mono_class_setup_supertypes (klass);
-
-               if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
-                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
-                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
-                       MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
-               }
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
-               mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
-       }
-}
-
-static void
-mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
-{
-       mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
-}
-
-static void 
-mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
-{
-       int val_reg;
-
-       g_assert (val == 0);
-
-       if (align == 0)
-               align = 4;
-
-       if ((size <= SIZEOF_REGISTER) && (size <= align)) {
-               switch (size) {
-               case 1:
-                       MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
-                       return;
-               case 2:
-                       MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
-                       return;
-               case 4:
-                       MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
-                       return;
-#if SIZEOF_REGISTER == 8
-               case 8:
-                       MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
-                       return;
-#endif
-               }
-       }
-
-       val_reg = alloc_preg (cfg);
-
-       if (SIZEOF_REGISTER == 8)
-               MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
-       else
-               MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
-
-       if (align < 4) {
-               /* This could be optimized further if neccesary */
-               while (size >= 1) {
-                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
-                       offset += 1;
-                       size -= 1;
-               }
-               return;
-       }       
-
-       if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
-               if (offset % 8) {
-                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
-                       offset += 4;
-                       size -= 4;
-               }
-               while (size >= 8) {
-                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
-                       offset += 8;
-                       size -= 8;
-               }
-       }       
-
-       while (size >= 4) {
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
-               offset += 4;
-               size -= 4;
-       }
-       while (size >= 2) {
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
-               offset += 2;
-               size -= 2;
-       }
-       while (size >= 1) {
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
-               offset += 1;
-               size -= 1;
+               gpointer getter = mono_tls_get_tls_getter (key, FALSE);
+               return mono_emit_jit_icall (cfg, getter, NULL);
        }
 }
 
-void 
-mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
+static MonoInst*
+mono_create_tls_set (MonoCompile *cfg, MonoInst *value, MonoTlsKey key)
 {
-       int cur_reg;
-
-       if (align == 0)
-               align = 4;
-
-       /*FIXME arbitrary hack to avoid unbound code expansion.*/
-       g_assert (size < 10000);
-
-       if (align < 4) {
-               /* This could be optimized further if neccesary */
-               while (size >= 1) {
-                       cur_reg = alloc_preg (cfg);
-                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
-                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
-                       doffset += 1;
-                       soffset += 1;
-                       size -= 1;
-               }
-       }
+       MonoInst *fast_tls = NULL;
 
-       if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
-               while (size >= 8) {
-                       cur_reg = alloc_preg (cfg);
-                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
-                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
-                       doffset += 8;
-                       soffset += 8;
-                       size -= 8;
-               }
-       }       
+       if (!mini_get_debug_options ()->use_fallback_tls)
+               fast_tls = mono_create_fast_tls_setter (cfg, value, key);
 
-       while (size >= 4) {
-               cur_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
-               doffset += 4;
-               soffset += 4;
-               size -= 4;
-       }
-       while (size >= 2) {
-               cur_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
-               doffset += 2;
-               soffset += 2;
-               size -= 2;
+       if (fast_tls) {
+               MONO_ADD_INS (cfg->cbb, fast_tls);
+               return fast_tls;
        }
-       while (size >= 1) {
-               cur_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
-               doffset += 1;
-               soffset += 1;
-               size -= 1;
-       }
-}
-
-static void
-emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
-{
-       MonoInst *ins, *c;
 
        if (cfg->compile_aot) {
-               EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
-               MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
-               ins->sreg1 = sreg1;
-               ins->sreg2 = c->dreg;
-               MONO_ADD_INS (cfg->cbb, ins);
+               MonoInst *addr;
+               EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_SET_TLS_TRAMP, (void*)key);
+               return mini_emit_calli (cfg, helper_sig_set_tls_tramp, &value, addr, NULL, NULL);
        } else {
-               MONO_INST_NEW (cfg, ins, OP_TLS_SET);
-               ins->sreg1 = sreg1;
-               ins->inst_offset = mini_get_tls_offset (tls_key);
-               MONO_ADD_INS (cfg->cbb, ins);
+               gpointer setter = mono_tls_get_tls_setter (key, FALSE);
+               return mono_emit_jit_icall (cfg, setter, &value);
        }
 }
 
@@ -2002,79 +1696,40 @@ emit_push_lmf (MonoCompile *cfg)
         * lmf->prev_lmf = *lmf_addr
         * *lmf_addr = lmf
         */
-       int lmf_reg, prev_lmf_reg;
        MonoInst *ins, *lmf_ins;
 
        if (!cfg->lmf_ir)
                return;
 
-       if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
-               /* Load current lmf */
-               lmf_ins = mono_get_lmf_intrinsic (cfg);
-               g_assert (lmf_ins);
-               MONO_ADD_INS (cfg->cbb, lmf_ins);
-               EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
-               lmf_reg = ins->dreg;
-               /* Save previous_lmf */
-               EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
-               /* Set new LMF */
-               emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
-       } else {
-               /*
-                * Store lmf_addr in a variable, so it can be allocated to a global register.
-                */
-               if (!cfg->lmf_addr_var)
-                       cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+       int lmf_reg, prev_lmf_reg;
+       /*
+        * Store lmf_addr in a variable, so it can be allocated to a global register.
+        */
+       if (!cfg->lmf_addr_var)
+               cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
 
 #ifdef HOST_WIN32
-               ins = mono_get_jit_tls_intrinsic (cfg);
-               if (ins) {
-                       int jit_tls_dreg = ins->dreg;
-
-                       MONO_ADD_INS (cfg->cbb, ins);
-                       lmf_reg = alloc_preg (cfg);
-                       EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
-               } else {
-                       lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
-               }
-#else
-               lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
-               if (lmf_ins) {
-                       MONO_ADD_INS (cfg->cbb, lmf_ins);
-               } else {
-#ifdef TARGET_IOS
-                       MonoInst *args [16], *jit_tls_ins, *ins;
+       ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
+       g_assert (ins);
+       int jit_tls_dreg = ins->dreg;
 
-                       /* Inline mono_get_lmf_addr () */
-                       /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
-
-                       /* Load mono_jit_tls_id */
-                       if (cfg->compile_aot)
-                               EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
-                       else
-                               EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
-                       /* call pthread_getspecific () */
-                       jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
-                       /* lmf_addr = &jit_tls->lmf */
-                       EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
-                       lmf_ins = ins;
+       lmf_reg = alloc_preg (cfg);
+       EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
 #else
-                       lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
-#endif
-               }
+       lmf_ins = mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
+       g_assert (lmf_ins);
 #endif
-               lmf_ins->dreg = cfg->lmf_addr_var->dreg;
+       lmf_ins->dreg = cfg->lmf_addr_var->dreg;
 
-               EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
-               lmf_reg = ins->dreg;
+       EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
+       lmf_reg = ins->dreg;
 
-               prev_lmf_reg = alloc_preg (cfg);
-               /* Save previous_lmf */
-               EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
-               EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
-               /* Set new lmf */
-               EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
-       }
+       prev_lmf_reg = alloc_preg (cfg);
+       /* Save previous_lmf */
+       EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
+       EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
+       /* Set new lmf */
+       EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
 }
 
 /*
@@ -2085,7 +1740,7 @@ emit_push_lmf (MonoCompile *cfg)
 static void
 emit_pop_lmf (MonoCompile *cfg)
 {
-       int lmf_reg, lmf_addr_reg, prev_lmf_reg;
+       int lmf_reg, lmf_addr_reg;
        MonoInst *ins;
 
        if (!cfg->lmf_ir)
@@ -2094,26 +1749,19 @@ emit_pop_lmf (MonoCompile *cfg)
        EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
        lmf_reg = ins->dreg;
 
-       if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
-               /* Load previous_lmf */
-               prev_lmf_reg = alloc_preg (cfg);
-               EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
-               /* Set new LMF */
-               emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
-       } else {
-               /*
-                * Emit IR to pop the LMF:
-                * *(lmf->lmf_addr) = lmf->prev_lmf
-                */
-               /* This could be called before emit_push_lmf () */
-               if (!cfg->lmf_addr_var)
-                       cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
-               lmf_addr_reg = cfg->lmf_addr_var->dreg;
+       int prev_lmf_reg;
+       /*
+        * Emit IR to pop the LMF:
+        * *(lmf->lmf_addr) = lmf->prev_lmf
+        */
+       /* This could be called before emit_push_lmf () */
+       if (!cfg->lmf_addr_var)
+               cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+       lmf_addr_reg = cfg->lmf_addr_var->dreg;
 
-               prev_lmf_reg = alloc_preg (cfg);
-               EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
-               EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
-       }
+       prev_lmf_reg = alloc_preg (cfg);
+       EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
+       EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
 }
 
 static void
@@ -2486,7 +2134,7 @@ emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, Mon
                        method_reg = alloc_preg (cfg);
                        MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
                } else {
-                       MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
+                       MonoInst *ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
                        method_reg = ins->dreg;
                }
 
@@ -2501,7 +2149,7 @@ emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, Mon
                method_reg = alloc_preg (cfg);
                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
        } else {
-               MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
+               MonoInst *ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
                method_reg = ins->dreg;
        }
 
@@ -2520,7 +2168,7 @@ mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpoint
        return ji;
 }
 
-static int
+int
 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
 {
        if (cfg->gshared)
@@ -2703,8 +2351,8 @@ set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rg
 #endif
 }      
 
-inline static MonoInst*
-mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
+MonoInst*
+mini_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
 {
        MonoCallInst *call;
        MonoInst *ins;
@@ -2765,13 +2413,8 @@ mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, Mo
        return (MonoInst*)call;
 }
 
-static MonoInst*
-emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
-
 static MonoInst*
 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
-static MonoInst*
-emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
 
 static MonoInst*
 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
@@ -2822,7 +2465,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
 
                addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
 
-               return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
+               return mini_emit_calli (cfg, sig, args, addr, NULL, NULL);
        }
 #endif
 
@@ -3041,7 +2684,7 @@ emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **or
        tmp_reg = alloc_preg (cfg);
        EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
        csig = sig_to_rgctx_sig (fsig);
-       return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
+       return mini_emit_calli (cfg, csig, args, call_target, NULL, NULL);
 }
 
 /* Emit an indirect call to the function descriptor ADDR */
@@ -3068,6 +2711,8 @@ emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **arg
 static gboolean
 direct_icalls_enabled (MonoCompile *cfg)
 {
+       return FALSE;
+
        /* LLVM on amd64 can't handle calls to non-32 bit addresses */
 #ifdef TARGET_AMD64
        if (cfg->compile_llvm && !cfg->llvm_only)
@@ -3160,18 +2805,18 @@ mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *
 
 
 static void
-emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
+emit_method_access_failure (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
 {
        MonoInst *args [16];
 
-       args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
-       args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
+       args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (caller), caller, MONO_RGCTX_INFO_METHOD);
+       args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (callee), callee, MONO_RGCTX_INFO_METHOD);
 
        mono_emit_jit_icall (cfg, mono_throw_method_access, args);
 }
 
-static MonoMethod*
-get_memcpy_method (void)
+MonoMethod*
+mini_get_memcpy_method (void)
 {
        static MonoMethod *memcpy_method = NULL;
        if (!memcpy_method) {
@@ -3205,8 +2850,8 @@ create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bi
        }
 }
 
-static void
-emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
+void
+mini_emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
 {
        int card_table_shift_bits;
        gpointer card_table_mask;
@@ -3229,11 +2874,18 @@ emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
                wbarrier->sreg1 = ptr->dreg;
                wbarrier->sreg2 = value->dreg;
                MONO_ADD_INS (cfg->cbb, wbarrier);
-       } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
+       } else if (card_table) {
                int offset_reg = alloc_preg (cfg);
                int card_reg;
                MonoInst *ins;
 
+               /*
+                * We emit a fast light weight write barrier. This always marks cards as in the concurrent
+                * collector case, so, for the serial collector, it might slightly slow down nursery
+                * collections. We also expect that the host system and the target system have the same card
+                * table configuration, which is the case if they have the same pointer size.
+                */
+
                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
                if (card_table_mask)
                        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
@@ -3241,7 +2893,7 @@ emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
                /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
                 * IMM's larger than 32bits.
                 */
-               ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
+               ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
                card_reg = ins->dreg;
 
                MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
@@ -3254,8 +2906,8 @@ emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
        EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
 }
 
-static gboolean
-mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
+gboolean
+mini_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
 {
        int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
        unsigned need_wb = 0;
@@ -3267,24 +2919,11 @@ mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4
        if (align < SIZEOF_VOID_P)
                return FALSE;
 
-       /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
-       if (size > 32 * SIZEOF_VOID_P)
+       if (size > 5 * SIZEOF_VOID_P)
                return FALSE;
 
        create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
 
-       /* We don't unroll more than 5 stores to avoid code bloat. */
-       if (size > 5 * SIZEOF_VOID_P) {
-               /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
-               size += (SIZEOF_VOID_P - 1);
-               size &= ~(SIZEOF_VOID_P - 1);
-
-               EMIT_NEW_ICONST (cfg, iargs [2], size);
-               EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
-               mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
-               return TRUE;
-       }
-
        destreg = iargs [0]->dreg;
        srcreg = iargs [1]->dreg;
        offset = 0;
@@ -3306,7 +2945,7 @@ mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4
                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
 
                if (need_wb & 0x1)
-                       emit_write_barrier (cfg, iargs [0], load_inst);
+                       mini_emit_write_barrier (cfg, iargs [0], load_inst);
 
                offset += SIZEOF_VOID_P;
                size -= SIZEOF_VOID_P;
@@ -3369,8 +3008,8 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
 
        if (mini_is_gsharedvt_klass (klass)) {
                g_assert (!native);
-               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);
+               size_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
+               memcpy_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
        }
 
        if (native)
@@ -3378,6 +3017,8 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
        else
                n = mono_class_value_size (klass, &align);
 
+       if (!align)
+               align = SIZEOF_VOID_P;
        /* if native is true there should be no references in the struct */
        if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
                /* Avoid barriers when storing to the stack */
@@ -3391,21 +3032,29 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
                        context_used = mini_class_check_context_used (cfg, klass);
 
                        /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
-                       if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
+                       if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mini_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
                                return;
-                       } else if (context_used) {
-                               iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
-                       }  else {
-                               iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
-                               if (!cfg->compile_aot)
-                                       mono_class_compute_gc_descriptor (klass);
-                       }
+                       } else if (size_ins || align < SIZEOF_VOID_P) {
+                               if (context_used) {
+                                       iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+                               }  else {
+                                       iargs [2] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
+                                       if (!cfg->compile_aot)
+                                               mono_class_compute_gc_descriptor (klass);
+                               }
+                               if (size_ins)
+                                       mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
+                               else
+                                       mono_emit_jit_icall (cfg, mono_value_copy, iargs);
+                       } else {
+                               /* We don't unroll more than 5 stores to avoid code bloat. */
+                               /*This is harmless and simplify mono_gc_get_range_copy_func */
+                               n += (SIZEOF_VOID_P - 1);
+                               n &= ~(SIZEOF_VOID_P - 1);
 
-                       if (size_ins)
-                               mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
-                       else
-                               mono_emit_jit_icall (cfg, mono_value_copy, iargs);
-                       return;
+                               EMIT_NEW_ICONST (cfg, iargs [2], n);
+                               mono_emit_jit_icall (cfg, mono_gc_get_range_copy_func (), iargs);
+                       }
                }
        }
 
@@ -3420,16 +3069,16 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
                else
                        EMIT_NEW_ICONST (cfg, iargs [2], n);
                
-               memcpy_method = get_memcpy_method ();
+               memcpy_method = mini_get_memcpy_method ();
                if (memcpy_ins)
-                       mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
+                       mini_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
                else
                        mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
        }
 }
 
-static MonoMethod*
-get_memset_method (void)
+MonoMethod*
+mini_get_memset_method (void)
 {
        static MonoMethod *memset_method = NULL;
        if (!memset_method) {
@@ -3454,14 +3103,14 @@ mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass
        /* FIXME: Optimize this for the case when dest is an LDADDR */
        mono_class_init (klass);
        if (mini_is_gsharedvt_klass (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);
+               size_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
+               bzero_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
                if (!bzero_method)
                        bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
                g_assert (bzero_method);
                iargs [0] = dest;
                iargs [1] = size_ins;
-               mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
+               mini_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
                return;
        }
 
@@ -3473,7 +3122,7 @@ mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass
                mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
        }
        else {
-               memset_method = get_memset_method ();
+               memset_method = mini_get_memset_method ();
                iargs [0] = dest;
                EMIT_NEW_ICONST (cfg, iargs [1], 0);
                EMIT_NEW_ICONST (cfg, iargs [2], n);
@@ -3496,8 +3145,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;
@@ -3509,10 +3158,20 @@ emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
                EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
 
                return mrgctx_var;
-       } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
-               MonoInst *vtable_loc, *vtable_var;
+       } else if (MONO_CLASS_IS_INTERFACE (cfg->method->klass)) {
+               MonoInst *mrgctx_loc, *mrgctx_var;
 
-               g_assert (!this_ins);
+               /* Default interface methods need an mrgctx since the vtabke at runtime points at an implementing class */
+               mrgctx_loc = mono_get_vtable_var (cfg);
+               EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
+
+               g_assert (mono_method_needs_static_rgctx_invoke (cfg->method, TRUE));
+
+               return mrgctx_var;
+       } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
+               MonoInst *vtable_loc, *vtable_var;
+
+               g_assert (!this_ins);
 
                vtable_loc = mono_get_vtable_var (cfg);
                EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
@@ -3674,12 +3333,12 @@ emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *ent
                return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
 }
 
-static MonoInst*
-emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
+MonoInst*
+mini_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 +3347,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 +3365,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 +3388,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 +3401,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 +3431,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 +3442,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);
 }
@@ -3845,8 +3504,8 @@ emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgct
        return ins;
 }
 
-static MonoInst*
-emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
+MonoInst*
+mini_emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
 {
        return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
 }
@@ -3863,7 +3522,7 @@ emit_class_init (MonoCompile *cfg, MonoClass *klass)
        context_used = mini_class_check_context_used (cfg, klass);
 
        if (context_used) {
-               vtable_arg = emit_get_rgctx_klass (cfg, context_used,
+               vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
                                                                                   klass, MONO_RGCTX_INFO_VTABLE);
        } else {
                MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
@@ -3884,20 +3543,13 @@ emit_class_init (MonoCompile *cfg, MonoClass *klass)
                ins->sreg1 = vtable_arg->dreg;
                MONO_ADD_INS (cfg->cbb, ins);
        } else {
-               static int byte_offset = -1;
-               static guint8 bitmask;
-               int bits_reg, inited_reg;
+               int inited_reg;
                MonoBasicBlock *inited_bb;
                MonoInst *args [16];
 
-               if (byte_offset < 0)
-                       mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
-
-               bits_reg = alloc_ireg (cfg);
                inited_reg = alloc_ireg (cfg);
 
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
+               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, inited_reg, vtable_arg->dreg, MONO_STRUCT_OFFSET (MonoVTable, initialized));
 
                NEW_BBLOCK (cfg, inited_bb);
 
@@ -3924,8 +3576,8 @@ emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_
        }
 }
 
-static void
-save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
+void
+mini_save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
 {
        if (mini_get_debug_options ()->better_cast_details) {
                int vtable_reg = alloc_preg (cfg);
@@ -3941,13 +3593,12 @@ save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean nul
                        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
                }
 
-               tls_get = mono_get_jit_tls_intrinsic (cfg);
+               tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
                if (!tls_get) {
                        fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
                        exit (1);
                }
 
-               MONO_ADD_INS (cfg->cbb, tls_get);
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
 
@@ -3957,7 +3608,7 @@ save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean nul
                if (context_used) {
                        MonoInst *class_ins;
 
-                       class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+                       class_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
                        to_klass_reg = class_ins->dreg;
                } else {
                        to_klass_reg = alloc_preg (cfg);
@@ -3970,14 +3621,12 @@ save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean nul
        }
 }
 
-static void
-reset_cast_details (MonoCompile *cfg)
+void
+mini_reset_cast_details (MonoCompile *cfg)
 {
        /* Reset the variables holding the cast details */
        if (mini_get_debug_options ()->better_cast_details) {
-               MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
-
-               MONO_ADD_INS (cfg->cbb, tls_get);
+               MonoInst *tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
                /* It is enough to reset the from field */
                MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
        }
@@ -3994,7 +3643,7 @@ mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_cl
 
        context_used = mini_class_check_context_used (cfg, array_class);
 
-       save_cast_details (cfg, array_class, obj->dreg, FALSE);
+       mini_save_cast_details (cfg, array_class, obj->dreg, FALSE);
 
        MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
 
@@ -4003,12 +3652,12 @@ mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_cl
                MonoInst *ins;
 
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-               ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
+               ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
                MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
        } else if (context_used) {
                MonoInst *vtable_ins;
 
-               vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
+               vtable_ins = mini_emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
                MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
        } else {
                if (cfg->compile_aot) {
@@ -4030,7 +3679,7 @@ mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_cl
        
        MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
 
-       reset_cast_details (cfg);
+       mini_reset_cast_details (cfg);
 }
 
 /**
@@ -4054,9 +3703,9 @@ 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);
+                       return mini_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
                }
        } else {
                gboolean pass_vtable, pass_mrgctx;
@@ -4106,15 +3755,15 @@ handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_use
                /* This assertion is from the unboxcast insn */
                g_assert (klass->rank == 0);
 
-               element_class = emit_get_rgctx_klass (cfg, context_used,
+               element_class = mini_emit_get_rgctx_klass (cfg, context_used,
                                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");
        } else {
-               save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
+               mini_save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
                mini_emit_class_check (cfg, eclass_reg, klass->element_class);
-               reset_cast_details (cfg);
+               mini_reset_cast_details (cfg);
        }
 
        NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
@@ -4133,7 +3782,7 @@ handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
        MonoInst *ins;
        int dreg, addr_reg;
 
-       klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
+       klass_inst = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
 
        /* obj */
        args [0] = obj;
@@ -4147,7 +3796,7 @@ handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
        NEW_BBLOCK (cfg, is_ref_bb);
        NEW_BBLOCK (cfg, is_nullable_bb);
        NEW_BBLOCK (cfg, end_bb);
-       is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
+       is_ref = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
 
@@ -4178,7 +3827,7 @@ handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
        MONO_START_BB (cfg, is_nullable_bb);
 
        {
-               MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
+               MonoInst *addr = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
                MonoInst *unbox_call;
                MonoMethodSignature *unbox_sig;
 
@@ -4190,7 +3839,7 @@ handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
                if (cfg->llvm_only)
                        unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
                else
-                       unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
+                       unbox_call = mini_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
 
                EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
                addr->dreg = addr_reg;
@@ -4228,7 +3877,7 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_
                        rgctx_info = MONO_RGCTX_INFO_KLASS;
                else
                        rgctx_info = MONO_RGCTX_INFO_VTABLE;
-               data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
+               data = mini_emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
 
                if (cfg->opt & MONO_OPT_SHARED) {
                        EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
@@ -4321,9 +3970,9 @@ 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);
+                               return mini_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
                        }
                } else {
                        gboolean pass_vtable, pass_mrgctx;
@@ -4353,7 +4002,7 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
                NEW_BBLOCK (cfg, is_ref_bb);
                NEW_BBLOCK (cfg, is_nullable_bb);
                NEW_BBLOCK (cfg, end_bb);
-               is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
+               is_ref = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
                MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
 
@@ -4362,624 +4011,109 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
 
                /* Non-ref case */
                alloc = handle_alloc (cfg, klass, TRUE, context_used);
-               if (!alloc)
-                       return NULL;
-               EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
-               ins->opcode = OP_STOREV_MEMBASE;
-
-               EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
-               res->type = STACK_OBJ;
-               res->klass = klass;
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-               
-               /* Ref case */
-               MONO_START_BB (cfg, is_ref_bb);
-
-               /* val is a vtype, so has to load the value manually */
-               src_var = get_vreg_to_inst (cfg, val->dreg);
-               if (!src_var)
-                       src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
-               EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-
-               /* Nullable case */
-               MONO_START_BB (cfg, is_nullable_bb);
-
-               {
-                       MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
-                                                                                                       MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
-                       MonoInst *box_call;
-                       MonoMethodSignature *box_sig;
-
-                       /*
-                        * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
-                        * construct that method at JIT time, so have to do things by hand.
-                        */
-                       box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
-                       box_sig->ret = &mono_defaults.object_class->byval_arg;
-                       box_sig->param_count = 1;
-                       box_sig->params [0] = &klass->byval_arg;
-
-                       if (cfg->llvm_only)
-                               box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
-                       else
-                               box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
-                       EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
-                       res->type = STACK_OBJ;
-                       res->klass = klass;
-               }
-
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-
-               MONO_START_BB (cfg, end_bb);
-
-               return res;
-       } else {
-               alloc = handle_alloc (cfg, klass, TRUE, context_used);
-               if (!alloc)
-                       return NULL;
-
-               EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
-               return alloc;
-       }
-}
-
-static gboolean
-mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
-{
-       int i;
-       MonoGenericContainer *container;
-       MonoGenericInst *ginst;
-
-       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;
-       }
-
-       for (i = 0; i < container->type_argc; ++i) {
-               MonoType *type;
-               if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
-                       continue;
-               type = ginst->type_argv [i];
-               if (mini_type_is_reference (type))
-                       return TRUE;
-       }
-       return FALSE;
-}
-
-static GHashTable* direct_icall_type_hash;
-
-static gboolean
-icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
-{
-       /* LLVM on amd64 can't handle calls to non-32 bit addresses */
-       if (!direct_icalls_enabled (cfg))
-               return FALSE;
-
-       /*
-        * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
-        * Whitelist a few icalls for now.
-        */
-       if (!direct_icall_type_hash) {
-               GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
-
-               g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
-               g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
-               g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
-               g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
-               mono_memory_barrier ();
-               direct_icall_type_hash = h;
-       }
-
-       if (cmethod->klass == mono_defaults.math_class)
-               return TRUE;
-       /* No locking needed */
-       if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
-               return TRUE;
-       return FALSE;
-}
-
-static gboolean
-method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
-{
-       if (cmethod->klass == mono_defaults.systemtype_class) {
-               if (!strcmp (cmethod->name, "GetType"))
-                       return TRUE;
-       }
-       return FALSE;
-}
-
-#define is_complex_isinst(klass) (mono_class_is_interface (klass) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || mono_class_is_sealed (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
-
-static MonoInst*
-emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
-{
-       MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
-       return mono_emit_method_call (cfg, mono_isinst, args, NULL);
-}
-
-static MonoInst*
-emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
-{
-       MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
-       MonoInst *res;
-
-       save_cast_details (cfg, klass, args [0]->dreg, TRUE);
-       res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
-       reset_cast_details (cfg);
-
-       return res;
-}
-
-static int
-get_castclass_cache_idx (MonoCompile *cfg)
-{
-       /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
-       cfg->castclass_cache_index ++;
-       return (cfg->method_index << 16) | cfg->castclass_cache_index;
-}
-
-
-static MonoInst*
-emit_isinst_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
-{
-       MonoInst *args [3];
-       int idx;
-
-       args [0] = obj; /* obj */
-       EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
-
-       idx = get_castclass_cache_idx (cfg); /* inline cache*/
-       args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
-
-       return emit_isinst_with_cache (cfg, klass, args);
-}
-
-static MonoInst*
-emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
-{
-       MonoInst *args [3];
-       int idx;
-
-       /* obj */
-       args [0] = obj;
-
-       /* klass */
-       EMIT_NEW_CLASSCONST (cfg, args [1], klass);
-
-       /* inline cache*/
-       idx = get_castclass_cache_idx (cfg);
-       args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
-
-       /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
-       return emit_castclass_with_cache (cfg, klass, args);
-}
-
-/*
- * Returns NULL and set the cfg exception on error.
- */
-static MonoInst*
-handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
-{
-       MonoBasicBlock *is_null_bb;
-       int obj_reg = src->dreg;
-       int vtable_reg = alloc_preg (cfg);
-       MonoInst *klass_inst = NULL;
-
-       if (MONO_INS_IS_PCONST_NULL (src))
-               return src;
-
-       if (context_used) {
-               MonoInst *args [3];
-
-               if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
-                       MonoInst *cache_ins;
-
-                       cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
-
-                       /* obj */
-                       args [0] = src;
-
-                       /* klass - it's the second element of the cache entry*/
-                       EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
-
-                       /* cache */
-                       args [2] = cache_ins;
-
-                       return emit_castclass_with_cache (cfg, klass, args);
-               }
-
-               klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
-       }
-
-       NEW_BBLOCK (cfg, is_null_bb);
-
-       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
-
-       save_cast_details (cfg, klass, obj_reg, FALSE);
-
-       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 {
-               int klass_reg = alloc_preg (cfg);
-
-               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) && 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);
-                               if (!vt) {
-                                       mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
-                                       cfg->exception_ptr = klass;
-                                       return NULL;
-                               }
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
-                       } else {
-                               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
-                       }
-                       MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
-               } else {
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-                       mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
-               }
-       }
-
-       MONO_START_BB (cfg, is_null_bb);
-
-       reset_cast_details (cfg);
-
-       return src;
-}
-
-/*
- * Returns NULL and set the cfg exception on error.
- */
-static MonoInst*
-handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
-{
-       MonoInst *ins;
-       MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
-       int obj_reg = src->dreg;
-       int vtable_reg = alloc_preg (cfg);
-       int res_reg = alloc_ireg_ref (cfg);
-       MonoInst *klass_inst = NULL;
-
-       if (context_used) {
-               MonoInst *args [3];
-
-               if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
-                       MonoInst *cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
-
-                       args [0] = src; /* obj */
-
-                       /* klass - it's the second element of the cache entry*/
-                       EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
-
-                       args [2] = cache_ins; /* cache */
-                       return emit_isinst_with_cache (cfg, klass, args);
-               }
-
-               klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
-       }
-
-       NEW_BBLOCK (cfg, is_null_bb);
-       NEW_BBLOCK (cfg, false_bb);
-       NEW_BBLOCK (cfg, end_bb);
-
-       /* Do the assignment at the beginning, so the other assignment can be if converted */
-       EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
-       ins->type = STACK_OBJ;
-       ins->klass = klass;
-
-       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
-
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-
-       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);
-       } else {
-               int klass_reg = alloc_preg (cfg);
-
-               if (klass->rank) {
-                       int rank_reg = alloc_preg (cfg);
-                       int eclass_reg = alloc_preg (cfg);
-
-                       g_assert (!context_used);
-                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
-                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
-                       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
-                       if (klass->cast_class == mono_defaults.object_class) {
-                               int parent_reg = alloc_preg (cfg);
-                               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
-                               mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
-                               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 == mono_defaults.enum_class->parent) {
-                               mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
-                               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 == 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 (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)) {
-                                       /* Check that the object is a vector too */
-                                       int bounds_reg = alloc_preg (cfg);
-                                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
-                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
-                                       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
-                               }
-
-                               /* the is_null_bb target simply copies the input register to the output */
-                               mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
-                       }
-               } else if (mono_class_is_nullable (klass)) {
-                       g_assert (!context_used);
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-                       /* 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) && 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.*/
-                                       MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
-                                       if (!vt) {
-                                               mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
-                                               cfg->exception_ptr = klass;
-                                               return NULL;
-                                       }
-                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
-                               } else {
-                                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
-                               }
-                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
-                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
-                       } else {
-                               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-                               /* the is_null_bb target simply copies the input register to the output */
-                               mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
-                       }
-               }
-       }
-
-       MONO_START_BB (cfg, false_bb);
-
-       MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-
-       MONO_START_BB (cfg, is_null_bb);
-
-       MONO_START_BB (cfg, end_bb);
-
-       return ins;
-}
-
-static MonoInst*
-handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
-{
-       /* This opcode takes as input an object reference and a class, and returns:
-       0) if the object is an instance of the class,
-       1) if the object is not instance of the class,
-       2) if the object is a proxy whose type cannot be determined */
-
-       MonoInst *ins;
-#ifndef DISABLE_REMOTING
-       MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
-#else
-       MonoBasicBlock *true_bb, *false_bb, *end_bb;
-#endif
-       int obj_reg = src->dreg;
-       int dreg = alloc_ireg (cfg);
-       int tmp_reg;
-#ifndef DISABLE_REMOTING
-       int klass_reg = alloc_preg (cfg);
-#endif
-
-       NEW_BBLOCK (cfg, true_bb);
-       NEW_BBLOCK (cfg, false_bb);
-       NEW_BBLOCK (cfg, end_bb);
-#ifndef DISABLE_REMOTING
-       NEW_BBLOCK (cfg, false2_bb);
-       NEW_BBLOCK (cfg, no_proxy_bb);
-#endif
-
-       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
-
-       if (mono_class_is_interface (klass)) {
-#ifndef DISABLE_REMOTING
-               NEW_BBLOCK (cfg, interface_fail_bb);
-#endif
-
-               tmp_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-#ifndef DISABLE_REMOTING
-               mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
-               MONO_START_BB (cfg, interface_fail_bb);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-               
-               mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
-
-               tmp_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
-#else
-               mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
-#endif
-       } else {
-#ifndef DISABLE_REMOTING
-               tmp_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-
-               mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
-               tmp_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
-
-               tmp_reg = alloc_preg (cfg);             
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
-               
-               mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
-
-               MONO_START_BB (cfg, no_proxy_bb);
-
-               mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
-#else
-               g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
-#endif
-       }
-
-       MONO_START_BB (cfg, false_bb);
-
-       MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-
-#ifndef DISABLE_REMOTING
-       MONO_START_BB (cfg, false2_bb);
-
-       MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-#endif
-
-       MONO_START_BB (cfg, true_bb);
-
-       MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
-
-       MONO_START_BB (cfg, end_bb);
-
-       /* FIXME: */
-       MONO_INST_NEW (cfg, ins, OP_ICONST);
-       ins->dreg = dreg;
-       ins->type = STACK_I4;
-
-       return ins;
-}
-
-static MonoInst*
-handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
-{
-       /* This opcode takes as input an object reference and a class, and returns:
-       0) if the object is an instance of the class,
-       1) if the object is a proxy whose type cannot be determined
-       an InvalidCastException exception is thrown otherwhise*/
-       
-       MonoInst *ins;
-#ifndef DISABLE_REMOTING
-       MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
-#else
-       MonoBasicBlock *ok_result_bb;
-#endif
-       int obj_reg = src->dreg;
-       int dreg = alloc_ireg (cfg);
-       int tmp_reg = alloc_preg (cfg);
-
-#ifndef DISABLE_REMOTING
-       int klass_reg = alloc_preg (cfg);
-       NEW_BBLOCK (cfg, end_bb);
-#endif
-
-       NEW_BBLOCK (cfg, ok_result_bb);
-
-       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
-
-       save_cast_details (cfg, klass, obj_reg, FALSE);
-
-       if (mono_class_is_interface (klass)) {
-#ifndef DISABLE_REMOTING
-               NEW_BBLOCK (cfg, interface_fail_bb);
-       
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-               mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
-               MONO_START_BB (cfg, interface_fail_bb);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-
-               mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
+               if (!alloc)
+                       return NULL;
+               EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
+               ins->opcode = OP_STOREV_MEMBASE;
 
-               tmp_reg = alloc_preg (cfg);             
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
-               MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
-               
-               MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
+               EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
+               res->type = STACK_OBJ;
+               res->klass = klass;
                MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-#else
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-               mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
-#endif
-       } else {
-#ifndef DISABLE_REMOTING
-               NEW_BBLOCK (cfg, no_proxy_bb);
+               
+               /* Ref case */
+               MONO_START_BB (cfg, is_ref_bb);
 
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-               mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
+               /* val is a vtype, so has to load the value manually */
+               src_var = get_vreg_to_inst (cfg, val->dreg);
+               if (!src_var)
+                       src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
+               EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
 
-               tmp_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
+               /* Nullable case */
+               MONO_START_BB (cfg, is_nullable_bb);
 
-               tmp_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
+               {
+                       MonoInst *addr = mini_emit_get_gsharedvt_info_klass (cfg, klass,
+                                                                                                       MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
+                       MonoInst *box_call;
+                       MonoMethodSignature *box_sig;
 
-               NEW_BBLOCK (cfg, fail_1_bb);
-               
-               mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
+                       /*
+                        * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
+                        * construct that method at JIT time, so have to do things by hand.
+                        */
+                       box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
+                       box_sig->ret = &mono_defaults.object_class->byval_arg;
+                       box_sig->param_count = 1;
+                       box_sig->params [0] = &klass->byval_arg;
 
-               MONO_START_BB (cfg, fail_1_bb);
+                       if (cfg->llvm_only)
+                               box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
+                       else
+                               box_call = mini_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
+                       EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
+                       res->type = STACK_OBJ;
+                       res->klass = klass;
+               }
 
-               MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
                MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
 
-               MONO_START_BB (cfg, no_proxy_bb);
+               MONO_START_BB (cfg, end_bb);
 
-               mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
-#else
-               g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
-#endif
+               return res;
+       } else {
+               alloc = handle_alloc (cfg, klass, TRUE, context_used);
+               if (!alloc)
+                       return NULL;
+
+               EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
+               return alloc;
        }
+}
 
-       MONO_START_BB (cfg, ok_result_bb);
+static GHashTable* direct_icall_type_hash;
 
-       MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
+static gboolean
+icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
+{
+       /* LLVM on amd64 can't handle calls to non-32 bit addresses */
+       if (!direct_icalls_enabled (cfg))
+               return FALSE;
 
-#ifndef DISABLE_REMOTING
-       MONO_START_BB (cfg, end_bb);
-#endif
+       /*
+        * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
+        * Whitelist a few icalls for now.
+        */
+       if (!direct_icall_type_hash) {
+               GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
 
-       /* FIXME: */
-       MONO_INST_NEW (cfg, ins, OP_ICONST);
-       ins->dreg = dreg;
-       ins->type = STACK_I4;
+               g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
+               g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
+               g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
+               g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
+               mono_memory_barrier ();
+               direct_icall_type_hash = h;
+       }
 
-       return ins;
+       if (cmethod->klass == mono_defaults.math_class)
+               return TRUE;
+       /* No locking needed */
+       if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
+               return TRUE;
+       return FALSE;
+}
+
+static gboolean
+method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
+{
+       if (cmethod->klass == mono_defaults.systemtype_class) {
+               if (!strcmp (cmethod->name, "GetType"))
+                       return TRUE;
+       }
+       return FALSE;
 }
 
 static G_GNUC_UNUSED MonoInst*
@@ -5061,7 +4195,7 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
                if (cfg->gen_write_barriers) {
                        dreg = alloc_preg (cfg);
                        EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
-                       emit_write_barrier (cfg, ptr, target);
+                       mini_emit_write_barrier (cfg, ptr, target);
                }
        }
 
@@ -5091,7 +4225,7 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
                        }
                        mono_domain_unlock (domain);
 
-                       code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
+                       code_slot_ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
                }
                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
        }
@@ -5187,7 +4321,7 @@ handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMe
         * pack the arguments into an array, and do the rest of the work in in an icall.
         */
        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)) &&
+               (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mono_class_is_enum (mono_class_from_mono_type (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];
 
@@ -5204,7 +4338,7 @@ handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMe
                        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);
+               args [2] = mini_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) {
@@ -5218,7 +4352,7 @@ handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMe
                        if (mini_is_gsharedvt_type (fsig->params [0])) {
                                int addr_reg, deref_arg_reg;
 
-                               ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
+                               ins = mini_emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
                                deref_arg_reg = alloc_preg (cfg);
                                /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
                                EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
@@ -5239,7 +4373,7 @@ handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMe
 
                if (mini_is_gsharedvt_type (fsig->ret)) {
                        ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
-               } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
+               } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mono_class_is_enum (mono_class_from_mono_type (fsig->ret))) {
                        MonoInst *add;
 
                        /* Unbox */
@@ -5312,7 +4446,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)
@@ -5331,9 +4465,11 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
        /* also consider num_locals? */
        /* Do the size check early to avoid creating vtables */
        if (!inline_limit_inited) {
-               if (g_getenv ("MONO_INLINELIMIT"))
-                       inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
-               else
+               char *inlinelimit;
+               if ((inlinelimit = g_getenv ("MONO_INLINELIMIT"))) {
+                       inline_limit = atoi (inlinelimit);
+                       g_free (inlinelimit);
+               } else
                        inline_limit = INLINE_LENGTH_LIMIT;
                inline_limit_inited = TRUE;
        }
@@ -5346,17 +4482,22 @@ 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 (mono_class_is_before_field_init (method->klass)) {
@@ -5440,7 +4581,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;
@@ -5462,7 +4603,11 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono
 #if SIZEOF_REGISTER == 8
        /* The array reg is 64 bits but the index reg is only 32 */
        if (COMPILE_LLVM (cfg)) {
-               /* Not needed */
+               /*
+                * abcrem can't handle the OP_SEXT_I4, so add this after abcrem,
+                * during OP_BOUNDS_CHECK decomposition, and in the implementation
+                * of OP_X86_LEA for llvm.
+                */
                index2_reg = index_reg;
        } else {
                index2_reg = alloc_preg (cfg);
@@ -5501,7 +4646,7 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono
                g_assert (cfg->gshared);
                context_used = mini_class_check_context_used (cfg, klass);
                g_assert (context_used);
-               rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
+               rgctx_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
                MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
        } else {
                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
@@ -5628,18 +4773,18 @@ static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
 
 /**
  * mono_set_break_policy:
- * policy_callback: the new callback function
+ * \param policy_callback the new callback function
  *
  * Allow embedders to decide wherther to actually obey breakpoint instructions
- * (both break IL instructions and Debugger.Break () method calls), for example
+ * (both break IL instructions and \c Debugger.Break method calls), for example
  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
  * untrusted or semi-trusted code.
  *
- * @policy_callback will be called every time a break point instruction needs to
- * be inserted with the method argument being the method that calls Debugger.Break()
- * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
+ * \p policy_callback will be called every time a break point instruction needs to
+ * be inserted with the method argument being the method that calls \c Debugger.Break
+ * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
  * if it wants the breakpoint to not be effective in the given method.
- * #MONO_BREAK_POLICY_ALWAYS is the default.
+ * \c MONO_BREAK_POLICY_ALWAYS is the default.
  */
 void
 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
@@ -5679,7 +4824,7 @@ emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst
                EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
                EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
                if (mini_type_is_reference (&eklass->byval_arg))
-                       emit_write_barrier (cfg, addr, load);
+                       mini_emit_write_barrier (cfg, addr, load);
        } else {
                EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
                EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
@@ -5742,7 +4887,7 @@ emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean sa
                        MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
                        EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
                        if (generic_class_is_reference_type (cfg, klass))
-                               emit_write_barrier (cfg, addr, sp [2]);
+                               mini_emit_write_barrier (cfg, addr, sp [2]);
                }
                return ins;
        }
@@ -5881,8 +5026,8 @@ mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignat
        return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
 }
 
-static MonoInst*
-emit_memory_barrier (MonoCompile *cfg, int kind)
+MonoInst*
+mini_emit_memory_barrier (MonoCompile *cfg, int kind)
 {
        MonoInst *ins = NULL;
        MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
@@ -5973,8 +5118,7 @@ static MonoInst*
 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
        MonoInst *ins = NULL;
-
-        MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
+       MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
 
        if (cmethod->klass == mono_defaults.string_class) {
                if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
@@ -6120,6 +5264,37 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
        } else if (cmethod->klass == runtime_helpers_class) {
                if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
                        EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
+                       return ins;
+               } else if (strcmp (cmethod->name, "IsReferenceOrContainsReferences") == 0 && fsig->param_count == 0) {
+                       MonoGenericContext *ctx = mono_method_get_context (cmethod);
+                       g_assert (ctx);
+                       g_assert (ctx->method_inst);
+                       g_assert (ctx->method_inst->type_argc == 1);
+                       MonoType *t = mini_get_underlying_type (ctx->method_inst->type_argv [0]);
+                       MonoClass *klass = mono_class_from_mono_type (t);
+
+                       ins = NULL;
+
+                       mono_class_init (klass);
+                       if (MONO_TYPE_IS_REFERENCE (t))
+                               EMIT_NEW_ICONST (cfg, ins, 1);
+                       else if (MONO_TYPE_IS_PRIMITIVE (t))
+                               EMIT_NEW_ICONST (cfg, ins, 0);
+                       else if (cfg->gshared && (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (t))
+                               EMIT_NEW_ICONST (cfg, ins, 1);
+                       else if (!cfg->gshared || !mini_class_check_context_used (cfg, klass))
+                               EMIT_NEW_ICONST (cfg, ins, klass->has_references ? 1 : 0);
+                       else {
+                               g_assert (cfg->gshared);
+
+                               int context_used = mini_class_check_context_used (cfg, klass);
+
+                               /* This returns 1 or 2 */
+                               MonoInst *info = mini_emit_get_rgctx_klass (cfg, context_used, klass,   MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS);
+                               int dreg = alloc_ireg (cfg);
+                               EMIT_NEW_BIALU_IMM (cfg, ins, OP_ISUB_IMM, dreg, info->dreg, 1);
+                       }
+
                        return ins;
                } else
                        return NULL;
@@ -6146,7 +5321,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        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, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
+                       ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_internal : (gpointer)mono_monitor_enter_internal, args);
                        MONO_START_BB (cfg, end_bb);
                        return ins;
                }
@@ -6156,7 +5331,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        MONO_ADD_INS (cfg->cbb, ins);
                        return ins;
                } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
-                       return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
+                       return mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
                } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
                        guint32 opcode = 0;
                        gboolean is_ref = mini_type_is_reference (fsig->params [0]);
@@ -6227,7 +5402,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                                if (opcode == OP_LOADI8_MEMBASE)
                                        ins = mono_decompose_opcode (cfg, ins);
 
-                               emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
+                               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
 
                                return ins;
                        }
@@ -6251,7 +5426,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                                opcode = OP_STORE_MEMBASE_REG;
 
                        if (opcode) {
-                               emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
+                               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
 
                                MONO_INST_NEW (cfg, ins, opcode);
                                ins->sreg1 = args [1]->dreg;
@@ -6282,7 +5457,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        } else {
                                MonoInst *load_ins;
 
-                               emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
+                               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
 
                                /* 64 bit reads are already atomic */
                                MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
@@ -6292,7 +5467,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                                load_ins->type = STACK_I8;
                                MONO_ADD_INS (cfg->cbb, load_ins);
 
-                               emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
+                               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
 
                                ins = load_ins;
                        }
@@ -6469,7 +5644,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        }
 
                        if (cfg->gen_write_barriers && is_ref)
-                               emit_write_barrier (cfg, args [0], args [1]);
+                               mini_emit_write_barrier (cfg, args [0], args [1]);
                }
                else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
                        MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
@@ -6571,7 +5746,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        }
 
                        if (cfg->gen_write_barriers && is_ref)
-                               emit_write_barrier (cfg, args [0], args [1]);
+                               mini_emit_write_barrier (cfg, args [0], args [1]);
                }
                else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
                         fsig->params [1]->type == MONO_TYPE_I4) {
@@ -6607,7 +5782,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        cfg->has_atomic_cas_i4 = TRUE;
                }
                else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
-                       ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
+                       ins = mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
 
                if (ins)
                        return ins;
@@ -6745,7 +5920,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                                MONO_ADD_INS (cfg->cbb, ins);
 
                                if (cfg->gen_write_barriers && is_ref)
-                                       emit_write_barrier (cfg, args [0], args [1]);
+                                       mini_emit_write_barrier (cfg, args [0], args [1]);
                        }
                }
 
@@ -6808,6 +5983,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") &&
@@ -7073,6 +6255,12 @@ emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
        }
 }
 
+int
+mini_inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, guchar *ip, guint real_offset, gboolean inline_always)
+{
+       return inline_method (cfg, cmethod, fsig, sp, ip, real_offset, inline_always);
+}
+
 /*
  * inline_method:
  *
@@ -7204,7 +6392,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 */
@@ -7218,7 +6406,8 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                 * Get rid of the begin and end bblocks if possible to aid local
                 * optimizations.
                 */
-               mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
+               if (prev_cbb->out_count == 1)
+                       mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
 
                if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
                        mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
@@ -7426,7 +6615,7 @@ mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, Mono
 {
        MonoMethod *method;
 
-       mono_error_init (error);
+       error_init (error);
 
        if (m->wrapper_type != MONO_WRAPPER_NONE) {
                method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
@@ -7457,7 +6646,7 @@ mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klas
        return method;
 }
 
-static inline MonoClass*
+MonoClass*
 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
 {
        MonoError error;
@@ -7483,7 +6672,7 @@ mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *conte
 {
        MonoMethodSignature *fsig;
 
-       mono_error_init (error);
+       error_init (error);
        if (method->wrapper_type != MONO_WRAPPER_NONE) {
                fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
        } else {
@@ -7593,14 +6782,12 @@ initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, Mono
                        return NULL;
                if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
                        return NULL;
-               switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
-               case MONO_TYPE_BOOLEAN:
+               switch (mini_get_underlying_type (&klass->byval_arg)->type) {
                case MONO_TYPE_I1:
                case MONO_TYPE_U1:
                        size = 1; break;
                /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
-               case MONO_TYPE_CHAR:
                case MONO_TYPE_I2:
                case MONO_TYPE_U2:
                        size = 2; break;
@@ -7721,6 +6908,7 @@ emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig
        gboolean variant_iface = FALSE;
        guint32 slot;
        int offset;
+       gboolean special_array_interface = cmethod->klass->is_array_special_interface;
 
        /*
         * In llvm-only mode, vtables contain function descriptors instead of
@@ -7779,7 +6967,7 @@ emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig
                return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
        }
 
-       if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
+       if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt && !special_array_interface) {
                /*
                 * A simple interface call
                 *
@@ -7813,12 +7001,12 @@ emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig
                icall_args [0] = thunk_arg_ins;
                icall_args [1] = emit_get_rgctx_method (cfg, context_used,
                                                                                                cmethod, MONO_RGCTX_INFO_METHOD);
-               ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
+               ftndesc_ins = mini_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
 
                return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
        }
 
-       if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
+       if ((fsig->generic_param_count || variant_iface || special_array_interface) && !is_gsharedvt) {
                /*
                 * This is similar to the interface case, the vtable slot points to an imt thunk which is
                 * dynamically extended as more instantiations are discovered.
@@ -7856,7 +7044,7 @@ emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig
                icall_args [0] = thunk_arg_ins;
                icall_args [1] = emit_get_rgctx_method (cfg, context_used,
                                                                                                cmethod, MONO_RGCTX_INFO_METHOD);
-               ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
+               ftndesc_ins = mini_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
                ftndesc_ins->dreg = ftndesc_reg;
                /*
                 * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
@@ -8042,7 +7230,7 @@ handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fs
                                                                                                cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
                } else {
                        if (context_used) {
-                               vtable_arg = emit_get_rgctx_klass (cfg, context_used,
+                               vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
                                                                                                   cmethod->klass, MONO_RGCTX_INFO_VTABLE);
                        } else {
                                MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
@@ -8085,7 +7273,7 @@ handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fs
                        // FIXME: Avoid initializing vtable_arg
                        emit_llvmonly_calli (cfg, fsig, sp, addr);
                } else {
-                       mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
+                       mini_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
                }
        } else if (context_used &&
                           ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
@@ -8102,7 +7290,7 @@ handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fs
                        cmethod_addr = emit_get_rgctx_method (cfg, context_used,
                                                                                                  cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
 
-                       mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
+                       mini_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
                }
        } else {
                INLINE_FAILURE ("ctor call");
@@ -8257,6 +7445,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
                        }
                        g_free (sps);
+
+                       MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method);
+                       if (asyncMethod) {
+                               for (i = 0; asyncMethod != NULL && i < asyncMethod->num_awaits; i++)
+                               {
+                                       mono_bitset_set_fast (seq_point_locs, asyncMethod->resume_offsets[i]);
+                                       mono_bitset_set_fast (seq_point_locs, asyncMethod->yield_offsets[i]);
+                               }
+                               mono_debug_free_method_async_debug_info (asyncMethod);
+                       }
                } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
                        /* Methods without line number info like auto-generated property accessors */
                        seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
@@ -9170,7 +8368,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                addr = emit_get_rgctx_sig (cfg, context_used,
                                                                                          fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
-                               ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
+                               ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, callee);
                                goto calli_end;
                        }
 
@@ -9203,7 +8401,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        goto calli_end;
                                }
                        }
-                       ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
+                       ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
 
                        calli_end:
 
@@ -9292,6 +8490,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                CHECK_CFG_ERROR;
                                        }
                                }
+
+                               if (constrained_class->enumtype && !strcmp (cmethod->name, "GetHashCode")) {
+                                       /* Use the corresponding method from the base type to avoid boxing */
+                                       MonoType *base_type = mono_class_enum_basetype (constrained_class);
+                                       g_assert (base_type);
+                                       constrained_class = mono_class_from_mono_type (base_type);
+                                       cmethod = mono_class_get_method_from_name (constrained_class, cmethod->name, 0);
+                                       g_assert (cmethod);
+                               }
                        }
                                        
                        if (!dont_verify && !cfg->skip_visibility) {
@@ -9393,6 +8600,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        sp -= n;
 
+                       if (cmethod && cmethod->klass->image == mono_defaults.corlib && !strcmp (cmethod->klass->name, "ThrowHelper"))
+                               cfg->cbb->out_of_line = TRUE;
+
                        /*
                         * We have the `constrained.' prefix opcode.
                         */
@@ -9455,7 +8665,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
 
                                                /* Non-ref case */
-                                               nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
+                                               nonbox_call = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
 
                                                MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
 
@@ -9464,7 +8674,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                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));
-                                               ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
+                                               ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
 
                                                MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
 
@@ -9476,7 +8686,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        } else {
                                                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);
+                                               ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
                                                goto call_end;
                                        }
                                } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
@@ -9582,13 +8792,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 * request a generic sharing context.
                                 */
                                if (context_used &&
-                                               ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
+                                               ((cfg->method->flags & METHOD_ATTRIBUTE_STATIC) || cfg->method->klass->valuetype))
                                        mono_get_vtable_var (cfg);
                        }
 
                        if (pass_vtable) {
                                if (context_used) {
-                                       vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
+                                       vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
                                } else {
                                        MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
 
@@ -9673,7 +8883,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
 
-                                       ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
+                                       ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
                                }
 
                                goto call_end;
@@ -9844,7 +9054,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        // FIXME: Avoid initializing vtable_arg
                                        ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
                                } else {
-                                       ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
+                                       ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
                                }
                                goto call_end;
                        }
@@ -9885,7 +9095,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
                                } else {
                                        addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
-                                       ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
+                                       ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
                                }
                                goto call_end;
                        }
@@ -9932,7 +9142,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 && !MONO_INS_IS_PCONST_NULL (val))
-                                               emit_write_barrier (cfg, addr, val);
+                                               mini_emit_write_barrier (cfg, addr, val);
                                        if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
                                                GSHAREDVT_FAILURE (*ip);
                                } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
@@ -10027,7 +9237,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        /* Common call */
-                       INLINE_FAILURE ("call");
+                       if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) && !(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);
 
@@ -10424,32 +9635,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (1);
                        --sp;
 
-                       switch (*ip) {
-                       case CEE_LDIND_R4:
-                       case CEE_LDIND_R8:
-                               dreg = alloc_freg (cfg);
-                               break;
-                       case CEE_LDIND_I8:
-                               dreg = alloc_lreg (cfg);
-                               break;
-                       case CEE_LDIND_REF:
-                               dreg = alloc_ireg_ref (cfg);
-                               break;
-                       default:
-                               dreg = alloc_preg (cfg);
-                       }
-
-                       NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
-                       ins->type = ldind_type [*ip - CEE_LDIND_I1];
-                       if (*ip == CEE_LDIND_R4)
-                               ins->type = cfg->r4_stack_type;
-                       ins->flags |= ins_flag;
-                       MONO_ADD_INS (cfg->cbb, ins);
+                       ins = mini_emit_memory_load (cfg, &ldind_to_type (*ip)->byval_arg, sp [0], 0, ins_flag);
                        *sp++ = ins;
-                       if (ins_flag & MONO_INST_VOLATILE) {
-                               /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
-                               emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
-                       }
                        ins_flag = 0;
                        ++ip;
                        break;
@@ -10466,7 +9653,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if (ins_flag & MONO_INST_VOLATILE) {
                                /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
-                               emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
+                               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
                        }
 
                        NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
@@ -10476,7 +9663,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 && !MONO_INS_IS_PCONST_NULL (sp [1]))
-                               emit_write_barrier (cfg, sp [0], sp [1]);
+                               mini_emit_write_barrier (cfg, sp [0], sp [1]);
 
                        inline_costs += 1;
                        ++ip;
@@ -10679,7 +9866,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_ADD_INS (cfg->cbb, store);
 
                                if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
-                                       emit_write_barrier (cfg, sp [0], sp [1]);
+                                       mini_emit_write_barrier (cfg, sp [0], sp [1]);
                        } else {
                                mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
                        }
@@ -10724,7 +9911,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += stloc_len;
                                if (ins_flag & MONO_INST_VOLATILE) {
                                        /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
-                                       emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
+                                       mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
                                }
                                ins_flag = 0;
                                break;
@@ -10745,15 +9932,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
 
-                       EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
-                       ins->flags |= ins_flag;
+                       ins = mini_emit_memory_load (cfg, &klass->byval_arg, sp [0], 0, ins_flag);
                        *sp++ = ins;
 
-                       if (ins_flag & MONO_INST_VOLATILE) {
-                               /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
-                               emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
-                       }
-
                        ip += 5;
                        ins_flag = 0;
                        inline_costs += 1;
@@ -11387,7 +10568,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        if (ins_flag & MONO_INST_VOLATILE) {
                                                /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
-                                               emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
+                                               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
                                        }
 
                                        if (mini_is_gsharedvt_klass (klass)) {
@@ -11412,7 +10593,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        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]);
+                                                       mini_emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
                                                } else {
                                                        /* insert call to write barrier */
                                                        MonoInst *ptr;
@@ -11420,7 +10601,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                                        dreg = alloc_ireg_mp (cfg);
                                                        EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
-                                                       emit_write_barrier (cfg, ptr, sp [1]);
+                                                       mini_emit_write_barrier (cfg, ptr, sp [1]);
                                                }
                                        }
 
@@ -11501,19 +10682,29 @@ 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;
+                                               }
+                                       }
+
+                                       MonoInst *field_add_inst = sp [0];
                                        if (mini_is_gsharedvt_klass (klass)) {
                                                MonoInst *offset_ins;
 
                                                offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
                                                /* The value is offset by 1 */
                                                EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
-                                               dreg = alloc_ireg_mp (cfg);
-                                               EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
-                                               EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
-                                       } else {
-                                               EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
+                                               EMIT_NEW_BIALU (cfg, field_add_inst, OP_PADD, alloc_ireg_mp (cfg), sp [0]->dreg, offset_ins->dreg);
+                                               foffset = 0;
                                        }
-                                       load->flags |= ins_flag;
+
+                                       load = mini_emit_memory_load (cfg, field->type, field_add_inst, foffset, ins_flag);
+
                                        if (sp [0]->opcode != OP_LDADDR)
                                                load->flags |= MONO_INST_FAULT;
                                        *sp++ = load;
@@ -11549,7 +10740,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        is_special_static = mono_class_field_is_special_static (field);
 
                        if (is_special_static && ((gsize)addr & 0x80000000) == 0)
-                               thread_ins = mono_get_thread_intrinsic (cfg);
+                               thread_ins = mono_create_tls_get (cfg, TLS_KEY_THREAD);
                        else
                                thread_ins = NULL;
 
@@ -11563,9 +10754,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                guint32 offset;
                                int idx, static_data_reg, array_reg, dreg;
 
-                               GSHAREDVT_FAILURE (op);
+                               if (context_used && cfg->gsharedvt && mini_is_gsharedvt_klass (klass))
+                                       GSHAREDVT_FAILURE (op);
 
-                               MONO_ADD_INS (cfg->cbb, thread_ins);
                                static_data_reg = alloc_ireg (cfg);
                                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
 
@@ -11627,7 +10818,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 *
                                 *   super_info.static_data + field->offset
                                 */
-                               static_data = emit_get_rgctx_klass (cfg, context_used,
+                               static_data = mini_emit_get_rgctx_klass (cfg, context_used,
                                        klass, MONO_RGCTX_INFO_STATIC_DATA);
 
                                if (mini_is_gsharedvt_klass (klass)) {
@@ -11644,7 +10835,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        int addr_reg = mono_alloc_preg (cfg);
                                        EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
                                }
-                               } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
+                       } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
                                MonoInst *iargs [2];
 
                                g_assert (field->parent);
@@ -11699,7 +10890,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
                                /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
-                               emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
+                               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
                        }
 
                        if (op == CEE_LDSFLDA) {
@@ -11810,7 +11001,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
                                /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
-                               emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
+                               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
                        }
 
                        ins_flag = 0;
@@ -11824,18 +11015,9 @@ 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);
-                       if (ins_flag & MONO_INST_VOLATILE) {
-                               /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
-                               emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
-                       }
+
                        /* FIXME: should check item at sp [1] is compatible with the type of the store. */
-                       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) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
-                               /* insert call to write barrier */
-                               emit_write_barrier (cfg, sp [0], sp [1]);
-                       }
+                       mini_emit_memory_store (cfg, &klass->byval_arg, sp [0], sp [1], ins_flag);
                        ins_flag = 0;
                        ip += 5;
                        inline_costs += 1;
@@ -11858,6 +11040,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
+                       if (klass->byval_arg.type == MONO_TYPE_VOID)
+                               UNVERIFIED;
 
                        context_used = mini_class_check_context_used (cfg, klass);
 
@@ -11878,7 +11062,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
 
                                /* vtable */
-                               args [0] = emit_get_rgctx_klass (cfg, context_used,
+                               args [0] = mini_emit_get_rgctx_klass (cfg, context_used,
                                        array_class, MONO_RGCTX_INFO_VTABLE);
                                /* array len */
                                args [1] = sp [0];
@@ -11930,7 +11114,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         * ensure the rva field is big enough
                         */
                        if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, cfg->cbb, ip + 6) && (len_ins->opcode == OP_ICONST) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, klass, len_ins->inst_c0, &data_size, &field_token))) {
-                               MonoMethod *memcpy_method = get_memcpy_method ();
+                               MonoMethod *memcpy_method = mini_get_memcpy_method ();
                                MonoInst *iargs [3];
                                int add_reg = alloc_ireg_mp (cfg);
 
@@ -12134,7 +11318,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (context_used) {
                                MonoInst *klass_ins;
 
-                               klass_ins = emit_get_rgctx_klass (cfg, context_used,
+                               klass_ins = mini_emit_get_rgctx_klass (cfg, context_used,
                                                klass, MONO_RGCTX_INFO_KLASS);
 
                                // FIXME:
@@ -12171,7 +11355,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoInst *const_ins;
                                int type_reg = alloc_preg (cfg);
 
-                               const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+                               const_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
                                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);
@@ -12268,11 +11452,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        mono_class_init (tclass);
                                        if (context_used) {
-                                               ins = emit_get_rgctx_klass (cfg, context_used,
+                                               ins = mini_emit_get_rgctx_klass (cfg, context_used,
                                                        tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
                                        } else if (cfg->compile_aot) {
                                                if (method->wrapper_type) {
-                                                       mono_error_init (&error); //got to do it since there are multiple conditionals below
+                                                       error_init (&error); //got to do it since there are multiple conditionals below
                                                        if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
                                                                /* Special case for static synchronized wrappers */
                                                                EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
@@ -12300,7 +11484,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        if (context_used) {
                                                if (handle_class == mono_defaults.typehandle_class) {
-                                                       ins = emit_get_rgctx_klass (cfg, context_used,
+                                                       ins = mini_emit_get_rgctx_klass (cfg, context_used,
                                                                        mono_class_from_mono_type ((MonoType *)handle),
                                                                        MONO_RGCTX_INFO_TYPE);
                                                } else if (handle_class == mono_defaults.methodhandle_class) {
@@ -12516,16 +11700,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                switch (ip [1]) {
                                        case CEE_MONO_LDPTR_CARD_TABLE:
-                                               ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
+                                               ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
                                                break;
                                        case CEE_MONO_LDPTR_NURSERY_START:
-                                               ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
+                                               ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
                                                break;
                                        case CEE_MONO_LDPTR_NURSERY_BITS:
-                                               ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
+                                               ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
                                                break;
                                        case CEE_MONO_LDPTR_INT_REQ_FLAG:
-                                               ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
+                                               ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
                                                break;
                                }
 
@@ -12578,7 +11762,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);
@@ -12693,22 +11887,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 6;
                                break;
                        }
-                       case CEE_MONO_CISINST:
-                       case CEE_MONO_CCASTCLASS: {
-                               int token;
-                               CHECK_STACK (1);
-                               --sp;
-                               CHECK_OPSIZE (6);
-                               token = read32 (ip + 2);
-                               klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
-                               if (ip [1] == CEE_MONO_CISINST)
-                                       ins = handle_cisinst (cfg, klass, sp [0]);
-                               else
-                                       ins = handle_ccastclass (cfg, klass, sp [0]);
-                               *sp++ = ins;
-                               ip += 6;
-                               break;
-                       }
                        case CEE_MONO_SAVE_LMF:
                        case CEE_MONO_RESTORE_LMF:
                                ip += 2;
@@ -12735,18 +11913,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                g_assert (key < TLS_KEY_NUM);
 
                                ins = mono_create_tls_get (cfg, key);
-                               if (!ins) {
-                                       if (cfg->compile_aot) {
-                                               DISABLE_AOT (cfg);
-                                               MONO_INST_NEW (cfg, ins, OP_TLS_GET);
-                                               ins->dreg = alloc_preg (cfg);
-                                               ins->type = STACK_PTR;
-                                       } else {
-                                               g_assert_not_reached ();
-                                       }
-                               }
+                               g_assert (ins);
                                ins->type = STACK_PTR;
-                               MONO_ADD_INS (cfg->cbb, ins);
                                *sp++ = ins;
                                ip += 6;
                                break;
@@ -12782,7 +11950,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                        case CEE_MONO_MEMORY_BARRIER: {
                                CHECK_OPSIZE (6);
-                               emit_memory_barrier (cfg, (int)read32 (ip + 2));
+                               mini_emit_memory_barrier (cfg, (int)read32 (ip + 2));
                                ip += 6;
                                break;
                        }
@@ -12814,10 +11982,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                EMIT_NEW_PCONST (cfg, ins, NULL);
                                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
 
-                               ad_ins = mono_get_domain_intrinsic (cfg);
-                               jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
+                               ad_ins = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
+                               jit_tls_ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
 
-                               if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
+                               if (ad_ins && jit_tls_ins) {
                                        NEW_BBLOCK (cfg, next_bb);
                                        NEW_BBLOCK (cfg, call_bb);
 
@@ -12827,11 +11995,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        } else {
                                                EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
                                        }
-                                       MONO_ADD_INS (cfg->cbb, ad_ins);
                                        MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
                                        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
 
-                                       MONO_ADD_INS (cfg->cbb, jit_tls_ins);
                                        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
                                        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
 
@@ -12841,13 +12007,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 = mini_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;
                        }
@@ -12990,9 +12167,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                                addr = emit_get_rgctx_sig (cfg, context_used,
                                                                                                   fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
-                                               ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
+                                               ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, callee);
                                        } else {
-                                               ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
+                                               ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
                                        }
                                }
 
@@ -13021,6 +12198,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->type = STACK_I4;
                                MONO_ADD_INS (cfg->cbb, ins);
 
+                               ip += 2;
+                               *sp++ = ins;
+                               break;
+                       case CEE_MONO_GET_RGCTX_ARG:
+                               CHECK_OPSIZE (2);
+                               CHECK_STACK_OVF (1);
+
+                               mono_create_rgctx_var (cfg);
+
+                               MONO_INST_NEW (cfg, ins, OP_MOVE);
+                               ins->dreg = alloc_dreg (cfg, STACK_PTR);
+                               ins->sreg1 = cfg->rgctx_var->dreg;
+                               ins->type = STACK_PTR;
+                               MONO_ADD_INS (cfg->cbb, ins);
+
                                ip += 2;
                                *sp++ = ins;
                                break;
@@ -13460,21 +12652,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                 * FIXME: We emit full barriers on both sides of the operation for
                                                 * simplicity. We should have a separate atomic memcpy method instead.
                                                 */
-                                               MonoMethod *memcpy_method = get_memcpy_method ();
+                                               MonoMethod *memcpy_method = mini_get_memcpy_method ();
 
                                                if (ins_flag & MONO_INST_VOLATILE)
-                                                       emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
+                                                       mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
 
                                                call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
                                                call->flags |= ins_flag;
 
                                                if (ins_flag & MONO_INST_VOLATILE)
-                                                       emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
+                                                       mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
                                        } else {
-                                               MonoMethod *memset_method = get_memset_method ();
+                                               MonoMethod *memset_method = mini_get_memset_method ();
                                                if (ins_flag & MONO_INST_VOLATILE) {
                                                        /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
-                                                       emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
+                                                       mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
                                                }
                                                call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
                                                call->flags |= ins_flag;
@@ -13619,11 +12811,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                cfg->cbb = init_localsbb;
 
-               if ((get_domain = mono_get_domain_intrinsic (cfg))) {
-                       MONO_ADD_INS (cfg->cbb, get_domain);
-               } else {
-                       get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
-               }
+               get_domain = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
                NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
                MONO_ADD_INS (cfg->cbb, store);
        }
@@ -14336,6 +13524,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:
@@ -14512,7 +13701,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
        int orig_next_vreg;
        guint32 *vreg_to_lvreg;
        guint32 *lvregs;
-       guint32 i, lvregs_len;
+       guint32 i, lvregs_len, lvregs_size;
        gboolean dest_has_lvreg = FALSE;
        MonoStackType stacktypes [128];
        MonoInst **live_range_start, **live_range_end;
@@ -14585,7 +13774,8 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
         */
        orig_next_vreg = cfg->next_vreg;
        vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
-       lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
+       lvregs_size = 1024;
+       lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * lvregs_size);
        lvregs_len = 0;
 
        /* 
@@ -14968,7 +14158,12 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                                }
                                                                g_assert (sreg != -1);
                                                                vreg_to_lvreg [var->dreg] = sreg;
-                                                               g_assert (lvregs_len < 1024);
+                                                               if (lvregs_len >= lvregs_size) {
+                                                                       guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
+                                                                       memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
+                                                                       lvregs = new_lvregs;
+                                                                       lvregs_size *= 2;
+                                                               }
                                                                lvregs [lvregs_len ++] = var->dreg;
                                                        }
                                                }
@@ -15015,7 +14210,12 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                        if (dest_has_lvreg) {
                                g_assert (ins->dreg != -1);
                                vreg_to_lvreg [prev_dreg] = ins->dreg;
-                               g_assert (lvregs_len < 1024);
+                               if (lvregs_len >= lvregs_size) {
+                                       guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
+                                       memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
+                                       lvregs = new_lvregs;
+                                       lvregs_size *= 2;
+                               }
                                lvregs [lvregs_len ++] = prev_dreg;
                                dest_has_lvreg = FALSE;
                        }
@@ -15103,73 +14303,6 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
        g_free (live_range_end_bb);
 }
 
-static void
-mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
-{
-       MonoInst *ret, *move, *source;
-       MonoClass *klass = ins->klass;
-       int context_used = mini_class_check_context_used (cfg, klass);
-       int is_isinst = ins->opcode == OP_ISINST;
-       g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
-       source = get_vreg_to_inst (cfg, ins->sreg1);
-       if (!source || source == (MonoInst *) -1)
-               source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
-       g_assert (source && source != (MonoInst *) -1);
-
-       MonoBasicBlock *first_bb;
-       NEW_BBLOCK (cfg, first_bb);
-       cfg->cbb = first_bb;
-
-       if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
-               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) || mono_class_is_interface (klass))) {
-               MonoInst *iargs [1];
-               int costs;
-
-               iargs [0] = source;
-               if (is_isinst) {
-                       MonoMethod *wrapper = mono_marshal_get_isinst (klass);
-                       costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
-               } else {
-                       MonoMethod *wrapper = mono_marshal_get_castclass (klass);
-                       save_cast_details (cfg, klass, source->dreg, TRUE);
-                       costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
-                       reset_cast_details (cfg);
-               }
-               g_assert (costs > 0);
-               ret = iargs [0];
-       } else {
-               if (is_isinst)
-                       ret = handle_isinst (cfg, klass, source, context_used);
-               else
-                       ret = handle_castclass (cfg, klass, source, context_used);
-       }
-       EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
-
-       g_assert (cfg->cbb->code || first_bb->code);
-       MonoInst *prev = ins->prev;
-       mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
-}
-
-void
-mono_decompose_typechecks (MonoCompile *cfg)
-{
-       for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoInst *ins;
-               MONO_BB_FOR_EACH_INS (bb, ins) {
-                       switch (ins->opcode) {
-                       case OP_ISINST:
-                       case OP_CASTCLASS:
-                               mono_decompose_typecheck (cfg, bb, ins);
-                               break;
-                       }
-               }
-       }
-}
-
 
 /**
  * FIXME:
@@ -15295,4 +14428,11 @@ NOTES
   the values on the stack before emitting the last instruction of the bb.
 */
 
-#endif /* DISABLE_JIT */
+#else /* !DISABLE_JIT */
+
+void
+mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
+{
+}
+
+#endif /* !DISABLE_JIT */