Delete DelegateInvokeThunk (#72903)
authorJan Kotas <jkotas@microsoft.com>
Wed, 27 Jul 2022 07:07:03 +0000 (00:07 -0700)
committerGitHub <noreply@github.com>
Wed, 27 Jul 2022 07:07:03 +0000 (16:07 +0900)
- DelegateInvokeThunk used by Delegate.DynamicInvoke was redundant with delegate Invoke method that is always preserved for delegates. The implementation of the DelegateInvokeThunk was even piggy backing on the delegate Invoke method for default parameter values.
- Add generic cache for per-type scenario specific data. Switched over Enum info to use it (same as CoreCLR), and leverage it for caching of the dynamic delegate info.
- nullability annotation fixes

This is prep-work for #72548

28 files changed:
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Augments/ReflectionAugments.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Core/Execution/ExecutionEnvironment.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Core/Execution/MethodInvoker.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/ReflectionExecutionDomainCallbacks.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Delegate.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/DelegateDynamicInvokeInfo.cs [new file with mode: 0644]
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvoker.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/OpenMethodInvoker.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.TypeComponentsCache.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs
src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Reflection/ReflectionCoreCallbacksImplementation.cs
src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Reflection/ReflectionExecutionDomainCallbacksImplementation.cs
src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.Runtime.cs
src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/MethodInvokers/InstanceMethodInvoker.cs
src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/MethodInvokers/MethodInvokerWithMethodInvokeInfo.cs
src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/MethodInvokers/StaticMethodInvoker.cs
src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/MethodInvokers/VirtualMethodInvoker.cs
src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ReflectionExecutionDomainCallbacksImplementation.cs
src/coreclr/tools/Common/TypeSystem/IL/DelegateInfo.cs
src/coreclr/tools/Common/TypeSystem/IL/Stubs/DelegateThunks.cs

index 1ee466f..ff03a2c 100644 (file)
@@ -166,5 +166,7 @@ namespace Internal.Reflection.Augments
         public abstract Assembly[] GetLoadedAssemblies();
 
         public abstract EnumInfo GetEnumInfo(Type type);
+
+        public abstract DelegateDynamicInvokeInfo GetDelegateDynamicInvokeInfo(Type type);
     }
 }
index 00d4529..7942977 100644 (file)
@@ -98,6 +98,7 @@ namespace Internal.Reflection.Core.Execution
         //==============================================================================================
         public abstract FieldAccessor CreateLiteralFieldAccessor(object value, RuntimeTypeHandle fieldTypeHandle);
         public abstract EnumInfo GetEnumInfo(RuntimeTypeHandle typeHandle);
+        public abstract IntPtr GetDynamicInvokeThunk(MethodInvoker invoker, out IntPtr genericDictionary);
 
         //==============================================================================================
         // Non-public methods
index 8ddf492..fe85e92 100644 (file)
@@ -30,7 +30,7 @@ namespace Internal.Reflection.Core.Execution
             System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
             return result;
         }
-        protected abstract object? Invoke(object? thisObject, object?[] arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException);
+        protected abstract object? Invoke(object? thisObject, object?[]? arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException);
         public abstract Delegate CreateDelegate(RuntimeTypeHandle delegateType, object target, bool isStatic, bool isVirtual, bool isOpen);
 
         // This property is used to retrieve the target method pointer. It is used by the RuntimeMethodHandle.GetFunctionPointer API
index ea5e805..fdd5ba2 100644 (file)
@@ -50,17 +50,6 @@ namespace Internal.Runtime.Augments
         public abstract MethodBase GetMethodBaseFromStartAddressIfAvailable(IntPtr methodStartAddress);
         public abstract Assembly GetAssemblyForHandle(RuntimeTypeHandle typeHandle);
 
-        /// <summary>
-        /// Retrieves the default value for a parameter of a method.
-        /// </summary>
-        /// <param name="defaultParametersContext">The default parameters context used to invoke the method,
-        /// this should identify the method in question. This is passed to the RuntimeAugments.CallDynamicInvokeMethod.</param>
-        /// <param name="thType">The type of the parameter to retrieve.</param>
-        /// <param name="argIndex">The index of the parameter on the method to retrieve.</param>
-        /// <param name="defaultValue">The default value of the parameter if available.</param>
-        /// <returns>true if the default parameter value is available, otherwise false.</returns>
-        public abstract bool TryGetDefaultParameterValue(object defaultParametersContext, RuntimeTypeHandle thType, int argIndex, out object defaultValue);
-
         public abstract RuntimeTypeHandle GetTypeHandleIfAvailable(Type type);
         public abstract bool SupportsReflection(Type type);
 
index ebf9a55..6aaee12 100644 (file)
@@ -17,6 +17,7 @@
 //    Reflection.Execution.dll
 
 using System;
+using System.Reflection;
 using System.Runtime;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
@@ -360,23 +361,23 @@ namespace Internal.Runtime.Augments
         public static unsafe int ObjectHeaderSize => sizeof(EETypePtr);
 
         [DebuggerGuidedStepThroughAttribute]
-        public static object CallDynamicInvokeMethod(
-            object thisPtr,
+        public static object? CallDynamicInvokeMethod(
+            object? thisPtr,
             IntPtr methodToCall,
             IntPtr dynamicInvokeHelperMethod,
             IntPtr dynamicInvokeHelperGenericDictionary,
-            object defaultParametersContext,
-            object[] parameters,
+            MethodBase targetMethod,
+            object?[]? parameters,
             BinderBundle binderBundle,
             bool wrapInTargetInvocationException,
             bool methodToCallIsThisCall)
         {
-            object result = InvokeUtils.CallDynamicInvokeMethod(
+            object? result = InvokeUtils.CallDynamicInvokeMethod(
                 thisPtr,
                 methodToCall,
                 dynamicInvokeHelperMethod,
                 dynamicInvokeHelperGenericDictionary,
-                defaultParametersContext,
+                targetMethod,
                 parameters,
                 binderBundle,
                 wrapInTargetInvocationException,
index 5790623..941bb14 100644 (file)
     <Compile Include="System\Reflection\Attribute.NativeAot.cs" />
     <Compile Include="System\Reflection\Assembly.NativeAot.cs" />
     <Compile Include="System\Reflection\BinderBundle.cs" />
+    <Compile Include="System\Reflection\DelegateDynamicInvokeInfo.cs" />
     <Compile Include="System\Reflection\Emit\AssemblyBuilder.cs" />
     <Compile Include="System\Reflection\Emit\ConstructorBuilder.cs" />
     <Compile Include="System\Reflection\Emit\CustomAttributeBuilder.cs" />
index cdb12aa..9250223 100644 (file)
@@ -52,9 +52,8 @@ namespace System
         private protected const int ClosedStaticThunk = 1;
         private protected const int OpenStaticThunk = 2;
         private protected const int ClosedInstanceThunkOverGenericMethod = 3; // This may not exist
-        private protected const int DelegateInvokeThunk = 4;
-        private protected const int OpenInstanceThunk = 5;        // This may not exist
-        private protected const int ObjectArrayThunk = 6;         // This may not exist
+        private protected const int OpenInstanceThunk = 4;        // This may not exist
+        private protected const int ObjectArrayThunk = 5;         // This may not exist
 
         //
         // If the thunk does not exist, the function will return IntPtr.Zero.
@@ -266,31 +265,22 @@ namespace System
         }
 
         [DebuggerGuidedStepThroughAttribute]
-        protected virtual object DynamicInvokeImpl(object?[]? args)
+        protected virtual object? DynamicInvokeImpl(object?[]? args)
         {
             if (IsDynamicDelegate())
             {
                 // DynamicDelegate case
-                object result = ((Func<object?[]?, object>)m_helperObject)(args);
+                object? result = ((Func<object?[]?, object?>)m_helperObject)(args);
                 DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
                 return result;
             }
             else
             {
-                IntPtr invokeThunk = this.GetThunk(DelegateInvokeThunk);
+                DelegateDynamicInvokeInfo invokeInfo = ReflectionAugments.ReflectionCoreCallbacks.GetDelegateDynamicInvokeInfo(GetType());
 
-                IntPtr genericDictionary = IntPtr.Zero;
-                if (FunctionPointerOps.IsGenericMethodPointer(invokeThunk))
-                {
-                    unsafe
-                    {
-                        GenericMethodDescriptor* descriptor = FunctionPointerOps.ConvertToGenericDescriptor(invokeThunk);
-                        genericDictionary = descriptor->InstantiationArgument;
-                        invokeThunk = descriptor->MethodFunctionPointer;
-                    }
-                }
-
-                object result = InvokeUtils.CallDynamicInvokeMethod(this.m_firstParameter, this.m_functionPointer, invokeThunk, genericDictionary, this, args, binderBundle: null, wrapInTargetInvocationException: true);
+                object? result = InvokeUtils.CallDynamicInvokeMethod(m_firstParameter, m_functionPointer,
+                    invokeInfo.InvokeThunk, invokeInfo.GenericDictionary, invokeInfo.InvokeMethod,
+                    args, binderBundle: null, wrapInTargetInvocationException: true);
                 DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
                 return result;
             }
index 1b87d59..325b286 100644 (file)
@@ -311,61 +311,54 @@ namespace System
             public object?[]? parameters;
             public object[] nullableCopyBackObjects;
             public int curIndex;
-            public object targetMethodOrDelegate;
+            public MethodBase targetMethod;
             public BinderBundle? binderBundle;
             public object?[] customBinderProvidedParameters;
         }
 
-        private static object GetDefaultValue(object targetMethodOrDelegate, RuntimeTypeHandle thType, int argIndex)
+        private static object GetDefaultValue(MethodBase targetMethod, int argIndex)
         {
-            if (targetMethodOrDelegate == null)
+            ParameterInfo parameterInfo = targetMethod.GetParametersNoCopy()[argIndex];
+            if (!parameterInfo.HasDefaultValue)
             {
-                throw new ArgumentException(SR.Arg_VarMissNull);
+                // If the parameter is optional, with no default value and we're asked for its default value,
+                // it means the caller specified Missing.Value as the value for the parameter. In this case the behavior
+                // is defined as passing in the Missing.Value, regardless of the parameter type.
+                // If Missing.Value is convertible to the parameter type, it will just work, otherwise we will fail
+                // due to type mismatch.
+                if (!parameterInfo.IsOptional)
+                    throw new ArgumentException(SR.Arg_VarMissNull, "parameters");
+
+                return Missing.Value;
             }
 
-            bool hasDefaultValue = RuntimeAugments.Callbacks.TryGetDefaultParameterValue(targetMethodOrDelegate, thType, argIndex, out object defaultValue);
-            if (!hasDefaultValue)
-            {
-                throw new ArgumentException(SR.Arg_VarMissNull, "parameters");
-            }
-
-            // Note that we might return null even for value types which cannot have null value here.
-            // This case is handled in the CheckArgument method which is called after this one on the returned parameter value.
-            return defaultValue;
+            return parameterInfo.DefaultValue;
         }
 
         // This is only called if we have to invoke a custom binder to coerce a parameter type. It leverages s_targetMethodOrDelegate to retrieve
         // the unaltered parameter type to pass to the binder.
         private static Type GetExactTypeForCustomBinder(in ArgSetupState argSetupState)
         {
-            Debug.Assert(argSetupState.binderBundle != null && argSetupState.targetMethodOrDelegate is MethodBase);
-            MethodBase method = (MethodBase)argSetupState.targetMethodOrDelegate;
-
             // DynamicInvokeParamHelperCore() increments s_curIndex before calling us - that's why we have to subtract 1.
-            return method.GetParametersNoCopy()[argSetupState.curIndex - 1].ParameterType;
+            return argSetupState.targetMethod.GetParametersNoCopy()[argSetupState.curIndex - 1].ParameterType;
         }
 
         [DebuggerGuidedStepThroughAttribute]
         internal static unsafe object CallDynamicInvokeMethod(
-            object thisPtr,
+            object? thisPtr,
             IntPtr methodToCall,
             IntPtr dynamicInvokeHelperMethod,
             IntPtr dynamicInvokeHelperGenericDictionary,
-            object targetMethodOrDelegate,
+            MethodBase targetMethod,
             object?[]? parameters,
             BinderBundle? binderBundle,
             bool wrapInTargetInvocationException,
             bool methodToCallIsThisCall = true)
         {
-            // This assert is needed because we've double-purposed "targetMethodOrDelegate" (which is actually a MethodBase anytime a custom binder is used)
-            // as a way of obtaining the true parameter type which we need to pass to Binder.ChangeType(). (The type normally passed to DynamicInvokeParamHelperCore
-            // isn't always the exact type (byref stripped off, enums converted to int, etc.)
-            Debug.Assert(!(binderBundle != null && !(targetMethodOrDelegate is MethodBase)), "The only callers that can pass a custom binder are those servicing MethodBase.Invoke() apis.");
-
             ArgSetupState argSetupState = new ArgSetupState
             {
                 binderBundle = binderBundle,
-                targetMethodOrDelegate = targetMethodOrDelegate,
+                targetMethod = targetMethod
             };
 
             {
@@ -571,7 +564,7 @@ namespace System
             // Handle default parameters
             if ((incomingParam == System.Reflection.Missing.Value) && paramType == DynamicInvokeParamType.In)
             {
-                incomingParam = GetDefaultValue(argSetupState.targetMethodOrDelegate, type, index);
+                incomingParam = GetDefaultValue(argSetupState.targetMethod, index);
                 if (incomingParam != null && nullable)
                 {
                     // In case if the parameter is nullable Enum type the ParameterInfo.DefaultValue returns a raw value which
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/DelegateDynamicInvokeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/DelegateDynamicInvokeInfo.cs
new file mode 100644 (file)
index 0000000..7fd5cad
--- /dev/null
@@ -0,0 +1,23 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Runtime;
+using System.Runtime.CompilerServices;
+
+namespace System.Reflection
+{
+    [ReflectionBlocked]
+    public sealed class DelegateDynamicInvokeInfo
+    {
+        public DelegateDynamicInvokeInfo()
+        {
+        }
+
+        internal MethodInfo InvokeMethod { get; init; }
+        internal IntPtr InvokeThunk { get; init; }
+        internal IntPtr GenericDictionary { get; init; }
+    }
+}
index 00165a6..da84727 100644 (file)
@@ -404,6 +404,40 @@ namespace System.Reflection.Runtime.General
 
         public sealed override Assembly[] GetLoadedAssemblies() => RuntimeAssemblyInfo.GetLoadedAssemblies();
 
-        public sealed override EnumInfo GetEnumInfo(Type type) => type.CastToRuntimeTypeInfo().EnumInfo;
+        public sealed override EnumInfo GetEnumInfo(Type type)
+        {
+            RuntimeTypeInfo runtimeType = type.CastToRuntimeTypeInfo();
+
+            EnumInfo? info = runtimeType.GenericCache as EnumInfo;
+            if (info != null)
+                return info;
+
+            info = ReflectionCoreExecution.ExecutionDomain.ExecutionEnvironment.GetEnumInfo(runtimeType.TypeHandle);
+            runtimeType.GenericCache = info;
+            return info;
+        }
+
+        public sealed override DelegateDynamicInvokeInfo GetDelegateDynamicInvokeInfo(Type type)
+        {
+            RuntimeTypeInfo runtimeType = type.CastToRuntimeTypeInfo();
+
+            DelegateDynamicInvokeInfo? info = runtimeType.GenericCache as DelegateDynamicInvokeInfo;
+            if (info != null)
+                return info;
+
+            RuntimeMethodInfo invokeMethod = runtimeType.GetInvokeMethod();
+
+            MethodInvoker methodInvoker = invokeMethod.MethodInvoker;
+            IntPtr invokeThunk = ReflectionCoreExecution.ExecutionDomain.ExecutionEnvironment.GetDynamicInvokeThunk(methodInvoker, out IntPtr genericDictionary);
+
+            info = new DelegateDynamicInvokeInfo()
+            {
+                InvokeMethod = invokeMethod,
+                InvokeThunk = invokeThunk,
+                GenericDictionary = genericDictionary
+            };
+            runtimeType.GenericCache = info;
+            return info;
+        }
     }
 }
index 3ae697e..d0b3cab 100644 (file)
@@ -21,19 +21,18 @@ namespace System.Reflection.Runtime.MethodInfos
             _parameterTypes = parameterTypes;
         }
 
-        protected sealed override object? Invoke(object? thisObject, object?[] arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
+        protected sealed override object? Invoke(object? thisObject, object?[]? arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
         {
-            Debug.Assert(arguments != null);
-
             // This does not handle optional parameters. None of the methods we use custom invocation for have them.
             if (!(thisObject == null && 0 != (_options & InvokerOptions.AllowNullThis)))
                 ValidateThis(thisObject, _thisType.TypeHandle);
 
-            if (arguments.Length != _parameterTypes.Length)
+            int argCount = (arguments != null) ? arguments.Length : 0;
+            if (argCount != _parameterTypes.Length)
                 throw new TargetParameterCountException();
 
-            object[] convertedArguments = new object[arguments.Length];
-            for (int i = 0; i < arguments.Length; i++)
+            object[] convertedArguments = new object[argCount];
+            for (int i = 0; i < convertedArguments.Length; i++)
             {
                 convertedArguments[i] = RuntimeAugments.CheckArgument(arguments[i], _parameterTypes[i].TypeHandle, binderBundle);
             }
index 49e7f61..7066a5b 100644 (file)
@@ -14,7 +14,7 @@ namespace System.Reflection.Runtime.MethodInfos
 {
     internal sealed class OpenMethodInvoker : MethodInvoker
     {
-        protected sealed override object? Invoke(object? thisObject, object?[] arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
+        protected sealed override object? Invoke(object? thisObject, object?[]? arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
         {
             throw new InvalidOperationException(SR.Arg_UnboundGenParam);
         }
index f1f4075..63c847e 100644 (file)
@@ -163,7 +163,6 @@ namespace System.Reflection.Runtime.MethodInfos
         [DebuggerGuidedStepThroughAttribute]
         public sealed override object? Invoke(object? obj, BindingFlags invokeAttr, Binder binder, object?[]? parameters, CultureInfo culture)
         {
-            parameters ??= Array.Empty<object>();
             MethodInvoker methodInvoker = this.MethodInvoker;
             object? result = methodInvoker.Invoke(obj, parameters, binder, invokeAttr, culture);
             System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
index 655b4fb..56836f9 100644 (file)
@@ -78,8 +78,6 @@ namespace System.Reflection.Runtime.MethodInfos
         [DebuggerGuidedStepThrough]
         public sealed override object Invoke(BindingFlags invokeAttr, Binder? binder, object?[]? parameters, CultureInfo? culture)
         {
-            parameters ??= Array.Empty<object>();
-
             // Most objects are allocated by NewObject and their constructors return "void". But in many frameworks,
             // there are "weird" cases (e.g. String) where the constructor must do both the allocation and initialization.
             // Reflection.Core does not hardcode these special cases. It's up to the ExecutionEnvironment to steer
index 187cbfc..45ee597 100644 (file)
@@ -79,8 +79,6 @@ namespace System.Reflection.Runtime.MethodInfos
         [DebuggerGuidedStepThrough]
         public sealed override object Invoke(BindingFlags invokeAttr, Binder? binder, object?[]? parameters, CultureInfo? culture)
         {
-            parameters ??= Array.Empty<object>();
-
             object ctorAllocatedObject = this.MethodInvoker.Invoke(null, parameters, binder, invokeAttr, culture)!;
             System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
             return ctorAllocatedObject;
index b1631bb..90f4064 100644 (file)
@@ -211,7 +211,15 @@ namespace System.Reflection.Runtime.TypeInfos
 
         private TypeComponentsCache Cache => _lazyCache ??= new TypeComponentsCache(this);
 
-        private volatile TypeComponentsCache _lazyCache;
+        // Generic cache for scenario specific data. For example, it is used to cache Enum names and values.
+        // TODO: This cache should be attached to the RuntimeType via weak reference, similar to how it is done in CoreCLR.
+        internal object? GenericCache
+        {
+            get => _lazyCache?._genericCache;
+            set => Cache._genericCache = value;
+        }
+
+        private volatile TypeComponentsCache? _lazyCache;
 
         private const int GenericParameterCountAny = -1;
     }
index 3888328..eb38835 100644 (file)
@@ -74,8 +74,6 @@ namespace System.Reflection.Runtime.TypeInfos
                 return Unsafe.As<QueriedMemberList<M>>(result);
             }
 
-            public EnumInfo EnumInfo => _lazyEnumInfo ??= ReflectionCoreExecution.ExecutionDomain.ExecutionEnvironment.GetEnumInfo(_type.TypeHandle);
-
             private static object[] CreatePerNameQueryCaches(RuntimeTypeInfo type, bool ignoreCase)
             {
                 object[] perNameCaches = new object[MemberTypeIndex.Count];
@@ -102,7 +100,8 @@ namespace System.Reflection.Runtime.TypeInfos
 
             private readonly RuntimeTypeInfo _type;
 
-            private volatile EnumInfo _lazyEnumInfo;
+            // Generic cache for scenario specific data. For example, it is used to cache Enum names and values.
+            internal object? _genericCache;
 
             //
             // Each PerName cache persists the results of a Type.Get(name, bindingFlags) for a particular MemberInfoType "M".
index d496622..9815e51 100644 (file)
@@ -605,8 +605,6 @@ namespace System.Reflection.Runtime.TypeInfos
             }
         }
 
-        internal EnumInfo EnumInfo => Cache.EnumInfo;
-
         internal abstract Type InternalDeclaringType { get; }
 
         //
index 9f51a21..954eba2 100644 (file)
@@ -21,6 +21,8 @@ namespace Internal.Reflection
                 isFlags: false);
         }
 
+        public override DelegateDynamicInvokeInfo GetDelegateDynamicInvokeInfo(Type type)
+            => throw new NotSupportedException(SR.Reflection_Disabled);
         public override object ActivatorCreateInstance(
             [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
             Type type, bool nonPublic) => throw new NotSupportedException(SR.Reflection_Disabled);
index 11b4305..54f0931 100644 (file)
@@ -26,11 +26,6 @@ namespace Internal.Reflection
         public override RuntimeTypeHandle GetTypeHandleIfAvailable(Type type) => type.TypeHandle;
         public override bool IsReflectionBlocked(RuntimeTypeHandle typeHandle) => false;
         public override bool SupportsReflection(Type type) => false;
-        public override bool TryGetDefaultParameterValue(object defaultParametersContext, RuntimeTypeHandle thType, int argIndex, out object defaultValue)
-        {
-            defaultValue = null;
-            return false;
-        }
         public override IntPtr TryGetStaticClassConstructionContext(RuntimeTypeHandle runtimeTypeHandle) => throw new NotSupportedException(SR.Reflection_Disabled);
     }
 }
index cdb8b89..52b1b0c 100644 (file)
@@ -102,7 +102,7 @@ namespace Internal.Reflection.Execution
                 tMethods[i] = (MethodInfo)methodBase;
                 continue;
 
-notFound:
+            notFound:
                 if (instanceType.IsAbstract)
                 {
                     throw new PlatformNotSupportedException(SR.Format(SR.Arg_InterfaceMapMustNotBeAbstract, interfaceType.FullName, instanceType.FullName));
@@ -162,5 +162,12 @@ notFound:
 #endif
             return null;
         }
+
+        public override IntPtr GetDynamicInvokeThunk(MethodInvoker invoker, out IntPtr genericDictionary)
+        {
+            MethodInvokeInfo invokeInfo = ((MethodInvokerWithMethodInvokeInfo)invoker).MethodInvokeInfo;
+            genericDictionary = invokeInfo.DynamicInvokeGenericDictionary;
+            return invokeInfo.DynamicInvokeMethod;
+        }
     }
 }
index 054d8cd..5a1ab72 100644 (file)
@@ -27,10 +27,10 @@ namespace Internal.Reflection.Execution.MethodInvokers
         }
 
         [DebuggerGuidedStepThroughAttribute]
-        protected sealed override object Invoke(object thisObject, object[] arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
+        protected sealed override object? Invoke(object? thisObject, object?[]? arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
         {
             ValidateThis(thisObject, _declaringTypeHandle);
-            object result = RuntimeAugments.CallDynamicInvokeMethod(
+            object? result = RuntimeAugments.CallDynamicInvokeMethod(
                 thisObject,
                 MethodInvokeInfo.LdFtnResult,
                 MethodInvokeInfo.DynamicInvokeMethod,
index 4e292fc..04bd56e 100644 (file)
@@ -63,6 +63,6 @@ namespace Internal.Reflection.Execution.MethodInvokers
                 return new InstanceMethodInvoker(methodInvokeInfo, declaringTypeHandle);
         }
 
-        protected MethodInvokeInfo MethodInvokeInfo { get; private set; }
+        internal MethodInvokeInfo MethodInvokeInfo { get; private set; }
     }
 }
index 0907ee1..44cc4ab 100644 (file)
@@ -24,9 +24,9 @@ namespace Internal.Reflection.Execution.MethodInvokers
         }
 
         [DebuggerGuidedStepThroughAttribute]
-        protected sealed override object Invoke(object thisObject, object[] arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
+        protected sealed override object? Invoke(object? thisObject, object?[]? arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
         {
-            object result = RuntimeAugments.CallDynamicInvokeMethod(
+            object? result = RuntimeAugments.CallDynamicInvokeMethod(
                 thisObject,
                 MethodInvokeInfo.LdFtnResult,
                 MethodInvokeInfo.DynamicInvokeMethod,
index 1438285..9634e69 100644 (file)
@@ -51,13 +51,13 @@ namespace Internal.Reflection.Execution.MethodInvokers
         }
 
         [DebuggerGuidedStepThroughAttribute]
-        protected sealed override object Invoke(object thisObject, object[] arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
+        protected sealed override object? Invoke(object? thisObject, object?[]? arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
         {
             ValidateThis(thisObject, _declaringTypeHandle);
 
             IntPtr resolvedVirtual = OpenMethodResolver.ResolveMethod(MethodInvokeInfo.VirtualResolveData, thisObject);
 
-            object result = RuntimeAugments.CallDynamicInvokeMethod(
+            object? result = RuntimeAugments.CallDynamicInvokeMethod(
                 thisObject,
                 resolvedVirtual,
                 MethodInvokeInfo.DynamicInvokeMethod,
index 9955490..a7941c1 100644 (file)
@@ -118,63 +118,6 @@ namespace Internal.Reflection.Execution
             return ExecutionEnvironmentImplementation.TryGetStaticClassConstructionContext(runtimeTypeHandle);
         }
 
-        /// <summary>
-        /// Retrieves the default value for a parameter of a method.
-        /// </summary>
-        /// <param name="defaultParametersContext">The default parameters context used to invoke the method,
-        /// this should identify the method in question. This is passed to the RuntimeAugments.CallDynamicInvokeMethod.</param>
-        /// <param name="thType">The type of the parameter to retrieve.</param>
-        /// <param name="argIndex">The index of the parameter on the method to retrieve.</param>
-        /// <param name="defaultValue">The default value of the parameter if available.</param>
-        /// <returns>true if the default parameter value is available, otherwise false.</returns>
-        public sealed override bool TryGetDefaultParameterValue(object defaultParametersContext, RuntimeTypeHandle thType, int argIndex, out object defaultValue)
-        {
-            defaultValue = null;
-
-            MethodBase methodBase = defaultParametersContext as MethodBase;
-            if (methodBase is null)
-            {
-                if (defaultParametersContext is Delegate)
-                {
-                    methodBase = GetDelegateInvokeMethod(defaultParametersContext.GetType());
-                }
-
-                if (methodBase is null)
-                {
-                    return false;
-                }
-
-                [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
-                    Justification = "Delegates always generate metadata for the Invoke method")]
-                static MethodBase GetDelegateInvokeMethod(Type delegateType)
-                {
-                    MethodInfo result = delegateType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
-                    Debug.Assert(result != null);
-                    return result;
-                }
-            }
-
-            ParameterInfo parameterInfo = methodBase.GetParametersNoCopy()[argIndex];
-            if (!parameterInfo.HasDefaultValue)
-            {
-                // If the parameter is optional, with no default value and we're asked for its default value,
-                // it means the caller specified Missing.Value as the value for the parameter. In this case the behavior
-                // is defined as passing in the Missing.Value, regardless of the parameter type.
-                // If Missing.Value is convertible to the parameter type, it will just work, otherwise we will fail
-                // due to type mismatch.
-                if (parameterInfo.IsOptional)
-                {
-                    defaultValue = Missing.Value;
-                    return true;
-                }
-
-                return false;
-            }
-
-            defaultValue = parameterInfo.DefaultValue;
-            return true;
-        }
-
         public sealed override RuntimeTypeHandle GetTypeHandleIfAvailable(Type type)
         {
             return _executionDomain.GetTypeHandleIfAvailable(type);
index d6993f0..1edcea5 100644 (file)
@@ -234,18 +234,16 @@ namespace Internal.IL
         ClosedStaticThunk = 1,
         OpenStaticThunk = 2,
         ClosedInstanceThunkOverGenericMethod = 3, // This may not exist
-        DelegateInvokeThunk = 4,
-        OpenInstanceThunk = 5,        // This may not exist
-        ObjectArrayThunk = 6,         // This may not exist
+        OpenInstanceThunk = 4,        // This may not exist
+        ObjectArrayThunk = 5,         // This may not exist
     }
 
     [Flags]
     public enum DelegateFeature
     {
-        DynamicInvoke = 0x1,
-        ObjectArrayThunk = 0x2,
-        OpenInstanceThunk = 0x4,
+        ObjectArrayThunk = 0x1,
+        OpenInstanceThunk = 0x2,
 
-        All = 0x7,
+        All = 0x3,
     }
 }
index 5e9ed17..55037d7 100644 (file)
@@ -697,15 +697,11 @@ namespace Internal.IL.Stubs
 
             ILCodeLabel returnNullLabel = emitter.NewCodeLabel();
 
-            bool hasDynamicInvokeThunk = (_delegateInfo.SupportedFeatures & DelegateFeature.DynamicInvoke) != 0 &&
-                DynamicInvokeMethodThunk.SupportsSignature(_delegateInfo.Signature);
-
             ILCodeLabel[] labels = new ILCodeLabel[(int)DelegateThunkCollection.MaxThunkKind];
             for (DelegateThunkKind i = 0; i < DelegateThunkCollection.MaxThunkKind; i++)
             {
                 MethodDesc thunk = _delegateInfo.Thunks[i];
-                if (thunk != null || 
-                    (i == DelegateThunkKind.DelegateInvokeThunk && hasDynamicInvokeThunk))
+                if (thunk != null)
                     labels[(int)i] = emitter.NewCodeLabel();
                 else
                     labels[(int)i] = returnNullLabel;
@@ -718,43 +714,15 @@ namespace Internal.IL.Stubs
 
             for (DelegateThunkKind i = 0; i < DelegateThunkCollection.MaxThunkKind; i++)
             {
-                MethodDesc targetMethod = null;
-
-                // Dynamic invoke thunk is special since we're calling into a shared helper
-                if (i == DelegateThunkKind.DelegateInvokeThunk && hasDynamicInvokeThunk)
-                {
-                    Debug.Assert(_delegateInfo.Thunks[i] == null);
-
-                    var sig = new DynamicInvokeMethodSignature(_delegateInfo.Signature);
-                    // TODO: layering violation. Should move delegate thunk stuff to ILCompiler.Compiler.
-                    MethodDesc thunk = ((ILCompiler.CompilerTypeSystemContext)Context).GetDynamicInvokeThunk(sig);
-
-                    if (thunk.HasInstantiation)
-                    {
-                        TypeDesc[] inst = DynamicInvokeMethodThunk.GetThunkInstantiationForMethod(_delegateInfo.Type.InstantiateAsOpen().GetMethod("Invoke", null));
-                        targetMethod = Context.GetInstantiatedMethod(thunk, new Instantiation(inst));
-                    }
-                    else
-                    {
-                        targetMethod = thunk;
-                    }
-                }
-                else
-                {
-                    MethodDesc thunk = _delegateInfo.Thunks[i];
+                MethodDesc thunk = _delegateInfo.Thunks[i];
+                if (thunk == null)
+                    continue;
 
-                    if (thunk != null)
-                    {
-                        targetMethod = thunk.InstantiateAsOpen();
-                    }
-                }
+                MethodDesc targetMethod = thunk.InstantiateAsOpen();
 
-                if (targetMethod != null)
-                {
-                    codeStream.EmitLabel(labels[(int)i]);
-                    codeStream.Emit(ILOpcode.ldftn, emitter.NewToken(targetMethod));
-                    codeStream.Emit(ILOpcode.ret);
-                }
+                codeStream.EmitLabel(labels[(int)i]);
+                codeStream.Emit(ILOpcode.ldftn, emitter.NewToken(targetMethod));
+                codeStream.Emit(ILOpcode.ret);
             }
 
             codeStream.EmitLabel(returnNullLabel);