From eda4e807158dc295e444eb967189b0748d68c7bc Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 25 Aug 2020 07:08:44 -0700 Subject: [PATCH] Reflection SetField fixes --- BeefLibs/corlib/src/Reflection/FieldInfo.bf | 53 ++++++++++++------- IDEHelper/Tests/src/Reflection.bf | 57 +++++++++++++++++++-- 2 files changed, 89 insertions(+), 21 deletions(-) diff --git a/BeefLibs/corlib/src/Reflection/FieldInfo.bf b/BeefLibs/corlib/src/Reflection/FieldInfo.bf index 9120a7e7..4da02322 100644 --- a/BeefLibs/corlib/src/Reflection/FieldInfo.bf +++ b/BeefLibs/corlib/src/Reflection/FieldInfo.bf @@ -46,25 +46,27 @@ namespace System.Reflection public Result SetValue(Object obj, Object value) { - int32 dataOffsetAdjust = 0; + void* dataAddr = ((uint8*)Internal.UnsafeCastToPtr(obj)); if (mTypeInstance.IsStruct) { Type boxedType = obj.[Friend]RawGetType(); bool typeMatched = false; if (boxedType.IsBoxed) - { - if (mTypeInstance == boxedType.UnderlyingType) - { - dataOffsetAdjust = boxedType.[Friend]mMemberDataOffset; - typeMatched = true; - } - } + { + if (mTypeInstance == boxedType.UnderlyingType) + { + dataAddr = (void*)((int)dataAddr + boxedType.[Friend]mMemberDataOffset); + if (boxedType.IsBoxedStructPtr) + dataAddr = *(void**)dataAddr; + typeMatched = true; + } + } if (!typeMatched) return .Err(.InvalidTargetType); // "Invalid target type"); } + dataAddr = (void*)((int)dataAddr + mFieldData.mData); Type fieldType = Type.[Friend]GetType(mFieldData.mFieldTypeId); - void* fieldDataAddr = ((uint8*)Internal.UnsafeCastToPtr(obj)) + (int)mFieldData.mData + dataOffsetAdjust; if (value == null) { @@ -74,13 +76,15 @@ namespace System.Reflection } else { - *((int*)fieldDataAddr) = 0; + *((int*)dataAddr) = 0; return .Ok; } } Type rawValueType = value.[Friend]RawGetType(); void* valueDataAddr = ((uint8*)Internal.UnsafeCastToPtr(value)) + rawValueType.[Friend]mMemberDataOffset; + if (rawValueType.IsBoxedStructPtr) + valueDataAddr = *(void**)valueDataAddr; Type valueType = value.GetType(); @@ -90,9 +94,9 @@ namespace System.Reflection if (valueType == fieldType) { if (valueType.IsObject) - *((void**)fieldDataAddr) = Internal.UnsafeCastToPtr(value); + *((void**)dataAddr) = Internal.UnsafeCastToPtr(value); else - Internal.MemCpy(fieldDataAddr, valueDataAddr, fieldType.[Friend]mSize); + Internal.MemCpy(dataAddr, valueDataAddr, fieldType.[Friend]mSize); } else { @@ -104,7 +108,7 @@ namespace System.Reflection public Result SetValue(Object obj, Variant value) { - int32 dataOffsetAdjust = 0; + void* dataAddr = ((uint8*)Internal.UnsafeCastToPtr(obj)); if (mTypeInstance.IsStruct) { Type boxedType = obj.[Friend]RawGetType(); @@ -113,20 +117,31 @@ namespace System.Reflection { if (mTypeInstance == boxedType.UnderlyingType) { - dataOffsetAdjust = boxedType.[Friend]mMemberDataOffset; + dataAddr = (void*)((int)dataAddr + boxedType.[Friend]mMemberDataOffset); + if (boxedType.IsBoxedStructPtr) + dataAddr = *(void**)dataAddr; typeMatched = true; } } if (!typeMatched) return .Err;//("Invalid target type"); } + dataAddr = (void*)((int)dataAddr + mFieldData.mData); Type fieldType = Type.[Friend]GetType(mFieldData.mFieldTypeId); - - void* dataAddr = ((uint8*)Internal.UnsafeCastToPtr(obj)) + (int)mFieldData.mData + dataOffsetAdjust; - if (value.VariantType != fieldType) - return .Err;//("Invalid type"); + let variantType = value.VariantType; + if (variantType != fieldType) + { + if ((variantType.IsPointer) && (variantType.UnderlyingType == fieldType)) + { + void* srcPtr = value.Get(); + Internal.MemCpy(dataAddr, srcPtr, fieldType.Size); + return .Ok; + } + else + return .Err;//("Invalid type"); + } value.CopyValueData(dataAddr); @@ -149,6 +164,8 @@ namespace System.Reflection /*if (type.IsStruct) return &value;*/ + if (type.IsBoxedStructPtr) + return *(void**)(((uint8*)Internal.UnsafeCastToPtr(value)) + type.[Friend]mMemberDataOffset); if (type.IsBoxed) return ((uint8*)Internal.UnsafeCastToPtr(value)) + type.[Friend]mMemberDataOffset; return ((uint8*)Internal.UnsafeCastToPtr(value)); diff --git a/IDEHelper/Tests/src/Reflection.bf b/IDEHelper/Tests/src/Reflection.bf index 432ed455..92333e68 100644 --- a/IDEHelper/Tests/src/Reflection.bf +++ b/IDEHelper/Tests/src/Reflection.bf @@ -125,11 +125,18 @@ namespace Tests } } + struct StructC + { + public float mA; + public float mB; + } + [Reflect, AlwaysInclude(AssumeInstantiated=true, IncludeAllMethods=true)] struct StructB { public int mA; public String mB; + public StructC mC; } class ClassA2 : ClassA @@ -485,20 +492,64 @@ namespace Tests StructB sb; sb.mA = 25; sb.mB = "Struct B"; + sb.mC = .() { mA = 1.2f, mB = 2.3f }; let type = sb.GetType() as TypeInstance; let fields = type.GetFields(); int fieldIdx = 0; for (let field in fields) { - let refP = field.GetValue(sb); + let fieldVal = field.GetValue(sb); + let fieldVal2 = field.GetValue(&sb); switch (fieldIdx) { case 0: - Test.Assert(refP.Value.Get() == 25); + Test.Assert(fieldVal.Value.Get() == 25); + Variant newVal = Variant.Create(32); + field.SetValue(sb, newVal); + Test.Assert(sb.mA == 25); + + Test.Assert(fieldVal2.Value.Get() == 25); + field.SetValue(&sb, newVal); + Test.Assert(sb.mA == 32); case 1: - Test.Assert(refP.Value.Get() === "Struct B"); + Test.Assert(fieldVal.Value.Get() === "Struct B"); + field.SetValue(&sb, "Struct C"); + Test.Assert(sb.mB == "Struct C"); case 2: + StructC sc = .() { mA = 1.2f, mB = 2.3f }; + Test.Assert(fieldVal.Value.Get() == sc); + Test.Assert(fieldVal2.Value.Get() == sc); + sc.mA += 100; + sc.mB += 100; + field.SetValue(&sb, sc); + Test.Assert(sb.mC.mA == 101.2f); + Test.Assert(sb.mC.mB == 102.3f); + sc.mA += 100; + sc.mB += 100; + field.SetValue(&sb, &sc); + Test.Assert(sb.mC.mA == 201.2f); + Test.Assert(sb.mC.mB == 202.3f); + sc.mA += 100; + sc.mB += 100; + Variant newVariant = Variant.Create(sc); + field.SetValue(&sb, newVariant); + Test.Assert(sb.mC.mA == 301.2f); + Test.Assert(sb.mC.mB == 302.3f); + sc.mA += 100; + sc.mB += 100; + newVariant.Dispose(); + newVariant = Variant.Create(&sc); + field.SetValue(&sb, newVariant); + Test.Assert(sb.mC.mA == 401.2f); + Test.Assert(sb.mC.mB == 402.3f); + sc.mA += 100; + sc.mB += 100; + newVariant = Variant.CreateReference(typeof(StructC), &sc); + field.SetValue(&sb, newVariant); + Test.Assert(sb.mC.mA == 501.2f); + Test.Assert(sb.mC.mB == 502.3f); + case 3: Test.FatalError(); } fieldIdx++;