Skip to content

Commit 59a3093

Browse files
authored
Move TypeReference.ToObject to managed (CoreCLR) (#70055)
* Initial partial TypedReference.ToObject managed port * Port rest of mamaged TypeDesc method table logic * Add RuntimeTypeHandle.GetElementTypeMethodTable FCall * Remove TypedReference.InternalToObject FCall * Remove throwing path, add an assert * Remove unnecessary TypeDesc paths * Remove ParamTypeDesc::m_TemplateMT and related code * Fix TypeDesc::GetMethodTable * Reuse RuntimeTypeHandle.GetValueInternal to drop an FCall * Add unit tests for TypedReference.ToObject and type desc * Move ifdef methods to TypedReference.Mono file * Skip new TypedReference tests on Mono * Use [ActiveIssue] instead of [SkipOnMono] * Commented tests out to skip Mono AOT failure
1 parent 2fb5b3b commit 59a3093

File tree

14 files changed

+99
-116
lines changed

14 files changed

+99
-116
lines changed

src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,11 @@ public TypeHandle(void* tAddr)
621621
m_asTAddr = tAddr;
622622
}
623623

624+
/// <summary>
625+
/// Gets whether the current instance wraps a <see langword="null"/> pointer.
626+
/// </summary>
627+
public bool IsNull => m_asTAddr is null;
628+
624629
/// <summary>
625630
/// Gets whether or not this <see cref="TypeHandle"/> wraps a <c>TypeDesc</c> pointer.
626631
/// Only if this returns <see langword="false"/> it is safe to call <see cref="AsMethodTable"/>.

src/coreclr/System.Private.CoreLib/src/System/TypedReference.CoreCLR.cs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
// TypedReference is basically only ever seen on the call stack, and in param arrays.
5-
// These are blob that must be dealt with by the compiler.
5+
// These are blob that must be dealt with by the compiler.
6+
7+
using System.Diagnostics;
8+
using System.Runtime.CompilerServices;
69

710
namespace System
811
{
@@ -11,5 +14,38 @@ public ref partial struct TypedReference
1114
{
1215
private readonly ByReference<byte> _value;
1316
private readonly IntPtr _type;
17+
18+
public static unsafe object? ToObject(TypedReference value)
19+
{
20+
TypeHandle typeHandle = new((void*)value._type);
21+
22+
if (typeHandle.IsNull)
23+
{
24+
ThrowHelper.ThrowArgumentException_ArgumentNull_TypedRefType();
25+
}
26+
27+
// The only case where a type handle here might be a type desc is when the type is either a
28+
// pointer or a function pointer. In those cases, just always return the method table pointer
29+
// for System.UIntPtr without inspecting the type desc any further. Otherwise, the type handle
30+
// is just wrapping a method table pointer, so return that directly with a reinterpret cast.
31+
MethodTable* pMethodTable = typeHandle.IsTypeDesc
32+
? (MethodTable*)RuntimeTypeHandle.GetValueInternal(typeof(UIntPtr).TypeHandle)
33+
: typeHandle.AsMethodTable();
34+
35+
Debug.Assert(pMethodTable is not null);
36+
37+
object? result;
38+
39+
if (pMethodTable->IsValueType)
40+
{
41+
result = RuntimeHelpers.Box(pMethodTable, ref value._value.Value);
42+
}
43+
else
44+
{
45+
result = Unsafe.As<byte, object>(ref value._value.Value);
46+
}
47+
48+
return result;
49+
}
1450
}
1551
}

src/coreclr/vm/clsload.cpp

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2940,7 +2940,6 @@ TypeHandle ClassLoader::CreateTypeHandleForTypeKey(TypeKey* pKey, AllocMemTracke
29402940

29412941
CorElementType kind = pKey->GetKind();
29422942
TypeHandle paramType = pKey->GetElementType();
2943-
MethodTable *templateMT;
29442943

29452944
// Create a new type descriptor and insert into constructed type table
29462945
if (CorTypeInfo::IsArray(kind))
@@ -2970,7 +2969,8 @@ TypeHandle ClassLoader::CreateTypeHandleForTypeKey(TypeKey* pKey, AllocMemTracke
29702969
ThrowTypeLoadException(pKey, IDS_CLASSLOAD_RANK_TOOLARGE);
29712970
}
29722971

2973-
templateMT = pLoaderModule->CreateArrayMethodTable(paramType, kind, rank, pamTracker);
2972+
MethodTable *templateMT = pLoaderModule->CreateArrayMethodTable(paramType, kind, rank, pamTracker);
2973+
29742974
typeHnd = TypeHandle(templateMT);
29752975
}
29762976
else
@@ -2984,15 +2984,8 @@ TypeHandle ClassLoader::CreateTypeHandleForTypeKey(TypeKey* pKey, AllocMemTracke
29842984
// We do allow parametrized types of ByRefLike types. Languages may restrict them to produce safe or verifiable code,
29852985
// but there is not a good reason for restricting them in the runtime.
29862986

2987-
// let <Type>* type have a method table
2988-
// System.UIntPtr's method table is used for types like int*, void *, string * etc.
2989-
if (kind == ELEMENT_TYPE_PTR)
2990-
templateMT = CoreLibBinder::GetElementType(ELEMENT_TYPE_U);
2991-
else
2992-
templateMT = NULL;
2993-
29942987
BYTE* mem = (BYTE*) pamTracker->Track(pLoaderModule->GetAssembly()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(ParamTypeDesc))));
2995-
typeHnd = TypeHandle(new(mem) ParamTypeDesc(kind, templateMT, paramType));
2988+
typeHnd = TypeHandle(new(mem) ParamTypeDesc(kind, paramType));
29962989
}
29972990
}
29982991

src/coreclr/vm/ecalllist.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ FCFuncStart(gExceptionFuncs)
120120
FCFuncEnd()
121121

122122
FCFuncStart(gTypedReferenceFuncs)
123-
FCFuncElement("InternalToObject", ReflectionInvocation::TypedReferenceToObject)
124123
FCFuncElement("InternalMakeTypedReference", ReflectionInvocation::MakeTypedReference)
125124
FCFuncEnd()
126125

src/coreclr/vm/reflectioninvocation.cpp

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1470,38 +1470,6 @@ FCIMPL4(void, ReflectionInvocation::MakeTypedReference, TypedByRef * value, Obje
14701470
}
14711471
FCIMPLEND
14721472

1473-
// This is an internal helper function to TypedReference class.
1474-
// It extracts the object from the typed reference.
1475-
FCIMPL1(Object*, ReflectionInvocation::TypedReferenceToObject, TypedByRef * value) {
1476-
FCALL_CONTRACT;
1477-
1478-
OBJECTREF Obj = NULL;
1479-
1480-
TypeHandle th(value->type);
1481-
1482-
if (th.IsNull())
1483-
FCThrowRes(kArgumentNullException, W("ArgumentNull_TypedRefType"));
1484-
1485-
MethodTable* pMT = th.GetMethodTable();
1486-
PREFIX_ASSUME(NULL != pMT);
1487-
1488-
if (pMT->IsValueType())
1489-
{
1490-
// value->data is protected by the caller
1491-
HELPER_METHOD_FRAME_BEGIN_RET_1(Obj);
1492-
1493-
Obj = pMT->Box(value->data);
1494-
1495-
HELPER_METHOD_FRAME_END();
1496-
}
1497-
else {
1498-
Obj = ObjectToOBJECTREF(*((Object**)value->data));
1499-
}
1500-
1501-
return OBJECTREFToObject(Obj);
1502-
}
1503-
FCIMPLEND
1504-
15051473
FCIMPL2_IV(Object*, ReflectionInvocation::CreateEnum, ReflectClassBaseObject *pTypeUNSAFE, INT64 value) {
15061474
FCALL_CONTRACT;
15071475

src/coreclr/vm/reflectioninvocation.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ class ReflectionInvocation {
5252

5353
// TypedReference functions, should go somewhere else
5454
static FCDECL4(void, MakeTypedReference, TypedByRef * value, Object* targetUNSAFE, ArrayBase* fldsUNSAFE, ReflectClassBaseObject *pFieldType);
55-
static FCDECL1(Object*, TypedReferenceToObject, TypedByRef * value);
5655

5756
#ifdef FEATURE_COMINTEROP
5857
static FCDECL8(Object*, InvokeDispMethod, ReflectClassBaseObject* refThisUNSAFE, StringObject* nameUNSAFE, INT32 invokeAttr, Object* targetUNSAFE, PTRArray* argsUNSAFE, PTRArray* byrefModifiersUNSAFE, LCID lcid, PTRArray* namedParametersUNSAFE);

src/coreclr/vm/runtimehandles.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,7 @@ class RuntimeTypeHandle {
176176
static FCDECL1(MethodDesc *, GetFirstIntroducedMethod, ReflectClassBaseObject* pType);
177177
static FCDECL1(void, GetNextIntroducedMethod, MethodDesc **ppMethod);
178178

179-
static
180-
FCDECL1(IMDInternalImport*, GetMetadataImport, ReflectClassBaseObject * pModuleUNSAFE);
179+
static FCDECL1(IMDInternalImport*, GetMetadataImport, ReflectClassBaseObject * pModuleUNSAFE);
181180

182181
// Helper methods not called by managed code
183182

src/coreclr/vm/typedesc.cpp

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ BOOL ParamTypeDesc::Verify() {
3030
STATIC_CONTRACT_DEBUG_ONLY;
3131
STATIC_CONTRACT_SUPPORTS_DAC;
3232

33-
_ASSERTE((m_TemplateMT == NULL) || GetTemplateMethodTableInternal()->SanityCheck());
3433
_ASSERTE(!GetTypeParam().IsNull());
3534
_ASSERTE(CorTypeInfo::IsModifier_NoThrow(GetInternalCorElementType()) ||
3635
GetInternalCorElementType() == ELEMENT_TYPE_VALUETYPE);
@@ -133,26 +132,6 @@ PTR_Module TypeDesc::GetModule() {
133132
return GetLoaderModule();
134133
}
135134

136-
BOOL ParamTypeDesc::OwnsTemplateMethodTable()
137-
{
138-
CONTRACTL
139-
{
140-
NOTHROW;
141-
GC_NOTRIGGER;
142-
}
143-
CONTRACTL_END;
144-
145-
CorElementType kind = GetInternalCorElementType();
146-
147-
// The m_TemplateMT for pointer types is UIntPtr
148-
if (!CorTypeInfo::IsArray_NoThrow(kind))
149-
{
150-
return FALSE;
151-
}
152-
153-
return TRUE;
154-
}
155-
156135
Assembly* TypeDesc::GetAssembly() {
157136
STATIC_CONTRACT_NOTHROW;
158137
STATIC_CONTRACT_GC_NOTRIGGER;
@@ -532,12 +511,6 @@ OBJECTREF ParamTypeDesc::GetManagedClassObject()
532511
pLoaderAllocator->FreeHandle(hExposedClassObject);
533512
}
534513

535-
if (OwnsTemplateMethodTable())
536-
{
537-
// Set the handle on template methodtable as well to make Object.GetType for arrays take the fast path
538-
GetTemplateMethodTableInternal()->GetWriteableDataForWrite()->m_hExposedClassObject = m_hExposedClassObject;
539-
}
540-
541514
GCPROTECT_END();
542515
}
543516
return GetManagedClassObjectIfExists();
@@ -690,14 +663,6 @@ void TypeDesc::DoFullyLoad(Generics::RecursionGraph *pVisited, ClassLoadLevel le
690663

691664
// Fully load the type parameter
692665
GetTypeParam().DoFullyLoad(&newVisited, level, pPending, &fBailed, pInstContext);
693-
694-
ParamTypeDesc* pPTD = (ParamTypeDesc*) this;
695-
696-
// Fully load the template method table
697-
if (pPTD->m_TemplateMT != NULL)
698-
{
699-
pPTD->GetTemplateMethodTableInternal()->DoFullyLoad(&newVisited, level, pPending, &fBailed, pInstContext);
700-
}
701666
}
702667

703668
switch (level)
@@ -1722,12 +1687,6 @@ ParamTypeDesc::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
17221687
SUPPORTS_DAC;
17231688
DAC_ENUM_DTHIS();
17241689

1725-
PTR_MethodTable pTemplateMT = GetTemplateMethodTableInternal();
1726-
if (pTemplateMT.IsValid())
1727-
{
1728-
pTemplateMT->EnumMemoryRegions(flags);
1729-
}
1730-
17311690
m_Arg.EnumMemoryRegions(flags);
17321691
}
17331692

src/coreclr/vm/typedesc.h

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -220,13 +220,11 @@ class ParamTypeDesc : public TypeDesc {
220220

221221
public:
222222
#ifndef DACCESS_COMPILE
223-
ParamTypeDesc(CorElementType type, MethodTable* pMT, TypeHandle arg)
223+
ParamTypeDesc(CorElementType type, TypeHandle arg)
224224
: TypeDesc(type), m_Arg(arg), m_hExposedClassObject(0) {
225225

226226
LIMITED_METHOD_CONTRACT;
227227

228-
m_TemplateMT = pMT;
229-
230228
// ParamTypeDescs start out life not fully loaded
231229
m_typeAndFlags |= TypeDesc::enum_flag_IsNotFullyLoaded;
232230

@@ -276,8 +274,6 @@ class ParamTypeDesc : public TypeDesc {
276274

277275
TypeHandle GetTypeParam();
278276

279-
BOOL OwnsTemplateMethodTable();
280-
281277
#ifdef DACCESS_COMPILE
282278
void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
283279
#endif
@@ -288,13 +284,8 @@ class ParamTypeDesc : public TypeDesc {
288284
friend class ArrayOpLinker;
289285
#endif
290286
protected:
291-
PTR_MethodTable GetTemplateMethodTableInternal() {
292-
WRAPPER_NO_CONTRACT;
293-
return m_TemplateMT;
294-
}
295287

296288
// the m_typeAndFlags field in TypeDesc tell what kind of parameterized type we have
297-
PTR_MethodTable m_TemplateMT; // The shared method table, some variants do not use this field (it is null)
298289
TypeHandle m_Arg; // The type that is being modified
299290
LOADERHANDLE m_hExposedClassObject; // handle back to the internal reflection Type object
300291
};

src/coreclr/vm/typedesc.inl

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,18 @@ inline PTR_MethodTable TypeDesc::GetMethodTable() {
1818

1919
LIMITED_METHOD_DAC_CONTRACT;
2020

21-
if (IsGenericVariable())
22-
return NULL;
23-
24-
if (GetInternalCorElementType() == ELEMENT_TYPE_FNPTR)
21+
switch (GetInternalCorElementType())
22+
{
23+
case ELEMENT_TYPE_PTR:
24+
case ELEMENT_TYPE_FNPTR:
2525
return CoreLibBinder::GetElementType(ELEMENT_TYPE_U);
2626

27-
_ASSERTE(HasTypeParam());
28-
ParamTypeDesc* asParam = dac_cast<PTR_ParamTypeDesc>(this);
27+
case ELEMENT_TYPE_VALUETYPE:
28+
return dac_cast<PTR_MethodTable>(dac_cast<PTR_ParamTypeDesc>(this)->m_Arg.AsMethodTable());
2929

30-
if (GetInternalCorElementType() == ELEMENT_TYPE_VALUETYPE)
31-
return dac_cast<PTR_MethodTable>(asParam->m_Arg.AsMethodTable());
32-
else
33-
return(asParam->GetTemplateMethodTableInternal());
30+
default:
31+
return NULL;
32+
}
3433
}
3534

3635
inline TypeHandle TypeDesc::GetTypeParam() {

0 commit comments

Comments
 (0)