[jit] Fix constrained calls from gsharedvt methods using an interface type to vtype...
authorZoltan Varga <vargaz@gmail.com>
Fri, 22 Sep 2017 22:44:10 +0000 (00:44 +0200)
committerGitHub <noreply@github.com>
Fri, 22 Sep 2017 22:44:10 +0000 (00:44 +0200)
mono/mini/gshared.cs
mono/mini/jit-icalls.c

index 6b5bc95f134ca449ac6306ed403d3ee321c920ef..75ea14aad6a91463ecc7f3ba0eb2769e97f7be1d 100644 (file)
@@ -1823,6 +1823,19 @@ public class Tests
                }
        }
 
+       struct StructTest : IFaceTest {
+
+               int i;
+
+               public StructTest (int arg) {
+                       i = arg;
+               }
+
+               public int iface_method () {
+                       return i;
+               }
+       }
+
        // Test constrained calls on an interface made from gsharedvt methods
        public static int test_42_gsharedvt_constrained_iface () {
                IFaceConstrainedIFace obj = new ConstrainedIFace ();
@@ -1830,6 +1843,12 @@ public class Tests
                return obj.foo<IFaceTest, int> (ref t);
        }
 
+       public static int test_42_gsharedvt_constrained_iface_vtype () {
+               IFaceConstrainedIFace obj = new ConstrainedIFace ();
+               IFaceTest t = new StructTest (42);
+               return obj.foo<IFaceTest, int> (ref t);
+       }
+
        // Sign extension tests
        // 0x55   == 85    == 01010101
        // 0xAA   == 170   == 10101010
index 56c7bc8169f76b54e7f1f01caa0e23471a01a259..fa3d7a4681971e74fafa19d297ab476de42c470d 100644 (file)
@@ -1328,12 +1328,15 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k
 {
        MonoMethod *m;
        int vt_slot, iface_offset;
+       gboolean is_iface = FALSE;
 
        error_init (error);
 
        if (mono_class_is_interface (klass)) {
                MonoObject *this_obj;
 
+               is_iface = TRUE;
+
                /* Have to use the receiver's type instead of klass, the receiver is a ref type */
                this_obj = *(MonoObject**)mp;
                g_assert (this_obj);
@@ -1359,21 +1362,33 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k
                        m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
        }
 
-       if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
+       if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class)) {
                /*
                 * Calling a non-vtype method with a vtype receiver, has to box.
                 */
                *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
-       else if (klass->valuetype)
-               /*
-                * Calling a vtype method with a vtype receiver
-                */
-               *this_arg = mp;
-       else
+       } else if (klass->valuetype) {
+               if (is_iface) {
+                       /*
+                        * The original type is an interface, so the receiver is a ref,
+                          the called method is a vtype method, need to unbox.
+                       */
+                       MonoObject *this_obj = *(MonoObject**)mp;
+
+                       *this_arg = mono_object_unbox (this_obj);
+               } else {
+                       /*
+                        * Calling a vtype method with a vtype receiver
+                        */
+                       *this_arg = mp;
+               }
+       } else {
                /*
                 * Calling a non-vtype method
                 */
                *this_arg = *(gpointer*)mp;
+       }
+
        return m;
 }