Add support for constrained gsharedvt calls to IComparable<T>.CompareTo ()/IEquatable...
authorZoltan Varga <vargaz@gmail.com>
Sun, 4 Aug 2013 07:18:49 +0000 (09:18 +0200)
committerZoltan Varga <vargaz@gmail.com>
Sun, 4 Aug 2013 07:18:49 +0000 (09:18 +0200)
mono/mini/gshared.cs
mono/mini/jit-icalls.c
mono/mini/jit-icalls.h
mono/mini/method-to-ir.c
mono/mini/mini.c

index b45afd85b6efd22463e760c088215fc531ae1bc9..ebbdbc26b2fa6807e14d203a3458ab4f25ce21ea 100644 (file)
@@ -1225,6 +1225,10 @@ public class Tests
                void foo_ref_arg (string s);
        }
 
+       interface IConstrained<T3> {
+               void foo_gsharedvt_arg (T3 s);
+       }
+
        static object constrained_res;
 
        struct ConsStruct : IConstrained {
@@ -1251,9 +1255,16 @@ public class Tests
                }
        }
 
+       struct ConsStruct<T> : IConstrained<T> {
+               public void foo_gsharedvt_arg (T s) {
+                       constrained_res = s;
+               }
+       }
+
        interface IFaceConstrained {
                void constrained_void_iface_call<T, T2>(T t, T2 t2) where T2 : IConstrained;
                void constrained_void_iface_call_ref_arg<T, T2>(T t, T2 t2) where T2 : IConstrained;
+               void constrained_void_iface_call_gsharedvt_arg<T, T2, T3>(T t, T2 t2, T3 t3) where T2 : IConstrained<T>;
        }
 
        class ClassConstrained : IFaceConstrained {
@@ -1266,6 +1277,11 @@ public class Tests
                public void constrained_void_iface_call_ref_arg<T, T2>(T t, T2 t2) where T2 : IConstrained {
                        t2.foo_ref_arg ("A");
                }
+
+               [MethodImplAttribute (MethodImplOptions.NoInlining)]
+               public void constrained_void_iface_call_gsharedvt_arg<T, T2, T3>(T t, T2 t2, T3 t3) where T2 : IConstrained<T> {
+                       t2.foo_gsharedvt_arg (t);
+               }
        }
 
        public static int test_0_constrained_void_iface_call () {
@@ -1291,6 +1307,25 @@ public class Tests
                return 0;
        }
 
+       public static int test_0_constraine_void_iface_call_gsharedvt_arg () {
+               // This tests constrained calls through interfaces with one gsharedvt arg, like IComparable<T>.CompareTo ()
+               IFaceConstrained c = new ClassConstrained ();
+
+               var s = new ConsStruct<int> ();
+               constrained_res = null;
+               c.constrained_void_iface_call_gsharedvt_arg<int, ConsStruct<int>, int> (42, s, 55);
+               if (!(constrained_res is int) || ((int)constrained_res) != 42)
+                       return 1;
+
+               var s2 = new ConsStruct<string> ();
+               constrained_res = null;
+               c.constrained_void_iface_call_gsharedvt_arg<string, ConsStruct<string>, int> ("A", s2, 55);
+               if (!(constrained_res is string) || ((string)constrained_res) != "A")
+                       return 2;
+
+               return 0;
+       }
+
        public static async Task<T> FooAsync<T> (int i, int j) {
                Task<int> t = new Task<int> (delegate () { return 42; });
                var response = await t;
index 06e5df4184fadb1b2d762e394a4b3972c2108764..85165aaf71cd145c1d9a8e96e1d45486029d21ac 100644 (file)
@@ -1164,6 +1164,9 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k
        MonoMethod *m;
        int vt_slot;
 
+       if (klass->flags & TYPE_ATTRIBUTE_INTERFACE)
+               mono_raise_exception (mono_get_exception_execution_engine ("Not yet supported."));
+
        /* Lookup the virtual method */
        mono_class_setup_vtable (klass);
        g_assert (klass->vtable);
@@ -1201,12 +1204,17 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k
  * the arguments to the method in the format used by mono_runtime_invoke ().
  */
 MonoObject*
-mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *args)
+mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
 {
        MonoMethod *m;
        gpointer this_arg;
+       gpointer new_args [16];
 
        m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
+       if (args && deref_arg) {
+               new_args [0] = *(gpointer*)args [0];
+               args = new_args;
+       }
        return mono_runtime_invoke (m, this_arg, args, NULL);
 }
 
index bf04ae68196db80eb8f94c2ed4bdf4743b221a23..dd99e7c763559c3834f0076a69fc2090930fcccf 100644 (file)
@@ -176,7 +176,7 @@ MonoObject*
 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache);
 
 MonoObject*
-mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *args) MONO_INTERNAL;
+mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args) MONO_INTERNAL;
 
 void mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass) MONO_INTERNAL;
 
index a8a0fd3d60480a3e18d55b0d190459b5345aeb83..167aa974dc2d1b6eceb432190e9f9a522d04e397 100644 (file)
@@ -7602,16 +7602,22 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                /* The 'Own method' case below */
                                        } else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) &&
                                                           (MONO_TYPE_IS_VOID (fsig->ret) || fsig->ret->type == MONO_TYPE_I4 || fsig->ret->type == MONO_TYPE_BOOLEAN || fsig->ret->type == MONO_TYPE_STRING) &&
-                                                          (fsig->param_count == 0 || (fsig->param_count == 1 && MONO_TYPE_IS_REFERENCE (fsig->params [0])))) {
+                                                          (fsig->param_count == 0 || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || mini_is_gsharedvt_type (cfg, fsig->params [0]))))) {
                                                MonoInst *args [16];
 
                                                /*
-                                                * This case handles calls to object:ToString()/Equals()/GetHashCode(), plus some simple interface calls enough to support
-                                                * AsyncTaskMethodBuilder.
+                                                * This case handles calls to
+                                                * - object:ToString()/Equals()/GetHashCode(),
+                                                * - System.IComparable<T>:CompareTo()
+                                                * - System.IEquatable<T>:Equals ()
+                                                * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
                                                 */
 
                                                args [0] = sp [0];
-                                               EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
+                                               if (mono_method_check_context_used (cmethod))
+                                                       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_call), constrained_call, MONO_RGCTX_INFO_KLASS);
 
                                                if (fsig->param_count) {
@@ -7620,11 +7626,23 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                        ins->dreg = alloc_preg (cfg);
                                                        ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
                                                        MONO_ADD_INS (cfg->cbb, ins);
-                                                       args [3] = ins;
+                                                       args [4] = ins;
+
+                                                       if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
+                                                               int addr_reg;
+
+                                                               args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
 
-                                                       EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [3]->dreg, 0, sp [1]->dreg);
+                                                               EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
+                                                               addr_reg = ins->dreg;
+                                                               EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
+                                                       } else {
+                                                               EMIT_NEW_ICONST (cfg, args [3], 0);
+                                                               EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
+                                                       }
                                                } else {
                                                        EMIT_NEW_ICONST (cfg, args [3], 0);
+                                                       EMIT_NEW_ICONST (cfg, args [4], 0);
                                                }
                                                ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
                                                emit_widen = FALSE;
index 4cc9e152323e63b4f43597de1b670084a6c934ee..e6e14311c2765296dd2cb278bacf32ee7489d3ac 100644 (file)
@@ -7266,7 +7266,7 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE);
        register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
        register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
-       register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr", TRUE);
+       register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", TRUE);
        register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
 
        register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);