Implement support for interface calls from gsharedvt methods.
authorZoltan Varga <vargaz@gmail.com>
Sun, 4 Nov 2012 00:55:10 +0000 (01:55 +0100)
committerZoltan Varga <vargaz@gmail.com>
Sun, 20 Jan 2013 12:02:18 +0000 (13:02 +0100)
mono/mini/gshared.cs
mono/mini/method-to-ir.c
mono/mini/mini-arm.c
mono/mini/mini-generic-sharing.c
mono/mini/mini-trampolines.c
mono/mini/mini-x86.c
mono/mini/mini.h

index c697a98619b7c9855526f6edec6abb641be71dbc..fd40b50132927d7a28d5212a06cbab6c2450e58f 100644 (file)
@@ -559,6 +559,10 @@ public class Tests
                return 0;
        }
 
+       public interface IFace<T> {
+               T return_t_iface (T t);
+       }
+
        public class Parent<T> {
                public virtual T return_t_vcall (T t) {
                        throw new Exception ();
@@ -566,10 +570,13 @@ public class Tests
                }
        }
 
-       public class Child<T> : Parent<T> {
+       public class Child<T> : Parent<T>, IFace<T> {
                public override T return_t_vcall (T t) {
                        return t;
                }
+               public T return_t_iface (T t) {
+                       return t;
+               }
        }
 
        [MethodImplAttribute (MethodImplOptions.NoInlining)]
@@ -590,6 +597,19 @@ public class Tests
                return 0;
        }
 
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       static T return_t_iface<T> (IFace<T> r, T t) {
+               return r.return_t_iface (t);
+       }
+
+       public static int test_0_iface_calls () {
+               if (return_t_iface (new Child<int> (), 2) != 2)
+                       return 1;
+               if (return_t_iface (new Child<double> (), 2.0) != 2.0)
+                       return 3;
+               return 0;
+       }
+
        static KeyValuePair<T1, T2> make_kvp<T1, T2> (T1 t1, T2 t2) {
                return new KeyValuePair<T1, T2> (t1, t2);
        }
index 9a6dd3c62333c3a7d31f5a2e0c29d1529dd12836..1a732eb025a8f96f5a4f4ac9bb4be904fbbd609e 100644 (file)
@@ -2182,7 +2182,7 @@ callvirt_to_call_membase (int opcode)
 
 #ifdef MONO_ARCH_HAVE_IMT
 static void
-emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
+emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
 {
        int method_reg;
 
@@ -2192,11 +2192,11 @@ emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
                if (imt_arg) {
                        MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
                } else if (cfg->compile_aot) {
-                       MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
+                       MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
                } else {
                        MonoInst *ins;
                        MONO_INST_NEW (cfg, ins, OP_PCONST);
-                       ins->inst_p0 = call->method;
+                       ins->inst_p0 = method;
                        ins->dreg = method_reg;
                        MONO_ADD_INS (cfg->cbb, ins);
                }
@@ -2219,11 +2219,11 @@ emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
        if (imt_arg) {
                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
        } else if (cfg->compile_aot) {
-               MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
+               MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
        } else {
                MonoInst *ins;
                MONO_INST_NEW (cfg, ins, OP_PCONST);
-               ins->inst_p0 = call->method;
+               ins->inst_p0 = method;
                ins->dreg = method_reg;
                MONO_ADD_INS (cfg->cbb, ins);
        }
@@ -2385,6 +2385,33 @@ mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, Mo
        return (MonoInst*)call;
 }
 
+/* This is like calli, but we pass rgctx/imt arguments as well */
+static MonoInst*
+emit_gsharedvt_call (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoMethod *method, MonoInst *imt_arg, MonoInst *rgctx_arg)
+{
+       MonoCallInst *call;
+       int rgctx_reg = -1;
+
+       if (rgctx_arg) {
+               rgctx_reg = mono_alloc_preg (cfg);
+               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
+       }
+
+       call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
+
+       call->inst.sreg1 = addr->dreg;
+
+       if (imt_arg)
+               emit_imt_argument (cfg, call, method, imt_arg);
+
+       MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
+
+       if (rgctx_arg)
+               set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
+
+       return (MonoInst*)call;
+}
+
 static MonoInst*
 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
 static MonoInst*
@@ -2518,7 +2545,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
 #ifdef MONO_ARCH_HAVE_IMT
                                if (mono_use_imt) {
                                        guint32 imt_slot = mono_method_get_imt_slot (method);
-                                       emit_imt_argument (cfg, call, imt_arg);
+                                       emit_imt_argument (cfg, call, call->method, imt_arg);
                                        slot_reg = vtable_reg;
                                        call->inst.inst_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
                                }
@@ -2535,7 +2562,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
 #ifdef MONO_ARCH_HAVE_IMT
                                if (imt_arg) {
                                        g_assert (mono_method_signature (method)->generic_param_count);
-                                       emit_imt_argument (cfg, call, imt_arg);
+                                       emit_imt_argument (cfg, call, call->method, imt_arg);
                                }
 #endif
                        }
@@ -7470,8 +7497,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoInst *addr;
 
                                if (virtual) {
-                                       if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
-                                               GSHAREDVT_FAILURE (*ip);
+                                       //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
+                                               //GSHAREDVT_FAILURE (*ip);
                                        // disable for possible remoting calls
                                        if (fsig->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))
                                                GSHAREDVT_FAILURE (*ip);
@@ -7488,7 +7515,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                else
                                        addr = emit_get_rgctx_method (cfg, context_used,
                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
-                               ins = mono_emit_calli (cfg, fsig, sp, addr, vtable_arg);
+                               ins = emit_gsharedvt_call (cfg, fsig, sp, addr, cmethod, imt_arg, vtable_arg);
 
                                if (!MONO_TYPE_IS_VOID (fsig->ret))
                                        *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
index ba27a5bdfaa27f005959bb2a12dfa677032952b5..b4490f923de15a00cb2d32c580216fd33f6d4a51 100644 (file)
@@ -6262,7 +6262,7 @@ mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
 }
 
 gpointer
-mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethod *normal_method, MonoMethod *gsharedvt_method, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gboolean virtual)
+mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethod *normal_method, MonoMethod *gsharedvt_method, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset)
 {
        NOT_IMPLEMENTED;
        return NULL;
index f100cb6b89beea77407a6a597941b027b8021548..9e093a2ed42e80696d9dcb9f9f223be12c9b6644 100644 (file)
@@ -973,6 +973,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
                gpointer addr;
                MonoJitInfo *ji;
                gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
+               gint32 vcall_offset;
 
                g_assert (method->is_inflated);
 
@@ -981,6 +982,22 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
                else
                        addr = NULL;
 
+               if (virtual) {
+                       /* Same as in mono_emit_method_call_full () */
+#ifndef MONO_ARCH_HAVE_IMT
+                       NOT_IMPLEMENTED;
+#endif
+                       if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                               guint32 imt_slot = mono_method_get_imt_slot (method);
+                               vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
+                       } else {
+                               vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
+                                       ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
+                       }
+               } else {
+                       vcall_offset = -1;
+               }
+
                /*
                 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
                 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
@@ -1011,7 +1028,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
 
                        mini_init_gsctx (context, &gsctx);
 
-                       info = mono_arch_get_gsharedvt_call_info (addr, method, gm, &gsctx, FALSE, virtual);
+                       info = mono_arch_get_gsharedvt_call_info (addr, method, gm, &gsctx, FALSE, vcall_offset);
 
                        if (!tramp_addr) {
                                wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
@@ -1050,7 +1067,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
                        // FIXME: This is just a workaround
                        if (caller_method == method) {
                        } else {
-                               info = mono_arch_get_gsharedvt_call_info (ji->code_start, method, ji->method, &gsctx, TRUE, FALSE);
+                               info = mono_arch_get_gsharedvt_call_info (ji->code_start, method, ji->method, &gsctx, TRUE, -1);
 
                                if (!tramp_addr) {
                                        wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
index f5af17d12609e20936d7e06a8a09392a02f60b81..4eb071cbbefca5fa32b6c8815c2e246ac600689c 100644 (file)
@@ -352,7 +352,7 @@ mini_add_method_trampoline (MonoMethod *orig_method, MonoMethod *m, gpointer com
                /* Call from normal/gshared code to gsharedvt code with variable signature */
                gsctx = mono_jit_info_get_generic_sharing_context (ji);
 
-               info = mono_arch_get_gsharedvt_call_info (compiled_method, m, ji->method, gsctx, TRUE, FALSE);
+               info = mono_arch_get_gsharedvt_call_info (compiled_method, m, ji->method, gsctx, TRUE, -1);
 
                if (!tramp_addr) {
                        wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
index 284cb0d809f65004dfe8ca14aa802e8f4dc9b489..43ef918c1a6011df571f93a4c679ad7c510398da 100644 (file)
@@ -6705,7 +6705,7 @@ mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
 }
 
 gpointer
-mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethod *normal_method, MonoMethod *gsharedvt_method, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gboolean virtual)
+mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethod *normal_method, MonoMethod *gsharedvt_method, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset)
 {
        NOT_IMPLEMENTED;
        return NULL;
index 4f4e4de3d6b403d76d72b22e65e344a8499cc6ea..aa5ea7879adb3e22927020c8f12589968c3cb79f 100644 (file)
@@ -2141,7 +2141,7 @@ GSList*   mono_arch_get_cie_program             (void) MONO_INTERNAL;
 void      mono_arch_set_target                  (char *mtriple) MONO_INTERNAL;
 gboolean  mono_arch_gsharedvt_sig_supported     (MonoMethodSignature *sig) MONO_INTERNAL;
 gpointer  mono_arch_get_gsharedvt_trampoline    (MonoTrampInfo **info, gboolean aot) MONO_INTERNAL;
-gpointer  mono_arch_get_gsharedvt_call_info     (gpointer addr, MonoMethod *m, MonoMethod *gsharedvt_method, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gboolean virtual) MONO_INTERNAL;
+gpointer  mono_arch_get_gsharedvt_call_info     (gpointer addr, MonoMethod *m, MonoMethod *gsharedvt_method, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset) MONO_INTERNAL;
 
 /* Soft Debug support */
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED