[corlib] Implement TypedReference:MakeTypedReference ().
authorZoltan Varga <vargaz@gmail.com>
Thu, 19 Mar 2015 08:18:10 +0000 (04:18 -0400)
committerZoltan Varga <vargaz@gmail.com>
Thu, 19 Mar 2015 08:18:10 +0000 (04:18 -0400)
mcs/class/corlib/System/TypedReference.cs
mcs/class/corlib/Test/System/TypedReferenceTest.cs
mono/metadata/icall-def.h
mono/metadata/icall.c

index 6e10c5c260e1a7c320912c2bd5f66cd69d783b78..bbdb2c41510c5a00144d5310ac26116303b31db3 100644 (file)
@@ -76,7 +76,8 @@ namespace System
                        if (flds.Length == 0) {
                                throw new ArgumentException (Locale.GetText ("flds has no elements"));
                        }
-                       throw new NotImplementedException ();
+
+                       return MakeTypedReferenceInternal (target, flds);
                }
 
                /* how can we set something in value if it's passed by value? */
@@ -97,5 +98,8 @@ namespace System
 
                [MethodImpl (MethodImplOptions.InternalCall)]
                public extern static object ToObject (TypedReference value);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static TypedReference MakeTypedReferenceInternal (object target, FieldInfo[] fields);
        }
 }
index c0df2197c2dfd20b7c058512ec12bd5b7d245f92..8ab04ac15cb8457ac9463b1ba47b6bed1978fcad 100644 (file)
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Reflection;
 using NUnit.Framework;
 
 namespace MonoTests.System
@@ -47,5 +48,21 @@ namespace MonoTests.System
                        TypedReference ti = __makeref(fields);
                        Assert.AreEqual (typeof (TestFields), TypedReference.GetTargetType (ti));
                }
+
+               struct AStruct {
+                       public int b;
+               }
+
+               class CClass {
+                       public AStruct a;
+               }
+
+               [Test]
+               public void MakeTypedReference ()
+               {
+                       var o = new CClass () { a = new AStruct () { b = 5 }};
+                       TypedReference r = TypedReference.MakeTypedReference (o, new FieldInfo[] { typeof (CClass).GetField ("a"), typeof (AStruct).GetField ("b") });
+                       Assert.AreEqual (5, TypedReference.ToObject (r));
+               }
        }
 }
index 6e665f1697392085549dd6b16bf055a46d039c37..44559ac929930a9cc903617ec9dc20f36fe908c1 100644 (file)
@@ -1016,8 +1016,9 @@ ICALL(TYPE_1, "internal_from_handle", ves_icall_type_from_handle)
 ICALL(TYPE_2, "internal_from_name", ves_icall_type_from_name)
 
 ICALL_TYPE(TYPEDR, "System.TypedReference", TYPEDR_1)
-ICALL(TYPEDR_1, "ToObject",    mono_TypedReference_ToObject)
-ICALL(TYPEDR_2, "ToObjectInternal",    mono_TypedReference_ToObjectInternal)
+ICALL(TYPEDR_1, "MakeTypedReferenceInternal", mono_TypedReference_MakeTypedReferenceInternal)
+ICALL(TYPEDR_2, "ToObject",    mono_TypedReference_ToObject)
+ICALL(TYPEDR_3, "ToObjectInternal",    mono_TypedReference_ToObjectInternal)
 
 ICALL_TYPE(VALUET, "System.ValueType", VALUET_1)
 ICALL(VALUET_1, "InternalEquals", ves_icall_System_ValueType_Equals)
index a7a725a8d32c35459d1a1124050853c295e09720..3d39b5aceddd31e262422b716cb832a814d43936 100644 (file)
@@ -6985,6 +6985,48 @@ mono_TypedReference_ToObjectInternal (MonoType *type, gpointer value, MonoClass
        return mono_value_box (mono_domain_get (), klass, value);
 }
 
+ICALL_EXPORT MonoTypedRef
+mono_TypedReference_MakeTypedReferenceInternal (MonoObject *target, MonoArray *fields)
+{
+       MonoTypedRef res;
+       MonoReflectionField *f;
+       MonoClass *klass;
+       MonoType *ftype;
+       guint8 *p;
+       int i;
+
+       memset (&res, 0, sizeof (res));
+
+       g_assert (fields);
+       g_assert (mono_array_length (fields) > 0);
+
+       klass = target->vtable->klass;
+
+       for (i = 0; i < mono_array_length (fields); ++i) {
+               f = mono_array_get (fields, MonoReflectionField*, i);
+               if (f == NULL) {
+                       mono_set_pending_exception (mono_get_exception_argument_null ("field"));
+                       return res;
+               }
+               if (f->field->parent != klass) {
+                       mono_set_pending_exception (mono_get_exception_argument ("field", ""));
+                       return res;
+               }
+               if (i == 0)
+                       p = (guint8*)target + f->field->offset;
+               else
+                       p += f->field->offset - sizeof (MonoObject);
+               klass = mono_class_from_mono_type (f->field->type);
+               ftype = f->field->type;
+       }
+
+       res.type = ftype;
+       res.klass = mono_class_from_mono_type (ftype);
+       res.value = p;
+
+       return res;
+}
+
 static void
 prelink_method (MonoMethod *method)
 {