- 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
public abstract Assembly[] GetLoadedAssemblies();
public abstract EnumInfo GetEnumInfo(Type type);
+
+ public abstract DelegateDynamicInvokeInfo GetDelegateDynamicInvokeInfo(Type type);
}
}
//==============================================================================================
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
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
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);
// Reflection.Execution.dll
using System;
+using System.Reflection;
using System.Runtime;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
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,
<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" />
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.
}
[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;
}
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
};
{
// 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
--- /dev/null
+// 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; }
+ }
+}
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;
+ }
}
}
_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);
}
{
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);
}
[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();
[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
[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;
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;
}
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];
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".
}
}
- internal EnumInfo EnumInfo => Cache.EnumInfo;
-
internal abstract Type InternalDeclaringType { get; }
//
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);
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);
}
}
tMethods[i] = (MethodInfo)methodBase;
continue;
-notFound:
+ notFound:
if (instanceType.IsAbstract)
{
throw new PlatformNotSupportedException(SR.Format(SR.Arg_InterfaceMapMustNotBeAbstract, interfaceType.FullName, instanceType.FullName));
#endif
return null;
}
+
+ public override IntPtr GetDynamicInvokeThunk(MethodInvoker invoker, out IntPtr genericDictionary)
+ {
+ MethodInvokeInfo invokeInfo = ((MethodInvokerWithMethodInvokeInfo)invoker).MethodInvokeInfo;
+ genericDictionary = invokeInfo.DynamicInvokeGenericDictionary;
+ return invokeInfo.DynamicInvokeMethod;
+ }
}
}
}
[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,
return new InstanceMethodInvoker(methodInvokeInfo, declaringTypeHandle);
}
- protected MethodInvokeInfo MethodInvokeInfo { get; private set; }
+ internal MethodInvokeInfo MethodInvokeInfo { get; private set; }
}
}
}
[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,
}
[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,
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);
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,
}
}
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;
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);