From 2427b67722a40fed059241de920b17d9fe8c82b3 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Tue, 25 Jul 2023 10:46:11 -0500 Subject: [PATCH] Enable Mono for using faster invoke stubs (#89108) --- .../src/System/Reflection/InvokeUtils.cs | 8 +------ .../src/System/Reflection/InvokerEmitUtil.cs | 21 +++++++++++++---- .../src/System/Reflection/MethodBaseInvoker.cs | 27 +++++++++++----------- .../src/System/Reflection/MethodInvokerCommon.cs | 6 ++--- .../src/System/RuntimeType.Mono.cs | 4 ++-- 5 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokeUtils.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokeUtils.cs index b128d70..1471d1d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokeUtils.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokeUtils.cs @@ -111,18 +111,12 @@ namespace System.Reflection private static bool TryConvertPointer(object srcObject, [NotNullWhen(true)] out object? dstPtr) { - if (srcObject is IntPtr) + if (srcObject is IntPtr or UIntPtr) { dstPtr = srcObject; return true; } - if (srcObject is UIntPtr) - { - dstPtr = (IntPtr)(UIntPtr)srcObject; - return true; - } - // The source pointer should already have been converted to an IntPtr. Debug.Assert(srcObject is not Pointer); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs index e99a79b..a850553 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs @@ -69,11 +69,11 @@ namespace System.Reflection if (parameterType.IsPointer) { - il.Emit(OpCodes.Unbox_Any, typeof(IntPtr)); + Unbox(il, typeof(IntPtr)); } else if (parameterType.IsValueType) { - il.Emit(OpCodes.Unbox_Any, parameterType); + Unbox(il, parameterType); } } @@ -126,11 +126,11 @@ namespace System.Reflection if (parameterType.IsPointer) { - il.Emit(OpCodes.Unbox_Any, typeof(IntPtr)); + Unbox(il, typeof(IntPtr)); } else if (parameterType.IsValueType) { - il.Emit(OpCodes.Unbox_Any, parameterType); + Unbox(il, parameterType); } } @@ -196,6 +196,15 @@ namespace System.Reflection return (InvokeFunc_RefArgs)dm.CreateDelegate(typeof(InvokeFunc_RefArgs), target: null); } + private static void Unbox(ILGenerator il, Type parameterType) + { + // Unbox without using OpCodes.Unbox\UnboxAny to avoid a type check since that was already done by reflection. + // Also required for unboxing true nullables created by reflection since that is not necessarily a valid CLI operation. + Debug.Assert(parameterType.IsValueType); + il.Emit(OpCodes.Call, Methods.Object_GetRawData()); + il.Emit(OpCodes.Ldobj, parameterType); + } + private static void EmitCallAndReturnHandling(ILGenerator il, MethodBase method, bool emitNew, bool backwardsCompat) { // For CallStack reasons, don't inline target method. @@ -316,6 +325,10 @@ namespace System.Reflection public static MethodInfo ThrowHelper_Throw_NullReference_InvokeNullRefReturned() => s_ThrowHelper_Throw_NullReference_InvokeNullRefReturned ??= typeof(ThrowHelper).GetMethod(nameof(ThrowHelper.Throw_NullReference_InvokeNullRefReturned))!; + private static MethodInfo? s_Object_GetRawData; + public static MethodInfo Object_GetRawData() => + s_Object_GetRawData ??= typeof(RuntimeHelpers).GetMethod(nameof(RuntimeHelpers.GetRawData), BindingFlags.NonPublic | BindingFlags.Static)!; + private static MethodInfo? s_Pointer_Box; public static MethodInfo Pointer_Box() => s_Pointer_Box ??= typeof(Pointer).GetMethod(nameof(Pointer.Box), new[] { typeof(void*), typeof(Type) })!; diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs index d82b718..30e250d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs @@ -80,14 +80,14 @@ namespace System.Reflection bool copyBack = false; Span shouldCopyBack = new(ref copyBack); - CheckArguments(parametersSpan, copyOfArgs, shouldCopyBack, binder, culture, invokeAttr); - object? ret; if ((_strategy & InvokerStrategy.StrategyDetermined_ObjSpanArgs) == 0) { DetermineStrategy_ObjSpanArgs(ref _strategy, ref _invokeFunc_ObjSpanArgs, _method, _needsByRefStrategy, backwardsCompat: true); } + CheckArguments(parametersSpan, copyOfArgs, shouldCopyBack, binder, culture, invokeAttr); + if (_invokeFunc_ObjSpanArgs is not null) { try @@ -98,12 +98,12 @@ namespace System.Reflection { throw new TargetInvocationException(e); } - - CopyBack(parameters, copyOfArgs, shouldCopyBack); - return ret; + } + else + { + ret = InvokeDirectByRefWithFewArgs(obj, copyOfArgs, invokeAttr); } - ret = InvokeDirectByRefWithFewArgs(obj, copyOfArgs, invokeAttr); CopyBack(parameters, copyOfArgs, shouldCopyBack); return ret; } @@ -121,14 +121,14 @@ namespace System.Reflection Span copyOfArgs = stackArgStorage._args.AsSpan(_argCount); Span shouldCopyBack = stackArgStorage._shouldCopyBack.AsSpan(_argCount); - CheckArguments(parameters, copyOfArgs, shouldCopyBack, binder, culture, invokeAttr); - object? ret; if ((_strategy & InvokerStrategy.StrategyDetermined_ObjSpanArgs) == 0) { DetermineStrategy_ObjSpanArgs(ref _strategy, ref _invokeFunc_ObjSpanArgs, _method, _needsByRefStrategy, backwardsCompat: true); } + CheckArguments(parameters, copyOfArgs, shouldCopyBack, binder, culture, invokeAttr); + if (_invokeFunc_ObjSpanArgs is not null) { try @@ -139,12 +139,13 @@ namespace System.Reflection { throw new TargetInvocationException(e); } - - CopyBack(parameters, copyOfArgs, shouldCopyBack); - return ret; } + else + { + ret = InvokeDirectByRefWithFewArgs(obj, copyOfArgs, invokeAttr); + + } - ret = InvokeDirectByRefWithFewArgs(obj, copyOfArgs, invokeAttr); CopyBack(parameters, copyOfArgs, shouldCopyBack); return ret; } @@ -378,7 +379,7 @@ namespace System.Reflection } else if (!ReferenceEquals(arg.GetType(), sigType)) { - // Determine if we can use the fast path for byref types + // Determine if we can use the fast path for byref types. if (TryByRefFastPath(sigType, ref arg)) { // Fast path when the value's type matches the signature type of a byref parameter. diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvokerCommon.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvokerCommon.cs index b21900a..191228b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvokerCommon.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvokerCommon.cs @@ -107,12 +107,11 @@ namespace System.Reflection } else { -#if !MONO // Temporary until Mono can unbox a true Nullable if (RuntimeFeature.IsDynamicCodeSupported) { invokeFunc_ObjSpanArgs = CreateInvokeDelegate_ObjSpanArgs(method, backwardsCompat); } -#endif + strategy |= InvokerStrategy.StrategyDetermined_ObjSpanArgs; } } @@ -136,12 +135,11 @@ namespace System.Reflection } else { -#if !MONO // Temporary until Mono can unbox a true Nullable if (RuntimeFeature.IsDynamicCodeSupported) { invokeFunc_Obj4Args = CreateInvokeDelegate_Obj4Args(method, backwardsCompat); } -#endif + strategy |= InvokerStrategy.StrategyDetermined_Obj4Args; } } diff --git a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs index 0322094..5405392 100644 --- a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs @@ -1792,9 +1792,9 @@ namespace System } else if (IsPointer) { - Type? vtype = value.GetType(); - if (vtype == typeof(IntPtr) || vtype == typeof(UIntPtr)) + if (value is IntPtr or UIntPtr) return CheckValueStatus.Success; + if (value is Pointer pointer) { Type pointerType = pointer.GetPointerType(); -- 2.7.4