Merge pull request #607 from maksimenko/master
[mono.git] / mono / mini / method-to-ir.c
index 08122e9f7ed9dfb87562153d0f7bc93a06d083db..7e0121d5778226621ec86e243031fd48d4d8f5cc 100644 (file)
@@ -11,6 +11,9 @@
  */
 
 #include <config.h>
+
+#ifndef DISABLE_JIT
+
 #include <signal.h>
 
 #ifdef HAVE_UNISTD_H
                        goto exception_exit;    \
                }                       \
        } while (0)
+#define GSHAREDVT_FAILURE(opcode) do {         \
+       if (cfg->gsharedvt) {                                                                                           \
+               cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __FILE__, __LINE__); \
+               if (cfg->verbose_level >= 2)                                                                    \
+                       printf ("%s\n", cfg->exception_message); \
+               mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
+               goto exception_exit;                                                                                    \
+       }                                                                                                                                       \
+       } while (0)
 #define OUT_OF_MEMORY_FAILURE do {     \
                mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
                goto exception_exit;    \
@@ -119,8 +131,6 @@ int mono_op_to_op_imm (int opcode);
 int mono_op_to_op_imm_noemul (int opcode);
 
 MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
-void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
-void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
 
 /* helper methods signatures */
 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
@@ -147,7 +157,7 @@ static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL
 #define FREG 'f'
 #define VREG 'v'
 #define XREG 'x'
-#if SIZEOF_REGISTER == 8
+#if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOIDP
 #define LREG IREG
 #else
 #define LREG 'l'
@@ -305,7 +315,10 @@ handle_enum:
        case MONO_TYPE_VAR:
        case MONO_TYPE_MVAR:
                g_assert (cfg->generic_sharing_context);
-               return OP_MOVE;
+               if (mini_type_var_is_vt (cfg, type))
+                       return OP_VMOVE;
+               else
+                       return OP_MOVE;
        default:
                g_error ("unknown type 0x%02x in type_to_regstore", type->type);
        }
@@ -341,13 +354,22 @@ mono_create_helper_signatures (void)
        helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
 }
 
-/* 
- * Can't put this at the beginning, since other files reference stuff from this
- * file.
+/*
+ * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
+ * foo<T> (int i) { ldarg.0; box T; }
  */
-#ifndef DISABLE_JIT
-
-#define UNVERIFIED do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
+#define UNVERIFIED do { \
+       if (cfg->gsharedvt) { \
+               if (cfg->verbose_level > 2)                                                                     \
+                       printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
+               mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
+               goto exception_exit;                                                                                    \
+       }                                                                                                                                       \
+       if (mini_get_debug_options ()->break_on_unverified) \
+               G_BREAKPOINT (); \
+       else \
+               goto unverified; \
+} while (0)
 
 #define LOAD_ERROR do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto load_error; } while (0)
 
@@ -682,14 +704,15 @@ handle_enum:
        case MONO_TYPE_GENERICINST:
                type = &type->data.generic_class->container_class->byval_arg;
                goto handle_enum;
-       case MONO_TYPE_VAR :
-       case MONO_TYPE_MVAR :
-               /* FIXME: all the arguments must be references for now,
-                * later look inside cfg and see if the arg num is
-                * really a reference
-                */
+       case MONO_TYPE_VAR:
+       case MONO_TYPE_MVAR:
                g_assert (cfg->generic_sharing_context);
-               inst->type = STACK_OBJ;
+               if (mini_is_gsharedvt_type (cfg, type)) {
+                       g_assert (cfg->gsharedvt);
+                       inst->type = STACK_VTYPE;
+               } else {
+                       inst->type = STACK_OBJ;
+               }
                return;
        default:
                g_error ("unknown type 0x%02x in eval stack type", type->type);
@@ -2004,13 +2027,14 @@ target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
                }
        case MONO_TYPE_VAR:
        case MONO_TYPE_MVAR:
-               /* FIXME: all the arguments must be references for now,
-                * later look inside cfg and see if the arg num is
-                * really a reference
-                */
                g_assert (cfg->generic_sharing_context);
-               if (arg->type != STACK_OBJ)
-                       return 1;
+               if (mini_type_var_is_vt (cfg, simple_type)) {
+                       if (arg->type != STACK_VTYPE)
+                               return 1;
+               } else {
+                       if (arg->type != STACK_OBJ)
+                               return 1;
+               }
                return 0;
        default:
                g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
@@ -2154,8 +2178,9 @@ callvirt_to_call_membase (int opcode)
 }
 
 #ifdef MONO_ARCH_HAVE_IMT
+/* Either METHOD or IMT_ARG needs to be set */
 static void
-emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
+emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
 {
        int method_reg;
 
@@ -2165,11 +2190,11 @@ emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
                if (imt_arg) {
                        MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
                } else if (cfg->compile_aot) {
-                       MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
+                       MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
                } else {
                        MonoInst *ins;
                        MONO_INST_NEW (cfg, ins, OP_PCONST);
-                       ins->inst_p0 = call->method;
+                       ins->inst_p0 = method;
                        ins->dreg = method_reg;
                        MONO_ADD_INS (cfg->cbb, ins);
                }
@@ -2192,11 +2217,11 @@ emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
        if (imt_arg) {
                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
        } else if (cfg->compile_aot) {
-               MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
+               MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
        } else {
                MonoInst *ins;
                MONO_INST_NEW (cfg, ins, OP_PCONST);
-               ins->inst_p0 = call->method;
+               ins->inst_p0 = method;
                ins->dreg = method_reg;
                MONO_ADD_INS (cfg->cbb, ins);
        }
@@ -2220,6 +2245,24 @@ mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpoint
        return ji;
 }
 
+static int
+mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
+{
+       if (cfg->generic_sharing_context)
+               return mono_class_check_context_used (klass);
+       else
+               return 0;
+}
+
+static int
+mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
+{
+       if (cfg->generic_sharing_context)
+               return mono_method_check_context_used (method);
+       else
+               return 0;
+}
+
 inline static MonoCallInst *
 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
                                         MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
@@ -2241,11 +2284,11 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
        type_to_eval_stack_type ((cfg), sig->ret, &call->inst);
 
        if (tail) {
-               if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+               if (mini_type_is_vtype (cfg, sig->ret)) {
                        call->vret_var = cfg->vret_addr;
                        //g_assert_not_reached ();
                }
-       } else if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+       } else if (mini_type_is_vtype (cfg, sig->ret)) {
                MonoInst *temp = mono_compile_create_var (cfg, sig->ret, OP_LOCAL);
                MonoInst *loada;
 
@@ -2336,7 +2379,7 @@ set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rg
 }      
 
 inline static MonoInst*
-mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg)
+mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
 {
        MonoCallInst *call;
        int rgctx_reg = -1;
@@ -2350,6 +2393,9 @@ mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, Mo
 
        call->inst.sreg1 = addr->dreg;
 
+       if (imt_arg)
+               emit_imt_argument (cfg, call, NULL, imt_arg);
+
        MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
 
        if (rgctx_arg)
@@ -2367,7 +2413,7 @@ static MonoInst*
 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
                                                        MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
 {
-       gboolean might_be_remote;
+       gboolean might_be_remote = FALSE;
        gboolean virtual = this != NULL;
        gboolean enable_for_aot = TRUE;
        int context_used;
@@ -2389,10 +2435,11 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                sig = ctor_sig;
        }
 
-       context_used = mono_method_check_context_used (method);
+       context_used = mini_method_check_context_used (cfg, method);
 
+#ifndef DISABLE_REMOTING
        might_be_remote = this && sig->hasthis &&
-               (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
+               (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
                !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
 
        if (might_be_remote && context_used) {
@@ -2402,16 +2449,19 @@ 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);
+               return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
        }
+#endif
 
        need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
 
        call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, FALSE, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
 
+#ifndef DISABLE_REMOTING
        if (might_be_remote)
                call->method = mono_marshal_get_remoting_invoke_with_check (method);
        else
+#endif
                call->method = method;
        call->inst.flags |= MONO_INST_HAS_METHOD;
        call->inst.inst_left = this;
@@ -2455,18 +2505,20 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                        (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
                         (MONO_METHOD_IS_FINAL (method) &&
                          method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
-                       !(method->klass->marshalbyref && context_used)) {
+                       !(mono_class_is_marshalbyref (method->klass) && context_used)) {
                        /* 
                         * the method is not virtual, we just need to ensure this is not null
                         * and then we can call the method directly.
                         */
-                       if (method->klass->marshalbyref || method->klass == mono_defaults.object_class) {
+#ifndef DISABLE_REMOTING
+                       if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
                                /* 
                                 * The check above ensures method is not gshared, this is needed since
                                 * gshared methods can't have wrappers.
                                 */
                                method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
                        }
+#endif
 
                        if (!method->string_ctor)
                                MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
@@ -2491,7 +2543,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
 #ifdef MONO_ARCH_HAVE_IMT
                                if (mono_use_imt) {
                                        guint32 imt_slot = mono_method_get_imt_slot (method);
-                                       emit_imt_argument (cfg, call, imt_arg);
+                                       emit_imt_argument (cfg, call, call->method, imt_arg);
                                        slot_reg = vtable_reg;
                                        call->inst.inst_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
                                }
@@ -2508,7 +2560,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
 #ifdef MONO_ARCH_HAVE_IMT
                                if (imt_arg) {
                                        g_assert (mono_method_signature (method)->generic_param_count);
-                                       emit_imt_argument (cfg, call, imt_arg);
+                                       emit_imt_argument (cfg, call, call->method, imt_arg);
                                }
 #endif
                        }
@@ -2820,9 +2872,10 @@ void
 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
 {
        MonoInst *iargs [4];
-       int n;
+       int context_used, n;
        guint32 align = 0;
        MonoMethod *memcpy_method;
+       MonoInst *size_ins = NULL;
 
        g_assert (klass);
        /*
@@ -2830,6 +2883,12 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
         * g_assert (klass && klass == src->klass && klass == dest->klass);
         */
 
+       if (mini_is_gsharedvt_klass (cfg, klass)) {
+               g_assert (!native);
+               context_used = mini_class_check_context_used (cfg, klass);
+               size_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_VALUE_SIZE);
+       }
+
        if (native)
                n = mono_class_native_size (klass, &align);
        else
@@ -2840,16 +2899,15 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
                /* Avoid barriers when storing to the stack */
                if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
                          (dest->opcode == OP_LDADDR))) {
-                       int context_used = 0;
+                       int context_used;
 
                        iargs [0] = dest;
                        iargs [1] = src;
 
-                       if (cfg->generic_sharing_context)
-                               context_used = mono_class_check_context_used (klass);
+                       context_used = mini_class_check_context_used (cfg, klass);
 
                        /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
-                       if ((cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
+                       if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_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);
@@ -2867,13 +2925,16 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
                }
        }
 
-       if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
+       if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
                /* FIXME: Optimize the case when src/dest is OP_LDADDR */
                mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
        } else {
                iargs [0] = dest;
                iargs [1] = src;
-               EMIT_NEW_ICONST (cfg, iargs [2], n);
+               if (size_ins)
+                       iargs [2] = size_ins;
+               else
+                       EMIT_NEW_ICONST (cfg, iargs [2], n);
                
                memcpy_method = get_memcpy_method ();
                mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
@@ -2896,23 +2957,33 @@ void
 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
 {
        MonoInst *iargs [3];
-       int n;
+       int n, context_used;
        guint32 align;
        MonoMethod *memset_method;
+       MonoInst *size_ins = NULL;
 
        /* FIXME: Optimize this for the case when dest is an LDADDR */
 
        mono_class_init (klass);
-       n = mono_class_value_size (klass, &align);
+       if (mini_is_gsharedvt_klass (cfg, klass)) {
+               context_used = mini_class_check_context_used (cfg, klass);
+               size_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_VALUE_SIZE);
+               n = -1;
+       } else {
+               n = mono_class_value_size (klass, &align);
+       }
 
-       if (n <= sizeof (gpointer) * 5) {
+       if (!size_ins && n <= sizeof (gpointer) * 5) {
                mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
        }
        else {
                memset_method = get_memset_method ();
                iargs [0] = dest;
                EMIT_NEW_ICONST (cfg, iargs [1], 0);
-               EMIT_NEW_ICONST (cfg, iargs [2], n);
+               if (size_ins)
+                       iargs [2] = size_ins;
+               else
+                       EMIT_NEW_ICONST (cfg, iargs [2], n);
                mono_emit_method_call (cfg, memset_method, iargs, NULL);
        }
 }
@@ -2997,6 +3068,34 @@ emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
        return emit_rgctx_fetch (cfg, rgctx, entry);
 }
 
+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);
+
+       return emit_rgctx_fetch (cfg, rgctx, entry);
+}
+
+static MonoInst*
+emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
+                                                          MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
+{
+       MonoJumpInfoGSharedVtCall *call_info;
+       MonoJumpInfoRgctxEntry *entry;
+       MonoInst *rgctx;
+
+       call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
+       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);
+
+       return emit_rgctx_fetch (cfg, rgctx, entry);
+}
+
 /*
  * emit_get_rgctx_method:
  *
@@ -3046,10 +3145,9 @@ emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
 {
        MonoInst *vtable_arg;
        MonoCallInst *call;
-       int context_used = 0;
+       int context_used;
 
-       if (cfg->generic_sharing_context)
-               context_used = mono_class_check_context_used (klass);
+       context_used = mini_class_check_context_used (cfg, klass);
 
        if (context_used) {
                vtable_arg = emit_get_rgctx_klass (cfg, context_used,
@@ -3129,10 +3227,9 @@ static void
 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
 {
        int vtable_reg = alloc_preg (cfg);
-       int context_used = 0;
+       int context_used;
 
-       if (cfg->generic_sharing_context)
-               context_used = mono_class_check_context_used (array_class);
+       context_used = mini_class_check_context_used (cfg, array_class);
 
        save_cast_details (cfg, array_class, obj->dreg);
 
@@ -3196,7 +3293,7 @@ handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int co
 
                rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 
-               return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
+               return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
        } else {
                return mono_emit_method_call (cfg, method, &val, NULL);
        }
@@ -3353,19 +3450,61 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
                                                                                                        MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
                        MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 
-                       return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
+                       return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
                } else {
                        return mono_emit_method_call (cfg, method, &val, NULL);
                }
        }
 
-       alloc = handle_alloc (cfg, klass, TRUE, context_used);
-       if (!alloc)
-               return NULL;
+       if (mini_is_gsharedvt_klass (cfg, klass)) {
+               MonoBasicBlock *is_ref_bb, *end_bb;
+               MonoInst *res, *is_ref, *src_var, *addr;
+               int addr_reg, dreg;
+
+               dreg = alloc_ireg (cfg);
+
+               NEW_BBLOCK (cfg, is_ref_bb);
+               NEW_BBLOCK (cfg, end_bb);
+               is_ref = emit_get_rgctx_klass (cfg, context_used, klass,
+                                                                          MONO_RGCTX_INFO_CLASS_IS_REF);
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
+
+               /* 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);
+               addr_reg = alloc_ireg (cfg);
+
+               /* val is a vtype, so has to load the value manually */
+               src_var = get_vreg_to_inst (cfg, val->dreg);
+               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);
 
-       EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
+               MONO_START_BB (cfg, end_bb);
 
-       return alloc;
+               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;
+       }
 }
 
 
@@ -3398,7 +3537,7 @@ mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *
 }
 
 // FIXME: This doesn't work yet (class libs tests fail?)
-#define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
+#define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
 
 /*
  * Returns NULL and set the cfg exception on error.
@@ -3653,26 +3792,37 @@ handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
        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, false2_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 (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+#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, G_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, G_STRUCT_OFFSET (MonoVTable, klass));
@@ -3683,7 +3833,11 @@ handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_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, G_STRUCT_OFFSET (MonoObject, vtable));
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
@@ -3704,6 +3858,9 @@ handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
                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);
@@ -3711,10 +3868,12 @@ handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
        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);
 
@@ -3739,13 +3898,20 @@ handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
        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);
-       int klass_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);
@@ -3754,6 +3920,7 @@ handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
        save_cast_details (cfg, klass, obj_reg);
 
        if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+#ifndef DISABLE_REMOTING
                NEW_BBLOCK (cfg, interface_fail_bb);
        
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
@@ -3770,8 +3937,13 @@ handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
                
                MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
                MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-               
+#else
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_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);
 
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
@@ -3799,13 +3971,18 @@ handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
                MONO_START_BB (cfg, no_proxy_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
        }
 
        MONO_START_BB (cfg, ok_result_bb);
 
        MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
 
+#ifndef DISABLE_REMOTING
        MONO_START_BB (cfg, end_bb);
+#endif
 
        /* FIXME: */
        MONO_INST_NEW (cfg, ins, OP_ICONST);
@@ -3920,6 +4097,7 @@ mono_emit_load_got_addr (MonoCompile *cfg)
                return;
 
        MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
+       getaddr->cil_code = cfg->header->code;
        getaddr->dreg = cfg->got_var->dreg;
 
        /* Add it to the start of the first bblock */
@@ -3978,7 +4156,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
        /*runtime, icall and pinvoke are checked by summary call*/
        if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
            (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
-           (method->klass->marshalbyref) ||
+           (mono_class_is_marshalbyref (method->klass)) ||
            header.has_clauses)
                return FALSE;
 
@@ -4081,9 +4259,14 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono
        MonoInst *ins;
        guint32 size;
        int mult_reg, add_reg, array_reg, index_reg, index2_reg;
+       int context_used;
 
-       mono_class_init (klass);
-       size = mono_class_array_element_size (klass);
+       if (mini_is_gsharedvt_klass (cfg, klass)) {
+               size = -1;
+       } else {
+               mono_class_init (klass);
+               size = mono_class_array_element_size (klass);
+       }
 
        mult_reg = alloc_preg (cfg);
        array_reg = arr->dreg;
@@ -4124,7 +4307,18 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono
 
        add_reg = alloc_ireg_mp (cfg);
 
-       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
+       if (size == -1) {
+               MonoInst *rgctx_ins;
+
+               /* gsharedvt */
+               g_assert (cfg->generic_sharing_context);
+               context_used = mini_class_check_context_used (cfg, klass);
+               g_assert (context_used);
+               rgctx_ins = emit_get_rgctx_klass (cfg, context_used, 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);
+       }
        MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
        NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
        ins->klass = mono_class_get_element_class (klass);
@@ -4337,7 +4531,15 @@ emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean sa
                return mono_emit_method_call (cfg, helper, iargs, sp [0]);
        } else {
                MonoInst *ins;
-               if (sp [1]->opcode == OP_ICONST) {
+
+               if (mini_is_gsharedvt_klass (cfg, klass)) {
+                       MonoInst *addr;
+
+                       // FIXME-VT: OP_ICONST optimization
+                       addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
+                       EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
+                       ins->opcode = OP_STOREV_MEMBASE;
+               } else if (sp [1]->opcode == OP_ICONST) {
                        int array_reg = sp [0]->dreg;
                        int index_reg = sp [1]->dreg;
                        int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
@@ -4884,6 +5086,9 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                }
 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
 
+               if (strcmp (cmethod->name, "MemoryBarrier") == 0)
+                       ins = emit_memory_barrier (cfg, FullBarrier);
+
                if (ins)
                        return ins;
        } else if (cmethod->klass->image == mono_defaults.corlib) {
@@ -5409,6 +5614,7 @@ get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset,
        }
        return 0;
 unverified:
+exception_exit:
        *pos = ip;
        return 1;
 }
@@ -5418,10 +5624,13 @@ mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, Mono
 {
        MonoMethod *method;
 
-       if (m->wrapper_type != MONO_WRAPPER_NONE)
-               return mono_method_get_wrapper_data (m, token);
-
-       method = mono_get_method_full (m->klass->image, token, klass, context);
+       if (m->wrapper_type != MONO_WRAPPER_NONE) {
+               method = mono_method_get_wrapper_data (m, token);
+               if (context)
+                       method = mono_class_inflate_generic_method (method, context);
+       } else {
+               method = mono_get_method_full (m->klass->image, token, klass, context);
+       }
 
        return method;
 }
@@ -5442,15 +5651,38 @@ mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
 {
        MonoClass *klass;
 
-       if (method->wrapper_type != MONO_WRAPPER_NONE)
+       if (method->wrapper_type != MONO_WRAPPER_NONE) {
                klass = mono_method_get_wrapper_data (method, token);
-       else
+               if (context)
+                       klass = mono_class_inflate_generic_class (klass, context);
+       } else {
                klass = mono_class_get_full (method->klass->image, token, context);
+       }
        if (klass)
                mono_class_init (klass);
        return klass;
 }
 
+static inline MonoMethodSignature*
+mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
+{
+       MonoMethodSignature *fsig;
+
+       if (method->wrapper_type != MONO_WRAPPER_NONE) {
+               MonoError error;
+
+               fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
+               if (context) {
+                       fsig = mono_inflate_generic_signature (fsig, context, &error);
+                       // FIXME:
+                       g_assert (mono_error_ok (&error));
+               }
+       } else {
+               fsig = mono_metadata_parse_signature (method->klass->image, token);
+       }
+       return fsig;
+}
+
 /*
  * Returns TRUE if the JIT should abort inlining because "callee"
  * is influenced by security attributes.
@@ -5990,6 +6222,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        init_locals = header->init_locals;
 
        seq_points = cfg->gen_seq_points && cfg->method == method;
+#ifdef PLATFORM_ANDROID
+       seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
+#endif
+
+       if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
+               /* We could hit a seq point before attaching to the JIT (#8338) */
+               seq_points = FALSE;
+       }
 
        if (cfg->gen_seq_points && cfg->method == method) {
                minfo = mono_debug_lookup_method (method);
@@ -6795,6 +7035,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MonoCallInst *call;
 
                        INLINE_FAILURE ("jmp");
+                       GSHAREDVT_FAILURE (*ip);
 
                        CHECK_OPSIZE (5);
                        if (stack_start != sp)
@@ -6857,26 +7098,31 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        int calli = *ip == CEE_CALLI;
                        gboolean pass_imt_from_rgctx = FALSE;
                        MonoInst *imt_arg = NULL;
+                       MonoInst *keep_this_alive = NULL;
                        gboolean pass_vtable = FALSE;
                        gboolean pass_mrgctx = FALSE;
                        MonoInst *vtable_arg = NULL;
                        gboolean check_this = FALSE;
                        gboolean supported_tail_call = FALSE;
                        gboolean need_seq_point = FALSE;
+                       guint32 call_opcode = *ip;
+                       gboolean emit_widen = TRUE;
+                       gboolean push_res = TRUE;
+                       gboolean skip_ret = FALSE;
+                       gboolean delegate_invoke = FALSE;
 
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
 
+                       ins = NULL;
+
                        if (calli) {
+                               //GSHAREDVT_FAILURE (*ip);
                                cmethod = NULL;
                                CHECK_STACK (1);
                                --sp;
                                addr = *sp;
-                               if (method->wrapper_type != MONO_WRAPPER_NONE)
-                                       fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
-                               else
-                                       fsig = mono_metadata_parse_signature (image, token);
-
+                               fsig = mini_get_signature (method, token, generic_context);
                                n = fsig->param_count + fsig->hasthis;
 
                                if (method->dynamic && fsig->pinvoke) {
@@ -6895,37 +7141,36 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                        } else {
                                MonoMethod *cil_method;
-                               
-                               if (method->wrapper_type != MONO_WRAPPER_NONE) {
-                                       if (constrained_call && cfg->verbose_level > 2)
-                                               printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
-                                       cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
-                                       cil_method = cmethod;
-                                       if (constrained_call && !((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
-                                                       constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
-                                                       cfg->generic_sharing_context)) {
-                                               cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context);
-                                       }
-                               } else if (constrained_call) {
-                                       if (cfg->verbose_level > 2)
-                                               printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
 
-                                       if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
-                                               /* 
-                                                * This is needed since get_method_constrained can't find 
-                                                * the method in klass representing a type var.
-                                                * The type var is guaranteed to be a reference type in this
-                                                * case.
-                                                */
-                                               cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
-                                               cil_method = cmethod;
-                                               g_assert (!cmethod->klass->valuetype);
+                               cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
+                               cil_method = cmethod;
+                               
+                               if (constrained_call) {
+                                       if (method->wrapper_type != MONO_WRAPPER_NONE) {
+                                               if (cfg->verbose_level > 2)
+                                                       printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
+                                               if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
+                                                          constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
+                                                         cfg->generic_sharing_context)) {
+                                                       cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context);
+                                               }
                                        } else {
-                                               cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
+                                               if (cfg->verbose_level > 2)
+                                                       printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
+
+                                               if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
+                                                       /* 
+                                                        * This is needed since get_method_constrained can't find 
+                                                        * the method in klass representing a type var.
+                                                        * The type var is guaranteed to be a reference type in this
+                                                        * case.
+                                                        */
+                                                       if (!mini_is_gsharedvt_klass (cfg, constrained_call))
+                                                               g_assert (!cmethod->klass->valuetype);
+                                               } else {
+                                                       cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
+                                               }
                                        }
-                               } else {
-                                       cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
-                                       cil_method = cmethod;
                                }
                                        
                                if (!cmethod || mono_loader_get_last_error ())
@@ -6956,7 +7201,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                         */
                                        const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
                                        const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
-                                       if (!virtual && cmethod->klass->marshalbyref && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
+                                       if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
                                                virtual = 1;
                                }
 
@@ -7004,6 +7249,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                n = fsig->param_count + fsig->hasthis;
 
+                               /* Don't support calls made using type arguments for now */
+                               /*
+                               if (cfg->gsharedvt) {
+                                       if (mini_is_gsharedvt_signature (cfg, fsig))
+                                               GSHAREDVT_FAILURE (*ip);
+                               }
+                               */
+
                                if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                                        if (check_linkdemand (cfg, method, cmethod))
                                                INLINE_FAILURE ("linkdemand");
@@ -7027,6 +7280,33 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        sp -= n;
 
                        if (constrained_call) {
+                               if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
+                                       /*
+                                        * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
+                                        */
+                                       /* Special case Object:ToString () as its easy to implement */
+                                       if (cmethod->klass == mono_defaults.object_class && !strcmp (cmethod->name, "ToString")) {
+                                               MonoInst *args [3];
+
+                                               args [0] = sp [0];
+                                               EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
+                                               args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
+                                               ins = mono_emit_jit_icall (cfg, mono_object_tostring_gsharedvt, args);
+                                               goto call_end;
+                                       } else if (cmethod->klass == mono_defaults.object_class && !strcmp (cmethod->name, "GetHashCode")) {
+                                               MonoInst *args [3];
+
+                                               args [0] = sp [0];
+                                               EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
+                                               args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
+                                               ins = mono_emit_jit_icall (cfg, mono_object_gethashcode_gsharedvt, args);
+                                               goto call_end;
+                                       } else if (constrained_call->valuetype && cmethod->klass->valuetype) {
+                                               /* The 'Own method' case below */
+                                       } else {
+                                               GSHAREDVT_FAILURE (*ip);
+                                       }
+                               }
                                /*
                                 * We have the `constrained.' prefix opcode.
                                 */
@@ -7039,6 +7319,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
                                        ins->klass = constrained_call;
                                        sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call));
+                                       bblock = cfg->cbb;
                                        CHECK_CFG_EXCEPTION;
                                } else if (!constrained_call->valuetype) {
                                        int dreg = alloc_ireg_ref (cfg);
@@ -7073,6 +7354,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                        EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
                                                        ins->klass = constrained_call;
                                                        sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call));
+                                                       bblock = cfg->cbb;
                                                        CHECK_CFG_EXCEPTION;
                                                }
                                        }
@@ -7081,24 +7363,22 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                constrained_call = NULL;
                        }
 
-                       if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
+                       if (!calli && check_call_signature (cfg, fsig, sp))
                                UNVERIFIED;
 
+#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
+                       if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
+                               delegate_invoke = TRUE;
+#endif
+
                        if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
                                bblock = cfg->cbb;
                                if (!MONO_TYPE_IS_VOID (fsig->ret)) {
                                        type_to_eval_stack_type ((cfg), fsig->ret, ins);
-                                       *sp = ins;
-                                       sp++;
+                                       emit_widen = FALSE;
                                }
 
-                               CHECK_CFG_EXCEPTION;
-
-                               ip += 5;
-                               ins_flag = 0;
-                               if (need_seq_point)
-                                       emit_seq_point (cfg, method, ip, FALSE);
-                               break;
+                               goto call_end;
                        }
 
                        /* 
@@ -7112,9 +7392,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if (cmethod && ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
                                        (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
-                               gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
-                               MonoGenericContext *context = mini_class_get_context (cmethod->klass);
-                               gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
+                               gboolean sharable = FALSE;
+
+                               if (mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
+                                       sharable = TRUE;
+                               } else {
+                                       gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
+                                       MonoGenericContext *context = mini_class_get_context (cmethod->klass);
+                                       gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
+
+                                       sharable = sharing_enabled && context_sharable;
+                               }
 
                                /*
                                 * Pass vtable iff target method might
@@ -7123,27 +7411,32 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 * context is sharable (and it's not a
                                 * generic method).
                                 */
-                               if (sharing_enabled && context_sharable &&
-                                       !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
+                               if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
                                        pass_vtable = TRUE;
                        }
 
                        if (cmethod && mini_method_get_context (cmethod) &&
                                        mini_method_get_context (cmethod)->method_inst) {
-                               gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
-                               MonoGenericContext *context = mini_method_get_context (cmethod);
-                               gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
-
                                g_assert (!pass_vtable);
 
-                               if (sharing_enabled && context_sharable)
-                                       pass_mrgctx = TRUE;
+                               if (mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
+                                       pass_mrgctx = TRUE;
+                               } else {
+                                       gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
+                                       MonoGenericContext *context = mini_method_get_context (cmethod);
+                                       gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
+
+                                       if (sharing_enabled && context_sharable)
+                                               pass_mrgctx = TRUE;
+                                       if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
+                                               pass_mrgctx = TRUE;
+                               }
                        }
 
                        if (cfg->generic_sharing_context && cmethod) {
                                MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
 
-                               context_used = mono_method_check_context_used (cmethod);
+                               context_used = mini_method_check_context_used (cfg, cmethod);
 
                                if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
                                        /* Generic method interface
@@ -7198,7 +7491,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* !marshalbyref is needed to properly handle generic methods + remoting */
                                if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
                                         MONO_METHOD_IS_FINAL (cmethod)) &&
-                                       !cmethod->klass->marshalbyref) {
+                                       !mono_class_is_marshalbyref (cmethod->klass)) {
                                        if (virtual)
                                                check_this = TRUE;
                                        virtual = 0;
@@ -7221,26 +7514,33 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                            (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
                            !(MONO_METHOD_IS_FINAL (cmethod) && 
                              cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
-                           mono_method_signature (cmethod)->generic_param_count) {
+                           fsig->generic_param_count && 
+                               !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
                                MonoInst *this_temp, *this_arg_temp, *store;
                                MonoInst *iargs [4];
+                               gboolean use_imt = FALSE;
 
-                               g_assert (mono_method_signature (cmethod)->is_inflated);
+                               g_assert (fsig->is_inflated);
 
                                /* Prevent inlining of methods that contain indirect calls */
                                INLINE_FAILURE ("virtual generic call");
 
+                               if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
+                                       GSHAREDVT_FAILURE (*ip);
+
 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
-                               if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt) {
+                               if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
+                                       use_imt = TRUE;
+#endif
+
+                               if (use_imt) {
                                        g_assert (!imt_arg);
                                        if (!context_used)
                                                g_assert (cmethod->is_inflated);
                                        imt_arg = emit_get_rgctx_method (cfg, context_used,
                                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
                                        ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, sp [0], imt_arg, NULL);
-                               } else
-#endif
-                               {
+                               } else {
                                        this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
                                        NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
                                        MONO_ADD_INS (bblock, store);
@@ -7257,19 +7557,10 @@ 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);
+                                       ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
                                }
 
-                               if (!MONO_TYPE_IS_VOID (fsig->ret))
-                                       *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
-
-                               CHECK_CFG_EXCEPTION;
-
-                               ip += 5;
-                               ins_flag = 0;
-                               if (need_seq_point)
-                                       emit_seq_point (cfg, method, ip, FALSE);
-                               break;
+                               goto call_end;
                        }
 
                        /*
@@ -7304,21 +7595,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                bblock = cfg->cbb;
                                if (!MONO_TYPE_IS_VOID (fsig->ret)) {
                                        type_to_eval_stack_type ((cfg), fsig->ret, ins);
-                                       *sp = ins;
-                                       sp++;
+                                       emit_widen = FALSE;
                                }
-
-                               CHECK_CFG_EXCEPTION;
-
-                               ip += 5;
-                               ins_flag = 0;
-                               if (need_seq_point)
-                                       emit_seq_point (cfg, method, ip, FALSE);
-                               break;
+                               goto call_end;
                        }
 
                        /* Inlining */
-                       if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
+                       if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
                                (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
                            !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
                                 !g_list_find (dont_inline, cmethod)) {
@@ -7333,28 +7616,25 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        always = TRUE;
                                }
 
-                               if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always))) {
-                                       ip += 5;
+                               costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always);
+                               if (costs) {
                                        cfg->real_offset += 5;
                                        bblock = cfg->cbb;
 
                                        if (!MONO_TYPE_IS_VOID (fsig->ret)) {
                                                /* *sp is already set by inline_method */
                                                sp++;
+                                               push_res = FALSE;
                                        }
 
                                        inline_costs += costs;
-                                       ins_flag = 0;
-                                       if (need_seq_point)
-                                               emit_seq_point (cfg, method, ip, FALSE);
-                                       break;
+
+                                       goto call_end;
                                }
                        }
-                       
-                       inline_costs += 10 * num_calls++;
 
                        /* Tail recursion elimination */
-                       if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
+                       if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
                                gboolean has_vtargs = FALSE;
                                int i;
 
@@ -7379,23 +7659,77 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        /* skip the CEE_RET, too */
                                        if (ip_in_bb (cfg, bblock, ip + 5))
-                                               ip += 6;
-                                       else
-                                               ip += 5;
+                                               skip_ret = TRUE;
+                                       push_res = FALSE;
+                                       goto call_end;
+                               }
+                       }
 
-                                       ins_flag = 0;
-                                       break;
+                       inline_costs += 10 * num_calls++;
+
+                       /*
+                        * Making generic calls out of gsharedvt methods.
+                        */
+                       if (cmethod && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
+                               MonoRgctxInfoType info_type;
+
+                               if (virtual) {
+                                       //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
+                                               //GSHAREDVT_FAILURE (*ip);
+                                       // disable for possible remoting calls
+                                       if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
+                                               GSHAREDVT_FAILURE (*ip);
+                                       if (fsig->generic_param_count) {
+                                               /* virtual generic call */
+                                               g_assert (mono_use_imt);
+                                               g_assert (!imt_arg);
+                                               /* Same as the virtual generic case above */
+                                               imt_arg = emit_get_rgctx_method (cfg, context_used,
+                                                                                                                cmethod, MONO_RGCTX_INFO_METHOD);
+                                               /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
+                                               vtable_arg = NULL;
+                                       }
                                }
+
+                               if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
+                                       /* test_0_multi_dim_arrays () in gshared.cs */
+                                       GSHAREDVT_FAILURE (*ip);
+
+                               if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
+                                       keep_this_alive = sp [0];
+
+                               if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
+                                       info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
+                               else
+                                       info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
+                               addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
+
+                               ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
+                               goto call_end;
+                       } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
+                               /*
+                                * We pass the address to the gsharedvt trampoline in the rgctx reg
+                                */
+                               MonoInst *callee = addr;
+
+                               if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
+                                       /* Not tested */
+                                       GSHAREDVT_FAILURE (*ip);
+
+                               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);
+                               goto call_end;
                        }
 
                        /* Generic sharing */
                        /* FIXME: only do this for generic methods if
                           they are not shared! */
-                       if (context_used && !imt_arg && !array_rank &&
-                                       (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
-                                               !mono_class_generic_sharing_enabled (cmethod->klass)) &&
-                                       (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
-                                               !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
+                       if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
+                               (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
+                                !mono_class_generic_sharing_enabled (cmethod->klass)) &&
+                               (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
+                                !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
                                INLINE_FAILURE ("gshared");
 
                                g_assert (cfg->generic_sharing_context && cmethod);
@@ -7408,16 +7742,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 * the method in the rgctx and do an
                                 * indirect call.
                                 */
+                               if (fsig->hasthis)
+                                       MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
+
                                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);
+                               goto call_end;
                        }
 
                        /* Indirect calls */
                        if (addr) {
-                               g_assert (!imt_arg);
-
-                               if (*ip == CEE_CALL)
+                               if (call_opcode == CEE_CALL)
                                        g_assert (context_used);
-                               else if (*ip == CEE_CALLI)
+                               else if (call_opcode == CEE_CALLI)
                                        g_assert (!vtable_arg);
                                else
                                        /* FIXME: what the hell is this??? */
@@ -7427,33 +7764,30 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* Prevent inlining of methods with indirect calls */
                                INLINE_FAILURE ("indirect call");
 
-                               if (vtable_arg) {
-                                       ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, vtable_arg);
-                               } else {
-                                       if (addr->opcode == OP_AOTCONST && addr->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
-                                               /* 
-                                                * Instead of emitting an indirect call, emit a direct call
-                                                * with the contents of the aotconst as the patch info.
-                                                */
-                                               ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_p0, fsig, sp);
-                                               NULLIFY_INS (addr);
-                                       } else if (addr->opcode == OP_GOT_ENTRY && addr->inst_right->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
-                                               ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_right->inst_left, fsig, sp);
-                                               NULLIFY_INS (addr);
+                               if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
+                                       int info_type;
+                                       gpointer info_data;
+
+                                       /* 
+                                        * Instead of emitting an indirect call, emit a direct call
+                                        * with the contents of the aotconst as the patch info.
+                                        */
+                                       if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
+                                               info_type = addr->inst_c1;
+                                               info_data = addr->inst_p0;
                                        } else {
-                                               ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL);
+                                               info_type = addr->inst_right->inst_c1;
+                                               info_data = addr->inst_right->inst_left;
+                                       }
+                                       
+                                       if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
+                                               ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
+                                               NULLIFY_INS (addr);
+                                               goto call_end;
                                        }
                                }
-                               if (!MONO_TYPE_IS_VOID (fsig->ret))
-                                       *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
-
-                               CHECK_CFG_EXCEPTION;
-
-                               ip += 5;
-                               ins_flag = 0;
-                               if (need_seq_point)
-                                       emit_seq_point (cfg, method, ip, FALSE);
-                               break;
+                               ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
+                               goto call_end;
                        }
                                        
                        /* Array methods */
@@ -7480,8 +7814,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
 
                                        EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
-
-                                       *sp++ = ins;
                                } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
                                        if (!cmethod->klass->element_class->valuetype && !readonly)
                                                mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
@@ -7489,43 +7821,29 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        
                                        readonly = FALSE;
                                        addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
-                                       *sp++ = addr;
+                                       ins = addr;
                                } else {
                                        g_assert_not_reached ();
                                }
 
-                               CHECK_CFG_EXCEPTION;
-
-                               ip += 5;
-                               ins_flag = 0;
-                               emit_seq_point (cfg, method, ip, FALSE);
-                               break;
+                               emit_widen = FALSE;
+                               goto call_end;
                        }
 
                        ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
-                       if (ins) {
-                               if (!MONO_TYPE_IS_VOID (fsig->ret))
-                                       *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
-
-                               CHECK_CFG_EXCEPTION;
-
-                               ip += 5;
-                               ins_flag = 0;
-                               if (need_seq_point)
-                                       emit_seq_point (cfg, method, ip, FALSE);
-                               break;
-                       }
+                       if (ins)
+                               goto call_end;
 
                        /* Tail prefix / tail call optimization */
 
                        /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
                        /* FIXME: runtime generic context pointer for jumps? */
                        /* FIXME: handle this for generic sharing eventually */
-                       supported_tail_call = cmethod && 
-                               ((((ins_flag & MONO_INST_TAILCALL) && (*ip == CEE_CALL))
+                       if (cmethod && 
+                               ((((ins_flag & MONO_INST_TAILCALL) && (call_opcode == CEE_CALL))
                                  ))//|| ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && ip [5] == CEE_RET))
-                               && !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig);
-
+                               && !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig))
+                               supported_tail_call = TRUE;
                        if (supported_tail_call) {
                                MonoCallInst *call;
 
@@ -7561,21 +7879,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                link_bblock (cfg, bblock, end_bblock);                  
                                start_new_bblock = 1;
 
-                               CHECK_CFG_EXCEPTION;
-
-                               ip += 5;
-                               ins_flag = 0;
-
                                // FIXME: Eliminate unreachable epilogs
 
                                /*
                                 * OP_TAILCALL has no return value, so skip the CEE_RET if it is
                                 * only reachable from this call.
                                 */
-                               GET_BBLOCK (cfg, tblock, ip);
+                               GET_BBLOCK (cfg, tblock, ip + 5);
                                if (tblock == bblock || tblock->in_count == 0)
-                                       ip += 1;
-                               break;
+                                       skip_ret = TRUE;
+                               push_res = FALSE;
+
+                               goto call_end;
                        }
 
                        /* 
@@ -7586,22 +7901,42 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         * change the called method to a dummy wrapper, and resolve that wrapper
                         * to the real method in mono_jit_compile_method ().
                         */
-                       if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED && mono_marshal_method_from_wrapper (cfg->method) == cmethod) {
+                       if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED && mono_marshal_method_from_wrapper (cfg->method) == cmethod)
                                cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
-                       }
 
                        /* Common call */
                        INLINE_FAILURE ("call");
                        ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL,
                                                                                          imt_arg, vtable_arg);
 
-                       if (!MONO_TYPE_IS_VOID (fsig->ret))
-                               *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
+                       call_end:
+
+                       /* End of call, INS should contain the result of the call, if any */
+
+                       if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
+                               g_assert (ins);
+                               if (emit_widen)
+                                       *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
+                               else
+                                       *sp++ = ins;
+                       }
+
+                       if (keep_this_alive) {
+                               MonoInst *dummy_use;
+
+                               /* See mono_emit_method_call_full () */
+                               EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
+                       }
 
                        CHECK_CFG_EXCEPTION;
 
                        ip += 5;
+                       if (skip_ret) {
+                               g_assert (*ip == CEE_RET);
+                               ip += 1;
+                       }
                        ins_flag = 0;
+                       constrained_call = NULL;
                        if (need_seq_point)
                                emit_seq_point (cfg, method, ip, FALSE);
                        break;
@@ -8197,6 +8532,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ip++;
                        break;
                case CEE_CPOBJ:
+                       GSHAREDVT_FAILURE (*ip);
                        CHECK_OPSIZE (5);
                        CHECK_STACK (2);
                        token = read32 (ip + 1);
@@ -8371,8 +8707,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!mono_class_init (cmethod->klass))
                                TYPE_LOAD_ERROR (cmethod->klass);
 
-                       if (cfg->generic_sharing_context)
-                               context_used = mono_method_check_context_used (cmethod);
+                       context_used = mini_method_check_context_used (cfg, cmethod);
 
                        if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                                if (check_linkdemand (cfg, method, cmethod))
@@ -8387,6 +8722,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_TYPELOAD (cmethod->klass);
                        }
 
+                       /*
+                       if (cfg->gsharedvt) {
+                               if (mini_is_gsharedvt_variable_signature (sig))
+                                       GSHAREDVT_FAILURE (*ip);
+                       }
+                       */
+
                        if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
                                        mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
                                if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
@@ -8475,6 +8817,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
                                else if (fsig->param_count == 3)
                                        alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
+                               else if (fsig->param_count == 4)
+                                       alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
                                else
                                        alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
                        } else if (cmethod->string_ctor) {
@@ -8529,7 +8873,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                /* Now call the actual ctor */
                                /* Avoid virtual calls to ctors if possible */
-                               if (cmethod->klass->marshalbyref)
+                               if (mono_class_is_marshalbyref (cmethod->klass))
                                        callvirt_this_arg = sp [0];
 
 
@@ -8554,8 +8898,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                inline_costs += costs - 5;
                                        } else {
                                                INLINE_FAILURE ("inline failure");
+                                               // FIXME-VT: Clean this up
+                                               if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
+                                                       GSHAREDVT_FAILURE(*ip);
                                                mono_emit_method_call_full (cfg, cmethod, fsig, sp, callvirt_this_arg, NULL, NULL);
                                        }
+                               } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
+                                       MonoInst *addr;
+
+                                       addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
+                                       mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
                                } else if (context_used &&
                                                (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
                                                        !mono_class_generic_sharing_enabled (cmethod->klass))) {
@@ -8564,7 +8916,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        cmethod_addr = emit_get_rgctx_method (cfg, context_used,
                                                cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
 
-                                       mono_emit_calli (cfg, fsig, sp, cmethod_addr, vtable_arg);
+                                       mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
                                } else {
                                        INLINE_FAILURE ("ctor call");
                                        ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp,
@@ -8595,8 +8947,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
 
-                       if (cfg->generic_sharing_context)
-                               context_used = mono_class_check_context_used (klass);
+                       context_used = mini_class_check_context_used (cfg, klass);
 
                        if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
                                MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
@@ -8618,7 +8969,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
                                ip += 5;
                                inline_costs += 2;
-                       } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+                       } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
                                MonoMethod *mono_castclass;
                                MonoInst *iargs [1];
                                int costs;
@@ -8657,8 +9008,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
  
-                       if (cfg->generic_sharing_context)
-                               context_used = mono_class_check_context_used (klass);
+                       context_used = mini_class_check_context_used (cfg, klass);
 
                        if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
                                MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
@@ -8679,7 +9029,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
                                ip += 5;
                                inline_costs += 2;
-                       } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+                       } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
                                MonoMethod *mono_isinst;
                                MonoInst *iargs [1];
                                int costs;
@@ -8719,8 +9069,42 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
  
                        mono_save_token_info (cfg, image, token, klass);
 
-                       if (cfg->generic_sharing_context)
-                               context_used = mono_class_check_context_used (klass);
+                       context_used = mini_class_check_context_used (cfg, klass);
+
+                       if (mini_is_gsharedvt_klass (cfg, klass)) {
+                               MonoInst *obj, *addr, *klass_inst, *args[16];
+                               int dreg;
+
+                               /* Need to check for nullable types at runtime, but those are disabled in mini_is_gsharedvt_sharable_method*/
+                               if (mono_class_is_nullable (klass))
+                                       GSHAREDVT_FAILURE (*ip);
+
+                               obj = *sp;
+
+                               klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+
+                               /* obj */
+                               args [0] = obj;
+
+                               /* klass */
+                               args [1] = klass_inst;
+
+                               /* CASTCLASS */
+                               obj = mono_emit_jit_icall (cfg, mono_object_castclass, args);
+
+                               /* UNBOX */
+                               dreg = alloc_dreg (cfg, STACK_MP);
+                               NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, dreg, obj->dreg, sizeof (MonoObject));
+                               MONO_ADD_INS (cfg->cbb, addr);
+
+                               /* LDOBJ */
+                               EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
+                               *sp++ = ins;
+
+                               ip += 5;
+                               inline_costs += 2;
+                               break;
+                       }
 
                        if (generic_class_is_reference_type (cfg, klass)) {
                                /* CASTCLASS FIXME kill this huge slice of duplicated code*/
@@ -8745,7 +9129,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
                                        ip += 5;
                                        inline_costs += 2;
-                               } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+                               } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
                                        MonoMethod *mono_castclass;
                                        MonoInst *iargs [1];
                                        int costs;
@@ -8807,8 +9191,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        mono_save_token_info (cfg, image, token, klass);
 
-                       if (cfg->generic_sharing_context)
-                               context_used = mono_class_check_context_used (klass);
+                       context_used = mini_class_check_context_used (cfg, klass);
 
                        if (generic_class_is_reference_type (cfg, klass)) {
                                *sp++ = val;
@@ -8895,6 +9278,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        *sp++ = handle_box (cfg, val, klass, context_used);
+                       bblock = cfg->cbb;
 
                        CHECK_CFG_EXCEPTION;
                        ip += 5;
@@ -8911,8 +9295,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        mono_save_token_info (cfg, image, token, klass);
 
-                       if (cfg->generic_sharing_context)
-                               context_used = mono_class_check_context_used (klass);
+                       context_used = mini_class_check_context_used (cfg, klass);
 
                        if (mono_class_is_nullable (klass)) {
                                MonoInst *val;
@@ -9017,16 +9400,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                is_instance = FALSE;
                        }
 
+                       context_used = mini_class_check_context_used (cfg, klass);
+
                        /* INSTANCE CASE */
 
                        foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
                        if (op == CEE_STFLD) {
                                if (target_type_is_incompatible (cfg, field->type, sp [1]))
                                        UNVERIFIED;
-                               if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
+#ifndef DISABLE_REMOTING
+                               if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
                                        MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
                                        MonoInst *iargs [5];
 
+                                       GSHAREDVT_FAILURE (op);
+
                                        iargs [0] = sp [0];
                                        EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
                                        EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
@@ -9047,12 +9435,26 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        } else {
                                                mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
                                        }
-                               } else {
+                               } else
+#endif
+                               {
                                        MonoInst *store;
 
                                        MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
 
-                                       EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
+                                       if (mini_is_gsharedvt_klass (cfg, klass)) {
+                                               MonoInst *offset_ins;
+
+                                               context_used = mini_class_check_context_used (cfg, klass);
+
+                                               offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
+                                               dreg = alloc_ireg_mp (cfg);
+                                               EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
+                                               EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
+                                               // FIXME-VT: wbarriers ?
+                                       } else {
+                                               EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
+                                       }
                                        if (sp [0]->opcode != OP_LDADDR)
                                                store->flags |= MONO_INST_FAULT;
 
@@ -9073,10 +9475,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
 
-                       if (is_instance && ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class)) {
+#ifndef DISABLE_REMOTING
+                       if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
                                MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
                                MonoInst *iargs [4];
 
+                               GSHAREDVT_FAILURE (op);
+
                                iargs [0] = sp [0];
                                EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
                                EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
@@ -9097,7 +9502,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
                                        *sp++ = ins;
                                }
-                       } else if (is_instance) {
+                       } else 
+#endif
+                       if (is_instance) {
                                if (sp [0]->type == STACK_VTYPE) {
                                        MonoInst *var;
 
@@ -9115,6 +9522,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                if (op == CEE_LDFLDA) {
                                        if (is_magic_tls_access (field)) {
+                                               GSHAREDVT_FAILURE (*ip);
                                                ins = sp [0];
                                                *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
                                        } else {
@@ -9125,7 +9533,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                                dreg = alloc_ireg_mp (cfg);
 
-                                               EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
+                                               if (mini_is_gsharedvt_klass (cfg, klass)) {
+                                                       MonoInst *offset_ins;
+
+                                                       offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
+                                                       EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
+                                               } else {
+                                                       EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
+                                               }
                                                ins->klass = mono_class_from_mono_type (field->type);
                                                ins->type = STACK_MP;
                                                *sp++ = ins;
@@ -9135,7 +9550,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
 
-                                       EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
+                                       if (mini_is_gsharedvt_klass (cfg, klass)) {
+                                               MonoInst *offset_ins;
+
+                                               offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
+                                               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);
+                                       }
                                        load->flags |= ins_flag;
                                        if (sp [0]->opcode != OP_LDADDR)
                                                load->flags |= MONO_INST_FAULT;
@@ -9161,8 +9585,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        GENERIC_SHARING_FAILURE (op);
 #endif
 
-                       if (cfg->generic_sharing_context)
-                               context_used = mono_class_check_context_used (klass);
+                       context_used = mini_class_check_context_used (cfg, klass);
 
                        ftype = mono_field_get_type (field);
 
@@ -9194,6 +9617,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                int idx, static_data_reg, array_reg, dreg;
                                MonoInst *thread_ins;
 
+                               GSHAREDVT_FAILURE (op);
+
                                // offset &= 0x7fffffff;
                                // idx = (offset >> 24) - 1;
                                //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
@@ -9264,7 +9689,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                static_data = emit_get_rgctx_klass (cfg, context_used,
                                        klass, MONO_RGCTX_INFO_STATIC_DATA);
 
-                               if (field->offset == 0) {
+                               if (mini_is_gsharedvt_klass (cfg, klass)) {
+                                       MonoInst *offset_ins;
+
+                                       offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
+                                       dreg = alloc_ireg_mp (cfg);
+                                       EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
+                               } else if (field->offset == 0) {
                                        ins = static_data;
                                } else {
                                        int addr_reg = mono_alloc_preg (cfg);
@@ -9345,6 +9776,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
                                                ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
                                        }
+
+                                       GSHAREDVT_FAILURE (op);
+
                                        /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
                                        is_const = TRUE;
                                        switch (ro_type) {
@@ -9462,8 +9896,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
 
-                       if (cfg->generic_sharing_context)
-                               context_used = mono_class_check_context_used (klass);
+                       context_used = mini_class_check_context_used (cfg, klass);
 
                        if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
                                MONO_INST_NEW (cfg, ins, OP_LCONV_TO_I4);
@@ -9477,21 +9910,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (context_used) {
                                MonoInst *args [3];
                                MonoClass *array_class = mono_array_class_get (klass, 1);
-                               /* FIXME: we cannot get a managed
-                                  allocator because we can't get the
-                                  open generic class's vtable.  We
-                                  have the same problem in
-                                  handle_alloc().  This
-                                  needs to be solved so that we can
-                                  have managed allocs of shared
-                                  generic classes. */
-                               /*
-                               MonoVTable *array_class_vtable = mono_class_vtable (cfg->domain, array_class);
-                               MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class_vtable, 1);
-                               */
-                               MonoMethod *managed_alloc = NULL;
+                               MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
 
-                               /* FIXME: Decompose later to help abcrem */
+                               /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
 
                                /* vtable */
                                args [0] = emit_get_rgctx_klass (cfg, context_used,
@@ -9639,7 +10060,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        cfg->flags |= MONO_CFG_HAS_LDELEMA;
 
-                       if (sp [1]->opcode == OP_ICONST) {
+                       if (mini_is_gsharedvt_klass (cfg, klass)) {
+                               // FIXME-VT: OP_ICONST optimization
+                               addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
+                               EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
+                               ins->opcode = OP_LOADV_MEMBASE;
+                       } else if (sp [1]->opcode == OP_ICONST) {
                                int array_reg = sp [0]->dreg;
                                int index_reg = sp [1]->dreg;
                                int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
@@ -9714,6 +10140,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        int klass_reg = alloc_preg (cfg);
                        int dreg = alloc_preg (cfg);
 
+                       GSHAREDVT_FAILURE (*ip);
+
                        CHECK_STACK (1);
                        MONO_INST_NEW (cfg, ins, *ip);
                        --sp;
@@ -9722,8 +10150,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
 
-                       if (cfg->generic_sharing_context)
-                               context_used = mono_class_check_context_used (klass);
+                       context_used = mini_class_check_context_used (cfg, klass);
 
                        // FIXME:
                        src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
@@ -9753,6 +10180,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_MKREFANY: {
                        MonoInst *loc, *addr;
 
+                       GSHAREDVT_FAILURE (*ip);
+
                        CHECK_STACK (1);
                        MONO_INST_NEW (cfg, ins, *ip);
                        --sp;
@@ -9761,8 +10190,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
 
-                       if (cfg->generic_sharing_context)
-                               context_used = mono_class_check_context_used (klass);
+                       context_used = mini_class_check_context_used (cfg, klass);
 
                        loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
                        EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
@@ -9833,11 +10261,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
                                                context_used = 0;
                                        else
-                                               context_used = mono_class_check_context_used (mono_class_from_mono_type (handle));
+                                               context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
                                } else if (handle_class == mono_defaults.fieldhandle_class)
-                                       context_used = mono_class_check_context_used (((MonoClassField*)handle)->parent);
+                                       context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
                                else if (handle_class == mono_defaults.methodhandle_class)
-                                       context_used = mono_method_check_context_used (handle);
+                                       context_used = mini_method_check_context_used (cfg, handle);
                                else
                                        g_assert_not_reached ();
                        }
@@ -9848,10 +10276,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoInst *addr, *vtvar, *iargs [3];
                                int method_context_used;
 
-                               if (cfg->generic_sharing_context)
-                                       method_context_used = mono_method_check_context_used (method);
-                               else
-                                       method_context_used = 0;
+                               method_context_used = mini_method_check_context_used (cfg, method);
 
                                vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
 
@@ -10112,23 +10537,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                token = read32 (ip + 2);
 
                                ptr = mono_method_get_wrapper_data (method, token);
-                               if (cfg->compile_aot && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
-                                       MonoJitICallInfo *callinfo;
-                                       const char *icall_name;
-
-                                       icall_name = method->name + strlen ("__icall_wrapper_");
-                                       g_assert (icall_name);
-                                       callinfo = mono_find_jit_icall_by_name (icall_name);
-                                       g_assert (callinfo);
-                                               
-                                       if (ptr == callinfo->func) {
-                                               /* Will be transformed into an AOTCONST later */
-                                               EMIT_NEW_PCONST (cfg, ins, ptr);
-                                               *sp++ = ins;
-                                               ip += 6;
-                                               break;
-                                       }
-                               }
                                /* FIXME: Generalize this */
                                if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
                                        EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
@@ -10144,6 +10552,23 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                cfg->disable_aot = 1;
                                break;
                        }
+                       case CEE_MONO_JIT_ICALL_ADDR: {
+                               MonoJitICallInfo *callinfo;
+                               gpointer ptr;
+
+                               CHECK_STACK_OVF (1);
+                               CHECK_OPSIZE (6);
+                               token = read32 (ip + 2);
+
+                               ptr = mono_method_get_wrapper_data (method, token);
+                               callinfo = mono_find_jit_icall_by_addr (ptr);
+                               g_assert (callinfo);
+                               EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
+                               *sp++ = ins;
+                               ip += 6;
+                               inline_costs += 10 * num_calls++;
+                               break;
+                       }
                        case CEE_MONO_ICALL_ADDR: {
                                MonoMethod *cmethod;
                                gpointer ptr;
@@ -10503,8 +10928,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                mono_save_token_info (cfg, image, n, cmethod);
 
-                               if (cfg->generic_sharing_context)
-                                       context_used = mono_method_check_context_used (cmethod);
+                               context_used = mini_method_check_context_used (cfg, cmethod);
 
                                cil_method = cmethod;
                                if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
@@ -10526,14 +10950,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
                                                MonoInst *target_ins;
                                                MonoMethod *invoke;
-                                               int invoke_context_used = 0;
+                                               int invoke_context_used;
 
                                                invoke = mono_get_delegate_invoke (ctor_method->klass);
                                                if (!invoke || !mono_method_signature (invoke))
                                                        LOAD_ERROR;
 
-                                               if (cfg->generic_sharing_context)
-                                                       invoke_context_used = mono_method_check_context_used (invoke);
+                                               invoke_context_used = mini_method_check_context_used (cfg, invoke);
 
                                                target_ins = sp [-1];
 
@@ -10584,8 +11007,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        LOAD_ERROR;
                                mono_class_init (cmethod->klass);
  
-                               if (cfg->generic_sharing_context)
-                                       context_used = mono_method_check_context_used (cmethod);
+                               context_used = mini_method_check_context_used (cfg, cmethod);
 
                                if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                                        if (check_linkdemand (cfg, method, cmethod))
@@ -10770,10 +11192,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        case CEE_CONSTRAINED_:
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
-                               if (method->wrapper_type != MONO_WRAPPER_NONE)
-                                       constrained_call =  (MonoClass *)mono_method_get_wrapper_data (method, token);
-                               else
-                                       constrained_call = mono_class_get_full (image, token, generic_context);
+                               constrained_call = mini_get_class (method, token, generic_context);
                                CHECK_TYPELOAD (constrained_call);
                                ip += 6;
                                break;
@@ -10849,6 +11268,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                guint32 val;
                                int ialign;
 
+                               GSHAREDVT_FAILURE (*ip);
+
                                CHECK_STACK_OVF (1);
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
@@ -10869,6 +11290,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        case CEE_REFANYTYPE: {
                                MonoInst *src_var, *src;
 
+                               GSHAREDVT_FAILURE (*ip);
+
                                CHECK_STACK (1);
                                --sp;
 
@@ -10978,6 +11401,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
                                   ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
                                MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
+                       } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, ptype)) {
+                               MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
                        } else {
                                MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
                        }
@@ -11094,8 +11519,6 @@ store_membase_reg_to_store_membase_imm (int opcode)
        return -1;
 }              
 
-#endif /* DISABLE_JIT */
-
 int
 mono_op_to_op_imm (int opcode)
 {
@@ -11551,8 +11974,6 @@ mono_op_to_op_imm_noemul (int opcode)
        }
 }
 
-#ifndef DISABLE_JIT
-
 /**
  * mono_handle_global_vregs:
  *
@@ -12041,6 +12462,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
 
                                        ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
 
+#if SIZEOF_REGISTER != 8
                                        if (regtype == 'l') {
                                                NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
                                                mono_bblock_insert_after_ins (bb, ins, store_ins);
@@ -12048,7 +12470,9 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                mono_bblock_insert_after_ins (bb, ins, store_ins);
                                                def_ins = store_ins;
                                        }
-                                       else {
+                                       else
+#endif
+                                       {
                                                g_assert (store_opcode != OP_STOREV_MEMBASE);
 
                                                /* Try to fuse the store into the instruction itself */
@@ -12207,6 +12631,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                sregs [srcindex] = sreg;
                                                //mono_inst_set_src_registers (ins, sregs);
 
+#if SIZEOF_REGISTER != 8
                                                if (regtype == 'l') {
                                                        NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
                                                        mono_bblock_insert_before_ins (bb, ins, load_ins);
@@ -12214,7 +12639,9 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                        mono_bblock_insert_before_ins (bb, ins, load_ins);
                                                        use_ins = load_ins;
                                                }
-                                               else {
+                                               else
+#endif
+                                               {
 #if SIZEOF_REGISTER == 4
                                                        g_assert (load_opcode != OP_LOADI8_MEMBASE);
 #endif