Skip to content

Commit

Permalink
Go with CorElementType only
Browse files Browse the repository at this point in the history
  • Loading branch information
huoyaoyuan committed Jun 3, 2024
1 parent b610b35 commit 3e350ac
Show file tree
Hide file tree
Showing 16 changed files with 295 additions and 356 deletions.
290 changes: 143 additions & 147 deletions src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ushort>(src, array.Length),
new Span<ushort>(ref Unsafe.As<byte, ushort>(ref dst), array.Length));
break;
case 4:
BinaryPrimitives.ReverseEndianness(
new ReadOnlySpan<uint>(src, array.Length),
new Span<uint>(ref Unsafe.As<byte, uint>(ref dst), array.Length));
break;
case 8:
BinaryPrimitives.ReverseEndianness(
new ReadOnlySpan<ulong>(src, array.Length),
new Span<ulong>(ref Unsafe.As<byte, ulong>(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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1085,7 +1085,7 @@ public RuntimeFieldInfoStub(RuntimeFieldHandleInternal fieldHandle, object keepa
}

[NonVersionable]
public unsafe partial struct RuntimeFieldHandle : IEquatable<RuntimeFieldHandle>, ISerializable
public unsafe struct RuntimeFieldHandle : IEquatable<RuntimeFieldHandle>, ISerializable
{
// Returns handle for interop with EE. The handle is guaranteed to be non-null.
internal RuntimeFieldHandle GetNativeHandle()
Expand Down Expand Up @@ -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);
Expand Down
113 changes: 113 additions & 0 deletions src/coreclr/classlibnative/bcltype/arraynative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 8 additions & 0 deletions src/coreclr/classlibnative/bcltype/arraynative.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
15 changes: 0 additions & 15 deletions src/coreclr/vm/comutilnative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/comutilnative.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
18 changes: 0 additions & 18 deletions src/coreclr/vm/qcall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/vm/qcallentrypoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 3e350ac

Please sign in to comment.