Skip to content

Commit d592d11

Browse files
Remove Helper Method Frames (HMF) from Reflection (#110211)
Create general purpose RuntimeTypeHandle.InternalAlloc() and RuntimeTypeHandle.InternalAllocNoChecks(). Convert RuntimeMethodHandle::ReboxToNullable() to managed. Convert RuntimeMethodHandle::ReboxFromNullable() to managed. Convert RuntimeMethodHandle::InvokeMethod() to QCall.
1 parent 6d12a30 commit d592d11

File tree

14 files changed

+188
-200
lines changed

14 files changed

+188
-200
lines changed

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

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -434,23 +434,10 @@ private bool BindToMethodInfo(object? target, IRuntimeMethodInfo method, Runtime
434434

435435
private static MulticastDelegate InternalAlloc(RuntimeType type)
436436
{
437-
MulticastDelegate? d = null;
438-
InternalAlloc(new QCallTypeHandle(ref type), ObjectHandleOnStack.Create(ref d));
439-
return d!;
437+
Debug.Assert(type.IsAssignableTo(typeof(MulticastDelegate)));
438+
return Unsafe.As<MulticastDelegate>(RuntimeTypeHandle.InternalAlloc(type));
440439
}
441440

442-
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Delegate_InternalAlloc")]
443-
private static partial void InternalAlloc(QCallTypeHandle type, ObjectHandleOnStack d);
444-
445-
internal static MulticastDelegate InternalAllocLike(MulticastDelegate d)
446-
{
447-
InternalAllocLike(ObjectHandleOnStack.Create(ref d));
448-
return d;
449-
}
450-
451-
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Delegate_InternalAllocLike")]
452-
private static partial void InternalAllocLike(ObjectHandleOnStack d);
453-
454441
[MethodImpl(MethodImplOptions.AggressiveInlining)]
455442
internal static unsafe bool InternalEqualTypes(object a, object b)
456443
{

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ private static bool TrySetSlot(object?[] a, int index, object o)
167167
private MulticastDelegate NewMulticastDelegate(object[] invocationList, int invocationCount, bool thisIsMultiCastAlready)
168168
{
169169
// First, allocate a new multicast delegate just like this one, i.e. same type as the this object
170-
MulticastDelegate result = InternalAllocLike(this);
170+
MulticastDelegate result = Unsafe.As<MulticastDelegate>(RuntimeTypeHandle.InternalAllocNoChecks((RuntimeType)GetType()));
171171

172172
// Performance optimization - if this already points to a true multicast delegate,
173173
// copy _methodPtr and _methodPtrAux fields rather than calling into the EE to get them

src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,32 @@ internal static void Unbox_Nullable(ref byte destPtr, MethodTable* typeMT, objec
596596
}
597597
}
598598

599+
[DebuggerHidden]
600+
internal static object? ReboxFromNullable(MethodTable* srcMT, object src)
601+
{
602+
Debug.Assert(srcMT->IsNullable);
603+
604+
ref byte nullableData = ref src.GetRawData();
605+
606+
// If 'hasValue' is false, return null.
607+
if (!Unsafe.As<byte, bool>(ref nullableData))
608+
return null;
609+
610+
// Allocate a new instance of the T in Nullable<T>.
611+
MethodTable* dstMT = srcMT->InstantiationArg0();
612+
object dst = RuntimeTypeHandle.InternalAlloc(dstMT);
613+
614+
// Copy data from the Nullable<T>.
615+
ref byte srcData = ref Unsafe.Add(ref nullableData, srcMT->NullableValueAddrOffset);
616+
ref byte dstData = ref RuntimeHelpers.GetRawData(dst);
617+
if (dstMT->ContainsGCPointers)
618+
Buffer.BulkMoveWithWriteBarrier(ref dstData, ref srcData, dstMT->GetNumInstanceFieldBytesIfContainsGCPointers());
619+
else
620+
SpanHelpers.Memmove(ref dstData, ref srcData, dstMT->GetNumInstanceFieldBytes());
621+
622+
return dst;
623+
}
624+
599625
[DebuggerHidden]
600626
[MethodImpl(MethodImplOptions.NoInlining)]
601627
private static ref byte Unbox_Helper(MethodTable* pMT1, object obj)

src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,36 @@ private static partial void CreateInstanceForAnotherGenericParameter(
269269
int cTypeHandles,
270270
ObjectHandleOnStack instantiatedObject);
271271

272+
internal static unsafe object InternalAlloc(MethodTable* pMT)
273+
{
274+
object? result = null;
275+
InternalAlloc(pMT, ObjectHandleOnStack.Create(ref result));
276+
return result!;
277+
}
278+
279+
internal static object InternalAlloc(RuntimeType type)
280+
{
281+
Debug.Assert(!type.GetNativeTypeHandle().IsTypeDesc);
282+
object result = InternalAlloc(type.GetNativeTypeHandle().AsMethodTable());
283+
GC.KeepAlive(type);
284+
return result;
285+
}
286+
287+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_InternalAlloc")]
288+
private static unsafe partial void InternalAlloc(MethodTable* pMT, ObjectHandleOnStack result);
289+
290+
internal static object InternalAllocNoChecks(RuntimeType type)
291+
{
292+
Debug.Assert(!type.GetNativeTypeHandle().IsTypeDesc);
293+
object? result = null;
294+
InternalAllocNoChecks(type.GetNativeTypeHandle().AsMethodTable(), ObjectHandleOnStack.Create(ref result));
295+
GC.KeepAlive(type);
296+
return result!;
297+
}
298+
299+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_InternalAllocNoChecks")]
300+
private static unsafe partial void InternalAllocNoChecks(MethodTable* pMT, ObjectHandleOnStack result);
301+
272302
/// <summary>
273303
/// Given a RuntimeType, returns information about how to activate it via calli
274304
/// semantics. This method will ensure the type object is fully initialized within
@@ -1026,14 +1056,59 @@ internal static MdUtf8String GetUtf8Name(RuntimeMethodHandleInternal method)
10261056

10271057
[DebuggerStepThrough]
10281058
[DebuggerHidden]
1029-
[MethodImpl(MethodImplOptions.InternalCall)]
1030-
internal static extern object? InvokeMethod(object? target, void** arguments, Signature sig, bool isConstructor);
1059+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_InvokeMethod")]
1060+
private static partial void InvokeMethod(ObjectHandleOnStack target, void** arguments, ObjectHandleOnStack sig, Interop.BOOL isConstructor, ObjectHandleOnStack result);
10311061

1032-
[MethodImpl(MethodImplOptions.InternalCall)]
1033-
internal static extern object? ReboxFromNullable(object? src);
1062+
[DebuggerStepThrough]
1063+
[DebuggerHidden]
1064+
internal static object? InvokeMethod(object? target, void** arguments, Signature sig, bool isConstructor)
1065+
{
1066+
object? result = null;
1067+
InvokeMethod(
1068+
ObjectHandleOnStack.Create(ref target),
1069+
arguments,
1070+
ObjectHandleOnStack.Create(ref sig),
1071+
isConstructor ? Interop.BOOL.TRUE : Interop.BOOL.FALSE,
1072+
ObjectHandleOnStack.Create(ref result));
1073+
return result;
1074+
}
10341075

1035-
[MethodImpl(MethodImplOptions.InternalCall)]
1036-
internal static extern object ReboxToNullable(object? src, RuntimeType destNullableType);
1076+
/// <summary>
1077+
/// For a true boxed Nullable{T}, re-box to a boxed {T} or null, otherwise just return the input.
1078+
/// </summary>
1079+
internal static object? ReboxFromNullable(object? src)
1080+
{
1081+
// If src is null or not NullableOfT, just return that state.
1082+
if (src is null)
1083+
{
1084+
return null;
1085+
}
1086+
1087+
MethodTable* pMT = RuntimeHelpers.GetMethodTable(src);
1088+
if (!pMT->IsNullable)
1089+
{
1090+
return src;
1091+
}
1092+
1093+
return CastHelpers.ReboxFromNullable(pMT, src);
1094+
}
1095+
1096+
/// <summary>
1097+
/// Convert a boxed value of {T} (which is either {T} or null) to a true boxed Nullable{T}.
1098+
/// </summary>
1099+
internal static object ReboxToNullable(object? src, RuntimeType destNullableType)
1100+
{
1101+
Debug.Assert(destNullableType.IsNullableOfT);
1102+
MethodTable* pMT = destNullableType.GetNativeTypeHandle().AsMethodTable();
1103+
object obj = RuntimeTypeHandle.InternalAlloc(pMT);
1104+
GC.KeepAlive(destNullableType); // The obj instance will keep the type alive.
1105+
1106+
CastHelpers.Unbox_Nullable(
1107+
ref obj.GetRawData(),
1108+
pMT,
1109+
src);
1110+
return obj;
1111+
}
10371112

10381113
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_GetMethodInstantiation")]
10391114
private static partial void GetMethodInstantiation(RuntimeMethodHandleInternal method, ObjectHandleOnStack types, Interop.BOOL fAsRuntimeTypeArray);

src/coreclr/vm/comdelegate.cpp

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2024,36 +2024,6 @@ Stub* COMDelegate::GetInvokeMethodStub(EEImplMethodDesc* pMD)
20242024
}
20252025
}
20262026

2027-
extern "C" void QCALLTYPE Delegate_InternalAlloc(QCall::TypeHandle pType, QCall::ObjectHandleOnStack d)
2028-
{
2029-
QCALL_CONTRACT;
2030-
2031-
BEGIN_QCALL;
2032-
2033-
GCX_COOP();
2034-
2035-
_ASSERTE(pType.AsTypeHandle().AsMethodTable()->IsDelegate());
2036-
2037-
d.Set(pType.AsTypeHandle().AsMethodTable()->Allocate());
2038-
2039-
END_QCALL;
2040-
}
2041-
2042-
extern "C" void QCALLTYPE Delegate_InternalAllocLike(QCall::ObjectHandleOnStack d)
2043-
{
2044-
QCALL_CONTRACT;
2045-
2046-
BEGIN_QCALL;
2047-
2048-
GCX_COOP();
2049-
2050-
_ASSERTE(d.Get()->GetMethodTable()->IsDelegate());
2051-
2052-
d.Set(d.Get()->GetMethodTable()->AllocateNoChecks());
2053-
2054-
END_QCALL;
2055-
}
2056-
20572027
void COMDelegate::ThrowIfInvalidUnmanagedCallersOnlyUsage(MethodDesc* pMD)
20582028
{
20592029
CONTRACTL

src/coreclr/vm/comdelegate.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,6 @@ extern "C" BOOL QCALLTYPE Delegate_BindToMethodName(QCall::ObjectHandleOnStack d
123123
extern "C" BOOL QCALLTYPE Delegate_BindToMethodInfo(QCall::ObjectHandleOnStack d, QCall::ObjectHandleOnStack target,
124124
MethodDesc * method, QCall::TypeHandle pMethodType, DelegateBindingFlags flags);
125125

126-
extern "C" void QCALLTYPE Delegate_InternalAlloc(QCall::TypeHandle pType, QCall::ObjectHandleOnStack d);
127-
128-
extern "C" void QCALLTYPE Delegate_InternalAllocLike(QCall::ObjectHandleOnStack d);
129-
130126
extern "C" void QCALLTYPE Delegate_FindMethodHandle(QCall::ObjectHandleOnStack d, QCall::ObjectHandleOnStack retMethodInfo);
131127

132128
extern "C" BOOL QCALLTYPE Delegate_InternalEqualMethodHandles(QCall::ObjectHandleOnStack left, QCall::ObjectHandleOnStack right);

src/coreclr/vm/ecalllist.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,6 @@ FCFuncStart(gSignatureNative)
146146
FCFuncEnd()
147147

148148
FCFuncStart(gRuntimeMethodHandle)
149-
FCFuncElement("InvokeMethod", RuntimeMethodHandle::InvokeMethod)
150-
FCFuncElement("ReboxFromNullable", RuntimeMethodHandle::ReboxFromNullable)
151-
FCFuncElement("ReboxToNullable", RuntimeMethodHandle::ReboxToNullable)
152149
FCFuncElement("GetImplAttributes", RuntimeMethodHandle::GetImplAttributes)
153150
FCFuncElement("GetAttributes", RuntimeMethodHandle::GetAttributes)
154151
FCFuncElement("GetMethodTable", RuntimeMethodHandle::GetMethodTable)

src/coreclr/vm/methodtable.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3940,18 +3940,17 @@ void MethodTable::CheckRunClassInitAsIfConstructingThrowing()
39403940
THROWS;
39413941
GC_TRIGGERS;
39423942
MODE_ANY;
3943+
PRECONDITION(HasPreciseInitCctors());
39433944
}
39443945
CONTRACTL_END;
3945-
if (HasPreciseInitCctors())
3946+
3947+
MethodTable *pMTCur = this;
3948+
while (pMTCur != NULL)
39463949
{
3947-
MethodTable *pMTCur = this;
3948-
while (pMTCur != NULL)
3949-
{
3950-
if (!pMTCur->GetClass()->IsBeforeFieldInit())
3951-
pMTCur->CheckRunClassInitThrowing();
3950+
if (!pMTCur->GetClass()->IsBeforeFieldInit())
3951+
pMTCur->CheckRunClassInitThrowing();
39523952

3953-
pMTCur = pMTCur->GetParentMethodTable();
3954-
}
3953+
pMTCur = pMTCur->GetParentMethodTable();
39553954
}
39563955
}
39573956

src/coreclr/vm/methodtable.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2676,8 +2676,8 @@ class MethodTable
26762676
// This flavor of Allocate is more efficient, but can only be used
26772677
// if CheckInstanceActivated(), IsClassInited() are known to be true.
26782678
// A sufficient condition is that another instance of the exact same type already
2679-
// exists in the same appdomain. It's currently called only from Delegate.Combine
2680-
// via COMDelegate::InternalAllocLike.
2679+
// exists in the same ALC. It's currently called only from Delegate.Combine
2680+
// via RuntimeTypeHandle_InternalAllocNoChecks.
26812681
OBJECTREF AllocateNoChecks();
26822682

26832683
OBJECTREF Box(void* data);
@@ -3921,12 +3921,11 @@ public :
39213921
TADDR m_ElementTypeHnd;
39223922
};
39233923
public:
3924-
union
3924+
union
39253925
{
39263926
PTR_InterfaceInfo m_pInterfaceMap;
39273927
TADDR m_encodedNullableUnboxData; // Used for Nullable<T> to represent the offset to the value field, and the size of the value field
39283928
};
3929-
39303929

39313930
// VTable slots go here
39323931

src/coreclr/vm/methodtable.inl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,7 +1230,7 @@ inline OBJECTREF MethodTable::AllocateNoChecks()
12301230
}
12311231
CONTRACTL_END;
12321232

1233-
// we know an instance of this class already exists in the same appdomain
1233+
// We know an instance of this class already exists
12341234
// therefore, some checks become redundant.
12351235
// this currently only happens for Delegate.Combine
12361236

@@ -1239,7 +1239,6 @@ inline OBJECTREF MethodTable::AllocateNoChecks()
12391239
return AllocateObject(this);
12401240
}
12411241

1242-
12431242
#ifndef DACCESS_COMPILE
12441243
//==========================================================================================
12451244
// unbox src into dest, No checks are done

0 commit comments

Comments
 (0)