Skip to content

Commit 2427b67

Browse files
authored
Enable Mono for using faster invoke stubs (#89108)
1 parent 12396a3 commit 2427b67

File tree

5 files changed

+36
-30
lines changed

5 files changed

+36
-30
lines changed

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

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,12 @@ public static object ConvertOrWiden(Type srcType, object srcObject, Type dstType
111111

112112
private static bool TryConvertPointer(object srcObject, [NotNullWhen(true)] out object? dstPtr)
113113
{
114-
if (srcObject is IntPtr)
114+
if (srcObject is IntPtr or UIntPtr)
115115
{
116116
dstPtr = srcObject;
117117
return true;
118118
}
119119

120-
if (srcObject is UIntPtr)
121-
{
122-
dstPtr = (IntPtr)(UIntPtr)srcObject;
123-
return true;
124-
}
125-
126120
// The source pointer should already have been converted to an IntPtr.
127121
Debug.Assert(srcObject is not Pointer);
128122

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

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ public static unsafe InvokeFunc_Obj4Args CreateInvokeDelegate_Obj4Args(MethodBas
6969

7070
if (parameterType.IsPointer)
7171
{
72-
il.Emit(OpCodes.Unbox_Any, typeof(IntPtr));
72+
Unbox(il, typeof(IntPtr));
7373
}
7474
else if (parameterType.IsValueType)
7575
{
76-
il.Emit(OpCodes.Unbox_Any, parameterType);
76+
Unbox(il, parameterType);
7777
}
7878
}
7979

@@ -126,11 +126,11 @@ public static unsafe InvokeFunc_ObjSpanArgs CreateInvokeDelegate_ObjSpanArgs(Met
126126

127127
if (parameterType.IsPointer)
128128
{
129-
il.Emit(OpCodes.Unbox_Any, typeof(IntPtr));
129+
Unbox(il, typeof(IntPtr));
130130
}
131131
else if (parameterType.IsValueType)
132132
{
133-
il.Emit(OpCodes.Unbox_Any, parameterType);
133+
Unbox(il, parameterType);
134134
}
135135
}
136136

@@ -196,6 +196,15 @@ public static unsafe InvokeFunc_RefArgs CreateInvokeDelegate_RefArgs(MethodBase
196196
return (InvokeFunc_RefArgs)dm.CreateDelegate(typeof(InvokeFunc_RefArgs), target: null);
197197
}
198198

199+
private static void Unbox(ILGenerator il, Type parameterType)
200+
{
201+
// Unbox without using OpCodes.Unbox\UnboxAny to avoid a type check since that was already done by reflection.
202+
// Also required for unboxing true nullables created by reflection since that is not necessarily a valid CLI operation.
203+
Debug.Assert(parameterType.IsValueType);
204+
il.Emit(OpCodes.Call, Methods.Object_GetRawData());
205+
il.Emit(OpCodes.Ldobj, parameterType);
206+
}
207+
199208
private static void EmitCallAndReturnHandling(ILGenerator il, MethodBase method, bool emitNew, bool backwardsCompat)
200209
{
201210
// For CallStack reasons, don't inline target method.
@@ -316,6 +325,10 @@ public static MethodInfo Span_get_Item() =>
316325
public static MethodInfo ThrowHelper_Throw_NullReference_InvokeNullRefReturned() =>
317326
s_ThrowHelper_Throw_NullReference_InvokeNullRefReturned ??= typeof(ThrowHelper).GetMethod(nameof(ThrowHelper.Throw_NullReference_InvokeNullRefReturned))!;
318327

328+
private static MethodInfo? s_Object_GetRawData;
329+
public static MethodInfo Object_GetRawData() =>
330+
s_Object_GetRawData ??= typeof(RuntimeHelpers).GetMethod(nameof(RuntimeHelpers.GetRawData), BindingFlags.NonPublic | BindingFlags.Static)!;
331+
319332
private static MethodInfo? s_Pointer_Box;
320333
public static MethodInfo Pointer_Box() =>
321334
s_Pointer_Box ??= typeof(Pointer).GetMethod(nameof(Pointer.Box), new[] { typeof(void*), typeof(Type) })!;

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

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,14 @@ internal static void ThrowTargetParameterCountException()
8080
bool copyBack = false;
8181
Span<bool> shouldCopyBack = new(ref copyBack);
8282

83-
CheckArguments(parametersSpan, copyOfArgs, shouldCopyBack, binder, culture, invokeAttr);
84-
8583
object? ret;
8684
if ((_strategy & InvokerStrategy.StrategyDetermined_ObjSpanArgs) == 0)
8785
{
8886
DetermineStrategy_ObjSpanArgs(ref _strategy, ref _invokeFunc_ObjSpanArgs, _method, _needsByRefStrategy, backwardsCompat: true);
8987
}
9088

89+
CheckArguments(parametersSpan, copyOfArgs, shouldCopyBack, binder, culture, invokeAttr);
90+
9191
if (_invokeFunc_ObjSpanArgs is not null)
9292
{
9393
try
@@ -98,12 +98,12 @@ internal static void ThrowTargetParameterCountException()
9898
{
9999
throw new TargetInvocationException(e);
100100
}
101-
102-
CopyBack(parameters, copyOfArgs, shouldCopyBack);
103-
return ret;
101+
}
102+
else
103+
{
104+
ret = InvokeDirectByRefWithFewArgs(obj, copyOfArgs, invokeAttr);
104105
}
105106

106-
ret = InvokeDirectByRefWithFewArgs(obj, copyOfArgs, invokeAttr);
107107
CopyBack(parameters, copyOfArgs, shouldCopyBack);
108108
return ret;
109109
}
@@ -121,14 +121,14 @@ internal static void ThrowTargetParameterCountException()
121121
Span<object?> copyOfArgs = stackArgStorage._args.AsSpan(_argCount);
122122
Span<bool> shouldCopyBack = stackArgStorage._shouldCopyBack.AsSpan(_argCount);
123123

124-
CheckArguments(parameters, copyOfArgs, shouldCopyBack, binder, culture, invokeAttr);
125-
126124
object? ret;
127125
if ((_strategy & InvokerStrategy.StrategyDetermined_ObjSpanArgs) == 0)
128126
{
129127
DetermineStrategy_ObjSpanArgs(ref _strategy, ref _invokeFunc_ObjSpanArgs, _method, _needsByRefStrategy, backwardsCompat: true);
130128
}
131129

130+
CheckArguments(parameters, copyOfArgs, shouldCopyBack, binder, culture, invokeAttr);
131+
132132
if (_invokeFunc_ObjSpanArgs is not null)
133133
{
134134
try
@@ -139,12 +139,13 @@ internal static void ThrowTargetParameterCountException()
139139
{
140140
throw new TargetInvocationException(e);
141141
}
142-
143-
CopyBack(parameters, copyOfArgs, shouldCopyBack);
144-
return ret;
145142
}
143+
else
144+
{
145+
ret = InvokeDirectByRefWithFewArgs(obj, copyOfArgs, invokeAttr);
146+
147+
}
146148

147-
ret = InvokeDirectByRefWithFewArgs(obj, copyOfArgs, invokeAttr);
148149
CopyBack(parameters, copyOfArgs, shouldCopyBack);
149150
return ret;
150151
}
@@ -378,7 +379,7 @@ BindingFlags invokeAttr
378379
}
379380
else if (!ReferenceEquals(arg.GetType(), sigType))
380381
{
381-
// Determine if we can use the fast path for byref types
382+
// Determine if we can use the fast path for byref types.
382383
if (TryByRefFastPath(sigType, ref arg))
383384
{
384385
// Fast path when the value's type matches the signature type of a byref parameter.

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,11 @@ ref InvokeFunc_ObjSpanArgs?
107107
}
108108
else
109109
{
110-
#if !MONO // Temporary until Mono can unbox a true Nullable<T>
111110
if (RuntimeFeature.IsDynamicCodeSupported)
112111
{
113112
invokeFunc_ObjSpanArgs = CreateInvokeDelegate_ObjSpanArgs(method, backwardsCompat);
114113
}
115-
#endif
114+
116115
strategy |= InvokerStrategy.StrategyDetermined_ObjSpanArgs;
117116
}
118117
}
@@ -136,12 +135,11 @@ internal static void DetermineStrategy_Obj4Args(
136135
}
137136
else
138137
{
139-
#if !MONO // Temporary until Mono can unbox a true Nullable<T>
140138
if (RuntimeFeature.IsDynamicCodeSupported)
141139
{
142140
invokeFunc_Obj4Args = CreateInvokeDelegate_Obj4Args(method, backwardsCompat);
143141
}
144-
#endif
142+
145143
strategy |= InvokerStrategy.StrategyDetermined_Obj4Args;
146144
}
147145
}

src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,9 +1792,9 @@ private CheckValueStatus TryChangeTypeSpecial(
17921792
}
17931793
else if (IsPointer)
17941794
{
1795-
Type? vtype = value.GetType();
1796-
if (vtype == typeof(IntPtr) || vtype == typeof(UIntPtr))
1795+
if (value is IntPtr or UIntPtr)
17971796
return CheckValueStatus.Success;
1797+
17981798
if (value is Pointer pointer)
17991799
{
18001800
Type pointerType = pointer.GetPointerType();

0 commit comments

Comments
 (0)