[mini] Extract type checking code into type-checking.c
authorRodrigo Kumpera <kumpera@gmail.com>
Thu, 24 Nov 2016 23:15:12 +0000 (15:15 -0800)
committerRodrigo Kumpera <kumpera@gmail.com>
Mon, 28 Nov 2016 23:58:50 +0000 (15:58 -0800)
mono/mini/method-to-ir.c
mono/mini/mini.c
mono/mini/mini.h
mono/mini/type-checking.c [new file with mode: 0644]

index df104c2e4fc45583860c41de89cf0d3c794c5fda..6f1cebfdb57ebad28698808b0584df7bcfe862f3 100644 (file)
@@ -1572,267 +1572,10 @@ emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer d
        return ins;
 }
 
-static void
-mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
-{
-       int ibitmap_reg = alloc_preg (cfg);
-#ifdef COMPRESSED_INTERFACE_BITMAP
-       MonoInst *args [2];
-       MonoInst *res, *ins;
-       NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
-       MONO_ADD_INS (cfg->cbb, ins);
-       args [0] = ins;
-       args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
-       res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
-       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
-#else
-       int ibitmap_byte_reg = alloc_preg (cfg);
-
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
-
-       if (cfg->compile_aot) {
-               int iid_reg = alloc_preg (cfg);
-               int shifted_iid_reg = alloc_preg (cfg);
-               int ibitmap_byte_address_reg = alloc_preg (cfg);
-               int masked_iid_reg = alloc_preg (cfg);
-               int iid_one_bit_reg = alloc_preg (cfg);
-               int iid_bit_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
-               MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
-               MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
-               MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
-               MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
-       } else {
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
-       }
-#endif
-}
-
-/* 
- * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
- * stored in "klass_reg" implements the interface "klass".
- */
-static void
-mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
-{
-       mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
-}
-
-/* 
- * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
- * stored in "vtable_reg" implements the interface "klass".
- */
-static void
-mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
-{
-       mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
-}
-
-/* 
- * Emit code which checks whenever the interface id of @klass is smaller than
- * than the value given by max_iid_reg.
-*/
-static void
-mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
-                                                MonoBasicBlock *false_target)
-{
-       if (cfg->compile_aot) {
-               int iid_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
-               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
-       }
-       else
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
-       if (false_target)
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
-       else
-               MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
-}
-
-/* Same as above, but obtains max_iid from a vtable */
-static void
-mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
-                                                                MonoBasicBlock *false_target)
-{
-       int max_iid_reg = alloc_preg (cfg);
-               
-       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
-       mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
-}
-
-/* Same as above, but obtains max_iid from a klass */
-static void
-mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
-                                                                MonoBasicBlock *false_target)
-{
-       int max_iid_reg = alloc_preg (cfg);
-
-       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
-       mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
-}
-
-static void
-mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
-{
-       int idepth_reg = alloc_preg (cfg);
-       int stypes_reg = alloc_preg (cfg);
-       int stype = alloc_preg (cfg);
-
-       mono_class_setup_supertypes (klass);
-
-       if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
-       }
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
-       if (klass_ins) {
-               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
-       } else if (cfg->compile_aot) {
-               int const_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
-               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
-       } else {
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
-       }
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
-}
-
-static void
-mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
-{
-       mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
-}
-
-static void
-mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
-{
-       int intf_reg = alloc_preg (cfg);
-
-       mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
-       mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
-       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
-       if (true_target)
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
-       else
-               MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
-}
-
-/*
- * Variant of the above that takes a register to the class, not the vtable.
- */
-static void
-mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
-{
-       int intf_bit_reg = alloc_preg (cfg);
-
-       mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
-       mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
-       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
-       if (true_target)
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
-       else
-               MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
-}
-
-static inline void
-mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
-{
-       if (klass_inst) {
-               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
-       } else {
-               MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
-               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
-       }
-       MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
-}
-
-static inline void
-mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
-{
-       mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
-}
-
-static inline void
-mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
-{
-       if (cfg->compile_aot) {
-               int const_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
-               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
-       } else {
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
-       }
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
-}
-
-static void
-mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
-       
-static void
-mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
-{
-       if (klass->rank) {
-               int rank_reg = alloc_preg (cfg);
-               int eclass_reg = alloc_preg (cfg);
-
-               g_assert (!klass_inst);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
-               MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
-               //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
-               if (klass->cast_class == mono_defaults.object_class) {
-                       int parent_reg = alloc_preg (cfg);
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
-                       mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
-                       mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
-               } else if (klass->cast_class == mono_defaults.enum_class->parent) {
-                       mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
-                       mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
-               } else if (klass->cast_class == mono_defaults.enum_class) {
-                       mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
-               } else if (mono_class_is_interface (klass->cast_class)) {
-                       mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
-               } else {
-                       // Pass -1 as obj_reg to skip the check below for arrays of arrays
-                       mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
-               }
-
-               if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
-                       /* Check that the object is a vector too */
-                       int bounds_reg = alloc_preg (cfg);
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
-                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
-                       MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
-               }
-       } else {
-               int idepth_reg = alloc_preg (cfg);
-               int stypes_reg = alloc_preg (cfg);
-               int stype = alloc_preg (cfg);
-
-               mono_class_setup_supertypes (klass);
-
-               if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
-                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
-                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
-                       MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
-               }
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
-               mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
-       }
-}
-
-static void
-mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
+MonoInst*
+mini_emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
 {
-       mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
+       return emit_runtime_constant (cfg, patch_type, data);
 }
 
 static void 
@@ -2773,8 +2516,6 @@ emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfo
 
 static MonoInst*
 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
-static MonoInst*
-emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
 
 static MonoInst*
 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
@@ -3397,7 +3138,7 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
                        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);
+                               iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
                        }  else {
                                iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
                                if (!cfg->compile_aot)
@@ -3677,8 +3418,8 @@ emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *ent
                return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
 }
 
-static MonoInst*
-emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
+MonoInst*
+mini_emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
                                          MonoClass *klass, MonoRgctxInfoType rgctx_type)
 {
        MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_CLASS, klass, rgctx_type);
@@ -3866,7 +3607,7 @@ emit_class_init (MonoCompile *cfg, MonoClass *klass)
        context_used = mini_class_check_context_used (cfg, klass);
 
        if (context_used) {
-               vtable_arg = emit_get_rgctx_klass (cfg, context_used,
+               vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
                                                                                   klass, MONO_RGCTX_INFO_VTABLE);
        } else {
                MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
@@ -3927,8 +3668,8 @@ emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_
        }
 }
 
-static void
-save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
+void
+mini_save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
 {
        if (mini_get_debug_options ()->better_cast_details) {
                int vtable_reg = alloc_preg (cfg);
@@ -3960,7 +3701,7 @@ save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean nul
                if (context_used) {
                        MonoInst *class_ins;
 
-                       class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+                       class_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
                        to_klass_reg = class_ins->dreg;
                } else {
                        to_klass_reg = alloc_preg (cfg);
@@ -3973,8 +3714,8 @@ save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean nul
        }
 }
 
-static void
-reset_cast_details (MonoCompile *cfg)
+void
+mini_reset_cast_details (MonoCompile *cfg)
 {
        /* Reset the variables holding the cast details */
        if (mini_get_debug_options ()->better_cast_details) {
@@ -3997,7 +3738,7 @@ mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_cl
 
        context_used = mini_class_check_context_used (cfg, array_class);
 
-       save_cast_details (cfg, array_class, obj->dreg, FALSE);
+       mini_save_cast_details (cfg, array_class, obj->dreg, FALSE);
 
        MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
 
@@ -4011,7 +3752,7 @@ mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_cl
        } else if (context_used) {
                MonoInst *vtable_ins;
 
-               vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
+               vtable_ins = mini_emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
                MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
        } else {
                if (cfg->compile_aot) {
@@ -4033,7 +3774,7 @@ mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_cl
        
        MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
 
-       reset_cast_details (cfg);
+       mini_reset_cast_details (cfg);
 }
 
 /**
@@ -4109,15 +3850,15 @@ handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_use
                /* This assertion is from the unboxcast insn */
                g_assert (klass->rank == 0);
 
-               element_class = emit_get_rgctx_klass (cfg, context_used,
+               element_class = mini_emit_get_rgctx_klass (cfg, context_used,
                                klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
 
                MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
                MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
        } else {
-               save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
+               mini_save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
                mini_emit_class_check (cfg, eclass_reg, klass->element_class);
-               reset_cast_details (cfg);
+               mini_reset_cast_details (cfg);
        }
 
        NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
@@ -4231,7 +3972,7 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_
                        rgctx_info = MONO_RGCTX_INFO_KLASS;
                else
                        rgctx_info = MONO_RGCTX_INFO_VTABLE;
-               data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
+               data = mini_emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
 
                if (cfg->opt & MONO_OPT_SHARED) {
                        EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
@@ -4428,34 +4169,6 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
        }
 }
 
-static gboolean
-mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
-{
-       int i;
-       MonoGenericContainer *container;
-       MonoGenericInst *ginst;
-
-       if (mono_class_is_ginst (klass)) {
-               container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
-               ginst = mono_class_get_generic_class (klass)->context.class_inst;
-       } else if (mono_class_is_gtd (klass) && context_used) {
-               container = mono_class_get_generic_container (klass);
-               ginst = container->context.class_inst;
-       } else {
-               return FALSE;
-       }
-
-       for (i = 0; i < container->type_argc; ++i) {
-               MonoType *type;
-               if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
-                       continue;
-               type = ginst->type_argv [i];
-               if (mini_type_is_reference (type))
-                       return TRUE;
-       }
-       return FALSE;
-}
-
 static GHashTable* direct_icall_type_hash;
 
 static gboolean
@@ -4498,493 +4211,6 @@ method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
        return FALSE;
 }
 
-#define is_complex_isinst(klass) (mono_class_is_interface (klass) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || mono_class_is_sealed (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
-
-static MonoInst*
-emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
-{
-       MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
-       return mono_emit_method_call (cfg, mono_isinst, args, NULL);
-}
-
-static MonoInst*
-emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
-{
-       MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
-       MonoInst *res;
-
-       save_cast_details (cfg, klass, args [0]->dreg, TRUE);
-       res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
-       reset_cast_details (cfg);
-
-       return res;
-}
-
-static int
-get_castclass_cache_idx (MonoCompile *cfg)
-{
-       /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
-       cfg->castclass_cache_index ++;
-       return (cfg->method_index << 16) | cfg->castclass_cache_index;
-}
-
-
-static MonoInst*
-emit_isinst_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
-{
-       MonoInst *args [3];
-       int idx;
-
-       args [0] = obj; /* obj */
-       EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
-
-       idx = get_castclass_cache_idx (cfg); /* inline cache*/
-       args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
-
-       return emit_isinst_with_cache (cfg, klass, args);
-}
-
-static MonoInst*
-emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
-{
-       MonoInst *args [3];
-       int idx;
-
-       /* obj */
-       args [0] = obj;
-
-       /* klass */
-       EMIT_NEW_CLASSCONST (cfg, args [1], klass);
-
-       /* inline cache*/
-       idx = get_castclass_cache_idx (cfg);
-       args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
-
-       /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
-       return emit_castclass_with_cache (cfg, klass, args);
-}
-
-/*
- * Returns NULL and set the cfg exception on error.
- */
-static MonoInst*
-handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
-{
-       MonoBasicBlock *is_null_bb;
-       int obj_reg = src->dreg;
-       int vtable_reg = alloc_preg (cfg);
-       MonoInst *klass_inst = NULL;
-
-       if (MONO_INS_IS_PCONST_NULL (src))
-               return src;
-
-       if (context_used) {
-               MonoInst *args [3];
-
-               if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
-                       MonoInst *cache_ins;
-
-                       cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
-
-                       /* obj */
-                       args [0] = src;
-
-                       /* klass - it's the second element of the cache entry*/
-                       EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
-
-                       /* cache */
-                       args [2] = cache_ins;
-
-                       return emit_castclass_with_cache (cfg, klass, args);
-               }
-
-               klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
-       }
-
-       NEW_BBLOCK (cfg, is_null_bb);
-
-       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
-
-       save_cast_details (cfg, klass, obj_reg, FALSE);
-
-       if (mono_class_is_interface (klass)) {
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-               mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
-       } else {
-               int klass_reg = alloc_preg (cfg);
-
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-
-               if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
-                       /* the remoting code is broken, access the class for now */
-                       if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
-                               MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
-                               if (!vt) {
-                                       mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
-                                       cfg->exception_ptr = klass;
-                                       return NULL;
-                               }
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
-                       } else {
-                               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
-                       }
-                       MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
-               } else {
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-                       mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
-               }
-       }
-
-       MONO_START_BB (cfg, is_null_bb);
-
-       reset_cast_details (cfg);
-
-       return src;
-}
-
-/*
- * Returns NULL and set the cfg exception on error.
- */
-static MonoInst*
-handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
-{
-       MonoInst *ins;
-       MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
-       int obj_reg = src->dreg;
-       int vtable_reg = alloc_preg (cfg);
-       int res_reg = alloc_ireg_ref (cfg);
-       MonoInst *klass_inst = NULL;
-
-       if (context_used) {
-               MonoInst *args [3];
-
-               if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
-                       MonoInst *cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
-
-                       args [0] = src; /* obj */
-
-                       /* klass - it's the second element of the cache entry*/
-                       EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
-
-                       args [2] = cache_ins; /* cache */
-                       return emit_isinst_with_cache (cfg, klass, args);
-               }
-
-               klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
-       }
-
-       NEW_BBLOCK (cfg, is_null_bb);
-       NEW_BBLOCK (cfg, false_bb);
-       NEW_BBLOCK (cfg, end_bb);
-
-       /* Do the assignment at the beginning, so the other assignment can be if converted */
-       EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
-       ins->type = STACK_OBJ;
-       ins->klass = klass;
-
-       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
-
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-
-       if (mono_class_is_interface (klass)) {
-               g_assert (!context_used);
-               /* the is_null_bb target simply copies the input register to the output */
-               mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
-       } else {
-               int klass_reg = alloc_preg (cfg);
-
-               if (klass->rank) {
-                       int rank_reg = alloc_preg (cfg);
-                       int eclass_reg = alloc_preg (cfg);
-
-                       g_assert (!context_used);
-                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
-                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
-                       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
-                       if (klass->cast_class == mono_defaults.object_class) {
-                               int parent_reg = alloc_preg (cfg);
-                               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
-                               mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
-                               mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
-                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
-                       } else if (klass->cast_class == mono_defaults.enum_class->parent) {
-                               mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
-                               mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
-                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
-                       } else if (klass->cast_class == mono_defaults.enum_class) {
-                               mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
-                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
-                       } else if (mono_class_is_interface (klass->cast_class)) {
-                               mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
-                       } else {
-                               if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
-                                       /* Check that the object is a vector too */
-                                       int bounds_reg = alloc_preg (cfg);
-                                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
-                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
-                                       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
-                               }
-
-                               /* the is_null_bb target simply copies the input register to the output */
-                               mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
-                       }
-               } else if (mono_class_is_nullable (klass)) {
-                       g_assert (!context_used);
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-                       /* the is_null_bb target simply copies the input register to the output */
-                       mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
-               } else {
-                       if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
-                               g_assert (!context_used);
-                               /* the remoting code is broken, access the class for now */
-                               if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
-                                       MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
-                                       if (!vt) {
-                                               mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
-                                               cfg->exception_ptr = klass;
-                                               return NULL;
-                                       }
-                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
-                               } else {
-                                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
-                               }
-                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
-                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
-                       } else {
-                               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-                               /* the is_null_bb target simply copies the input register to the output */
-                               mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
-                       }
-               }
-       }
-
-       MONO_START_BB (cfg, false_bb);
-
-       MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-
-       MONO_START_BB (cfg, is_null_bb);
-
-       MONO_START_BB (cfg, end_bb);
-
-       return ins;
-}
-
-static MonoInst*
-handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
-{
-       /* This opcode takes as input an object reference and a class, and returns:
-       0) if the object is an instance of the class,
-       1) if the object is not instance of the class,
-       2) if the object is a proxy whose type cannot be determined */
-
-       MonoInst *ins;
-#ifndef DISABLE_REMOTING
-       MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
-#else
-       MonoBasicBlock *true_bb, *false_bb, *end_bb;
-#endif
-       int obj_reg = src->dreg;
-       int dreg = alloc_ireg (cfg);
-       int tmp_reg;
-#ifndef DISABLE_REMOTING
-       int klass_reg = alloc_preg (cfg);
-#endif
-
-       NEW_BBLOCK (cfg, true_bb);
-       NEW_BBLOCK (cfg, false_bb);
-       NEW_BBLOCK (cfg, end_bb);
-#ifndef DISABLE_REMOTING
-       NEW_BBLOCK (cfg, false2_bb);
-       NEW_BBLOCK (cfg, no_proxy_bb);
-#endif
-
-       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
-
-       if (mono_class_is_interface (klass)) {
-#ifndef DISABLE_REMOTING
-               NEW_BBLOCK (cfg, interface_fail_bb);
-#endif
-
-               tmp_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-#ifndef DISABLE_REMOTING
-               mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
-               MONO_START_BB (cfg, interface_fail_bb);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-               
-               mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
-
-               tmp_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
-#else
-               mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
-#endif
-       } else {
-#ifndef DISABLE_REMOTING
-               tmp_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-
-               mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
-               tmp_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
-
-               tmp_reg = alloc_preg (cfg);             
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
-               
-               mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
-
-               MONO_START_BB (cfg, no_proxy_bb);
-
-               mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
-#else
-               g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
-#endif
-       }
-
-       MONO_START_BB (cfg, false_bb);
-
-       MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-
-#ifndef DISABLE_REMOTING
-       MONO_START_BB (cfg, false2_bb);
-
-       MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-#endif
-
-       MONO_START_BB (cfg, true_bb);
-
-       MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
-
-       MONO_START_BB (cfg, end_bb);
-
-       /* FIXME: */
-       MONO_INST_NEW (cfg, ins, OP_ICONST);
-       ins->dreg = dreg;
-       ins->type = STACK_I4;
-
-       return ins;
-}
-
-static MonoInst*
-handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
-{
-       /* This opcode takes as input an object reference and a class, and returns:
-       0) if the object is an instance of the class,
-       1) if the object is a proxy whose type cannot be determined
-       an InvalidCastException exception is thrown otherwhise*/
-       
-       MonoInst *ins;
-#ifndef DISABLE_REMOTING
-       MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
-#else
-       MonoBasicBlock *ok_result_bb;
-#endif
-       int obj_reg = src->dreg;
-       int dreg = alloc_ireg (cfg);
-       int tmp_reg = alloc_preg (cfg);
-
-#ifndef DISABLE_REMOTING
-       int klass_reg = alloc_preg (cfg);
-       NEW_BBLOCK (cfg, end_bb);
-#endif
-
-       NEW_BBLOCK (cfg, ok_result_bb);
-
-       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
-       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
-
-       save_cast_details (cfg, klass, obj_reg, FALSE);
-
-       if (mono_class_is_interface (klass)) {
-#ifndef DISABLE_REMOTING
-               NEW_BBLOCK (cfg, interface_fail_bb);
-       
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-               mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
-               MONO_START_BB (cfg, interface_fail_bb);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-
-               mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
-
-               tmp_reg = alloc_preg (cfg);             
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
-               MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
-               
-               MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-#else
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-               mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
-#endif
-       } else {
-#ifndef DISABLE_REMOTING
-               NEW_BBLOCK (cfg, no_proxy_bb);
-
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
-               mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
-
-               tmp_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
-
-               tmp_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
-
-               NEW_BBLOCK (cfg, fail_1_bb);
-               
-               mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
-
-               MONO_START_BB (cfg, fail_1_bb);
-
-               MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
-               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-
-               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);
-       ins->dreg = dreg;
-       ins->type = STACK_I4;
-
-       return ins;
-}
-
 static G_GNUC_UNUSED MonoInst*
 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
 {
@@ -5207,7 +4433,7 @@ handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMe
                        args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
                else
                        EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
-               args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
+               args [2] = mini_emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
 
                /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
                if (fsig->hasthis && fsig->param_count) {
@@ -7083,6 +6309,12 @@ emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
        }
 }
 
+int
+mini_inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, guchar *ip, guint real_offset, gboolean inline_always)
+{
+       return inline_method (cfg, cmethod, fsig, sp, ip, real_offset, inline_always);
+}
+
 /*
  * inline_method:
  *
@@ -8052,7 +7284,7 @@ handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fs
                                                                                                cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
                } else {
                        if (context_used) {
-                               vtable_arg = emit_get_rgctx_klass (cfg, context_used,
+                               vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
                                                                                                   cmethod->klass, MONO_RGCTX_INFO_VTABLE);
                        } else {
                                MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
@@ -9598,7 +8830,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if (pass_vtable) {
                                if (context_used) {
-                                       vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
+                                       vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
                                } else {
                                        MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
 
@@ -11648,7 +10880,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 *
                                 *   super_info.static_data + field->offset
                                 */
-                               static_data = emit_get_rgctx_klass (cfg, context_used,
+                               static_data = mini_emit_get_rgctx_klass (cfg, context_used,
                                        klass, MONO_RGCTX_INFO_STATIC_DATA);
 
                                if (mini_is_gsharedvt_klass (klass)) {
@@ -11899,7 +11131,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
 
                                /* vtable */
-                               args [0] = emit_get_rgctx_klass (cfg, context_used,
+                               args [0] = mini_emit_get_rgctx_klass (cfg, context_used,
                                        array_class, MONO_RGCTX_INFO_VTABLE);
                                /* array len */
                                args [1] = sp [0];
@@ -12155,7 +11387,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (context_used) {
                                MonoInst *klass_ins;
 
-                               klass_ins = emit_get_rgctx_klass (cfg, context_used,
+                               klass_ins = mini_emit_get_rgctx_klass (cfg, context_used,
                                                klass, MONO_RGCTX_INFO_KLASS);
 
                                // FIXME:
@@ -12192,7 +11424,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoInst *const_ins;
                                int type_reg = alloc_preg (cfg);
 
-                               const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+                               const_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
                                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
                                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
                                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
@@ -12289,7 +11521,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        mono_class_init (tclass);
                                        if (context_used) {
-                                               ins = emit_get_rgctx_klass (cfg, context_used,
+                                               ins = mini_emit_get_rgctx_klass (cfg, context_used,
                                                        tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
                                        } else if (cfg->compile_aot) {
                                                if (method->wrapper_type) {
@@ -12321,7 +11553,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        if (context_used) {
                                                if (handle_class == mono_defaults.typehandle_class) {
-                                                       ins = emit_get_rgctx_klass (cfg, context_used,
+                                                       ins = mini_emit_get_rgctx_klass (cfg, context_used,
                                                                        mono_class_from_mono_type ((MonoType *)handle),
                                                                        MONO_RGCTX_INFO_TYPE);
                                                } else if (handle_class == mono_defaults.methodhandle_class) {
@@ -12733,9 +11965,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                token = read32 (ip + 2);
                                klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
                                if (ip [1] == CEE_MONO_CISINST)
-                                       ins = handle_cisinst (cfg, klass, sp [0]);
+                                       ins = mini_emit_cisinst (cfg, klass, sp [0]);
                                else
-                                       ins = handle_ccastclass (cfg, klass, sp [0]);
+                                       ins = mini_emit_ccastclass (cfg, klass, sp [0]);
                                *sp++ = ins;
                                ip += 6;
                                break;
@@ -15135,73 +14367,6 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
        g_free (live_range_end_bb);
 }
 
-static void
-mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
-{
-       MonoInst *ret, *move, *source;
-       MonoClass *klass = ins->klass;
-       int context_used = mini_class_check_context_used (cfg, klass);
-       int is_isinst = ins->opcode == OP_ISINST;
-       g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
-       source = get_vreg_to_inst (cfg, ins->sreg1);
-       if (!source || source == (MonoInst *) -1)
-               source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
-       g_assert (source && source != (MonoInst *) -1);
-
-       MonoBasicBlock *first_bb;
-       NEW_BBLOCK (cfg, first_bb);
-       cfg->cbb = first_bb;
-
-       if (!context_used && (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || klass->is_array_special_interface)) {
-               if (is_isinst)
-                       ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
-               else
-                       ret = emit_castclass_with_cache_nonshared (cfg, source, klass);
-       } else if (!context_used && (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass))) {
-               MonoInst *iargs [1];
-               int costs;
-
-               iargs [0] = source;
-               if (is_isinst) {
-                       MonoMethod *wrapper = mono_marshal_get_isinst (klass);
-                       costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
-               } else {
-                       MonoMethod *wrapper = mono_marshal_get_castclass (klass);
-                       save_cast_details (cfg, klass, source->dreg, TRUE);
-                       costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
-                       reset_cast_details (cfg);
-               }
-               g_assert (costs > 0);
-               ret = iargs [0];
-       } else {
-               if (is_isinst)
-                       ret = handle_isinst (cfg, klass, source, context_used);
-               else
-                       ret = handle_castclass (cfg, klass, source, context_used);
-       }
-       EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
-
-       g_assert (cfg->cbb->code || first_bb->code);
-       MonoInst *prev = ins->prev;
-       mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
-}
-
-void
-mono_decompose_typechecks (MonoCompile *cfg)
-{
-       for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoInst *ins;
-               MONO_BB_FOR_EACH_INS (bb, ins) {
-                       switch (ins->opcode) {
-                       case OP_ISINST:
-                       case OP_CASTCLASS:
-                               mono_decompose_typecheck (cfg, bb, ins);
-                               break;
-                       }
-               }
-       }
-}
-
 
 /**
  * FIXME:
index cfca91bf6e82b1d10abb7ececa75b650c5e2504c..30609c8352c15ad84590eceef122c472d462c3ba 100644 (file)
@@ -47,6 +47,7 @@
 #include <mono/metadata/mempool-internals.h>
 #include <mono/metadata/attach.h>
 #include <mono/metadata/runtime.h>
+#include <mono/metadata/attrdefs.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-counters.h>
@@ -4033,6 +4034,34 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        return cfg;
 }
 
+gboolean
+mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
+{
+       int i;
+       MonoGenericContainer *container;
+       MonoGenericInst *ginst;
+
+       if (mono_class_is_ginst (klass)) {
+               container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
+               ginst = mono_class_get_generic_class (klass)->context.class_inst;
+       } else if (mono_class_is_gtd (klass) && context_used) {
+               container = mono_class_get_generic_container (klass);
+               ginst = container->context.class_inst;
+       } else {
+               return FALSE;
+       }
+
+       for (i = 0; i < container->type_argc; ++i) {
+               MonoType *type;
+               if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
+                       continue;
+               type = ginst->type_argv [i];
+               if (mini_type_is_reference (type))
+                       return TRUE;
+       }
+       return FALSE;
+}
+
 void*
 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
 {
index 239cdd38ebd3f904286268f91c53b52627de0e87..844b25c51a22aed15cd7a2b8fafed94656ec2593 100644 (file)
@@ -2642,6 +2642,22 @@ int               mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoB
                                                                         MonoInst *return_var, MonoInst **inline_args,
                                                                         guint inline_offset, gboolean is_virtual_call);
 
+//the following methods could just be renamed/moved from method-to-ir.c
+int               mini_inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, guchar *ip,
+                                                                         guint real_offset, gboolean inline_always);
+
+MonoInst*         mini_emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
+MonoInst*         mini_emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data);
+void              mini_save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check);
+void              mini_reset_cast_details (MonoCompile *cfg);
+void              mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass);
+
+MonoInst*         mini_emit_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src);
+MonoInst*         mini_emit_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src);
+
+gboolean          mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used);
+
+
 MonoInst         *mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins);
 void              mono_decompose_long_opts (MonoCompile *cfg);
 void              mono_decompose_vtype_opts (MonoCompile *cfg);
@@ -2653,6 +2669,8 @@ void              mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local
 void              mono_allocate_gsharedvt_vars (MonoCompile *cfg);
 void              mono_if_conversion (MonoCompile *cfg);
 
+
+
 /* Delegates */
 gpointer          mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr);
 void              mini_init_delegate (MonoDelegate *del);
diff --git a/mono/mini/type-checking.c b/mono/mini/type-checking.c
new file mode 100644 (file)
index 0000000..f9301ac
--- /dev/null
@@ -0,0 +1,847 @@
+#include <config.h>
+#include <mono/utils/mono-compiler.h>
+
+#ifndef DISABLE_JIT
+
+#include <mini.h>
+#include <ir-emit.h>
+#include <mono/metadata/abi-details.h>
+
+
+//XXX maybe move to mini.h / mini.c?
+
+static int
+mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
+{
+       if (cfg->gshared)
+               return mono_class_check_context_used (klass);
+       else
+               return 0;
+}
+
+
+#define is_complex_isinst(klass) (mono_class_is_interface (klass) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || mono_class_is_sealed (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
+
+static MonoInst*
+emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
+{
+       MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
+       return mono_emit_method_call (cfg, mono_isinst, args, NULL);
+}
+
+static int
+get_castclass_cache_idx (MonoCompile *cfg)
+{
+       /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
+       cfg->castclass_cache_index ++;
+       return (cfg->method_index << 16) | cfg->castclass_cache_index;
+}
+
+static MonoInst*
+emit_isinst_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
+{
+       MonoInst *args [3];
+       int idx;
+
+       args [0] = obj; /* obj */
+       EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
+
+       idx = get_castclass_cache_idx (cfg); /* inline cache*/
+       args [2] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
+
+       return emit_isinst_with_cache (cfg, klass, args);
+}
+
+static MonoInst*
+emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
+{
+       MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
+       MonoInst *res;
+
+       mini_save_cast_details (cfg, klass, args [0]->dreg, TRUE);
+       res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
+       mini_reset_cast_details (cfg);
+
+       return res;
+}
+
+static inline void
+mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
+{
+       if (klass_inst) {
+               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
+       } else {
+               MonoInst *ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
+               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
+       }
+       MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
+}
+
+
+static void
+mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
+{
+       int idepth_reg = alloc_preg (cfg);
+       int stypes_reg = alloc_preg (cfg);
+       int stype = alloc_preg (cfg);
+
+       mono_class_setup_supertypes (klass);
+
+       if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
+               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
+       }
+       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
+       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
+       if (klass_ins) {
+               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
+       } else if (cfg->compile_aot) {
+               int const_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
+               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
+       } else {
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
+       }
+       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
+}
+
+
+static void
+mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
+{
+       int ibitmap_reg = alloc_preg (cfg);
+#ifdef COMPRESSED_INTERFACE_BITMAP
+       MonoInst *args [2];
+       MonoInst *res, *ins;
+       NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
+       MONO_ADD_INS (cfg->cbb, ins);
+       args [0] = ins;
+       args [1] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
+       res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
+       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
+#else
+       int ibitmap_byte_reg = alloc_preg (cfg);
+
+       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
+
+       if (cfg->compile_aot) {
+               int iid_reg = alloc_preg (cfg);
+               int shifted_iid_reg = alloc_preg (cfg);
+               int ibitmap_byte_address_reg = alloc_preg (cfg);
+               int masked_iid_reg = alloc_preg (cfg);
+               int iid_one_bit_reg = alloc_preg (cfg);
+               int iid_bit_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
+               MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
+               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
+               MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
+               MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
+               MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
+       } else {
+               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
+       }
+#endif
+}
+
+/* 
+ * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
+ * stored in "klass_reg" implements the interface "klass".
+ */
+static void
+mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
+{
+       mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
+}
+
+/* 
+ * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
+ * stored in "vtable_reg" implements the interface "klass".
+ */
+static void
+mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
+{
+       mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
+}
+
+/* 
+ * Emit code which checks whenever the interface id of @klass is smaller than
+ * than the value given by max_iid_reg.
+*/
+static void
+mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
+                                                MonoBasicBlock *false_target)
+{
+       if (cfg->compile_aot) {
+               int iid_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
+               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
+       }
+       else
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
+       if (false_target)
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
+       else
+               MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
+}
+
+/* Same as above, but obtains max_iid from a vtable */
+static void
+mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
+                                                                MonoBasicBlock *false_target)
+{
+       int max_iid_reg = alloc_preg (cfg);
+               
+       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
+       mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
+}
+
+/* Same as above, but obtains max_iid from a klass */
+static void
+mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
+                                                                MonoBasicBlock *false_target)
+{
+       int max_iid_reg = alloc_preg (cfg);
+
+       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
+       mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
+}
+
+static inline void
+mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
+{
+       if (cfg->compile_aot) {
+               int const_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
+               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
+       } else {
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
+       }
+       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
+}
+
+
+static void
+mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
+{
+       mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
+}
+
+static void
+mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
+{
+       int intf_reg = alloc_preg (cfg);
+
+       mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
+       mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
+       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
+       if (true_target)
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
+       else
+               MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
+}
+
+/*
+ * Variant of the above that takes a register to the class, not the vtable.
+ */
+static void
+mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
+{
+       int intf_bit_reg = alloc_preg (cfg);
+
+       mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
+       mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
+       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
+       if (true_target)
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
+       else
+               MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
+}
+
+
+static void
+mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
+       
+static void
+mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
+{
+       if (klass->rank) {
+               int rank_reg = alloc_preg (cfg);
+               int eclass_reg = alloc_preg (cfg);
+
+               g_assert (!klass_inst);
+               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
+               MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
+               //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
+               if (klass->cast_class == mono_defaults.object_class) {
+                       int parent_reg = alloc_preg (cfg);
+                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
+                       mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
+                       mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
+               } else if (klass->cast_class == mono_defaults.enum_class->parent) {
+                       mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
+                       mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
+               } else if (klass->cast_class == mono_defaults.enum_class) {
+                       mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
+               } else if (mono_class_is_interface (klass->cast_class)) {
+                       mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
+               } else {
+                       // Pass -1 as obj_reg to skip the check below for arrays of arrays
+                       mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
+               }
+
+               if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
+                       /* Check that the object is a vector too */
+                       int bounds_reg = alloc_preg (cfg);
+                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
+                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
+                       MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
+               }
+       } else {
+               int idepth_reg = alloc_preg (cfg);
+               int stypes_reg = alloc_preg (cfg);
+               int stype = alloc_preg (cfg);
+
+               mono_class_setup_supertypes (klass);
+
+               if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
+                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
+                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
+                       MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
+               }
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
+               mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
+       }
+}
+
+static void
+mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
+{
+       mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
+}
+
+
+/*
+ * Returns NULL and set the cfg exception on error.
+ */
+static MonoInst*
+handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
+{
+       MonoBasicBlock *is_null_bb;
+       int obj_reg = src->dreg;
+       int vtable_reg = alloc_preg (cfg);
+       MonoInst *klass_inst = NULL;
+
+       if (MONO_INS_IS_PCONST_NULL (src))
+               return src;
+
+       if (context_used) {
+               MonoInst *args [3];
+
+               if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
+                       MonoInst *cache_ins;
+
+                       cache_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
+
+                       /* obj */
+                       args [0] = src;
+
+                       /* klass - it's the second element of the cache entry*/
+                       EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
+
+                       /* cache */
+                       args [2] = cache_ins;
+
+                       return emit_castclass_with_cache (cfg, klass, args);
+               }
+
+               klass_inst = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+       }
+
+       NEW_BBLOCK (cfg, is_null_bb);
+
+       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
+       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
+
+       mini_save_cast_details (cfg, klass, obj_reg, FALSE);
+
+       if (mono_class_is_interface (klass)) {
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
+               mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
+       } else {
+               int klass_reg = alloc_preg (cfg);
+
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
+
+               if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
+                       /* the remoting code is broken, access the class for now */
+                       if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
+                               MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
+                               if (!vt) {
+                                       mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
+                                       cfg->exception_ptr = klass;
+                                       return NULL;
+                               }
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
+                       } else {
+                               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
+                       }
+                       MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
+               } else {
+                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
+                       mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
+               }
+       }
+
+       MONO_START_BB (cfg, is_null_bb);
+
+       mini_reset_cast_details (cfg);
+
+       return src;
+}
+
+/*
+ * Returns NULL and set the cfg exception on error.
+ */
+static MonoInst*
+handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
+{
+       MonoInst *ins;
+       MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
+       int obj_reg = src->dreg;
+       int vtable_reg = alloc_preg (cfg);
+       int res_reg = alloc_ireg_ref (cfg);
+       MonoInst *klass_inst = NULL;
+
+       if (context_used) {
+               MonoInst *args [3];
+
+               if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
+                       MonoInst *cache_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
+
+                       args [0] = src; /* obj */
+
+                       /* klass - it's the second element of the cache entry*/
+                       EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
+
+                       args [2] = cache_ins; /* cache */
+                       return emit_isinst_with_cache (cfg, klass, args);
+               }
+
+               klass_inst = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+       }
+
+       NEW_BBLOCK (cfg, is_null_bb);
+       NEW_BBLOCK (cfg, false_bb);
+       NEW_BBLOCK (cfg, end_bb);
+
+       /* Do the assignment at the beginning, so the other assignment can be if converted */
+       EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
+       ins->type = STACK_OBJ;
+       ins->klass = klass;
+
+       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
+       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
+
+       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
+
+       if (mono_class_is_interface (klass)) {
+               g_assert (!context_used);
+               /* the is_null_bb target simply copies the input register to the output */
+               mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
+       } else {
+               int klass_reg = alloc_preg (cfg);
+
+               if (klass->rank) {
+                       int rank_reg = alloc_preg (cfg);
+                       int eclass_reg = alloc_preg (cfg);
+
+                       g_assert (!context_used);
+                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
+                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
+                       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
+                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
+                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
+                       if (klass->cast_class == mono_defaults.object_class) {
+                               int parent_reg = alloc_preg (cfg);
+                               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
+                               mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
+                               mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
+                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
+                       } else if (klass->cast_class == mono_defaults.enum_class->parent) {
+                               mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
+                               mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
+                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
+                       } else if (klass->cast_class == mono_defaults.enum_class) {
+                               mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
+                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
+                       } else if (mono_class_is_interface (klass->cast_class)) {
+                               mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
+                       } else {
+                               if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
+                                       /* Check that the object is a vector too */
+                                       int bounds_reg = alloc_preg (cfg);
+                                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
+                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
+                                       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
+                               }
+
+                               /* the is_null_bb target simply copies the input register to the output */
+                               mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
+                       }
+               } else if (mono_class_is_nullable (klass)) {
+                       g_assert (!context_used);
+                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
+                       /* the is_null_bb target simply copies the input register to the output */
+                       mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
+               } else {
+                       if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
+                               g_assert (!context_used);
+                               /* the remoting code is broken, access the class for now */
+                               if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
+                                       MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
+                                       if (!vt) {
+                                               mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
+                                               cfg->exception_ptr = klass;
+                                               return NULL;
+                                       }
+                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
+                               } else {
+                                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
+                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
+                               }
+                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
+                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
+                       } else {
+                               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
+                               /* the is_null_bb target simply copies the input register to the output */
+                               mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
+                       }
+               }
+       }
+
+       MONO_START_BB (cfg, false_bb);
+
+       MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
+       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+
+       MONO_START_BB (cfg, is_null_bb);
+
+       MONO_START_BB (cfg, end_bb);
+
+       return ins;
+}
+
+static MonoInst*
+emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
+{
+       MonoInst *args [3];
+       int idx;
+
+       /* obj */
+       args [0] = obj;
+
+       /* klass */
+       EMIT_NEW_CLASSCONST (cfg, args [1], klass);
+
+       /* inline cache*/
+       idx = get_castclass_cache_idx (cfg);
+       args [2] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
+
+       /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
+       return emit_castclass_with_cache (cfg, klass, args);
+}
+
+
+static void
+mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
+{
+       MonoInst *ret, *move, *source;
+       MonoClass *klass = ins->klass;
+       int context_used = mini_class_check_context_used (cfg, klass);
+       int is_isinst = ins->opcode == OP_ISINST;
+       g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
+       source = get_vreg_to_inst (cfg, ins->sreg1);
+       if (!source || source == (MonoInst *) -1)
+               source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
+       g_assert (source && source != (MonoInst *) -1);
+
+       MonoBasicBlock *first_bb;
+       NEW_BBLOCK (cfg, first_bb);
+       cfg->cbb = first_bb;
+
+       if (!context_used && (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || klass->is_array_special_interface)) {
+               if (is_isinst)
+                       ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
+               else
+                       ret = emit_castclass_with_cache_nonshared (cfg, source, klass);
+       } else if (!context_used && (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass))) {
+               MonoInst *iargs [1];
+               int costs;
+
+               iargs [0] = source;
+               if (is_isinst) {
+                       MonoMethod *wrapper = mono_marshal_get_isinst (klass);
+                       costs = mini_inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
+               } else {
+                       MonoMethod *wrapper = mono_marshal_get_castclass (klass);
+                       mini_save_cast_details (cfg, klass, source->dreg, TRUE);
+                       costs = mini_inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
+                       mini_reset_cast_details (cfg);
+               }
+               g_assert (costs > 0);
+               ret = iargs [0];
+       } else {
+               if (is_isinst)
+                       ret = handle_isinst (cfg, klass, source, context_used);
+               else
+                       ret = handle_castclass (cfg, klass, source, context_used);
+       }
+       EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
+
+       g_assert (cfg->cbb->code || first_bb->code);
+       MonoInst *prev = ins->prev;
+       mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
+}
+
+void
+mono_decompose_typechecks (MonoCompile *cfg)
+{
+       for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               MonoInst *ins;
+               MONO_BB_FOR_EACH_INS (bb, ins) {
+                       switch (ins->opcode) {
+                       case OP_ISINST:
+                       case OP_CASTCLASS:
+                               mono_decompose_typecheck (cfg, bb, ins);
+                               break;
+                       }
+               }
+       }
+}
+
+//Those two functions will go away as we get rid of CEE_MONO_CISINST and CEE_MONO_CCASTCLASS.
+MonoInst*
+mini_emit_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
+{
+       /* This opcode takes as input an object reference and a class, and returns:
+       0) if the object is an instance of the class,
+       1) if the object is not instance of the class,
+       2) if the object is a proxy whose type cannot be determined */
+
+       MonoInst *ins;
+#ifndef DISABLE_REMOTING
+       MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
+#else
+       MonoBasicBlock *true_bb, *false_bb, *end_bb;
+#endif
+       int obj_reg = src->dreg;
+       int dreg = alloc_ireg (cfg);
+       int tmp_reg;
+#ifndef DISABLE_REMOTING
+       int klass_reg = alloc_preg (cfg);
+#endif
+
+       NEW_BBLOCK (cfg, true_bb);
+       NEW_BBLOCK (cfg, false_bb);
+       NEW_BBLOCK (cfg, end_bb);
+#ifndef DISABLE_REMOTING
+       NEW_BBLOCK (cfg, false2_bb);
+       NEW_BBLOCK (cfg, no_proxy_bb);
+#endif
+
+       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
+       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
+
+       if (mono_class_is_interface (klass)) {
+#ifndef DISABLE_REMOTING
+               NEW_BBLOCK (cfg, interface_fail_bb);
+#endif
+
+               tmp_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
+#ifndef DISABLE_REMOTING
+               mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
+               MONO_START_BB (cfg, interface_fail_bb);
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
+               
+               mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
+
+               tmp_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
+#else
+               mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
+#endif
+       } else {
+#ifndef DISABLE_REMOTING
+               tmp_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
+
+               mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
+               tmp_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
+
+               tmp_reg = alloc_preg (cfg);             
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
+               
+               mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
+
+               MONO_START_BB (cfg, no_proxy_bb);
+
+               mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
+#else
+               g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
+#endif
+       }
+
+       MONO_START_BB (cfg, false_bb);
+
+       MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
+       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+
+#ifndef DISABLE_REMOTING
+       MONO_START_BB (cfg, false2_bb);
+
+       MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
+       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+#endif
+
+       MONO_START_BB (cfg, true_bb);
+
+       MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
+
+       MONO_START_BB (cfg, end_bb);
+
+       /* FIXME: */
+       MONO_INST_NEW (cfg, ins, OP_ICONST);
+       ins->dreg = dreg;
+       ins->type = STACK_I4;
+
+       return ins;
+}
+
+MonoInst*
+mini_emit_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
+{
+       /* This opcode takes as input an object reference and a class, and returns:
+       0) if the object is an instance of the class,
+       1) if the object is a proxy whose type cannot be determined
+       an InvalidCastException exception is thrown otherwhise*/
+       
+       MonoInst *ins;
+#ifndef DISABLE_REMOTING
+       MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
+#else
+       MonoBasicBlock *ok_result_bb;
+#endif
+       int obj_reg = src->dreg;
+       int dreg = alloc_ireg (cfg);
+       int tmp_reg = alloc_preg (cfg);
+
+#ifndef DISABLE_REMOTING
+       int klass_reg = alloc_preg (cfg);
+       NEW_BBLOCK (cfg, end_bb);
+#endif
+
+       NEW_BBLOCK (cfg, ok_result_bb);
+
+       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
+       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
+
+       mini_save_cast_details (cfg, klass, obj_reg, FALSE);
+
+       if (mono_class_is_interface (klass)) {
+#ifndef DISABLE_REMOTING
+               NEW_BBLOCK (cfg, interface_fail_bb);
+       
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
+               mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
+               MONO_START_BB (cfg, interface_fail_bb);
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
+
+               mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
+
+               tmp_reg = alloc_preg (cfg);             
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
+               MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
+               
+               MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+#else
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
+               mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
+#endif
+       } else {
+#ifndef DISABLE_REMOTING
+               NEW_BBLOCK (cfg, no_proxy_bb);
+
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
+               mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
+
+               tmp_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
+
+               tmp_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
+
+               NEW_BBLOCK (cfg, fail_1_bb);
+               
+               mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
+
+               MONO_START_BB (cfg, fail_1_bb);
+
+               MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+
+               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);
+       ins->dreg = dreg;
+       ins->type = STACK_I4;
+
+       return ins;
+}
+
+//API used by method-to-ir.c
+void
+mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
+{
+       mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
+}
+
+#endif
\ No newline at end of file