diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index 70e02de9c08a6..08b012c89af5f 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -179,6 +179,7 @@
+
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.CoreCLR.cs
index f58e24742dc50..1d0de80f09999 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.CoreCLR.cs
@@ -1,21 +1,34 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using static System.Reflection.InvokerEmitUtil;
+using static System.Reflection.MethodBase;
+using static System.RuntimeType;
+
namespace System.Reflection
{
public partial class ConstructorInvoker
{
- private readonly Signature? _signature;
+ private readonly CreateUninitializedCache? _allocator;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private object CreateUninitializedObject() => _allocator!.CreateUninitializedObject(_declaringType);
- internal unsafe ConstructorInvoker(RuntimeConstructorInfo constructor) : this(constructor, constructor.Signature.Arguments)
+ private bool ShouldAllocate => _allocator is not null;
+
+ private unsafe Delegate CreateInvokeDelegateForInterpreted()
{
- _signature = constructor.Signature;
- _invokeFunc_RefArgs = InterpretedInvoke;
+ Debug.Assert(MethodInvokerCommon.UseInterpretedPath);
+ Debug.Assert(_strategy == InvokerStrategy.Ref4 || _strategy == InvokerStrategy.RefMany);
+
+ return (InvokeFunc_RefArgs)InterpretedInvoke;
}
- private unsafe object? InterpretedInvoke(object? obj, IntPtr* args)
+ private unsafe object? InterpretedInvoke(object? obj, IntPtr _, IntPtr* args)
{
- return RuntimeMethodHandle.InvokeMethod(obj, (void**)args, _signature!, isConstructor: obj is null);
+ return RuntimeMethodHandle.InvokeMethod(obj, (void**)args, _method.Signature, isConstructor: obj is null);
}
}
}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.CoreCLR.cs
index abdb8be14b27a..61dce1500552c 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.CoreCLR.cs
@@ -90,7 +90,7 @@ private MethodBaseInvoker Invoker
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- return _invoker ??= new MethodBaseInvoker(this, Signature);
+ return _invoker ??= new MethodBaseInvoker(this, Signature.Arguments, ReturnType);
}
}
@@ -132,13 +132,17 @@ Signature LazyCreateSignature()
int argCount = (parameters != null) ? parameters.Length : 0;
if (Signature.Arguments.Length != argCount)
throw new TargetParameterCountException(SR.Arg_ParmCnt);
- object? retValue = argCount switch
+
+ object? retValue = Invoker.Strategy switch
{
- 0 => Invoker.InvokeWithNoArgs(obj, invokeAttr),
- 1 => Invoker.InvokeWithOneArg(obj, invokeAttr, binder, parameters!, culture),
- 2 or 3 or 4 => Invoker.InvokeWithFewArgs(obj, invokeAttr, binder, parameters!, culture),
- _ => Invoker.InvokeWithManyArgs(obj, invokeAttr, binder, parameters!, culture),
+ MethodBase.InvokerStrategy.Obj0 => Invoker.InvokeWithNoArgs(obj, invokeAttr),
+ MethodBase.InvokerStrategy.Obj1 => Invoker.InvokeWith1Arg(obj, invokeAttr, binder, parameters!, culture),
+ MethodBase.InvokerStrategy.Obj4 => Invoker.InvokeWith4Args(obj, invokeAttr, binder, parameters!, culture),
+ MethodBase.InvokerStrategy.ObjSpan => Invoker.InvokeWithSpanArgs(obj, invokeAttr, binder, parameters!, culture),
+ MethodBase.InvokerStrategy.Ref4 => Invoker.InvokeWith4RefArgs(obj, invokeAttr, binder, parameters, culture),
+ _ => Invoker.InvokeWithManyRefArgs(obj, invokeAttr, binder, parameters!, culture)
};
+
GC.KeepAlive(this);
return retValue;
}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.CoreCLR.cs
index 7bb6439468d19..74eeaadd95c94 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.CoreCLR.cs
@@ -1,38 +1,50 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Diagnostics;
using System.Reflection.Emit;
+using System.Runtime.CompilerServices;
+using static System.Reflection.InvokerEmitUtil;
+using static System.Reflection.MethodBase;
+using static System.RuntimeType;
namespace System.Reflection
{
internal partial class MethodBaseInvoker
{
- private readonly Signature? _signature;
+ private readonly CreateUninitializedCache? _allocator;
- internal unsafe MethodBaseInvoker(RuntimeMethodInfo method) : this(method, method.Signature.Arguments)
- {
- _signature = method.Signature;
- _invocationFlags = method.ComputeAndUpdateInvocationFlags();
- _invokeFunc_RefArgs = InterpretedInvoke_Method;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private object CreateUninitializedObject() => _allocator!.CreateUninitializedObject(_declaringType!);
- internal unsafe MethodBaseInvoker(RuntimeConstructorInfo constructor) : this(constructor, constructor.Signature.Arguments)
- {
- _signature = constructor.Signature;
- _invocationFlags = constructor.ComputeAndUpdateInvocationFlags();
- _invokeFunc_RefArgs = InterpretedInvoke_Constructor;
- }
+ private bool ShouldAllocate => _allocator is not null;
- internal unsafe MethodBaseInvoker(DynamicMethod method, Signature signature) : this(method, signature.Arguments)
+ private unsafe Delegate CreateInvokeDelegateForInterpreted()
{
- _signature = signature;
- _invokeFunc_RefArgs = InterpretedInvoke_Method;
+ Debug.Assert(MethodInvokerCommon.UseInterpretedPath);
+ Debug.Assert(_strategy == InvokerStrategy.Ref4 || _strategy == InvokerStrategy.RefMany);
+
+ if (_method is RuntimeMethodInfo)
+ {
+ return (InvokeFunc_RefArgs)InterpretedInvoke_Method;
+ }
+
+ if (_method is RuntimeConstructorInfo)
+ {
+ return (InvokeFunc_RefArgs)InterpretedInvoke_Constructor;
+ }
+
+ Debug.Assert(_method is DynamicMethod);
+ return (InvokeFunc_RefArgs)InterpretedInvoke_DynamicMethod;
}
- private unsafe object? InterpretedInvoke_Constructor(object? obj, IntPtr* args) =>
- RuntimeMethodHandle.InvokeMethod(obj, (void**)args, _signature!, isConstructor: obj is null);
+ private unsafe object? InterpretedInvoke_Method(object? obj, IntPtr _, IntPtr* args) =>
+ RuntimeMethodHandle.InvokeMethod(obj, (void**)args, ((RuntimeMethodInfo)_method).Signature, isConstructor: false);
+
+ private unsafe object? InterpretedInvoke_Constructor(object? obj, IntPtr _, IntPtr* args) =>
+ RuntimeMethodHandle.InvokeMethod(obj, (void**)args, ((RuntimeConstructorInfo)_method).Signature, isConstructor: obj is null);
- private unsafe object? InterpretedInvoke_Method(object? obj, IntPtr* args) =>
- RuntimeMethodHandle.InvokeMethod(obj, (void**)args, _signature!, isConstructor: false);
+ private unsafe object? InterpretedInvoke_DynamicMethod(object? obj, IntPtr _, IntPtr* args) =>
+ RuntimeMethodHandle.InvokeMethod(obj, (void**)args, ((DynamicMethod)_method).Signature, isConstructor: false);
}
}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodInvoker.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodInvoker.CoreCLR.cs
index 644364a77266e..5d9c06299639a 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodInvoker.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodInvoker.CoreCLR.cs
@@ -1,39 +1,41 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Diagnostics;
using System.Reflection.Emit;
+using static System.Reflection.InvokerEmitUtil;
+using static System.Reflection.MethodBase;
namespace System.Reflection
{
public partial class MethodInvoker
{
- private readonly Signature? _signature;
-
- private unsafe MethodInvoker(RuntimeMethodInfo method) : this(method, method.Signature.Arguments)
+ private unsafe Delegate CreateInvokeDelegateForInterpreted()
{
- _signature = method.Signature;
- _invokeFunc_RefArgs = InterpretedInvoke_Method;
- _invocationFlags = method.ComputeAndUpdateInvocationFlags();
- }
+ Debug.Assert(MethodInvokerCommon.UseInterpretedPath);
+ Debug.Assert(_strategy == InvokerStrategy.Ref4 || _strategy == InvokerStrategy.RefMany);
- private unsafe MethodInvoker(DynamicMethod method) : this(method, method.Signature.Arguments)
- {
- _signature = method.Signature;
- _invokeFunc_RefArgs = InterpretedInvoke_Method;
- // No _invocationFlags for DynamicMethod.
- }
+ if (_method is RuntimeMethodInfo)
+ {
+ return (InvokeFunc_RefArgs)InterpretedInvoke_Method;
+ }
- private unsafe MethodInvoker(RuntimeConstructorInfo constructor) : this(constructor, constructor.Signature.Arguments)
- {
- _signature = constructor.Signature;
- _invokeFunc_RefArgs = InterpretedInvoke_Constructor;
- _invocationFlags = constructor.ComputeAndUpdateInvocationFlags();
+ if (_method is RuntimeConstructorInfo)
+ {
+ return (InvokeFunc_RefArgs)InterpretedInvoke_Constructor;
+ }
+
+ Debug.Assert(_method is DynamicMethod);
+ return (InvokeFunc_RefArgs)InterpretedInvoke_DynamicMethod;
}
- private unsafe object? InterpretedInvoke_Method(object? obj, IntPtr* args) =>
- RuntimeMethodHandle.InvokeMethod(obj, (void**)args, _signature!, isConstructor: false);
+ private unsafe object? InterpretedInvoke_Constructor(object? obj, IntPtr _, IntPtr* args) =>
+ RuntimeMethodHandle.InvokeMethod(obj, (void**)args, ((RuntimeConstructorInfo)_method).Signature, isConstructor: obj is null);
+
+ private unsafe object? InterpretedInvoke_Method(object? obj, IntPtr _, IntPtr* args) =>
+ RuntimeMethodHandle.InvokeMethod(obj, (void**)args, ((RuntimeMethodInfo)_method).Signature, isConstructor: false);
- private unsafe object? InterpretedInvoke_Constructor(object? obj, IntPtr* args) =>
- RuntimeMethodHandle.InvokeMethod(obj, (void**)args, _signature!, isConstructor: obj is null);
+ private unsafe object? InterpretedInvoke_DynamicMethod(object? obj, IntPtr _, IntPtr* args) =>
+ RuntimeMethodHandle.InvokeMethod(obj, (void**)args, ((DynamicMethod)_method).Signature, isConstructor: false);
}
}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodInvokerCommon.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodInvokerCommon.CoreCLR.cs
new file mode 100644
index 0000000000000..e00439484be24
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodInvokerCommon.CoreCLR.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.CompilerServices;
+
+namespace System.Reflection
+{
+ internal static partial class MethodInvokerCommon
+ {
+ // For CoreClr, we may be able to remove the interpreted path; it is not used in the CoreCLR implementation
+ // unless the feature switch is enabled. Unlike Mono, there are no interpreted-only platforms.
+ internal static bool UseInterpretedPath => LocalAppContextSwitches.ForceInterpretedInvoke || !RuntimeFeature.IsDynamicCodeSupported;
+ }
+}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs
index c16d10e97b38d..1ef2c045bb60f 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.CoreCLR.cs
@@ -29,13 +29,19 @@ internal sealed partial class RuntimeConstructorInfo : ConstructorInfo, IRuntime
private readonly BindingFlags m_bindingFlags;
private Signature? m_signature;
private MethodBaseInvoker? m_invoker;
+ private InvocationFlags m_invocationFlags;
internal InvocationFlags InvocationFlags
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- InvocationFlags flags = Invoker._invocationFlags;
+ InvocationFlags flags = m_invocationFlags;
+ if (flags == InvocationFlags.Unknown)
+ {
+ m_invocationFlags = flags = ComputeInvocationFlags();
+ }
+
Debug.Assert((flags & InvocationFlags.Initialized) == InvocationFlags.Initialized);
return flags;
}
@@ -46,8 +52,7 @@ private MethodBaseInvoker Invoker
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- m_invoker ??= new MethodBaseInvoker(this);
- return m_invoker;
+ return m_invoker ??= new MethodBaseInvoker(this, ArgumentTypes, GetReturnType());
}
}
#endregion
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs
index a4bd430b62008..9e8a362aeb364 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs
@@ -28,13 +28,19 @@ internal sealed partial class RuntimeMethodInfo : MethodInfo, IRuntimeMethodInfo
private readonly RuntimeType m_declaringType;
private readonly object? m_keepalive;
private MethodBaseInvoker? m_invoker;
+ private InvocationFlags m_invocationFlags;
internal InvocationFlags InvocationFlags
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- InvocationFlags flags = Invoker._invocationFlags;
+ InvocationFlags flags = m_invocationFlags;
+ if (flags == InvocationFlags.Unknown)
+ {
+ m_invocationFlags = flags = ComputeInvocationFlags();
+ }
+
Debug.Assert((flags & InvocationFlags.Initialized) == InvocationFlags.Initialized);
return flags;
}
@@ -45,8 +51,7 @@ private MethodBaseInvoker Invoker
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- m_invoker ??= new MethodBaseInvoker(this);
- return m_invoker;
+ return m_invoker ??= new MethodBaseInvoker(this, ArgumentTypes, ReturnType);
}
}
#endregion
diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
index ea88559efeceb..709bd1cfb03d9 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
@@ -4370,161 +4370,3 @@ public override string ToString()
}
#endregion
}
-
-namespace System.Reflection
-{
- // Reliable hashtable thread safe for multiple readers and single writer. Note that the reliability goes together with thread
- // safety. Thread safety for multiple readers requires atomic update of the state that also makes the table
- // reliable in the presence of asynchronous exceptions.
- internal struct CerHashtable where K : class
- {
- private sealed class Table
- {
- // Note that m_keys and m_values arrays are immutable to allow lock-free reads. A new instance
- // of CerHashtable has to be allocated to grow the size of the hashtable.
- internal K[] m_keys;
- internal V[] m_values;
- internal int m_count;
-
- internal Table(int size)
- {
- size = HashHelpers.GetPrime(size);
- m_keys = new K[size];
- m_values = new V[size];
- }
-
- internal void Insert(K key, V value)
- {
- int hashcode = GetHashCodeHelper(key);
- if (hashcode < 0)
- hashcode = ~hashcode;
-
- K[] keys = m_keys;
- int index = hashcode % keys.Length;
-
- while (true)
- {
- K hit = keys[index];
-
- if (hit == null)
- {
- m_count++;
- m_values[index] = value;
-
- // This volatile write has to be last. It is going to publish the result atomically.
- //
- // Note that incrementing the count or setting the value does not do any harm without setting the key. The inconsistency will be ignored
- // and it will go away completely during next rehash.
- Volatile.Write(ref keys[index], key);
-
- break;
- }
- else
- {
- Debug.Assert(!hit.Equals(key), "Key was already in CerHashtable! Potential race condition (or bug) in the Reflection cache?");
-
- index++;
- if (index >= keys.Length)
- index -= keys.Length;
- }
- }
- }
- }
-
- private Table m_Table;
-
- private const int MinSize = 7;
-
- private static int GetHashCodeHelper(K key)
- {
- // For strings we don't want the key to differ across domains as CerHashtable might be shared.
- if (key is not string sKey)
- {
- return key.GetHashCode();
- }
- else
- {
- return sKey.GetNonRandomizedHashCode();
- }
- }
-
- private void Rehash(int newSize)
- {
- Table newTable = new Table(newSize);
-
- Table oldTable = m_Table;
- if (oldTable != null)
- {
- K[] keys = oldTable.m_keys;
- V[] values = oldTable.m_values;
-
- for (int i = 0; i < keys.Length; i++)
- {
- K key = keys[i];
-
- if (key != null)
- {
- newTable.Insert(key, values[i]);
- }
- }
- }
-
- // Publish the new table atomically
- Volatile.Write(ref m_Table, newTable);
- }
-
- internal V this[K key]
- {
- get
- {
- Table table = Volatile.Read(ref m_Table);
- if (table == null)
- return default!;
-
- int hashcode = GetHashCodeHelper(key);
- if (hashcode < 0)
- hashcode = ~hashcode;
-
- K[] keys = table.m_keys;
- int index = hashcode % keys.Length;
-
- while (true)
- {
- // This volatile read has to be first. It is reading the atomically published result.
- K hit = Volatile.Read(ref keys[index]);
-
- if (hit != null)
- {
- if (hit.Equals(key))
- return table.m_values[index];
-
- index++;
- if (index >= keys.Length)
- index -= keys.Length;
- }
- else
- {
- return default!;
- }
- }
- }
- set
- {
- Table table = m_Table;
-
- if (table != null)
- {
- int requiredSize = 2 * (table.m_count + 1);
- if (requiredSize >= table.m_keys.Length)
- Rehash(requiredSize);
- }
- else
- {
- Rehash(MinSize);
- }
-
- m_Table.Insert(key, value);
- }
- }
- }
-}
diff --git a/src/libraries/Common/tests/System/Reflection/InvokeEmitTests.cs b/src/libraries/Common/tests/System/Reflection/InvokeEmitTests.cs
index 149be11a98259..5009778e14b7a 100644
--- a/src/libraries/Common/tests/System/Reflection/InvokeEmitTests.cs
+++ b/src/libraries/Common/tests/System/Reflection/InvokeEmitTests.cs
@@ -12,24 +12,20 @@ public class InvokeEmitTests
public static void VerifyInvokeIsUsingEmit_Method()
{
MethodInfo method = typeof(TestClassThatThrows).GetMethod(nameof(TestClassThatThrows.Throw))!;
- TargetInvocationException ex = Assert.Throws(() => method.Invoke(null, null));
+ TargetInvocationException ex = Assert.Throws(() => method.Invoke(null, new object[] { "" }));
Exception exInner = ex.InnerException;
-
- Assert.Contains("Here", exInner.ToString());
- Assert.Contains("InvokeStub_TestClassThatThrows", exInner.ToString());
- Assert.DoesNotContain("InterpretedInvoke_Method", exInner.ToString());
+ Assert.Contains("Here", ex.ToString());
+ Assert.Contains("InvokeStub_