From 3e350ac26e79c27a99c13e738b883ec09446eb34 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 3 Jun 2024 17:59:06 +0800 Subject: [PATCH] Go with CorElementType only --- .../src/System/Array.CoreCLR.cs | 290 +++++++++--------- .../Runtime/CompilerServices/CastHelpers.cs | 2 +- .../RuntimeHelpers.CoreCLR.cs | 101 +----- .../src/System/RuntimeHandles.cs | 7 +- .../classlibnative/bcltype/arraynative.cpp | 113 +++++++ .../classlibnative/bcltype/arraynative.h | 8 + src/coreclr/vm/comutilnative.cpp | 15 - src/coreclr/vm/comutilnative.h | 1 - src/coreclr/vm/ecalllist.h | 3 + src/coreclr/vm/qcall.h | 18 -- src/coreclr/vm/qcallentrypoints.cpp | 2 - src/coreclr/vm/reflectioninvocation.cpp | 27 +- src/coreclr/vm/runtimehandles.h | 1 - .../Runtime/CompilerServices/QCallHandles.cs | 21 -- .../CompilerServices/RuntimeHelpers.cs | 30 -- .../src/System/ThrowHelper.cs | 12 + 16 files changed, 295 insertions(+), 356 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs index 60a1eb628566a..4d793d17aba18 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs @@ -34,6 +34,7 @@ private static unsafe Array InternalCreateFromArrayType(RuntimeType arrayType, i fromArrayType: true, ObjectHandleOnStack.Create(ref retArray)); return retArray!; } + private static unsafe void CopyImpl(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length, bool reliable) { if (sourceArray == null) @@ -104,7 +105,7 @@ private static unsafe void CopySlow(Array sourceArray, int sourceIndex, Array de AssignArrayEnum r = CanAssignArrayType(srcTH, destTH); if (r == AssignArrayEnum.AssignWrongType) - throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType); + ThrowHelper.ThrowArrayTypeMismatchException_CantAssignType(); if (length > 0) { @@ -175,7 +176,7 @@ private static unsafe void CopyImplUnBoxEachElement(Array sourceArray, int sourc } else if (obj is null || RuntimeHelpers.GetMethodTable(obj) != pDestMT) { - throw new InvalidCastException(SR.InvalidCast_DownCastArrayElement); + ThrowHelper.ThrowInvalidCastException_DownCastArrayElement(); } else if (pDestMT->ContainsGCPointers) { @@ -248,152 +249,147 @@ private static unsafe void CopyImplPrimitiveWiden(Array sourceArray, int sourceI ref byte srcElement = ref Unsafe.Add(ref srcData, (nuint)i * srcElSize); ref byte destElement = ref Unsafe.Add(ref data, (nuint)i * destElSize); - PrimitiveWiden(ref srcElement, ref destElement, srcElType, destElType); - } - } + switch (srcElType) + { + case CorElementType.ELEMENT_TYPE_U1: + switch (destElType) + { + case CorElementType.ELEMENT_TYPE_CHAR: + case CorElementType.ELEMENT_TYPE_I2: + case CorElementType.ELEMENT_TYPE_U2: + Unsafe.As(ref destElement) = srcElement; break; + case CorElementType.ELEMENT_TYPE_I4: + case CorElementType.ELEMENT_TYPE_U4: + Unsafe.As(ref destElement) = srcElement; break; + case CorElementType.ELEMENT_TYPE_I8: + case CorElementType.ELEMENT_TYPE_U8: + Unsafe.As(ref destElement) = srcElement; break; + case CorElementType.ELEMENT_TYPE_R4: + Unsafe.As(ref destElement) = srcElement; break; + case CorElementType.ELEMENT_TYPE_R8: + Unsafe.As(ref destElement) = srcElement; break; + default: + Debug.Fail("Array.Copy from U1 to another type hit unsupported widening conversion"); break; + } + break; - private static void PrimitiveWiden(ref byte srcElement, ref byte destElement, CorElementType srcElType, CorElementType destElType) - { - switch (srcElType) - { - case CorElementType.ELEMENT_TYPE_U1: - switch (destElType) - { - case CorElementType.ELEMENT_TYPE_CHAR: - case CorElementType.ELEMENT_TYPE_I2: - case CorElementType.ELEMENT_TYPE_U2: - Unsafe.As(ref destElement) = srcElement; break; - case CorElementType.ELEMENT_TYPE_I4: - case CorElementType.ELEMENT_TYPE_U4: - Unsafe.As(ref destElement) = srcElement; break; - case CorElementType.ELEMENT_TYPE_I8: - case CorElementType.ELEMENT_TYPE_U8: - Unsafe.As(ref destElement) = srcElement; break; - case CorElementType.ELEMENT_TYPE_R4: - Unsafe.As(ref destElement) = srcElement; break; - case CorElementType.ELEMENT_TYPE_R8: - Unsafe.As(ref destElement) = srcElement; break; - default: - Debug.Fail("Array.Copy from U1 to another type hit unsupported widening conversion"); break; - } - break; - - case CorElementType.ELEMENT_TYPE_I1: - switch (destElType) - { - case CorElementType.ELEMENT_TYPE_I2: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_I4: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_I8: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_R4: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_R8: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - default: - Debug.Fail("Array.Copy from I1 to another type hit unsupported widening conversion"); break; - } - break; - - case CorElementType.ELEMENT_TYPE_U2: - case CorElementType.ELEMENT_TYPE_CHAR: - switch (destElType) - { - case CorElementType.ELEMENT_TYPE_U2: - case CorElementType.ELEMENT_TYPE_CHAR: - // U2 and CHAR are identical in conversion - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_I4: - case CorElementType.ELEMENT_TYPE_U4: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_I8: - case CorElementType.ELEMENT_TYPE_U8: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_R4: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_R8: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - default: - Debug.Fail("Array.Copy from U2 to another type hit unsupported widening conversion"); break; - } - break; - - case CorElementType.ELEMENT_TYPE_I2: - switch (destElType) - { - case CorElementType.ELEMENT_TYPE_I4: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_I8: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_R4: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_R8: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - default: - Debug.Fail("Array.Copy from I2 to another type hit unsupported widening conversion"); break; - } - break; - - case CorElementType.ELEMENT_TYPE_U4: - switch (destElType) - { - case CorElementType.ELEMENT_TYPE_I8: - case CorElementType.ELEMENT_TYPE_U8: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_R4: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_R8: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - default: - Debug.Fail("Array.Copy from U4 to another type hit unsupported widening conversion"); break; - } - break; - - case CorElementType.ELEMENT_TYPE_I4: - switch (destElType) - { - case CorElementType.ELEMENT_TYPE_I8: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_R4: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_R8: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - default: - Debug.Fail("Array.Copy from I4 to another type hit unsupported widening conversion"); break; - } - break; - - case CorElementType.ELEMENT_TYPE_U8: - switch (destElType) - { - case CorElementType.ELEMENT_TYPE_R4: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_R8: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - default: - Debug.Fail("Array.Copy from U8 to another type hit unsupported widening conversion"); break; - } - break; - - case CorElementType.ELEMENT_TYPE_I8: - switch (destElType) - { - case CorElementType.ELEMENT_TYPE_R4: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - case CorElementType.ELEMENT_TYPE_R8: - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - default: - Debug.Fail("Array.Copy from I8 to another type hit unsupported widening conversion"); break; - } - break; - - case CorElementType.ELEMENT_TYPE_R4: - Debug.Assert(destElType == CorElementType.ELEMENT_TYPE_R8); - Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; - - default: - Debug.Fail("Fell through outer switch in PrimitiveWiden! Unknown primitive type for source array!"); break; + case CorElementType.ELEMENT_TYPE_I1: + switch (destElType) + { + case CorElementType.ELEMENT_TYPE_I2: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_I4: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_I8: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_R4: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_R8: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + default: + Debug.Fail("Array.Copy from I1 to another type hit unsupported widening conversion"); break; + } + break; + + case CorElementType.ELEMENT_TYPE_U2: + case CorElementType.ELEMENT_TYPE_CHAR: + switch (destElType) + { + case CorElementType.ELEMENT_TYPE_U2: + case CorElementType.ELEMENT_TYPE_CHAR: + // U2 and CHAR are identical in conversion + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_I4: + case CorElementType.ELEMENT_TYPE_U4: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_I8: + case CorElementType.ELEMENT_TYPE_U8: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_R4: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_R8: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + default: + Debug.Fail("Array.Copy from U2 to another type hit unsupported widening conversion"); break; + } + break; + + case CorElementType.ELEMENT_TYPE_I2: + switch (destElType) + { + case CorElementType.ELEMENT_TYPE_I4: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_I8: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_R4: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_R8: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + default: + Debug.Fail("Array.Copy from I2 to another type hit unsupported widening conversion"); break; + } + break; + + case CorElementType.ELEMENT_TYPE_U4: + switch (destElType) + { + case CorElementType.ELEMENT_TYPE_I8: + case CorElementType.ELEMENT_TYPE_U8: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_R4: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_R8: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + default: + Debug.Fail("Array.Copy from U4 to another type hit unsupported widening conversion"); break; + } + break; + + case CorElementType.ELEMENT_TYPE_I4: + switch (destElType) + { + case CorElementType.ELEMENT_TYPE_I8: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_R4: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_R8: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + default: + Debug.Fail("Array.Copy from I4 to another type hit unsupported widening conversion"); break; + } + break; + + case CorElementType.ELEMENT_TYPE_U8: + switch (destElType) + { + case CorElementType.ELEMENT_TYPE_R4: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_R8: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + default: + Debug.Fail("Array.Copy from U8 to another type hit unsupported widening conversion"); break; + } + break; + + case CorElementType.ELEMENT_TYPE_I8: + switch (destElType) + { + case CorElementType.ELEMENT_TYPE_R4: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + case CorElementType.ELEMENT_TYPE_R8: + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + default: + Debug.Fail("Array.Copy from I8 to another type hit unsupported widening conversion"); break; + } + break; + + case CorElementType.ELEMENT_TYPE_R4: + Debug.Assert(destElType == CorElementType.ELEMENT_TYPE_R8); + Unsafe.As(ref destElement) = Unsafe.As(ref srcElement); break; + + default: + Debug.Fail("Fell through outer switch in PrimitiveWiden! Unknown primitive type for source array!"); break; + } } } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs index 14c8a959cda5b..0c640dd1c2f0a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs @@ -29,7 +29,7 @@ internal static unsafe class CastHelpers // Unlike the IsInstanceOfInterface and IsInstanceOfClass functions, // this test must deal with all kinds of type tests [DebuggerHidden] - internal static object? IsInstanceOfAny(void* toTypeHnd, object? obj) + private static object? IsInstanceOfAny(void* toTypeHnd, object? obj) { if (obj != null) { diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs index 51c60b74f4168..a8cbf2ae7969a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs @@ -1,115 +1,28 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Buffers.Binary; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; +using System.Threading; namespace System.Runtime.CompilerServices { public static partial class RuntimeHelpers { [Intrinsic] - public static unsafe void InitializeArray(Array array, RuntimeFieldHandle fldHandle) - { - IRuntimeFieldInfo fldInfo = fldHandle.GetRuntimeFieldInfo(); - - if (array is null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - - if ((RuntimeFieldHandle.GetAttributes(fldInfo.Value) & FieldAttributes.HasFieldRVA) == 0) - throw new ArgumentException(SR.Argument_BadFieldForInitializeArray); - - // Note that we do not check that the field is actually in the PE file that is initializing - // the array. Basically the data being published is can be accessed by anyone with the proper - // permissions (C# marks these as assembly visibility, and thus are protected from outside - // snooping) - - if (!array.GetCorElementTypeOfElementType().IsPrimitiveType()) // Enum is included - throw new ArgumentException(SR.Argument_MustBePrimitiveArray); - - MethodTable* pMT = GetMethodTable(array); - nuint totalSize = pMT->ComponentSize * array.NativeLength; - - uint size = RuntimeFieldHandle.GetFieldSize(new QCallFieldHandle(ref fldInfo)); - - // make certain you don't go off the end of the rva static - if (totalSize > size) - throw new ArgumentException(SR.Argument_BadFieldForInitializeArray); - - void* src = (void*)RuntimeFieldHandle.GetStaticFieldAddress(fldInfo); - ref byte dst = ref MemoryMarshal.GetArrayDataReference(array); - - Debug.Assert(!pMT->GetArrayElementTypeHandle().AsMethodTable()->ContainsGCPointers); - - if (BitConverter.IsLittleEndian) - { - SpanHelpers.Memmove(ref dst, ref *(byte*)src, totalSize); - } - else - { - switch (pMT->ComponentSize) - { - case 1: - SpanHelpers.Memmove(ref dst, ref *(byte*)src, totalSize); - break; - case 2: - BinaryPrimitives.ReverseEndianness( - new ReadOnlySpan(src, array.Length), - new Span(ref Unsafe.As(ref dst), array.Length)); - break; - case 4: - BinaryPrimitives.ReverseEndianness( - new ReadOnlySpan(src, array.Length), - new Span(ref Unsafe.As(ref dst), array.Length)); - break; - case 8: - BinaryPrimitives.ReverseEndianness( - new ReadOnlySpan(src, array.Length), - new Span(ref Unsafe.As(ref dst), array.Length)); - break; - default: - Debug.Fail("Incorrect primitive type size!"); - break; - } - } - } + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern void InitializeArray(Array array, RuntimeFieldHandle fldHandle); - private static unsafe void* GetSpanDataFrom( + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern unsafe void* GetSpanDataFrom( RuntimeFieldHandle fldHandle, RuntimeTypeHandle targetTypeHandle, - out int count) - { - IRuntimeFieldInfo fldInfo = fldHandle.GetRuntimeFieldInfo(); - - if ((RuntimeFieldHandle.GetAttributes(fldInfo.Value) & FieldAttributes.HasFieldRVA) == 0) - throw new ArgumentException(SR.Argument_BadFieldForInitializeArray); - - TypeHandle th = new TypeHandle((void*)targetTypeHandle.Value); - Debug.Assert(!th.IsTypeDesc); // TypeDesc can't be used as generic parameter - - if (!th.GetVerifierCorElementType().IsPrimitiveType()) // Enum is included - throw new ArgumentException(SR.Argument_MustBePrimitiveArray); - - uint totalSize = RuntimeFieldHandle.GetFieldSize(new QCallFieldHandle(ref fldInfo)); - uint targetTypeSize = th.AsMethodTable()->GetNumInstanceFieldBytes(); - - IntPtr data = RuntimeFieldHandle.GetStaticFieldAddress(fldInfo); - if (data % targetTypeSize != 0) - throw new ArgumentException(SR.Argument_BadFieldForInitializeArray); - - if (!BitConverter.IsLittleEndian) - { - throw new PlatformNotSupportedException(); - } - - count = (int)(totalSize / targetTypeSize); - return (void*)data; - } + out int count); // GetObjectValue is intended to allow value classes to be manipulated as 'Object' // but have aliasing behavior of a value class. The intent is that you would use diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 472f4f6318a3d..380981993451e 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -1085,7 +1085,7 @@ public RuntimeFieldInfoStub(RuntimeFieldHandleInternal fieldHandle, object keepa } [NonVersionable] - public unsafe partial struct RuntimeFieldHandle : IEquatable, ISerializable + public unsafe struct RuntimeFieldHandle : IEquatable, ISerializable { // Returns handle for interop with EE. The handle is guaranteed to be non-null. internal RuntimeFieldHandle GetNativeHandle() @@ -1187,10 +1187,7 @@ internal static RuntimeType GetApproxDeclaringType(IRuntimeFieldInfo field) internal static extern int GetInstanceFieldOffset(RtFieldInfo field); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern IntPtr GetStaticFieldAddress(IRuntimeFieldInfo field); - - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeFieldHandle_GetFieldSize")] - internal static partial uint GetFieldSize(QCallFieldHandle field); + internal static extern IntPtr GetStaticFieldAddress(RtFieldInfo field); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern int GetToken(RtFieldInfo field); diff --git a/src/coreclr/classlibnative/bcltype/arraynative.cpp b/src/coreclr/classlibnative/bcltype/arraynative.cpp index 2e4f61e934f24..a4b458b8ef571 100644 --- a/src/coreclr/classlibnative/bcltype/arraynative.cpp +++ b/src/coreclr/classlibnative/bcltype/arraynative.cpp @@ -441,3 +441,116 @@ FCIMPL3(void, ArrayNative::SetValue, ArrayBase* refThisUNSAFE, Object* objUNSAFE } } FCIMPLEND + +// This method will initialize an array from a TypeHandle to a field. + +FCIMPL2_IV(void, ArrayNative::InitializeArray, ArrayBase* pArrayRef, FCALLRuntimeFieldHandle structField) +{ + FCALL_CONTRACT; + + BASEARRAYREF arr = BASEARRAYREF(pArrayRef); + REFLECTFIELDREF refField = (REFLECTFIELDREF)ObjectToOBJECTREF(FCALL_RFH_TO_REFLECTFIELD(structField)); + HELPER_METHOD_FRAME_BEGIN_2(arr, refField); + + if ((arr == 0) || (refField == NULL)) + COMPlusThrow(kArgumentNullException); + + FieldDesc* pField = (FieldDesc*) refField->GetField(); + + if (!pField->IsRVA()) + COMPlusThrow(kArgumentException); + + // Note that we do not check that the field is actually in the PE file that is initializing + // the array. Basically the data being published is can be accessed by anyone with the proper + // permissions (C# marks these as assembly visibility, and thus are protected from outside + // snooping) + + if (!CorTypeInfo::IsPrimitiveType(arr->GetArrayElementType()) && !arr->GetArrayElementTypeHandle().IsEnum()) + COMPlusThrow(kArgumentException); + + SIZE_T dwCompSize = arr->GetComponentSize(); + SIZE_T dwElemCnt = arr->GetNumComponents(); + SIZE_T dwTotalSize = dwCompSize * dwElemCnt; + + DWORD size = pField->LoadSize(); + + // make certain you don't go off the end of the rva static + if (dwTotalSize > size) + COMPlusThrow(kArgumentException); + + void *src = pField->GetStaticAddressHandle(NULL); + void *dest = arr->GetDataPtr(); + +#if BIGENDIAN + DWORD i; + switch (dwCompSize) { + case 1: + memcpyNoGCRefs(dest, src, dwElemCnt); + break; + case 2: + for (i = 0; i < dwElemCnt; i++) + *((UINT16*)dest + i) = GET_UNALIGNED_VAL16((UINT16*)src + i); + break; + case 4: + for (i = 0; i < dwElemCnt; i++) + *((UINT32*)dest + i) = GET_UNALIGNED_VAL32((UINT32*)src + i); + break; + case 8: + for (i = 0; i < dwElemCnt; i++) + *((UINT64*)dest + i) = GET_UNALIGNED_VAL64((UINT64*)src + i); + break; + default: + // should not reach here. + UNREACHABLE_MSG("Incorrect primitive type size!"); + break; + } +#else + memcpyNoGCRefs(dest, src, dwTotalSize); +#endif + + HELPER_METHOD_FRAME_END(); +} +FCIMPLEND + +FCIMPL3_VVI(void*, ArrayNative::GetSpanDataFrom, FCALLRuntimeFieldHandle structField, FCALLRuntimeTypeHandle targetTypeUnsafe, INT32* count) +{ + FCALL_CONTRACT; + struct + { + REFLECTFIELDREF refField; + REFLECTCLASSBASEREF refClass; + } gc; + gc.refField = (REFLECTFIELDREF)ObjectToOBJECTREF(FCALL_RFH_TO_REFLECTFIELD(structField)); + gc.refClass = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(FCALL_RTH_TO_REFLECTCLASS(targetTypeUnsafe)); + void* data = NULL; + HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); + + FieldDesc* pField = (FieldDesc*)gc.refField->GetField(); + + if (!pField->IsRVA()) + COMPlusThrow(kArgumentException); + + TypeHandle targetTypeHandle = gc.refClass->GetType(); + if (!CorTypeInfo::IsPrimitiveType(targetTypeHandle.GetSignatureCorElementType()) && !targetTypeHandle.IsEnum()) + COMPlusThrow(kArgumentException); + + DWORD totalSize = pField->LoadSize(); + DWORD targetTypeSize = targetTypeHandle.GetSize(); + + data = pField->GetStaticAddressHandle(NULL); + _ASSERTE(data != NULL); + _ASSERTE(count != NULL); + + if (AlignUp((UINT_PTR)data, targetTypeSize) != (UINT_PTR)data) + COMPlusThrow(kArgumentException); + + *count = (INT32)totalSize / targetTypeSize; + +#if BIGENDIAN + COMPlusThrow(kPlatformNotSupportedException); +#endif + + HELPER_METHOD_FRAME_END(); + return data; +} +FCIMPLEND diff --git a/src/coreclr/classlibnative/bcltype/arraynative.h b/src/coreclr/classlibnative/bcltype/arraynative.h index 15fd5c3daea51..508cd776ddff7 100644 --- a/src/coreclr/classlibnative/bcltype/arraynative.h +++ b/src/coreclr/classlibnative/bcltype/arraynative.h @@ -30,6 +30,14 @@ class ArrayNative // This set of methods will set a value in an array static FCDECL3(void, SetValue, ArrayBase* refThisUNSAFE, Object* objUNSAFE, INT_PTR flattenedIndex); + + // This method will initialize an array from a TypeHandle + // to a field. + static FCDECL2_IV(void, InitializeArray, ArrayBase* vArrayRef, FCALLRuntimeFieldHandle structField); + + // This method will acquire data to create a span from a TypeHandle + // to a field. + static FCDECL3_VVI(void*, GetSpanDataFrom, FCALLRuntimeFieldHandle structField, FCALLRuntimeTypeHandle targetTypeUnsafe, INT32* count); }; extern "C" void QCALLTYPE Array_CreateInstance(QCall::TypeHandle pTypeHnd, INT32 rank, INT32* pLengths, INT32* pBounds, BOOL createFromArrayType, QCall::ObjectHandleOnStack retArray); diff --git a/src/coreclr/vm/comutilnative.cpp b/src/coreclr/vm/comutilnative.cpp index 1823ffa2c07ac..b569143bbaa51 100644 --- a/src/coreclr/vm/comutilnative.cpp +++ b/src/coreclr/vm/comutilnative.cpp @@ -1809,21 +1809,6 @@ extern "C" BOOL QCALLTYPE MethodTable_AreTypesEquivalent(MethodTable* mta, Metho return bResult; } -extern "C" BOOL QCALLTYPE TypeHandle_CanCastTo(void* fromTypeHnd, void* toTypeHnd) -{ - QCALL_CONTRACT; - - BOOL ret = false; - - BEGIN_QCALL; - - ret = TypeHandle::FromPtr(fromTypeHnd).CanCastTo(TypeHandle::FromPtr(toTypeHnd)); - - END_QCALL; - - return ret; -} - static MethodTable * g_pStreamMT; static WORD g_slotBeginRead, g_slotEndRead; static WORD g_slotBeginWrite, g_slotEndWrite; diff --git a/src/coreclr/vm/comutilnative.h b/src/coreclr/vm/comutilnative.h index fb1038d7f3f5d..74f0c7967e745 100644 --- a/src/coreclr/vm/comutilnative.h +++ b/src/coreclr/vm/comutilnative.h @@ -249,7 +249,6 @@ class MethodTableNative { extern "C" BOOL QCALLTYPE MethodTable_AreTypesEquivalent(MethodTable* mta, MethodTable* mtb); extern "C" BOOL QCALLTYPE MethodTable_CanCompareBitsOrUseFastGetHashCode(MethodTable* mt); -extern "C" BOOL QCALLTYPE TypeHandle_CanCastTo(void* fromTypeHnd, void* toTypeHnd); extern "C" INT32 QCALLTYPE ValueType_GetHashCodeStrategy(MethodTable* mt, QCall::ObjectHandleOnStack objHandle, UINT32* fieldOffset, UINT32* fieldSize, MethodTable** fieldMT); class StreamNative { diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index e17df7c465b9d..7d7681894bef7 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -439,6 +439,8 @@ FCFuncStart(gMonitorFuncs) FCFuncEnd() FCFuncStart(gRuntimeHelpers) + FCFuncElement("InitializeArray", ArrayNative::InitializeArray) + FCFuncElement("GetSpanDataFrom", ArrayNative::GetSpanDataFrom) FCFuncElement("PrepareDelegate", ReflectionInvocation::PrepareDelegate) FCFuncElement("GetHashCode", ObjectNative::GetHashCode) FCFuncElement("TryGetHashCode", ObjectNative::TryGetHashCode) @@ -536,6 +538,7 @@ FCFuncEnd() // Note these have to remain sorted by name:namespace pair (Assert will wack you if you don't) // The sorting is case-sensitive +FCClassElement("Array", "System", gArrayFuncs) FCClassElement("AssemblyLoadContext", "System.Runtime.Loader", gAssemblyLoadContextFuncs) FCClassElement("Buffer", "System", gBufferFuncs) FCClassElement("CastHelpers", "System.Runtime.CompilerServices", gCastHelpers) diff --git a/src/coreclr/vm/qcall.h b/src/coreclr/vm/qcall.h index b63d2ffa7beac..e3154c7b1334c 100644 --- a/src/coreclr/vm/qcall.h +++ b/src/coreclr/vm/qcall.h @@ -293,24 +293,6 @@ class QCall } }; - struct FieldHandle - { - Object ** m_ppObject; - FieldDesc * m_pField; - - operator FieldDesc * () - { - LIMITED_METHOD_CONTRACT; - return m_pField; - } - - FieldDesc * operator -> () - { - LIMITED_METHOD_CONTRACT; - return m_pField; - } - }; - struct LoaderAllocatorHandle { LoaderAllocator * m_pLoaderAllocator; diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 084e6df167aca..e038db62831d9 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -103,7 +103,6 @@ static const Entry s_QCall[] = DllImportEntry(QCall_FreeGCHandleForTypeHandle) DllImportEntry(MethodTable_AreTypesEquivalent) DllImportEntry(MethodTable_CanCompareBitsOrUseFastGetHashCode) - DllImportEntry(TypeHandle_CanCastTo) DllImportEntry(ValueType_GetHashCodeStrategy) DllImportEntry(RuntimeTypeHandle_MakePointer) DllImportEntry(RuntimeTypeHandle_MakeByRef) @@ -133,7 +132,6 @@ static const Entry s_QCall[] = DllImportEntry(RuntimeModule_GetScopeName) DllImportEntry(RuntimeModule_GetFullyQualifiedName) DllImportEntry(RuntimeModule_GetTypes) - DllImportEntry(RuntimeFieldHandle_GetFieldSize) DllImportEntry(StackFrame_GetMethodDescFromNativeIP) DllImportEntry(ModuleBuilder_GetStringConstant) DllImportEntry(ModuleBuilder_GetTypeRef) diff --git a/src/coreclr/vm/reflectioninvocation.cpp b/src/coreclr/vm/reflectioninvocation.cpp index 65192d5a68738..f57e21801253a 100644 --- a/src/coreclr/vm/reflectioninvocation.cpp +++ b/src/coreclr/vm/reflectioninvocation.cpp @@ -1246,31 +1246,16 @@ FCIMPL1(void*, RuntimeFieldHandle::GetStaticFieldAddress, ReflectFieldObject *pF // IsFastPathSupported needs to checked before calling this method. _ASSERTE(IsFastPathSupportedHelper(pFieldDesc)); - if (pFieldDesc->IsRVA()) + PTR_BYTE base = 0; + if (!pFieldDesc->IsRVA()) { - Module* pModule = pFieldDesc->GetModule(); - return pModule->GetRvaField(pFieldDesc->GetOffset()); + // For RVA the base is ignored and offset is used. + base = pFieldDesc->GetBase(); } - else - { - PTR_BYTE base = pFieldDesc->GetBase(); - return PTR_VOID(base + pFieldDesc->GetOffset()); - } -} -FCIMPLEND -extern "C" UINT QCALLTYPE RuntimeFieldHandle_GetFieldSize(QCall::FieldHandle pField) -{ - QCALL_CONTRACT; - - UINT ret = 0; - - BEGIN_QCALL; - ret = pField->LoadSize(); - END_QCALL; - - return ret; + return PTR_VOID(base + pFieldDesc->GetOffset()); } +FCIMPLEND extern "C" void QCALLTYPE ReflectionInvocation_CompileMethod(MethodDesc * pMD) { diff --git a/src/coreclr/vm/runtimehandles.h b/src/coreclr/vm/runtimehandles.h index e0504d952880d..56bb2df245f9f 100644 --- a/src/coreclr/vm/runtimehandles.h +++ b/src/coreclr/vm/runtimehandles.h @@ -308,7 +308,6 @@ class RuntimeFieldHandle { static FCDECL1(FC_BOOL_RET, AcquiresContextFromThis, FieldDesc *pField); static FCDECL1(Object*, GetLoaderAllocator, FieldDesc *pField); }; -extern "C" UINT QCALLTYPE RuntimeFieldHandle_GetFieldSize(QCall::FieldHandle pField); class ModuleHandle { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs index e6ab54d12e5d7..240e9932bf624 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs @@ -95,25 +95,4 @@ internal QCallTypeHandle(ref RuntimeTypeHandle rth) _handle = rth.Value; } } - - // Wraps IRuntimeFieldInfo into a handle. Used to pass IRuntimeFieldInfo to native code without letting it be collected - internal unsafe ref struct QCallFieldHandle - { - private void* _ptr; - private IntPtr _handle; - -#if CORECLR - internal QCallFieldHandle(ref IRuntimeFieldInfo field) - { - _ptr = Unsafe.AsPointer(ref field); - _handle = field.Value.Value; - } -#endif - - internal QCallFieldHandle(ref RuntimeFieldHandle rth) - { - _ptr = Unsafe.AsPointer(ref rth); - _handle = rth.Value; - } - } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index 3715e6df74a11..63471d9f91967 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics; using System.Reflection; using System.Runtime.InteropServices; @@ -110,35 +109,6 @@ internal static bool IsPrimitiveType(this CorElementType et) // COR_ELEMENT_TYPE_I1,I2,I4,I8,U1,U2,U4,U8,R4,R8,I,U,CHAR,BOOLEAN => ((1 << (int)et) & 0b_0011_0000_0000_0011_1111_1111_1100) != 0; - private static ReadOnlySpan PrimitiveWidenTable => - [ - 0x00, // ELEMENT_TYPE_END - 0x00, // ELEMENT_TYPE_VOID - 0x0004, // ELEMENT_TYPE_BOOLEAN - 0x3F88, // ELEMENT_TYPE_CHAR (W = U2, CHAR, I4, U4, I8, U8, R4, R8) (U2 == Char) - 0x3550, // ELEMENT_TYPE_I1 (W = I1, I2, I4, I8, R4, R8) - 0x3FE8, // ELEMENT_TYPE_U1 (W = CHAR, U1, I2, U2, I4, U4, I8, U8, R4, R8) - 0x3540, // ELEMENT_TYPE_I2 (W = I2, I4, I8, R4, R8) - 0x3F88, // ELEMENT_TYPE_U2 (W = U2, CHAR, I4, U4, I8, U8, R4, R8) - 0x3500, // ELEMENT_TYPE_I4 (W = I4, I8, R4, R8) - 0x3E00, // ELEMENT_TYPE_U4 (W = U4, I8, R4, R8) - 0x3400, // ELEMENT_TYPE_I8 (W = I8, R4, R8) - 0x3800, // ELEMENT_TYPE_U8 (W = U8, R4, R8) - 0x3000, // ELEMENT_TYPE_R4 (W = R4, R8) - 0x2000, // ELEMENT_TYPE_R8 (W = R8) - ]; - - internal static bool CanPrimitiveWiden(CorElementType srcET, CorElementType dstET) - { - Debug.Assert(srcET.IsPrimitiveType() && dstET.IsPrimitiveType()); - if ((int)srcET >= PrimitiveWidenTable.Length) - { - // I or U - return srcET == dstET; - } - return (PrimitiveWidenTable[(int)srcET] & (1 << (int)dstET)) != 0; - } - /// Provide a fast way to access constant data stored in a module as a ReadOnlySpan{T} /// A field handle that specifies the location of the data to be referred to by the ReadOnlySpan{T}. The Rva of the field must be aligned on a natural boundary of type T /// A ReadOnlySpan{T} of the data stored in the field diff --git a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs index f742fe7a77e1c..eb9b5b7eb0261 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs @@ -71,6 +71,18 @@ internal static void ThrowArrayTypeMismatchException() throw new ArrayTypeMismatchException(); } + [DoesNotReturn] + internal static void ThrowArrayTypeMismatchException_CantAssignType() + { + throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType); + } + + [DoesNotReturn] + internal static void ThrowInvalidCastException_DownCastArrayElement() + { + throw new InvalidCastException(SR.InvalidCast_DownCastArrayElement); + } + [DoesNotReturn] internal static void ThrowInvalidTypeWithPointersNotSupported(Type targetType) {