[mini] Remove the need of the ininst wrapper for interfaces.
[mono.git] / mono / mini / type-checking.c
index 08be97e7151c8a70ea06cef1292c49199697c0f3..0fcd2f9679e85bf700d0c996b3017911cedce3bb 100644 (file)
@@ -357,8 +357,78 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context
        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);
+               int tmp_reg = alloc_preg (cfg);
+#ifndef DISABLE_REMOTING
+               MonoBasicBlock *interface_fail_bb;
+               int klass_reg = alloc_preg (cfg);
+
+               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, is_null_bb);
+
+               // iface bitmap check failed
+               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");
+
+               MonoInst *args [1] = { src };
+               MonoInst *proxy_test_inst = mono_emit_method_call (cfg, mono_marshal_get_proxy_cancast (klass), args, NULL);
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, proxy_test_inst->dreg, 0);
+               MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
+
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_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, is_null_bb);
+#endif
+       } else if (mono_class_is_marshalbyref (klass)) {
+#ifndef DISABLE_REMOTING
+               MonoBasicBlock *no_proxy_bb, *fail_1_bb;
+               int tmp_reg = alloc_preg (cfg);
+               int klass_reg = alloc_preg (cfg);
+
+               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, is_null_bb);
+
+               MONO_START_BB (cfg, fail_1_bb);
+
+               MonoInst *args [1] = { src };
+               MonoInst *proxy_test_inst = mono_emit_method_call (cfg, mono_marshal_get_proxy_cancast (klass), args, NULL);
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, proxy_test_inst->dreg, 0);
+               MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
+
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
+
+               MONO_START_BB (cfg, no_proxy_bb);
+
+               mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
+#else
+               g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
+#endif
        } else {
                int klass_reg = alloc_preg (cfg);
 
@@ -438,9 +508,37 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us
        MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
 
        if (mono_class_is_interface (klass)) {
-               g_assert (!context_used);
-               /* the is_null_bb target simply copies the input register to the output */
+               int tmp_reg, klass_reg;
+
+#ifndef DISABLE_REMOTING
+               MonoBasicBlock *interface_fail_bb, *call_proxy_isinst;
+
+               NEW_BBLOCK (cfg, interface_fail_bb);
+               NEW_BBLOCK (cfg, call_proxy_isinst);
+#endif
+
+#ifndef DISABLE_REMOTING
+               klass_reg = alloc_preg (cfg);
+               mini_emit_iface_cast (cfg, vtable_reg, klass, interface_fail_bb, is_null_bb);
+               MONO_START_BB (cfg, interface_fail_bb);
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_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_PBEQ, false_bb);
+
+               MONO_START_BB (cfg, call_proxy_isinst);
+
+               MonoInst *args [1] = { src };
+               MonoInst *proxy_test_inst = mono_emit_method_call (cfg, mono_marshal_get_proxy_cancast (klass), args, NULL);
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, proxy_test_inst->dreg, 0);
+               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_null_bb);
+#else
                mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
+#endif
        } else {
                int klass_reg = alloc_preg (cfg);
 
@@ -514,7 +612,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us
 
        MONO_START_BB (cfg, false_bb);
 
-       MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
+       MONO_EMIT_NEW_PCONST (cfg, res_reg, NULL);
        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
 
        MONO_START_BB (cfg, is_null_bb);
@@ -567,20 +665,13 @@ mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
                else
                        ret = emit_castclass_with_cache (cfg, klass, args);
 
-       } else if (!context_used && (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass))) {
+       } else if (!context_used && is_isinst && mono_class_is_marshalbyref (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);
-               }
+               MonoMethod *wrapper = mono_marshal_get_isinst (klass);
+               costs = mini_inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
                g_assert (costs > 0);
                ret = iargs [0];
        } else {
@@ -599,17 +690,22 @@ mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
 void
 mono_decompose_typechecks (MonoCompile *cfg)
 {
+       gboolean found_typetest = FALSE;
        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:
+                               found_typetest = TRUE;
                                mono_decompose_typecheck (cfg, bb, ins);
                                break;
                        }
                }
        }
+       if ((cfg->verbose_level > 2) && found_typetest)
+               mono_print_code (cfg, "AFTER DECOMPOSE TYPE_CHECKS");
+       
 }
 
 //Those two functions will go away as we get rid of CEE_MONO_CISINST and CEE_MONO_CCASTCLASS.
@@ -646,26 +742,7 @@ mini_emit_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
        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
+               g_error ("not supported");
        } else {
 #ifndef DISABLE_REMOTING
                tmp_reg = alloc_preg (cfg);
@@ -719,109 +796,6 @@ mini_emit_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
        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)