From b79c57efbfbec28f021453d0ca95ad3769a8336a Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Tue, 25 Jun 2024 05:07:59 +0800 Subject: [PATCH] Fix field accessor for RVA field (#103705) * Revert "Separate RVA reflection change out" This reverts commit 089ae127d131790998eac0ffbb815a9a6577f9e2. * Fix FieldAccessor getting RVA field * Disable test on NativeAot --- src/coreclr/vm/reflectioninvocation.cpp | 14 +++++---- .../src/System/Reflection/FieldAccessor.cs | 7 ++++- .../System.Reflection.Tests/FieldInfoTests.cs | 31 +++++++++++++++++++ 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/coreclr/vm/reflectioninvocation.cpp b/src/coreclr/vm/reflectioninvocation.cpp index a98dafd62a558..c89407275f81e 100644 --- a/src/coreclr/vm/reflectioninvocation.cpp +++ b/src/coreclr/vm/reflectioninvocation.cpp @@ -1246,14 +1246,16 @@ FCIMPL1(void*, RuntimeFieldHandle::GetStaticFieldAddress, ReflectFieldObject *pF // IsFastPathSupported needs to checked before calling this method. _ASSERTE(IsFastPathSupportedHelper(pFieldDesc)); - PTR_BYTE base = 0; - if (!pFieldDesc->IsRVA()) + if (pFieldDesc->IsRVA()) { - // For RVA the base is ignored and offset is used. - base = pFieldDesc->GetBase(); + Module* pModule = pFieldDesc->GetModule(); + return pModule->GetRvaField(pFieldDesc->GetOffset()); + } + else + { + PTR_BYTE base = pFieldDesc->GetBase(); + return PTR_VOID(base + pFieldDesc->GetOffset()); } - - return PTR_VOID(base + pFieldDesc->GetOffset()); } FCIMPLEND diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/FieldAccessor.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/FieldAccessor.cs index f8d9f6b1ba176..82e485fab51ff 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/FieldAccessor.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/FieldAccessor.cs @@ -48,7 +48,12 @@ private void Initialize() { _addressOrOffset = RuntimeFieldHandle.GetStaticFieldAddress(_fieldInfo); - if (fieldType.IsValueType) + if ((_fieldInfo.Attributes & FieldAttributes.HasFieldRVA) != 0) + { + _methodTable = (MethodTable*)fieldType.TypeHandle.Value; + _fieldAccessType = FieldAccessorType.StaticValueType; + } + else if (fieldType.IsValueType) { if (fieldType.IsEnum) { diff --git a/src/libraries/System.Runtime/tests/System.Reflection.Tests/FieldInfoTests.cs b/src/libraries/System.Runtime/tests/System.Reflection.Tests/FieldInfoTests.cs index d854e19c71ade..c3ff97fb34229 100644 --- a/src/libraries/System.Runtime/tests/System.Reflection.Tests/FieldInfoTests.cs +++ b/src/libraries/System.Runtime/tests/System.Reflection.Tests/FieldInfoTests.cs @@ -5,6 +5,8 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Xunit; #pragma warning disable 0414 @@ -121,6 +123,30 @@ public void GetValueWithFunctionPointers(Type type, string name, object obj, obj Assert.Equal(expected, fieldInfo.GetValue(obj)); } + // RVA field reflection is not supported in NativeAot + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNativeAot))] + public void GetValueFromRvaField() + { + byte[] valueArray = new byte[] { 1, 2, 3, 4, 5 }; + + // Roslyn uses SHA256 of raw data as data field name + FieldInfo fieldInfo = GetField( + typeof(FieldInfoTests).Assembly.GetType(""), + "74F81FE167D99B4CB41D6D0CCDA82278CAEE9F3E2F25D5E5A3936FF3DCEC60D0"); + Assert.NotNull(fieldInfo); + Assert.True(fieldInfo.IsStatic); + Assert.True((fieldInfo.Attributes & FieldAttributes.HasFieldRVA) != 0); + + for (int i = 0; i < 5; i++) + { + // FieldAccessor uses slow path until the class is initialized. + // Make sure subsequent invocations also succeed. + + object value = fieldInfo.GetValue(null); + Assert.Equal(valueArray, MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref value).Data, valueArray.Length)); + } + } + [Fact] public void GetAndSetValueTypeFromStatic() { @@ -839,5 +865,10 @@ public static class SettingsForMyTypeThatThrowsInClassInitializer { public static bool s_shouldThrow = true; } + + private class RawData + { + public byte Data; + } } }