diff options
author | Atsushi Kanamori <AtsushiKan@users.noreply.github.com> | 2017-09-05 18:04:10 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-05 18:04:10 +0300 |
commit | f7174c8e8cb28944e28b59258f37ae0af1571769 (patch) | |
tree | 88046ce34b9697759d6ca277b663e9acdf802bcb /src/System.Private.Reflection.Core | |
parent | cc9d93f207b4d2265a700433b23d08b74655c364 (diff) |
Fix late bound invoke on string constructors added in NS2.0 (#4449)
Fixes https://devdiv.visualstudio.com/DevDiv/_workitems/edit/476529
This fix also consolidates four different MethodInvokers into
one general purpose one (CustomMethodInvoker.)
- IntPtr/UIntPtr invokers - vaporized. The intrinsics all have
fallback bodies and late-bound invoke now works fine on them
using the normal path.
- String/Nullable invokers - the normal path still doesn't
work on them (no surprise since we never asked them to
support this.) These have been replaced with CustomMethodInvoker
and the NS2.0-added String constructors added.
- The array constructors and get/set methods. These used
the Synthetic invoker - Synthetic invoker was cleaned up
and rebranded as CustomMethodInvoker.
Diffstat (limited to 'src/System.Private.Reflection.Core')
17 files changed, 431 insertions, 65 deletions
diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionEnvironment.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionEnvironment.cs index 7a4e60e6d..5d8699ce3 100644 --- a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionEnvironment.cs +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionEnvironment.cs @@ -101,7 +101,6 @@ namespace Internal.Reflection.Core.Execution //============================================================================================== // Other //============================================================================================== - public abstract MethodInvoker GetSyntheticMethodInvoker(RuntimeTypeHandle thisType, RuntimeTypeHandle[] parameterTypes, InvokerOptions options, Func<Object, Object[], Object> invoker); public abstract bool IsCOMObject(Type type); public abstract FieldAccessor CreateLiteralFieldAccessor(object value, RuntimeTypeHandle fieldTypeHandle); diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/InvokerOptions.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/InvokerOptions.cs deleted file mode 100644 index 831a454f3..000000000 --- a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/InvokerOptions.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; - -namespace Internal.Reflection.Core.Execution -{ - [Flags] - public enum InvokerOptions - { - None = 0x00000000, - AllowNullThis = 0x00000001, // Don't raise an exception if the "thisObject" parameter to Invoker is null. - DontWrapException = 0x00000002, // Don't wrap target exceptions in TargetInvocationException. - } -} - diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/MethodInvoker.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/MethodInvoker.cs index 1234a12f9..efeb83909 100644 --- a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/MethodInvoker.cs +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/MethodInvoker.cs @@ -8,6 +8,8 @@ using System.Diagnostics; using System.Globalization; using System.Reflection.Runtime.General; +using Internal.Runtime.Augments; + namespace Internal.Reflection.Core.Execution { // @@ -32,6 +34,24 @@ namespace Internal.Reflection.Core.Execution // This property is used to retrieve the target method pointer. It is used by the RuntimeMethodHandle.GetFunctionPointer API public abstract IntPtr LdFtnResult { get; } + + protected static void ValidateThis(object thisObject, RuntimeTypeHandle declaringTypeHandle) + { + if (thisObject == null) + throw new TargetException(SR.RFLCT_Targ_StatMethReqTarg); + + RuntimeTypeHandle srcTypeHandle = thisObject.GetType().TypeHandle; + if (RuntimeAugments.IsAssignableFrom(declaringTypeHandle, srcTypeHandle)) + return; + + if (RuntimeAugments.IsInterface(declaringTypeHandle)) + { + if (RuntimeAugments.IsInstanceOfInterface(thisObject, declaringTypeHandle)) + return; + } + + throw new TargetException(SR.RFLCT_Targ_ITargMismatch); + } } } diff --git a/src/System.Private.Reflection.Core/src/Resources/Strings.resx b/src/System.Private.Reflection.Core/src/Resources/Strings.resx index 0f8ae09b5..4d7615699 100644 --- a/src/System.Private.Reflection.Core/src/Resources/Strings.resx +++ b/src/System.Private.Reflection.Core/src/Resources/Strings.resx @@ -376,4 +376,13 @@ <data name="CannotUseByRefLikeTypeInInstantiation" xml:space="preserve"> <value>Cannot instantiate a generic type on a byref-like type.</value> </data> + <data name="RFLCT_Targ_StatMethReqTarg" xml:space="preserve"> + <value>Non-static method requires a target.</value> + </data> + <data name="RFLCT_Targ_ITargMismatch" xml:space="preserve"> + <value>Object does not match target type.</value> + </data> + <data name="InvalidOperation_NoValue" xml:space="preserve"> + <value>Nullable object must have a value.</value> + </data> </root> diff --git a/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj b/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj index 33f9df314..e8fd88288 100644 --- a/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj +++ b/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj @@ -127,6 +127,12 @@ <Compile Include="System\Reflection\Runtime\General\QSignatureTypeHandle.cs" /> <Compile Include="System\Reflection\Runtime\General\QSignatureTypeHandle.NativeFormat.cs" /> <Compile Include="System\Reflection\Runtime\MethodInfos\NativeFormat\NativeFormatMethodCommon.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\CustomMethodInvoker.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\CustomMethodInvokerAction.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\CustomMethodMapper.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\CustomMethodMapper.Nullable.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\CustomMethodMapper.String.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\InvokerOptions.cs" /> <Compile Include="System\Reflection\Runtime\MethodInfos\OpenMethodInvoker.cs" /> <Compile Include="System\Reflection\Runtime\MethodInfos\RuntimeClsIdNullaryConstructorInfo.cs" /> <Compile Include="System\Reflection\Runtime\MethodInfos\RuntimeConstructedGenericMethodInfo.cs" /> @@ -195,7 +201,6 @@ <Compile Include="Internal\Reflection\Core\Execution\FieldAccessor.cs" /> <Compile Include="Internal\Reflection\Core\Execution\MethodInvoker.cs" /> <Compile Include="Internal\Reflection\Core\Execution\ReflectionCoreExecution.cs" /> - <Compile Include="Internal\Reflection\Core\Execution\InvokerOptions.cs" /> </ItemGroup> <ItemGroup Condition="'$(IsProjectNLibrary)' == 'true'"> <Compile Include="Internal\Reflection\Tracing\ReflectionTrace.Public.cs" /> diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Dispensers.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Dispensers.cs index fd9603606..79eca8868 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Dispensers.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Dispensers.cs @@ -143,9 +143,9 @@ namespace System.Reflection.Runtime.MethodInfos //----------------------------------------------------------------------------------------------------------- internal sealed partial class RuntimeSyntheticConstructorInfo : RuntimeConstructorInfo { - internal static RuntimeSyntheticConstructorInfo GetRuntimeSyntheticConstructorInfo(SyntheticMethodId syntheticMethodId, RuntimeArrayTypeInfo declaringType, RuntimeTypeInfo[] runtimeParameterTypes, InvokerOptions options, Func<Object, Object[], Object> invoker) + internal static RuntimeSyntheticConstructorInfo GetRuntimeSyntheticConstructorInfo(SyntheticMethodId syntheticMethodId, RuntimeArrayTypeInfo declaringType, RuntimeTypeInfo[] runtimeParameterTypes, InvokerOptions options, CustomMethodInvokerAction action) { - return new RuntimeSyntheticConstructorInfo(syntheticMethodId, declaringType, runtimeParameterTypes, options, invoker); + return new RuntimeSyntheticConstructorInfo(syntheticMethodId, declaringType, runtimeParameterTypes, options, action); } } @@ -189,9 +189,9 @@ namespace System.Reflection.Runtime.MethodInfos //----------------------------------------------------------------------------------------------------------- internal sealed partial class RuntimeSyntheticMethodInfo : RuntimeMethodInfo { - internal static RuntimeMethodInfo GetRuntimeSyntheticMethodInfo(SyntheticMethodId syntheticMethodId, String name, RuntimeArrayTypeInfo declaringType, RuntimeTypeInfo[] runtimeParameterTypes, RuntimeTypeInfo returnType, InvokerOptions options, Func<Object, Object[], Object> invoker) + internal static RuntimeMethodInfo GetRuntimeSyntheticMethodInfo(SyntheticMethodId syntheticMethodId, String name, RuntimeArrayTypeInfo declaringType, RuntimeTypeInfo[] runtimeParameterTypes, RuntimeTypeInfo returnType, InvokerOptions options, CustomMethodInvokerAction action) { - return new RuntimeSyntheticMethodInfo(syntheticMethodId, name, declaringType, runtimeParameterTypes, returnType, options, invoker).WithDebugName(); + return new RuntimeSyntheticMethodInfo(syntheticMethodId, name, declaringType, runtimeParameterTypes, returnType, options, action).WithDebugName(); } } } diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvoker.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvoker.cs new file mode 100644 index 000000000..ed124f01a --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvoker.cs @@ -0,0 +1,72 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +using Internal.Runtime.Augments; +using Internal.Reflection.Core.Execution; + +namespace System.Reflection.Runtime.MethodInfos +{ + // + // Custom invoker for edge case scenarios not handled by the toolchain. Examples: Strings and Nullables. + // + internal sealed class CustomMethodInvoker : MethodInvoker + { + public CustomMethodInvoker(Type thisType, Type[] parameterTypes, InvokerOptions options, CustomMethodInvokerAction action) + { + _action = action; + _options = options; + _thisType = thisType; + _parameterTypes = parameterTypes; + } + + 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) + throw new TargetParameterCountException(); + + object[] convertedArguments = new object[arguments.Length]; + for (int i = 0; i < arguments.Length; i++) + { + convertedArguments[i] = RuntimeAugments.CheckArgument(arguments[i], _parameterTypes[i].TypeHandle, binderBundle); + } + object result; + try + { + result = _action(thisObject, convertedArguments, _thisType); + } + catch (Exception e) when (wrapInTargetInvocationException && ((_options & InvokerOptions.DontWrapException) == 0)) + { + throw new TargetInvocationException(e); + } + return result; + } + + public sealed override Delegate CreateDelegate(RuntimeTypeHandle delegateType, object target, bool isStatic, bool isVirtual, bool isOpen) + { + if (_thisType.IsConstructedGenericType && _thisType.GetGenericTypeDefinition() == CommonRuntimeTypes.Nullable) + { + // Desktop compat: MethodInfos to Nullable<T> methods cannot be turned into delegates. + throw new ArgumentException(SR.Arg_DlgtTargMeth); + } + + throw new PlatformNotSupportedException(); + } + + public sealed override IntPtr LdFtnResult => throw new PlatformNotSupportedException(); + + private readonly InvokerOptions _options; + private readonly CustomMethodInvokerAction _action; + private readonly Type _thisType; + private readonly Type[] _parameterTypes; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvokerAction.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvokerAction.cs new file mode 100644 index 000000000..cf7ca94e2 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvokerAction.cs @@ -0,0 +1,8 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Reflection.Runtime.MethodInfos +{ + internal delegate object CustomMethodInvokerAction(object thisObject, object[] args, Type thisType); +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.Nullable.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.Nullable.cs new file mode 100644 index 000000000..fbf7418f3 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.Nullable.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Reflection.Runtime.General; + +namespace System.Reflection.Runtime.MethodInfos +{ + internal static partial class CustomMethodMapper + { + // + // Nullables are another edge case. + // + private static class NullableActions + { + public static Dictionary<MethodBase, CustomMethodInvokerAction> Map + { + get + { + if (s_lazyMap == null) + { + Dictionary<MethodBase, CustomMethodInvokerAction> map = new Dictionary<MethodBase, CustomMethodInvokerAction>(); + + Type type = CommonRuntimeTypes.Nullable; + Type theT = type.GetGenericTypeParameters()[0]; + + map.AddMethod(type, nameof(Nullable<int>.ToString), Array.Empty<Type>(), + (object thisObject, object[] args, Type thisType) => + { + return thisObject == null ? string.Empty : thisObject.ToString(); + } + ); + + map.AddMethod(type, nameof(Nullable<int>.Equals), new Type[] { CommonRuntimeTypes.Object }, + (object thisObject, object[] args, Type thisType) => + { + object other = args[0]; + if (thisObject == null) + return other == null; + if (other == null) + return false; + return thisObject.Equals(other); + } + ); + + map.AddMethod(type, nameof(Nullable<int>.GetHashCode), Array.Empty<Type>(), + (object thisObject, object[] args, Type thisType) => + { + return thisObject == null ? 0 : thisObject.GetHashCode(); + } + ); + + map.AddConstructor(type, new Type[] { theT }, + (object thisObject, object[] args, Type thisType) => + { + return args[0]; + } + ); + + map.AddMethod(type, "get_" + nameof(Nullable<int>.HasValue), Array.Empty<Type>(), + (object thisObject, object[] args, Type thisType) => + { + return thisObject != null; + } + ); + + map.AddMethod(type, "get_" + nameof(Nullable<int>.Value), Array.Empty<Type>(), + (object thisObject, object[] args, Type thisType) => + { + if (thisObject == null) + throw new InvalidOperationException(SR.InvalidOperation_NoValue); + return thisObject; + } + ); + + map.AddMethod(type, nameof(Nullable<int>.GetValueOrDefault), Array.Empty<Type>(), + (object thisObject, object[] args, Type thisType) => + { + if (thisObject == null) + return RuntimeHelpers.GetUninitializedObject(thisType); + + return thisObject; + } + ); + + map.AddMethod(type, nameof(Nullable<int>.GetValueOrDefault), new Type[] { theT }, + (object thisObject, object[] args, Type thisType) => + { + if (thisObject == null) + return args[0]; + return thisObject; + } + ); + + s_lazyMap = map; + } + + return s_lazyMap; + } + } + + private static volatile Dictionary<MethodBase, CustomMethodInvokerAction> s_lazyMap; + } + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.String.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.String.cs new file mode 100644 index 000000000..acd1dada3 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.String.cs @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text; +using System.Collections.Generic; + +namespace System.Reflection.Runtime.MethodInfos +{ + internal static partial class CustomMethodMapper + { + // + // String constructors require special casing down the stack, being the only variable-sized objects created via a constructor. + // + private static class StringActions + { + public static Dictionary<MethodBase, CustomMethodInvokerAction> Map + { + get + { + if (s_lazyMap == null) + { + Dictionary<MethodBase, CustomMethodInvokerAction> map = new Dictionary<MethodBase, CustomMethodInvokerAction>(); + + Type type = CommonRuntimeTypes.String; + + unsafe + { + map.AddConstructor(type, new Type[] { CommonRuntimeTypes.Char, CommonRuntimeTypes.Int32 }, + (object thisObject, object[] args, Type thisType) => + { + return new string((char)(args[0]), (int)(args[1])); + } + ); + + map.AddConstructor(type, new Type[] { typeof(char[]) }, + (object thisObject, object[] args, Type thisType) => + { + return new string((char[])(args[0])); + } + ); + + map.AddConstructor(type, new Type[] { typeof(char[]), CommonRuntimeTypes.Int32, CommonRuntimeTypes.Int32 }, + (object thisObject, object[] args, Type thisType) => + { + return new string((char[])(args[0]), (int)(args[1]), (int)(args[2])); + } + ); + + map.AddConstructor(type, new Type[] { typeof(char*) }, + (object thisObject, object[] args, Type thisType) => + { + return new string((char*)(IntPtr)(args[0])); + } + ); + + map.AddConstructor(type, new Type[] { typeof(char*), CommonRuntimeTypes.Int32, CommonRuntimeTypes.Int32 }, + (object thisObject, object[] args, Type thisType) => + { + return new string((char*)(IntPtr)(args[0]), (int)(args[1]), (int)(args[2])); + } + ); + + map.AddConstructor(type, new Type[] { typeof(sbyte*) }, + (object thisObject, object[] args, Type thisType) => + { + return new string((sbyte*)(IntPtr)(args[0])); + } + ); + + map.AddConstructor(type, new Type[] { typeof(sbyte*), CommonRuntimeTypes.Int32, CommonRuntimeTypes.Int32 }, + (object thisObject, object[] args, Type thisType) => + { + return new string((sbyte*)(IntPtr)(args[0]), (int)(args[1]), (int)(args[2])); + } + ); + + map.AddConstructor(type, new Type[] { typeof(sbyte*), CommonRuntimeTypes.Int32, CommonRuntimeTypes.Int32, typeof(Encoding) }, + (object thisObject, object[] args, Type thisType) => + { + return new string((sbyte*)(IntPtr)(args[0]), (int)(args[1]), (int)(args[2]), (Encoding)(args[3])); + } + ); + } + + s_lazyMap = map; + } + + return s_lazyMap; + } + } + private static volatile Dictionary<MethodBase, CustomMethodInvokerAction> s_lazyMap; + } + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.cs new file mode 100644 index 000000000..ce2306914 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.cs @@ -0,0 +1,71 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Collections.Generic; + +using Internal.Reflection.Core.Execution; + +namespace System.Reflection.Runtime.MethodInfos +{ + internal static partial class CustomMethodMapper + { + // + // Certain types and methods are edge-cases that require special handling. + // + public static MethodInvoker GetCustomMethodInvokerIfNeeded(this MethodBase methodBase) + { + Type declaringType = methodBase.DeclaringType; + bool isNullable = declaringType.IsConstructedGenericType && declaringType.GetGenericTypeDefinition() == CommonRuntimeTypes.Nullable; + + Dictionary<MethodBase, CustomMethodInvokerAction> map; + if (isNullable) + map = NullableActions.Map; + else if (declaringType == CommonRuntimeTypes.String) + map = StringActions.Map; + else + return null; + + if (!(map.TryGetValue(methodBase.MetadataDefinitionMethod, out CustomMethodInvokerAction action))) + return null; + + ParameterInfo[] parameterInfos = methodBase.GetParametersNoCopy(); + Type[] parameterTypes = new Type[parameterInfos.Length]; + for (int i = 0; i < parameterInfos.Length; i++) + { + parameterTypes[i] = parameterInfos[i].ParameterType; + } + + InvokerOptions options = (methodBase.IsStatic || methodBase is ConstructorInfo || isNullable) ? InvokerOptions.AllowNullThis : InvokerOptions.None; + return new CustomMethodInvoker(declaringType, parameterTypes, options, action); + } + + private static void AddConstructor(this Dictionary<MethodBase, CustomMethodInvokerAction> map, Type declaringType, Type[] parameterTypes, CustomMethodInvokerAction action) + { + map.AddMethod(declaringType, ConstructorInfo.ConstructorName, parameterTypes, action); + } + + private static void AddMethod(this Dictionary<MethodBase, CustomMethodInvokerAction> map, Type declaringType, string name, Type[] parameterTypes, CustomMethodInvokerAction action) + { + const BindingFlags bf = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.ExactBinding; + + MethodBase methodBase; + if (name == ConstructorInfo.ConstructorName) + { + methodBase = declaringType.GetConstructor(bf, null, parameterTypes, null); + } + else + { + methodBase = declaringType.GetMethod(name, 0, bf, null, parameterTypes, null); + } + + if (methodBase == null) + return; // If we got here, this specific member was not included in the metadata. + + Debug.Assert(methodBase == methodBase.MetadataDefinitionMethod); + map.Add(methodBase, action); + } + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/InvokerOptions.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/InvokerOptions.cs new file mode 100644 index 000000000..c5eb41ac6 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/InvokerOptions.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Reflection.Runtime.MethodInfos +{ + [Flags] + internal enum InvokerOptions + { + None = 0x00000000, + AllowNullThis = 0x00000001, // Don't raise an exception if the "thisObject" parameter to Invoker is null. + DontWrapException = 0x00000002, // Don't wrap target exceptions in TargetInvocationException. + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs index 40df076c1..c158d76f1 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs @@ -307,6 +307,10 @@ namespace System.Reflection.Runtime.MethodInfos { get { + MethodInvoker invoker = this.GetCustomMethodInvokerIfNeeded(); + if (invoker != null) + return invoker; + return GetUncachedMethodInvoker(Array.Empty<RuntimeTypeInfo>(), this); } } diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs index 0dbb40e00..fb5c6a122 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs @@ -195,6 +195,10 @@ namespace System.Reflection.Runtime.MethodInfos if (this.IsStatic) throw new MemberAccessException(SR.Acc_NotClassInit); + MethodInvoker invoker = this.GetCustomMethodInvokerIfNeeded(); + if (invoker != null) + return invoker; + return _common.GetUncachedMethodInvoker(Array.Empty<RuntimeTypeInfo>(), this); } } diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs index a0aa8a0aa..ef2dc9e27 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs @@ -20,12 +20,12 @@ namespace System.Reflection.Runtime.MethodInfos // internal sealed partial class RuntimeSyntheticConstructorInfo : RuntimeConstructorInfo, IRuntimeMemberInfoWithNoMetadataDefinition { - private RuntimeSyntheticConstructorInfo(SyntheticMethodId syntheticMethodId, RuntimeArrayTypeInfo declaringType, RuntimeTypeInfo[] runtimeParameterTypes, InvokerOptions options, Func<Object, Object[], Object> invoker) + private RuntimeSyntheticConstructorInfo(SyntheticMethodId syntheticMethodId, RuntimeArrayTypeInfo declaringType, RuntimeTypeInfo[] runtimeParameterTypes, InvokerOptions options, CustomMethodInvokerAction action) { _syntheticMethodId = syntheticMethodId; _declaringType = declaringType; _options = options; - _invoker = invoker; + _action = action; _runtimeParameterTypes = runtimeParameterTypes; } @@ -164,21 +164,7 @@ namespace System.Reflection.Runtime.MethodInfos } } - protected sealed override MethodInvoker UncachedMethodInvoker - { - get - { - RuntimeTypeInfo[] runtimeParameterTypes = _runtimeParameterTypes; - RuntimeTypeHandle[] runtimeParameterTypeHandles = new RuntimeTypeHandle[runtimeParameterTypes.Length]; - for (int i = 0; i < runtimeParameterTypes.Length; i++) - runtimeParameterTypeHandles[i] = runtimeParameterTypes[i].TypeHandle; - return ReflectionCoreExecution.ExecutionEnvironment.GetSyntheticMethodInvoker( - _declaringType.TypeHandle, - runtimeParameterTypeHandles, - _options, - _invoker); - } - } + protected sealed override MethodInvoker UncachedMethodInvoker => new CustomMethodInvoker(_declaringType, _runtimeParameterTypes, _options, _action); private volatile RuntimeParameterInfo[] _lazyParameters; @@ -186,6 +172,6 @@ namespace System.Reflection.Runtime.MethodInfos private readonly RuntimeArrayTypeInfo _declaringType; private readonly RuntimeTypeInfo[] _runtimeParameterTypes; private readonly InvokerOptions _options; - private readonly Func<Object, Object[], Object> _invoker; + private readonly CustomMethodInvokerAction _action; } } diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs index e439b4501..2a917563e 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs @@ -19,13 +19,13 @@ namespace System.Reflection.Runtime.MethodInfos // internal sealed partial class RuntimeSyntheticMethodInfo : RuntimeMethodInfo, IRuntimeMemberInfoWithNoMetadataDefinition { - private RuntimeSyntheticMethodInfo(SyntheticMethodId syntheticMethodId, String name, RuntimeArrayTypeInfo declaringType, RuntimeTypeInfo[] parameterTypes, RuntimeTypeInfo returnType, InvokerOptions options, Func<Object, Object[], Object> invoker) + private RuntimeSyntheticMethodInfo(SyntheticMethodId syntheticMethodId, String name, RuntimeArrayTypeInfo declaringType, RuntimeTypeInfo[] parameterTypes, RuntimeTypeInfo returnType, InvokerOptions options, CustomMethodInvokerAction action) { _syntheticMethodId = syntheticMethodId; _name = name; _declaringType = declaringType; _options = options; - _invoker = invoker; + _action = action; _runtimeParameterTypes = parameterTypes; _returnType = returnType; } @@ -171,21 +171,7 @@ namespace System.Reflection.Runtime.MethodInfos } } - protected sealed override MethodInvoker UncachedMethodInvoker - { - get - { - RuntimeTypeInfo[] runtimeParameterTypes = _runtimeParameterTypes; - RuntimeTypeHandle[] runtimeParameterTypeHandles = new RuntimeTypeHandle[runtimeParameterTypes.Length]; - for (int i = 0; i < runtimeParameterTypes.Length; i++) - runtimeParameterTypeHandles[i] = runtimeParameterTypes[i].TypeHandle; - return ReflectionCoreExecution.ExecutionEnvironment.GetSyntheticMethodInvoker( - _declaringType.TypeHandle, - runtimeParameterTypeHandles, - _options, - _invoker); - } - } + protected sealed override MethodInvoker UncachedMethodInvoker => new CustomMethodInvoker(_declaringType, _runtimeParameterTypes, _options, _action); internal sealed override RuntimeTypeInfo[] RuntimeGenericArgumentsOrParameters { @@ -238,6 +224,6 @@ namespace System.Reflection.Runtime.MethodInfos private readonly RuntimeTypeInfo[] _runtimeParameterTypes; private readonly RuntimeTypeInfo _returnType; private readonly InvokerOptions _options; - private readonly Func<Object, Object[], Object> _invoker; + private readonly CustomMethodInvokerAction _action; } } diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs index e058d0cdd..98db26c70 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs @@ -73,7 +73,7 @@ namespace System.Reflection.Runtime.TypeInfos arrayType, ctorParameters, InvokerOptions.AllowNullThis | InvokerOptions.DontWrapException, - delegate (Object _this, Object[] args) + delegate (Object _this, Object[] args, Type thisType) { int[] lengths = new int[rank]; for (int i = 0; i < rank; i++) @@ -111,7 +111,7 @@ namespace System.Reflection.Runtime.TypeInfos arrayType, ctorParameters, InvokerOptions.AllowNullThis | InvokerOptions.DontWrapException, - delegate (Object _this, Object[] args) + delegate (Object _this, Object[] args, Type thisType) { int[] lengths = new int[args.Length]; for (int i = 0; i < args.Length; i++) @@ -147,7 +147,7 @@ namespace System.Reflection.Runtime.TypeInfos arrayType, ctorParameters, InvokerOptions.AllowNullThis | InvokerOptions.DontWrapException, - delegate (Object _this, Object[] args) + delegate (Object _this, Object[] args, Type thisType) { int[] lengths = new int[rank]; int[] lowerBounds = new int[rank]; @@ -185,7 +185,7 @@ namespace System.Reflection.Runtime.TypeInfos getParameters, elementType, InvokerOptions.None, - delegate (Object _this, Object[] args) + delegate (Object _this, Object[] args, Type thisType) { Array array = (Array)_this; int[] indices = new int[rank]; @@ -208,7 +208,7 @@ namespace System.Reflection.Runtime.TypeInfos setParameters, voidType, InvokerOptions.None, - delegate (Object _this, Object[] args) + delegate (Object _this, Object[] args, Type thisType) { Array array = (Array)_this; int[] indices = new int[rank]; @@ -232,7 +232,7 @@ namespace System.Reflection.Runtime.TypeInfos addressParameters, elementType.GetByRefType(), InvokerOptions.None, - delegate (Object _this, Object[] args) + delegate (Object _this, Object[] args, Type thisType) { throw new NotSupportedException(); } |