Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test CI #102967

Closed
wants to merge 40 commits into from
Closed

Test CI #102967

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
566b15e
Implement IsSimpleCopy and CanAssignArrayType in managed code
huoyaoyuan May 27, 2024
8a592b9
Fold IsSimpleCopy back to CanAssignArrayType
huoyaoyuan May 27, 2024
0dce3d4
Delete FCall and QCall definitions for copy
huoyaoyuan May 27, 2024
d29e5d8
Convert InternalSetValue to managed
huoyaoyuan May 28, 2024
5dd0e3c
Setup FCalls
huoyaoyuan May 28, 2024
527021c
Remove FCall for GetCorElementTypeOfElementType
huoyaoyuan May 28, 2024
e7d843a
Complete TryUnBox
huoyaoyuan May 28, 2024
2bb5fe7
Fix FCall definition
huoyaoyuan May 28, 2024
f7da172
Implement InitializeArray in managed
huoyaoyuan May 28, 2024
0924555
Implement GetSpanDataFrom in managed
huoyaoyuan May 28, 2024
dc85381
Remove FCall definition
huoyaoyuan May 28, 2024
f99c553
Fix RVA field address
huoyaoyuan May 28, 2024
c5e6cc4
Fix RVA assert
huoyaoyuan May 28, 2024
470b86f
Do not use hydrated RtFieldInfo
huoyaoyuan May 28, 2024
c7821e6
Use QCall for LoadSize
huoyaoyuan May 29, 2024
5225203
Fix CanAssignArrayType condition
huoyaoyuan May 29, 2024
07293e3
Fix compilation
huoyaoyuan May 29, 2024
5da88c3
Simplify AssignType enum
huoyaoyuan May 29, 2024
5222bca
Fix I and U in CanPrimitiveWiden
huoyaoyuan May 29, 2024
335b2fb
CanCastTo should be QCall
huoyaoyuan May 30, 2024
93ec9d8
Remove ThrowHelper usages that not in hot path
huoyaoyuan May 31, 2024
44445a3
Revert
huoyaoyuan Jun 2, 2024
b59fa9d
GetCorElementTypeOfElementType
huoyaoyuan Jun 2, 2024
7ffe745
InternalSetValue
huoyaoyuan Jun 2, 2024
b610b35
Revert "GetCorElementTypeOfElementType"
huoyaoyuan Jun 2, 2024
3e350ac
Go with CorElementType only
huoyaoyuan Jun 3, 2024
0112e24
Add InitializeArray
huoyaoyuan Jun 3, 2024
5841ed8
Revert "Add InitializeArray"
huoyaoyuan Jun 4, 2024
a795d59
Add CopySlow and AssignType
huoyaoyuan Jun 4, 2024
b300d25
Go back to known broken commit
huoyaoyuan Jun 4, 2024
e369ca9
Exclude InitializeArray
huoyaoyuan Jun 4, 2024
68a48f7
Fix FCall
huoyaoyuan Jun 5, 2024
ea361ca
Revert to original failing commit
huoyaoyuan Jun 5, 2024
94acf75
Keep all native implementations
huoyaoyuan Jun 5, 2024
272883f
First exclude InternalSetValue
huoyaoyuan Jun 5, 2024
fa327da
Revert "First exclude InternalSetValue"
huoyaoyuan Jun 6, 2024
93f99e8
Exclude CopyImpl
huoyaoyuan Jun 6, 2024
faa706c
Merge branch 'main' into array-fcall-test
huoyaoyuan Jun 6, 2024
9853076
Exclude InitializeArray
huoyaoyuan Jun 6, 2024
46b1d4a
Exclude GetCorElementTypeOfElementType
huoyaoyuan Jun 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
381 changes: 239 additions & 142 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]
private static object? IsInstanceOfAny(void* toTypeHnd, object? obj)
internal static object? IsInstanceOfAny(void* toTypeHnd, object? obj)
{
if (obj != null)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// 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
{
Expand Down Expand Up @@ -652,6 +652,8 @@ public int MultiDimensionalArrayRank
// Warning! UNLIKE the similarly named Reflection api, this method also returns "true" for Enums.
public bool IsPrimitive => (Flags & enum_flag_Category_Mask) is enum_flag_Category_PrimitiveValueType or enum_flag_Category_TruePrimitive;

public bool IsTruePrimitive => (Flags & enum_flag_Category_Mask) is enum_flag_Category_TruePrimitive;

public bool HasInstantiation => (Flags & enum_flag_HasComponentSize) == 0 && (Flags & enum_flag_GenericsMask) != enum_flag_GenericsMask_NonGeneric;

public bool IsGenericTypeDefinition => (Flags & (enum_flag_HasComponentSize | enum_flag_GenericsMask)) == enum_flag_GenericsMask_TypicalInst;
Expand Down Expand Up @@ -681,6 +683,9 @@ public TypeHandle GetArrayElementTypeHandle()

[MethodImpl(MethodImplOptions.InternalCall)]
public extern uint GetNumInstanceFieldBytes();

[MethodImpl(MethodImplOptions.InternalCall)]
public extern CorElementType GetVerifierCorElementType();
}

// Subset of src\vm\methodtable.h
Expand All @@ -706,9 +711,9 @@ public bool CanCompareBitsOrUseFastGetHashCode
}

/// <summary>
/// A type handle, which can wrap either a pointer to a <c>TypeDesc</c> or to a <see cref="MethodTable"/>.
/// A type handle, which can wrap either a pointer to a <see cref="TypeDesc"/> or to a <see cref="MethodTable"/>.
/// </summary>
internal unsafe struct TypeHandle
internal readonly unsafe partial struct TypeHandle
{
// Subset of src\vm\typehandle.h

Expand Down Expand Up @@ -750,11 +755,67 @@ public bool IsTypeDesc
return (MethodTable*)m_asTAddr;
}

/// <summary>
/// Gets the <see cref="TypeDesc"/> pointer wrapped by the current instance.
/// </summary>
/// <remarks>This is only safe to call if <see cref="IsTypeDesc"/> returned <see langword="true"/>.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TypeDesc* AsTypeDesc()
{
Debug.Assert(IsTypeDesc);

return (TypeDesc*)((nint)m_asTAddr - 2);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TypeHandle TypeHandleOf<T>()
{
return new TypeHandle((void*)RuntimeTypeHandle.ToIntPtr(typeof(T).TypeHandle));
}

public static bool AreSameType(TypeHandle left, TypeHandle right) => left.m_asTAddr == right.m_asTAddr;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool CanCastTo(TypeHandle destTH)
{
CastResult result = CastCache.TryGet(CastHelpers.s_table!, (nuint)m_asTAddr, (nuint)destTH.m_asTAddr);

if (result != CastResult.MaybeCast)
return result == CastResult.CanCast;

return CanCastTo_NoCacheLookup(m_asTAddr, destTH.m_asTAddr);
}

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeHandle_CanCastTo")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool CanCastTo_NoCacheLookup(void* fromTypeHnd, void* toTypeHnd);

public bool IsValueType
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return IsTypeDesc
? AsTypeDesc()->GetInternalCorElementType() == CorElementType.ELEMENT_TYPE_VALUETYPE
: AsMethodTable()->IsValueType;
}
}

public bool IsInterface => !IsTypeDesc && AsMethodTable()->IsInterface;

public CorElementType GetVerifierCorElementType() => IsTypeDesc
? AsTypeDesc()->GetInternalCorElementType()
: AsMethodTable()->GetVerifierCorElementType();
}

internal unsafe struct TypeDesc
{
private readonly int m_typeAndFlags;

// This is the ELEMENT_TYPE* that would be used in the type sig for this type
// For enums this is the underlying type
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CorElementType GetInternalCorElementType() => (CorElementType)(m_typeAndFlags & 0xFF);
}

// Helper structs used for tail calls via helper.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1089,7 +1089,7 @@ public RuntimeFieldInfoStub(RuntimeFieldHandleInternal fieldHandle, object keepa
}

[NonVersionable]
public unsafe struct RuntimeFieldHandle : IEquatable<RuntimeFieldHandle>, ISerializable
public unsafe partial 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 @@ -1191,7 +1191,10 @@ internal static RuntimeType GetApproxDeclaringType(IRuntimeFieldInfo field)
internal static extern int GetInstanceFieldOffset(RtFieldInfo field);

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern IntPtr GetStaticFieldAddress(RtFieldInfo field);
internal static extern IntPtr GetStaticFieldAddress(IRuntimeFieldInfo field);

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeFieldHandle_GetFieldSize")]
internal static partial uint GetFieldSize(QCallFieldHandle field);

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int GetToken(RtFieldInfo field);
Expand Down
22 changes: 22 additions & 0 deletions src/coreclr/vm/comutilnative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1787,6 +1787,13 @@ FCIMPL1(UINT32, MethodTableNative::GetNumInstanceFieldBytes, MethodTable* mt)
}
FCIMPLEND

FCIMPL1(CorElementType, MethodTableNative::GetVerifierCorElementType, MethodTable* mt)
{
FCALL_CONTRACT;
return mt->GetVerifierCorElementType();
}
FCIMPLEND

extern "C" BOOL QCALLTYPE MethodTable_AreTypesEquivalent(MethodTable* mta, MethodTable* mtb)
{
QCALL_CONTRACT;
Expand All @@ -1802,6 +1809,21 @@ 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
2 changes: 2 additions & 0 deletions src/coreclr/vm/comutilnative.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,12 @@ extern "C" void QCALLTYPE Interlocked_MemoryBarrierProcessWide();
class MethodTableNative {
public:
static FCDECL1(UINT32, GetNumInstanceFieldBytes, MethodTable* mt);
static FCDECL1(CorElementType, GetVerifierCorElementType, MethodTable* mt);
};

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
1 change: 1 addition & 0 deletions src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ FCFuncEnd()

FCFuncStart(gMethodTableFuncs)
FCFuncElement("GetNumInstanceFieldBytes", MethodTableNative::GetNumInstanceFieldBytes)
FCFuncElement("GetVerifierCorElementType", MethodTableNative::GetVerifierCorElementType)
FCFuncEnd()

FCFuncStart(gStubHelperFuncs)
Expand Down
18 changes: 18 additions & 0 deletions src/coreclr/vm/qcall.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,24 @@ 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: 2 additions & 0 deletions src/coreclr/vm/qcallentrypoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ 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 @@ -132,6 +133,7 @@ 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
27 changes: 21 additions & 6 deletions src/coreclr/vm/reflectioninvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1246,17 +1246,32 @@ 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

extern "C" UINT QCALLTYPE RuntimeFieldHandle_GetFieldSize(QCall::FieldHandle pField)
{
QCALL_CONTRACT;

UINT ret = 0;

BEGIN_QCALL;
ret = pField->LoadSize();
END_QCALL;

return ret;
}

extern "C" void QCALLTYPE ReflectionInvocation_CompileMethod(MethodDesc * pMD)
{
QCALL_CONTRACT;
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/runtimehandles.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ 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 {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4322,4 +4322,10 @@
<data name="NotSupported_EmitDebugInfo" xml:space="preserve">
<value>Emitting debug info is not supported for this member.</value>
</data>
</root>
<data name="Argument_BadFieldForInitializeArray" xml:space="preserve">
<value>The field is invalid for initializing array or span.</value>
</data>
<data name="Argument_MustBePrimitiveArray" xml:space="preserve">
<value>The array must be array of primitive or enum type.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,25 @@ 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;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 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;

Expand Down Expand Up @@ -109,6 +110,35 @@ 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<short> 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;
}

/// <summary>Provide a fast way to access constant data stored in a module as a ReadOnlySpan{T}</summary>
/// <param name="fldHandle">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</param>
/// <returns>A ReadOnlySpan{T} of the data stored in the field</returns>
Expand Down
Loading
Loading