Skip to content

Commit d7f8b33

Browse files
committed
Use emitted thunks in RuntimeMethodHandle.InvokeMethod
1 parent 3e6efe5 commit d7f8b33

2 files changed

Lines changed: 47 additions & 11 deletions

File tree

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

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,16 +1203,37 @@ internal static MdUtf8String GetUtf8Name(RuntimeMethodHandleInternal method)
12031203
[RequiresUnsafe]
12041204
internal static object? InvokeMethod(object? target, void** arguments, Signature sig, bool isConstructor)
12051205
{
1206-
object? result = null;
1207-
InvokeMethod(
1208-
ObjectHandleOnStack.Create(ref target),
1209-
arguments,
1210-
ObjectHandleOnStack.Create(ref sig),
1211-
isConstructor ? Interop.BOOL.TRUE : Interop.BOOL.FALSE,
1212-
ObjectHandleOnStack.Create(ref result));
1213-
return result;
1206+
if (!RuntimeFeature.IsDynamicCodeSupported)
1207+
{
1208+
object? result = null;
1209+
InvokeMethod(
1210+
ObjectHandleOnStack.Create(ref target),
1211+
arguments,
1212+
ObjectHandleOnStack.Create(ref sig),
1213+
isConstructor ? Interop.BOOL.TRUE : Interop.BOOL.FALSE,
1214+
ObjectHandleOnStack.Create(ref result));
1215+
return result;
1216+
}
1217+
1218+
MethodBase? method = RuntimeType.GetMethodBase(sig.DeclaringType, sig.MethodHandle);
1219+
if (method is null)
1220+
{
1221+
throw new InvalidOperationException(SR.Arg_InvalidHandle);
1222+
}
1223+
1224+
Reflection.InvokerEmitUtil.InvokeFunc_RefArgs thunk = method is Reflection.RuntimeConstructorInfo && !isConstructor
1225+
? s_invokeMethodCtorNoAllocCache.GetValue(method, static m => Reflection.InvokerEmitUtil.CreateInvokeDelegate_RefArgs(m, backwardsCompat: true, constructorWithoutAllocation: true))
1226+
: s_invokeMethodCache.GetValue(method, static m => Reflection.InvokerEmitUtil.CreateInvokeDelegate_RefArgs(m, backwardsCompat: true));
1227+
1228+
return thunk(target, (IntPtr*)arguments);
12141229
}
12151230

1231+
private static readonly ConditionalWeakTable<MethodBase, Reflection.InvokerEmitUtil.InvokeFunc_RefArgs> s_invokeMethodCache =
1232+
new();
1233+
1234+
private static readonly ConditionalWeakTable<MethodBase, Reflection.InvokerEmitUtil.InvokeFunc_RefArgs> s_invokeMethodCtorNoAllocCache =
1235+
new();
1236+
12161237
/// <summary>
12171238
/// For a true boxed Nullable{T}, re-box to a boxed {T} or null, otherwise just return the input.
12181239
/// </summary>
@@ -2146,6 +2167,8 @@ public Signature(void* pCorSig, int cCorSig, RuntimeType declaringType)
21462167

21472168
#region Internal Members
21482169
internal CallingConventions CallingConvention => (CallingConventions)(_managedCallingConventionAndArgIteratorFlags & 0xff);
2170+
internal RuntimeMethodHandleInternal MethodHandle => _pMethod;
2171+
internal RuntimeType DeclaringType => _declaringType;
21492172
internal RuntimeType[] Arguments
21502173
{
21512174
get

src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,14 @@ public static InvokeFunc_ObjSpanArgs CreateInvokeDelegate_ObjSpanArgs(MethodBase
141141
}
142142

143143
public static InvokeFunc_RefArgs CreateInvokeDelegate_RefArgs(MethodBase method, bool backwardsCompat)
144+
=> CreateInvokeDelegate_RefArgs(method, backwardsCompat, constructorWithoutAllocation: false);
145+
146+
public static InvokeFunc_RefArgs CreateInvokeDelegate_RefArgs(MethodBase method, bool backwardsCompat, bool constructorWithoutAllocation)
144147
{
145148
Debug.Assert(!method.ContainsGenericParameters);
149+
Debug.Assert(!constructorWithoutAllocation || method is RuntimeConstructorInfo);
146150

147-
bool emitNew = method is RuntimeConstructorInfo;
151+
bool emitNew = method is RuntimeConstructorInfo && !constructorWithoutAllocation;
148152
bool hasThis = !(emitNew || method.IsStatic);
149153

150154
// The first parameter is unused but supports treating the DynamicMethod as an instance method which is slightly faster than a static.
@@ -190,7 +194,7 @@ public static InvokeFunc_RefArgs CreateInvokeDelegate_RefArgs(MethodBase method,
190194
}
191195
}
192196

193-
EmitCallAndReturnHandling(il, method, emitNew, backwardsCompat);
197+
EmitCallAndReturnHandling(il, method, emitNew, backwardsCompat, constructorWithoutAllocation);
194198

195199
// Create the delegate; it is also compiled at this point due to restrictedSkipVisibility=true.
196200
return (InvokeFunc_RefArgs)dm.CreateDelegate(typeof(InvokeFunc_RefArgs), target: null);
@@ -205,7 +209,7 @@ private static void Unbox(ILGenerator il, Type parameterType)
205209
il.Emit(OpCodes.Ldobj, parameterType);
206210
}
207211

208-
private static void EmitCallAndReturnHandling(ILGenerator il, MethodBase method, bool emitNew, bool backwardsCompat)
212+
private static void EmitCallAndReturnHandling(ILGenerator il, MethodBase method, bool emitNew, bool backwardsCompat, bool constructorWithoutAllocation = false)
209213
{
210214
// For CallStack reasons, don't inline target method.
211215
// Mono interpreter does not support\need this.
@@ -224,6 +228,11 @@ private static void EmitCallAndReturnHandling(ILGenerator il, MethodBase method,
224228
{
225229
il.Emit(OpCodes.Newobj, (ConstructorInfo)method);
226230
}
231+
else if (method is RuntimeConstructorInfo)
232+
{
233+
// Constructor invocation on an existing target object.
234+
il.Emit(OpCodes.Call, (ConstructorInfo)method);
235+
}
227236
else if (method.IsStatic || method.DeclaringType!.IsValueType)
228237
{
229238
il.Emit(OpCodes.Call, (MethodInfo)method);
@@ -242,6 +251,10 @@ private static void EmitCallAndReturnHandling(ILGenerator il, MethodBase method,
242251
il.Emit(OpCodes.Box, returnType);
243252
}
244253
}
254+
else if (constructorWithoutAllocation)
255+
{
256+
il.Emit(OpCodes.Ldnull);
257+
}
245258
else
246259
{
247260
RuntimeType returnType;

0 commit comments

Comments
 (0)