Merge pull request #4048 from kumpera/iface_casting_cleanup
authorRodrigo Kumpera <kumpera@users.noreply.github.com>
Thu, 1 Dec 2016 19:16:10 +0000 (11:16 -0800)
committerGitHub <noreply@github.com>
Thu, 1 Dec 2016 19:16:10 +0000 (11:16 -0800)
[mini] Reorg casting code + optimize casting of magic array interfaces.

1  2 
mono/mini/aot-compiler.c
mono/mini/aot-runtime.c
mono/mini/method-to-ir.c
mono/mini/mini.c
mono/mini/mini.h

diff --combined mono/mini/aot-compiler.c
index 32b0caa88025cf566aeca079c82a0f91973d17b7,cc8422f06f4205699984adaf1469b01811d0b072..91b9b1c52b7c6f040b1b89648e61b78ca91095ae
@@@ -3144,8 -3144,7 +3144,7 @@@ encode_method_ref (MonoAotCompile *acfg
                case MONO_WRAPPER_PROXY_ISINST:
                case MONO_WRAPPER_LDFLD:
                case MONO_WRAPPER_LDFLDA:
-               case MONO_WRAPPER_STFLD:
-               case MONO_WRAPPER_ISINST: {
+               case MONO_WRAPPER_STFLD: {
                        g_assert (info);
                        encode_klass_ref (acfg, info->d.proxy.klass, p, &p);
                        break;
@@@ -5847,7 -5846,6 +5846,7 @@@ encode_patch (MonoAotCompile *acfg, Mon
                break;
        case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
        case MONO_PATCH_INFO_GET_TLS_TRAMP:
 +      case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
                break;
        default:
                g_warning ("unable to handle jump info %d", patch_info->type);
@@@ -7273,7 -7271,6 +7272,6 @@@ can_encode_method (MonoAotCompile *acfg
                        case MONO_WRAPPER_LDFLD:
                        case MONO_WRAPPER_LDFLDA:
                        case MONO_WRAPPER_STELEMREF:
-                       case MONO_WRAPPER_ISINST:
                        case MONO_WRAPPER_PROXY_ISINST:
                        case MONO_WRAPPER_ALLOC:
                        case MONO_WRAPPER_REMOTING_INVOKE:
@@@ -7645,7 -7642,7 +7643,7 @@@ compile_method (MonoAotCompile *acfg, M
         * encountered.
         */
        depth = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_depth, method));
 -      if (!acfg->aot_opts.no_instances && depth < 32) {
 +      if (!acfg->aot_opts.no_instances && depth < 32 && mono_aot_mode_is_full (&acfg->aot_opts)) {
                for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                        switch (patch_info->type) {
                        case MONO_PATCH_INFO_RGCTX_FETCH:
  
                                if (!m)
                                        break;
 -                              if (m->is_inflated) {
 +                              if (m->is_inflated && mono_aot_mode_is_full (&acfg->aot_opts)) {
                                        if (!(mono_class_generic_sharing_enabled (m->klass) &&
                                                  mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE)) &&
                                                (!method_has_type_vars (m) || mono_method_is_generic_sharable_full (m, TRUE, TRUE, FALSE))) {
@@@ -9869,8 -9866,7 +9867,8 @@@ collect_methods (MonoAotCompile *acfg
                }
        }
  
 -      add_generic_instances (acfg);
 +      if (mono_aot_mode_is_full (&acfg->aot_opts))
 +              add_generic_instances (acfg);
  
        if (mono_aot_mode_is_full (&acfg->aot_opts))
                add_wrappers (acfg);
@@@ -9925,7 -9921,7 +9923,7 @@@ compile_methods (MonoAotCompile *acfg
                g_free (methods);
  
                for (i = 0; i < threads->len; ++i) {
 -                      mono_thread_info_wait_one_handle (g_ptr_array_index (threads, i), INFINITE, FALSE);
 +                      mono_thread_info_wait_one_handle (g_ptr_array_index (threads, i), MONO_INFINITE_WAIT, FALSE);
                        mono_threads_close_thread_handle (g_ptr_array_index (threads, i));
                }
        } else {
@@@ -10499,11 -10495,6 +10497,11 @@@ add_preinit_got_slots (MonoAotCompile *
        get_got_offset (acfg, FALSE, ji);
        get_got_offset (acfg, TRUE, ji);
  
 +      ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
 +      ji->type = MONO_PATCH_INFO_JIT_THREAD_ATTACH;
 +      get_got_offset (acfg, FALSE, ji);
 +      get_got_offset (acfg, TRUE, ji);
 +
        for (i = 0; i < sizeof (preinited_jit_icalls) / sizeof (char*); ++i) {
                ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
                ji->type = MONO_PATCH_INFO_INTERNAL_METHOD;
diff --combined mono/mini/aot-runtime.c
index 7d9a9114dbb2014c993cf961c7aa23a784b227fc,9be49e9773c35a95cdc40e06ecd8cc1041460cf6..d479dfeec89ac56a4dfa30de78b194b11a01dbf7
@@@ -903,8 -903,7 +903,7 @@@ decode_method_ref_with_target (MonoAotM
                }
                case MONO_WRAPPER_LDFLD:
                case MONO_WRAPPER_LDFLDA:
-               case MONO_WRAPPER_STFLD:
-               case MONO_WRAPPER_ISINST: {
+               case MONO_WRAPPER_STFLD: {
                        MonoClass *klass = decode_klass_ref (module, p, &p, error);
                        if (!klass)
                                return FALSE;
                                ref->method = mono_marshal_get_ldflda_wrapper (&klass->byval_arg);
                        else if (wrapper_type == MONO_WRAPPER_STFLD)
                                ref->method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
-                       else if (wrapper_type == MONO_WRAPPER_ISINST)
-                               ref->method = mono_marshal_get_isinst (klass);
                        else {
                                mono_error_set_bad_image_name (error, module->aot_name, "Unknown AOT wrapper type %d", wrapper_type);
                                return FALSE;
@@@ -3703,7 -3700,6 +3700,7 @@@ decode_patch (MonoAotModule *aot_module
        }
        case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
        case MONO_PATCH_INFO_GET_TLS_TRAMP:
 +      case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
                break;
        case MONO_PATCH_INFO_AOT_JIT_INFO:
                ji->data.index = decode_value (p, &p);
diff --combined mono/mini/method-to-ir.c
index 87a0974d0d62ea8ecff10fe43232a56e980cf247,cada92ac7bcf6004cf4acac6d2f9f1ec45ff8513..1b82009833f87b089f6dfc10c34c2c84a8579ed4
@@@ -156,7 -156,6 +156,7 @@@ emit_llvmonly_virtual_call (MonoCompil
  static MonoMethodSignature *helper_sig_domain_get;
  static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
  static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
 +static MonoMethodSignature *helper_sig_jit_thread_attach;
  
  /* type loading helpers */
  static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
@@@ -368,7 -367,6 +368,7 @@@ mono_create_helper_signatures (void
        helper_sig_domain_get = mono_create_icall_signature ("ptr");
        helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
        helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr");
 +      helper_sig_jit_thread_attach = mono_create_icall_signature ("ptr ptr");
  }
  
  static MONO_NEVER_INLINE void
@@@ -1574,267 -1572,10 +1574,10 @@@ emit_runtime_constant (MonoCompile *cfg
        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 
@@@ -2775,8 -2516,6 +2518,6 @@@ emit_get_gsharedvt_info_klass (MonoComp
  
  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,
@@@ -3399,7 -3138,7 +3140,7 @@@ mini_emit_stobj (MonoCompile *cfg, Mono
                        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)
@@@ -3501,8 -3240,8 +3242,8 @@@ emit_get_rgctx (MonoCompile *cfg, MonoM
  
        if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
                        !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
 -                      !method->klass->valuetype)
 -              EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
 +              !method->klass->valuetype)
 +              EMIT_NEW_VARLOAD (cfg, this_ins, cfg->this_arg, &mono_defaults.object_class->byval_arg);
  
        if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
                MonoInst *mrgctx_loc, *mrgctx_var;
@@@ -3679,12 -3418,12 +3420,12 @@@ emit_rgctx_fetch (MonoCompile *cfg, Mon
                return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
  }
  
static MonoInst*
- emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
+ MonoInst*
mini_emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
                                          MonoClass *klass, MonoRgctxInfoType rgctx_type)
  {
 -      MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_CLASS, klass, rgctx_type);
 -      MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 +      MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_CLASS, klass, rgctx_type);
 +      MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
  
        return emit_rgctx_fetch (cfg, rgctx, entry);
  }
@@@ -3693,8 -3432,8 +3434,8 @@@ static MonoInst
  emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
                                        MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
  {
 -      MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_SIGNATURE, sig, rgctx_type);
 -      MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 +      MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_SIGNATURE, sig, rgctx_type);
 +      MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
  
        return emit_rgctx_fetch (cfg, rgctx, entry);
  }
@@@ -3711,8 -3450,8 +3452,8 @@@ emit_get_rgctx_gsharedvt_call (MonoComp
        call_info->sig = sig;
        call_info->method = cmethod;
  
 -      entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_CALL, call_info, rgctx_type);
 -      rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 +      entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_CALL, call_info, rgctx_type);
 +      rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
  
        return emit_rgctx_fetch (cfg, rgctx, entry);
  }
@@@ -3734,8 -3473,8 +3475,8 @@@ emit_get_rgctx_virt_method (MonoCompil
        info->klass = klass;
        info->method = virt_method;
  
 -      entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_VIRT_METHOD, info, rgctx_type);
 -      rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 +      entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_VIRT_METHOD, info, rgctx_type);
 +      rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
  
        return emit_rgctx_fetch (cfg, rgctx, entry);
  }
@@@ -3747,8 -3486,8 +3488,8 @@@ emit_get_rgctx_gsharedvt_method (MonoCo
        MonoJumpInfoRgctxEntry *entry;
        MonoInst *rgctx;
  
 -      entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_METHOD, info, MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO);
 -      rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 +      entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_METHOD, info, MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO);
 +      rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
  
        return emit_rgctx_fetch (cfg, rgctx, entry);
  }
@@@ -3777,8 -3516,8 +3518,8 @@@ emit_get_rgctx_method (MonoCompile *cfg
                        g_assert_not_reached ();
                }
        } else {
 -              MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
 -              MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 +              MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
 +              MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
  
                return emit_rgctx_fetch (cfg, rgctx, entry);
        }
@@@ -3788,8 -3527,8 +3529,8 @@@ static MonoInst
  emit_get_rgctx_field (MonoCompile *cfg, int context_used,
                                          MonoClassField *field, MonoRgctxInfoType rgctx_type)
  {
 -      MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_FIELD, field, rgctx_type);
 -      MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 +      MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_FIELD, field, rgctx_type);
 +      MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
  
        return emit_rgctx_fetch (cfg, rgctx, entry);
  }
@@@ -3868,7 -3607,7 +3609,7 @@@ emit_class_init (MonoCompile *cfg, Mono
        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);
@@@ -3929,8 -3668,8 +3670,8 @@@ emit_seq_point (MonoCompile *cfg, MonoM
        }
  }
  
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);
                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);
        }
  }
  
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) {
@@@ -3999,7 -3738,7 +3740,7 @@@ mini_emit_check_array_type (MonoCompil
  
        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));
  
        } 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) {
        
        MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
  
-       reset_cast_details (cfg);
+       mini_reset_cast_details (cfg);
  }
  
  /**
@@@ -4059,7 -3798,7 +3800,7 @@@ handle_unbox_nullable (MonoCompile* cfg
                        cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
                        return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
                } else {
 -                      rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 +                      rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
  
                        return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
                }
@@@ -4111,15 -3850,15 +3852,15 @@@ handle_unbox (MonoCompile *cfg, MonoCla
                /* 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));
@@@ -4233,7 -3972,7 +3974,7 @@@ handle_alloc (MonoCompile *cfg, MonoCla
                        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]);
@@@ -4326,7 -4065,7 +4067,7 @@@ handle_box (MonoCompile *cfg, MonoInst 
                                   have to get the method address from the RGCTX. */
                                MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
                                                                                                                MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
 -                              MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 +                              MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
  
                                return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
                        }
        }
  }
  
- 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
@@@ -4500,493 -4211,6 +4213,6 @@@ method_needs_stack_walk (MonoCompile *c
        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)
  {
@@@ -5209,7 -4433,7 +4435,7 @@@ handle_constrained_gsharedvt_call (Mono
                        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) {
@@@ -5317,7 -4541,7 +4543,7 @@@ mono_method_check_inlining (MonoCompil
  
        if (cfg->disable_inline)
                return FALSE;
 -      if (cfg->gshared)
 +      if (cfg->gsharedvt)
                return FALSE;
  
        if (cfg->inline_depth > 10)
         * since it would mean inserting a call to mono_runtime_class_init()
         * inside the inlined code
         */
 +      if (cfg->gshared && method->klass->has_cctor && mini_class_check_context_used (cfg, method->klass))
 +              return FALSE;
 +
        if (!(cfg->opt & MONO_OPT_SHARED)) {
                /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
                if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
 -                      vtable = mono_class_vtable (cfg->domain, method->klass);
 -                      if (!vtable)
 -                              return FALSE;
 -                      if (!cfg->compile_aot) {
 -                              MonoError error;
 -                              if (!mono_runtime_class_init_full (vtable, &error)) {
 -                                      mono_error_cleanup (&error);
 +                      if (method->klass->has_cctor) {
 +                              vtable = mono_class_vtable (cfg->domain, method->klass);
 +                              if (!vtable)
                                        return FALSE;
 +                              if (!cfg->compile_aot) {
 +                                      MonoError error;
 +                                      if (!mono_runtime_class_init_full (vtable, &error)) {
 +                                              mono_error_cleanup (&error);
 +                                              return FALSE;
 +                                      }
                                }
                        }
                } else if (mono_class_is_before_field_init (method->klass)) {
@@@ -7090,6 -6309,12 +6316,12 @@@ emit_init_local (MonoCompile *cfg, int 
        }
  }
  
+ 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:
   *
@@@ -7221,7 -6446,7 +6453,7 @@@ inline_method (MonoCompile *cfg, MonoMe
        if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
                if (cfg->verbose_level > 2)
                        printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
 -              
 +
                cfg->stat_inlined_methods++;
  
                /* always add some code to avoid block split failures */
@@@ -8059,7 -7284,7 +7291,7 @@@ handle_ctor_call (MonoCompile *cfg, Mon
                                                                                                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);
@@@ -9605,7 -8830,7 +8837,7 @@@ mono_method_to_ir (MonoCompile *cfg, Mo
  
                        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);
  
                                 *
                                 *   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)) {
                                /* 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];
                        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:
                                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);
  
                                        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) {
  
                                        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) {
                                ip += 6;
                                break;
                        }
-                       case CEE_MONO_CISINST:
-                       case CEE_MONO_CCASTCLASS: {
-                               int token;
-                               CHECK_STACK (1);
-                               --sp;
-                               CHECK_OPSIZE (6);
-                               token = read32 (ip + 2);
-                               klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
-                               if (ip [1] == CEE_MONO_CISINST)
-                                       ins = handle_cisinst (cfg, klass, sp [0]);
-                               else
-                                       ins = handle_ccastclass (cfg, klass, sp [0]);
-                               *sp++ = ins;
-                               ip += 6;
-                               break;
-                       }
                        case CEE_MONO_SAVE_LMF:
                        case CEE_MONO_RESTORE_LMF:
                                ip += 2;
  
                                /* AOT code is only used in the root domain */
                                EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
 -                              ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
 +                              if (cfg->compile_aot) {
 +                                      MonoInst *addr;
 +
 +                                      /*
 +                                       * This is called on unattached threads, so it cannot go through the trampoline
 +                                       * infrastructure. Use an indirect call through a got slot initialized at load time
 +                                       * instead.
 +                                       */
 +                                      EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_JIT_THREAD_ATTACH, NULL);
 +                                      ins = mono_emit_calli (cfg, helper_sig_jit_thread_attach, args, addr, NULL, NULL);
 +                              } else {
 +                                      ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
 +                              }
                                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
  
                                if (next_bb)
                                        MONO_START_BB (cfg, next_bb);
  
 -
                                ip += 2;
                                break;
                        }
@@@ -15153,73 -14351,6 +14369,6 @@@ mono_spill_global_vars (MonoCompile *cf
        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:
diff --combined mono/mini/mini.c
index fa01d62cfe790eefc1e5a0edcafec2cb4dd2d041,30609c8352c15ad84590eceef122c472d462c3ba..0f26b72293a7e9548bd6c1dd720f2406f906f66c
@@@ -47,6 -47,7 +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>
@@@ -85,10 -86,6 +86,10 @@@ int mono_break_at_bb_bb_num
  gboolean mono_do_x86_stack_align = TRUE;
  gboolean mono_using_xdebug;
  
 +/* Counters */
 +static guint32 discarded_code;
 +static double discarded_jit_time;
 +
  #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
  #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
  static mono_mutex_t jit_mutex;
@@@ -2146,10 -2143,8 +2147,10 @@@ mono_compile_create_vars (MonoCompile *
  
        cfg->args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
  
 -      if (sig->hasthis)
 +      if (sig->hasthis) {
                cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
 +              cfg->this_arg = cfg->args [0];
 +      }
  
        for (i = 0; i < sig->param_count; ++i) {
                cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
@@@ -2419,10 -2414,13 +2420,10 @@@ mono_codegen (MonoCompile *cfg
   
        if (cfg->verbose_level > 0) {
                char* nm = mono_method_get_full_name (cfg->method);
 -              char *opt_descr = mono_opt_descr (cfg->opt);
 -              g_print ("Method %s emitted at %p to %p (code length %d) [%s] with opts %s\n", 
 +              g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n",
                                 nm, 
 -                               cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name,
 -                               opt_descr);
 +                               cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
                g_free (nm);
 -              g_free (opt_descr);
        }
  
        {
@@@ -2946,8 -2944,7 +2947,8 @@@ is_open_method (MonoMethod *method
        return FALSE;
  }
  
 -static void mono_insert_nop_in_empty_bb (MonoCompile *cfg)
 +static void
 +mono_insert_nop_in_empty_bb (MonoCompile *cfg)
  {
        MonoBasicBlock *bb;
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
@@@ -4037,6 -4034,34 +4038,34 @@@ mini_method_compile (MonoMethod *method
        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)
  {
@@@ -4261,9 -4286,7 +4290,9 @@@ mono_jit_compile_method_inner (MonoMeth
  
        jit_timer = mono_time_track_start ();
        cfg = mini_method_compile (method, opt, target_domain, JIT_FLAG_RUN_CCTORS, 0, -1);
 -      mono_time_track_end (&mono_jit_stats.jit_time, jit_timer);
 +      double jit_time = 0.0;
 +      mono_time_track_end (&jit_time, jit_timer);
 +      mono_jit_stats.jit_time += jit_time;
  
        prof_method = cfg->method;
  
                /* We can't use a domain specific method in another domain */
                if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
                        code = info->code_start;
 -//                    printf("Discarding code for method %s\n", method->name);
 +                      discarded_code ++;
 +                      discarded_jit_time += jit_time;
                }
        }
        if (code == NULL) {
@@@ -4452,9 -4474,6 +4481,9 @@@ mini_get_underlying_type (MonoType *typ
  void
  mini_jit_init (void)
  {
 +      mono_counters_register ("Discarded method code", MONO_COUNTER_JIT | MONO_COUNTER_INT, &discarded_code);
 +      mono_counters_register ("Time spent JITting discarded code", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &discarded_jit_time);
 +
        mono_os_mutex_init_recursive (&jit_mutex);
  #ifndef DISABLE_JIT
        current_backend = g_new0 (MonoBackend, 1);
diff --combined mono/mini/mini.h
index 66b87a1025cb1e30169eb1eec872f661ef25d7df,d272ed328581030c226c812eeac87fbc108c9c1e..b3eb72a0d3f0ec7cc9a843113eaf48695b7c40c3
  #endif
  
  /* Version number of the AOT file format */
 -#define MONO_AOT_FILE_VERSION 137
 +#define MONO_AOT_FILE_VERSION 138
  
  //TODO: This is x86/amd64 specific.
  #define mono_simd_shuffle_mask(a,b,c,d) ((a) | ((b) << 2) | ((c) << 4) | ((d) << 6))
@@@ -1193,14 -1193,6 +1193,14 @@@ typedef struct 
         * The calling assembly in llvmonly mode.
         */
        MonoImage *calling_image;
 +
 +      /*
 +       * The stack frame "high water mark" for ThreadAbortExceptions.
 +       * We will rethrow the exception upon exiting a catch clause that's
 +       * in a function stack frame above the water mark(isn't being called by
 +       * the catch block that caught the ThreadAbortException).
 +       */
 +      gpointer abort_exc_stack_threshold;
  } MonoJitTlsData;
  
  /*
@@@ -1593,7 -1585,6 +1593,7 @@@ typedef struct 
        MonoMethod      *current_method; /* The method currently processed by method_to_ir () */
        MonoMethod      *method_to_register; /* The method to register in JIT info tables */
        MonoGenericContext *generic_context;
 +      MonoInst        *this_arg;
  
        MonoBackend *backend;
  
@@@ -2651,6 -2642,19 +2651,19 @@@ int               mono_method_to_ir (Mo
                                                                         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);
+ 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);
@@@ -2662,6 -2666,8 +2675,8 @@@ void              mono_spill_global_var
  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);