Enable Mono for using faster invoke stubs (#89108)
authorSteve Harter <steveharter@users.noreply.github.com>
Tue, 25 Jul 2023 15:46:11 +0000 (10:46 -0500)
committerGitHub <noreply@github.com>
Tue, 25 Jul 2023 15:46:11 +0000 (10:46 -0500)
src/libraries/System.Private.CoreLib/src/System/Reflection/InvokeUtils.cs
src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs
src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs
src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvokerCommon.cs
src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs

index b128d70..1471d1d 100644 (file)
@@ -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);
 
index e99a79b..a850553 100644 (file)
@@ -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) })!;
index d82b718..30e250d 100644 (file)
@@ -80,14 +80,14 @@ namespace System.Reflection
             bool copyBack = false;
             Span<bool> 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<object?> copyOfArgs = stackArgStorage._args.AsSpan(_argCount);
             Span<bool> 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.
index b21900a..191228b 100644 (file)
@@ -107,12 +107,11 @@ namespace System.Reflection
             }
             else
             {
-#if !MONO // Temporary until Mono can unbox a true Nullable<T>
                 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<T>
                 if (RuntimeFeature.IsDynamicCodeSupported)
                 {
                     invokeFunc_Obj4Args = CreateInvokeDelegate_Obj4Args(method, backwardsCompat);
                 }
-#endif
+
                 strategy |= InvokerStrategy.StrategyDetermined_Obj4Args;
             }
         }
index 0322094..5405392 100644 (file)
@@ -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();