Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public MethodInvoker(MethodBase method, Signature signature)
}
else if (LocalAppContextSwitches.ForceEmitInvoke && !LocalAppContextSwitches.ForceInterpretedInvoke)
{
// Always use emit invoke (if IsDynamicCodeCompiled == true); useful for testing.
// Always use emit invoke (if IsDynamicCodeSupported == true); useful for testing.
_invoked = true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ public static void VerifyInvokeIsUsingEmit_Constructor()

private static bool IsEmitInvokeSupported()
{
// Emit is only used for Invoke when RuntimeFeature.IsDynamicCodeCompiled is true.
return RuntimeFeature.IsDynamicCodeCompiled;
// Emit is only used for Invoke when RuntimeFeature.IsDynamicCodeSupported is true.
return RuntimeFeature.IsDynamicCodeSupported;
}

private static string InterpretedMethodName => PlatformDetection.IsMonoRuntime ?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace System.Reflection.Tests
public class InvokeInterpretedTests
{
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/50957", typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser), nameof(PlatformDetection.IsMonoAOT))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/50957", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoAOT))]
public static void VerifyInvokeIsUsingEmit_Method()
{
MethodInfo method = typeof(TestClassThatThrows).GetMethod(nameof(TestClassThatThrows.Throw))!;
Expand All @@ -25,7 +25,7 @@ string InterpretedMethodName() => PlatformDetection.IsMonoRuntime ?
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/50957", typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser), nameof(PlatformDetection.IsMonoAOT))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/50957", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoAOT))]
public static void VerifyInvokeIsUsingEmit_Constructor()
{
ConstructorInfo ctor = typeof(TestClassThatThrows).GetConstructor(Type.EmptyTypes)!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,14 @@ public static ObjectFactory CreateFactory(
Type[] argumentTypes)
{
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP
if (!RuntimeFeature.IsDynamicCodeSupported)
if (!RuntimeFeature.IsDynamicCodeCompiled)
{
// Create a reflection-based factory when dynamic code isn't supported, e.g. app is published with NativeAOT.
// Reflection-based factory is faster than interpreted expressions and doesn't pull in System.Linq.Expressions dependency.
// Create a reflection-based factory when dynamic code is not compiled\jitted as would be the case with
// NativeAOT, iOS or WASM.
// For NativeAOT and iOS, using the reflection-based factory is faster than reflection-fallback interpreted
// expressions and also doesn't pull in the large System.Linq.Expressions dependency.
// For WASM, although it has the ability to use expressions (with dynamic code) and interpet the dynamic code
// efficiently, the size savings of not using System.Linq.Expressions is more important than CPU perf.
return CreateFactoryReflection(instanceType, argumentTypes);
}
#endif
Expand Down Expand Up @@ -163,10 +167,9 @@ public static ObjectFactory<T>
Type[] argumentTypes)
{
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP
if (!RuntimeFeature.IsDynamicCodeSupported)
if (!RuntimeFeature.IsDynamicCodeCompiled)
{
// Create a reflection-based factory when dynamic code isn't supported, e.g. app is published with NativeAOT.
// Reflection-based factory is faster than interpreted expressions and doesn't pull in System.Linq.Expressions dependency.
// See the comment above in the non-generic CreateFactory() for why we use 'IsDynamicCodeCompiled' here.
var factory = CreateFactoryReflection(typeof(T), argumentTypes);
return (serviceProvider, arguments) => (T)factory(serviceProvider, arguments);
}
Expand Down Expand Up @@ -311,6 +314,11 @@ private static ObjectFactory CreateFactoryReflection(

return (IServiceProvider serviceProvider, object?[]? arguments) =>
{
if (serviceProvider is null)
{
throw new ArgumentNullException(nameof(serviceProvider));
}

object?[] constructorArguments = new object?[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,12 @@ public void CreateFactory_CreatesFactoryMethod()
#if NETCOREAPP
[InlineData(false)]
#endif
public void CreateFactory_RemoteExecutor_CreatesFactoryMethod(bool isDynamicCodeSupported)
public void CreateFactory_RemoteExecutor_CreatesFactoryMethod(bool useDynamicCode)
{
var options = new RemoteInvokeOptions();
if (!isDynamicCodeSupported)
if (!useDynamicCode)
{
options.RuntimeConfigurationOptions.Add("System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported", "false");
DisableDynamicCode(options);
}

using var remoteHandle = RemoteExecutor.Invoke(static () =>
Expand Down Expand Up @@ -238,12 +238,12 @@ public void CreateFactory_RemoteExecutor_CreatesFactoryMethod(bool isDynamicCode
#if NETCOREAPP
[InlineData(false)]
#endif
public void CreateFactory_RemoteExecutor_NullArguments_Throws(bool isDynamicCodeSupported)
public void CreateFactory_RemoteExecutor_NullArguments_Throws(bool useDynamicCode)
{
var options = new RemoteInvokeOptions();
if (!isDynamicCodeSupported)
if (!useDynamicCode)
{
options.RuntimeConfigurationOptions.Add("System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported", "false");
DisableDynamicCode(options);
}

using var remoteHandle = RemoteExecutor.Invoke(static () =>
Expand All @@ -261,12 +261,12 @@ public void CreateFactory_RemoteExecutor_NullArguments_Throws(bool isDynamicCode
#if NETCOREAPP
[InlineData(false)]
#endif
public void CreateFactory_RemoteExecutor_NoArguments_UseNullDefaultValue(bool isDynamicCodeSupported)
public void CreateFactory_RemoteExecutor_NoArguments_UseNullDefaultValue(bool useDynamicCode)
{
var options = new RemoteInvokeOptions();
if (!isDynamicCodeSupported)
if (!useDynamicCode)
{
options.RuntimeConfigurationOptions.Add("System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported", "false");
DisableDynamicCode(options);
}

using var remoteHandle = RemoteExecutor.Invoke(static () =>
Expand All @@ -285,12 +285,12 @@ public void CreateFactory_RemoteExecutor_NoArguments_UseNullDefaultValue(bool is
#if NETCOREAPP
[InlineData(false)]
#endif
public void CreateFactory_RemoteExecutor_NoArguments_ThrowRequiredValue(bool isDynamicCodeSupported)
public void CreateFactory_RemoteExecutor_NoArguments_ThrowRequiredValue(bool useDynamicCode)
{
var options = new RemoteInvokeOptions();
if (!isDynamicCodeSupported)
if (!useDynamicCode)
{
options.RuntimeConfigurationOptions.Add("System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported", "false");
DisableDynamicCode(options);
}

using var remoteHandle = RemoteExecutor.Invoke(static () =>
Expand All @@ -309,12 +309,12 @@ public void CreateFactory_RemoteExecutor_NoArguments_ThrowRequiredValue(bool isD
#if NETCOREAPP
[InlineData(false)]
#endif
public void CreateFactory_RemoteExecutor_NullArgument_UseDefaultValue(bool isDynamicCodeSupported)
public void CreateFactory_RemoteExecutor_NullArgument_UseDefaultValue(bool useDynamicCode)
{
var options = new RemoteInvokeOptions();
if (!isDynamicCodeSupported)
if (!useDynamicCode)
{
options.RuntimeConfigurationOptions.Add("System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported", "false");
DisableDynamicCode(options);
}

using var remoteHandle = RemoteExecutor.Invoke(static () =>
Expand All @@ -333,12 +333,12 @@ public void CreateFactory_RemoteExecutor_NullArgument_UseDefaultValue(bool isDyn
#if NETCOREAPP
[InlineData(false)]
#endif
public void CreateFactory_RemoteExecutor_NoParameters_Success(bool isDynamicCodeSupported)
public void CreateFactory_RemoteExecutor_NoParameters_Success(bool useDynamicCode)
{
var options = new RemoteInvokeOptions();
if (!isDynamicCodeSupported)
if (!useDynamicCode)
{
options.RuntimeConfigurationOptions.Add("System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported", "false");
DisableDynamicCode(options);
}

using var remoteHandle = RemoteExecutor.Invoke(static () =>
Expand All @@ -351,6 +351,14 @@ public void CreateFactory_RemoteExecutor_NoParameters_Success(bool isDynamicCode
Assert.NotNull(item);
}, options);
}

private static void DisableDynamicCode(RemoteInvokeOptions options)
{
// We probably only need to set 'IsDynamicCodeCompiled' since only that is checked,
// but also set 'IsDynamicCodeSupported for correctness.
options.RuntimeConfigurationOptions.Add("System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported", "false");
options.RuntimeConfigurationOptions.Add("System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeCompiled", "false");
}
}

internal class A { }
Expand All @@ -361,8 +369,8 @@ internal class S { }
internal class ClassWithABCS : ClassWithABC
{
public S S { get; }
public ClassWithABCS(A a, B b, C c, S s) : base (a, b, c) { S = s; }
public ClassWithABCS(A a, C c, S s) : this (a, null, c, s) { }
public ClassWithABCS(A a, B b, C c, S s) : base(a, b, c) { S = s; }
public ClassWithABCS(A a, C c, S s) : this(a, null, c, s) { }
}

internal class ClassWithABC_FirstConstructorWithAttribute : ClassWithABC
Expand All @@ -374,9 +382,9 @@ public ClassWithABC_FirstConstructorWithAttribute(B b, C c) : this(null, b, c) {

internal class ClassWithABC_LastConstructorWithAttribute : ClassWithABC
{
public ClassWithABC_LastConstructorWithAttribute(B b, C c) : this(null, b, c) { }
public ClassWithABC_LastConstructorWithAttribute(B b, C c) : this(null, b, c) { }
[ActivatorUtilitiesConstructor]
public ClassWithABC_LastConstructorWithAttribute(A a, B b, C c) : base(a, b , c) { }
public ClassWithABC_LastConstructorWithAttribute(A a, B b, C c) : base(a, b, c) { }
}

internal class FakeServiceProvider : IServiceProvider
Expand Down Expand Up @@ -512,14 +520,14 @@ internal class ClassWithABC_DefaultConstructorFirst : ClassWithABC
{
public ClassWithABC_DefaultConstructorFirst() : base() { }
public ClassWithABC_DefaultConstructorFirst(A a) : base(a) { }
public ClassWithABC_DefaultConstructorFirst(A a, B b) : base (a, b) { }
public ClassWithABC_DefaultConstructorFirst(A a, B b, C c) : base (a, b, c) { }
public ClassWithABC_DefaultConstructorFirst(A a, B b) : base(a, b) { }
public ClassWithABC_DefaultConstructorFirst(A a, B b, C c) : base(a, b, c) { }
}

internal class ClassWithABC_DefaultConstructorLast : ClassWithABC
{
public ClassWithABC_DefaultConstructorLast(A a, B b, C c) : base (a, b, c) { }
public ClassWithABC_DefaultConstructorLast(A a, B b) : base (a, b) { }
public ClassWithABC_DefaultConstructorLast(A a, B b, C c) : base(a, b, c) { }
public ClassWithABC_DefaultConstructorLast(A a, B b) : base(a, b) { }
public ClassWithABC_DefaultConstructorLast(A a) : base(a) { }
public ClassWithABC_DefaultConstructorLast() : base() { }
}
Expand All @@ -533,3 +541,4 @@ public ClassWithStringDefaultValue(string text = "DEFAULT")
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,7 @@ Func<Type, ServiceCallSite> CreateAotCompatibilityCallSiteFactory()

RemoteInvokeOptions options = new RemoteInvokeOptions();
options.RuntimeConfigurationOptions.Add("System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported", "false");
options.RuntimeConfigurationOptions.Add("System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeCompiled", "false");

using RemoteInvokeHandle remoteHandle = RemoteExecutor.Invoke(() =>
{
Expand Down Expand Up @@ -966,7 +967,7 @@ Func<Type, ServiceCallSite> CreateAotCompatibilityCallSiteFactory()
Assert.Equal(2, ((Struct1)callSite.Value).Value);
}, options);

// Verify the above scenarios work when IsDynamicCodeSupported is not set
// Verify the above scenarios work when IsDynamicCodeSupported + IsDynamicCodeCompiled are not set
Func<Type, ServiceCallSite> callSiteFactory = CreateAotCompatibilityCallSiteFactory();

// Open Generics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public ConstructorInvoker(RuntimeConstructorInfo constructorInfo)
}
else if (LocalAppContextSwitches.ForceEmitInvoke && !LocalAppContextSwitches.ForceInterpretedInvoke)
{
// Always use emit invoke (if IsDynamicCodeCompiled == true); useful for testing.
// Always use emit invoke (if IsDynamicCodeSupported == true); useful for testing.
_invoked = true;
}
}
Expand Down Expand Up @@ -53,7 +53,7 @@ public ConstructorInvoker(RuntimeConstructorInfo constructorInfo)
}
else
{
if (RuntimeFeature.IsDynamicCodeCompiled)
if (RuntimeFeature.IsDynamicCodeSupported)
{
_invokeFunc = InvokerEmitUtil.CreateInvokeDelegate(_method);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,13 @@ public static unsafe InvokeFunc CreateInvokeDelegate(MethodBase method)

// Invoke the method.
// For CallStack reasons, don't inline target method.
#if MONO
il.Emit(OpCodes.Call, Methods.DisableInline());
#if TARGET_WASM
// Mono interpreter does not support\need this intrinsic.
#elif MONO
il.Emit(OpCodes.Call, Methods.DisableInline());
#else
il.Emit(OpCodes.Call, Methods.NextCallReturnAddress());
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Call, Methods.NextCallReturnAddress());
il.Emit(OpCodes.Pop);
#endif

if (emitNew)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ internal sealed partial class MethodInvoker
}
else
{
if (RuntimeFeature.IsDynamicCodeCompiled)
if (RuntimeFeature.IsDynamicCodeSupported)
{
_invokeFunc = InvokerEmitUtil.CreateInvokeDelegate(_method);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public MethodInvoker(MethodBase method)
}
else if (LocalAppContextSwitches.ForceEmitInvoke && !LocalAppContextSwitches.ForceInterpretedInvoke)
{
// Always use emit invoke (if IsDynamicCodeCompiled == true); useful for testing.
// Always use emit invoke (if IsDynamicCodeSupported == true); useful for testing.
_invoked = true;
}
}
Expand Down