diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp index 8c89f6ff7d2426..8615fd16409cfb 100644 --- a/src/coreclr/nativeaot/Bootstrap/main.cpp +++ b/src/coreclr/nativeaot/Bootstrap/main.cpp @@ -125,8 +125,6 @@ MANAGED_RUNTIME_EXPORT(AppendExceptionStackFrame) MANAGED_RUNTIME_EXPORT(GetSystemArrayEEType) MANAGED_RUNTIME_EXPORT(OnFirstChanceException) MANAGED_RUNTIME_EXPORT(OnUnhandledException) -MANAGED_RUNTIME_EXPORT(IDynamicCastableIsInterfaceImplemented) -MANAGED_RUNTIME_EXPORT(IDynamicCastableGetInterfaceImplementation) #ifdef FEATURE_OBJCMARSHAL MANAGED_RUNTIME_EXPORT(ObjectiveCMarshalTryGetTaggedMemory) MANAGED_RUNTIME_EXPORT(ObjectiveCMarshalGetIsTrackedReferenceCallback) @@ -145,8 +143,6 @@ static const pfn c_classlibFunctions[] = { &MANAGED_RUNTIME_EXPORT_NAME(GetSystemArrayEEType), &MANAGED_RUNTIME_EXPORT_NAME(OnFirstChanceException), &MANAGED_RUNTIME_EXPORT_NAME(OnUnhandledException), - &MANAGED_RUNTIME_EXPORT_NAME(IDynamicCastableIsInterfaceImplemented), - &MANAGED_RUNTIME_EXPORT_NAME(IDynamicCastableGetInterfaceImplementation), #ifdef FEATURE_OBJCMARSHAL &MANAGED_RUNTIME_EXPORT_NAME(ObjectiveCMarshalTryGetTaggedMemory), &MANAGED_RUNTIME_EXPORT_NAME(ObjectiveCMarshalGetIsTrackedReferenceCallback), diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs index 9a1b1ad7ef985a..7a6f07a01c0e19 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs @@ -4,6 +4,7 @@ using System; using System.Runtime; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Internal.Runtime; @@ -138,9 +139,7 @@ private static unsafe IntPtr RhResolveDispatchWorker(object pObject, void* cell, { // Dispatch not resolved through normal dispatch map, try using the IDynamicInterfaceCastable // This will either give us the appropriate result, or throw. - var pfnGetInterfaceImplementation = (delegate*) - pInstanceType->GetClasslibFunction(ClassLibFunctionId.IDynamicCastableGetInterfaceImplementation); - pTargetCode = pfnGetInterfaceImplementation(pObject, cellInfo.InterfaceType, cellInfo.InterfaceSlot); + pTargetCode = IDynamicInterfaceCastable.GetDynamicInterfaceImplementation((IDynamicInterfaceCastable)pObject, cellInfo.InterfaceType, cellInfo.InterfaceSlot); Diagnostics.Debug.Assert(pTargetCode != IntPtr.Zero); } return pTargetCode; diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs index 8f6dfb77bea39c..d7557d654a7217 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs @@ -44,12 +44,10 @@ internal enum ClassLibFunctionId GetSystemArrayEEType = 5, OnFirstChance = 6, OnUnhandledException = 7, - IDynamicCastableIsInterfaceImplemented = 8, - IDynamicCastableGetInterfaceImplementation = 9, - ObjectiveCMarshalTryGetTaggedMemory = 10, - ObjectiveCMarshalGetIsTrackedReferenceCallback = 11, - ObjectiveCMarshalGetOnEnteredFinalizerQueueCallback = 12, - ObjectiveCMarshalGetUnhandledExceptionPropagationHandler = 13, + ObjectiveCMarshalTryGetTaggedMemory = 8, + ObjectiveCMarshalGetIsTrackedReferenceCallback = 9, + ObjectiveCMarshalGetOnEnteredFinalizerQueueCallback = 10, + ObjectiveCMarshalGetUnhandledExceptionPropagationHandler = 11, } internal static class InternalCalls diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs index bc5abe5dc63dcc..5ea530800784d1 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs @@ -469,9 +469,7 @@ private static unsafe object CheckCastClassSpecial(MethodTable* pTargetType, obj private static unsafe bool IsInstanceOfInterfaceViaIDynamicInterfaceCastable(MethodTable* pTargetType, object obj, bool throwing) { - var pfnIsInterfaceImplemented = (delegate*) - pTargetType->GetClasslibFunction(ClassLibFunctionId.IDynamicCastableIsInterfaceImplemented); - return pfnIsInterfaceImplemented(obj, pTargetType, throwing); + return ((IDynamicInterfaceCastable)obj).IsInterfaceImplemented(new RuntimeTypeHandle(pTargetType), throwing); } internal static unsafe bool IsDerived(MethodTable* pDerivedType, MethodTable* pBaseType) diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/ThrowHelpers.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/ThrowHelpers.cs index e52c8a598ace00..3ee1884b129af7 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/ThrowHelpers.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/ThrowHelpers.cs @@ -57,5 +57,10 @@ private static void ThrowArgumentOutOfRangeException() // exception doesn't exist in MRT: throw PlatformNotSupportedException() instead throw new PlatformNotSupportedException(); } + + private static void ThrowFeatureBodyRemoved() + { + throw new NotSupportedException(); + } } } diff --git a/src/coreclr/nativeaot/Runtime/ICodeManager.h b/src/coreclr/nativeaot/Runtime/ICodeManager.h index 0fd8f60a5458fd..b9e157c5cae41a 100644 --- a/src/coreclr/nativeaot/Runtime/ICodeManager.h +++ b/src/coreclr/nativeaot/Runtime/ICodeManager.h @@ -105,12 +105,10 @@ enum class ClasslibFunctionId GetSystemArrayEEType = 5, OnFirstChanceException = 6, OnUnhandledException = 7, - IDynamicCastableIsInterfaceImplemented = 8, - IDynamicCastableGetInterfaceImplementation = 9, - ObjectiveCMarshalTryGetTaggedMemory = 10, - ObjectiveCMarshalGetIsTrackedReferenceCallback = 11, - ObjectiveCMarshalGetOnEnteredFinalizerQueueCallback = 12, - ObjectiveCMarshalGetUnhandledExceptionPropagationHandler = 13, + ObjectiveCMarshalTryGetTaggedMemory = 8, + ObjectiveCMarshalGetIsTrackedReferenceCallback = 9, + ObjectiveCMarshalGetOnEnteredFinalizerQueueCallback = 10, + ObjectiveCMarshalGetUnhandledExceptionPropagationHandler = 11, }; enum class AssociatedDataFlags : unsigned char diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index e91317e9d1f9d3..d614f6063830de 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -113,7 +113,6 @@ - @@ -202,6 +201,7 @@ + diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/IDynamicInterfaceCastableSupport.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/IDynamicInterfaceCastable.cs similarity index 82% rename from src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/IDynamicInterfaceCastableSupport.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/IDynamicInterfaceCastable.cs index a1e146fb1b0a8c..ee1e9d7435e39f 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/IDynamicInterfaceCastableSupport.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/IDynamicInterfaceCastable.cs @@ -3,28 +3,22 @@ using System; using System.Runtime; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Threading; +using Internal.Runtime; using Internal.Runtime.Augments; using Internal.TypeSystem; using Debug = System.Diagnostics.Debug; -namespace Internal.Runtime +namespace System.Runtime.InteropServices { - internal static unsafe class IDynamicCastableSupport + public unsafe partial interface IDynamicInterfaceCastable { - [RuntimeExport("IDynamicCastableIsInterfaceImplemented")] - internal static bool IDynamicCastableIsInterfaceImplemented(IDynamicInterfaceCastable instance, MethodTable* interfaceType, bool throwIfNotImplemented) - { - return instance.IsInterfaceImplemented(new RuntimeTypeHandle(interfaceType), throwIfNotImplemented); - } - private static readonly object s_thunkPoolHeap = RuntimeAugments.CreateThunksHeap(RuntimeImports.GetInteropCommonStubAddress()); - [RuntimeExport("IDynamicCastableGetInterfaceImplementation")] - internal static IntPtr IDynamicCastableGetInterfaceImplementation(IDynamicInterfaceCastable instance, MethodTable* interfaceType, ushort slot) + internal static nint GetDynamicInterfaceImplementation(IDynamicInterfaceCastable instance, MethodTable* interfaceType, ushort slot) { RuntimeTypeHandle handle = instance.GetInterfaceImplementation(new RuntimeTypeHandle(interfaceType)); MethodTable* implType = handle.ToMethodTable(); @@ -38,10 +32,10 @@ internal static IntPtr IDynamicCastableGetInterfaceImplementation(IDynamicInterf } MethodTable* genericContext = null; - IntPtr result = RuntimeImports.RhResolveDynamicInterfaceCastableDispatchOnType(implType, interfaceType, slot, &genericContext); - if (result == IntPtr.Zero) + nint result = RuntimeImports.RhResolveDynamicInterfaceCastableDispatchOnType(implType, interfaceType, slot, &genericContext); + if (result == nint.Zero) { - IDynamicCastableGetInterfaceImplementationFailure(instance, interfaceType, implType); + GetInterfaceImplementationFailure(instance, interfaceType, implType); } if (genericContext != null) @@ -73,7 +67,7 @@ private static void ThrowInvalidOperationException(MethodTable* resolvedImplType throw new InvalidOperationException(SR.Format(SR.IDynamicInterfaceCastable_NotInterface, Type.GetTypeFromMethodTable(resolvedImplType))); } - private static void IDynamicCastableGetInterfaceImplementationFailure(object instance, MethodTable* interfaceType, MethodTable* resolvedImplType) + private static void GetInterfaceImplementationFailure(object instance, MethodTable* interfaceType, MethodTable* resolvedImplType) { if (resolvedImplType->DispatchMap == null) throw new InvalidOperationException(SR.Format(SR.IDynamicInterfaceCastable_MissingImplementationAttribute, Type.GetTypeFromMethodTable(resolvedImplType), nameof(DynamicInterfaceCastableImplementationAttribute))); diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/Internal/Runtime/IDynamicInterfaceCastableSupport.cs b/src/coreclr/nativeaot/Test.CoreLib/src/Internal/Runtime/IDynamicInterfaceCastableSupport.cs deleted file mode 100644 index 08c2c0b0e3de07..00000000000000 --- a/src/coreclr/nativeaot/Test.CoreLib/src/Internal/Runtime/IDynamicInterfaceCastableSupport.cs +++ /dev/null @@ -1,24 +0,0 @@ -// 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.Runtime; - -namespace Internal.Runtime -{ - internal static unsafe class IDynamicCastableSupport - { - [RuntimeExport("IDynamicCastableIsInterfaceImplemented")] - internal static bool IDynamicCastableIsInterfaceImplemented(object instance, MethodTable* interfaceType, bool throwIfNotImplemented) - { - return false; - } - - [RuntimeExport("IDynamicCastableGetInterfaceImplementation")] - internal static IntPtr IDynamicCastableGetInterfaceImplementation(object instance, MethodTable* interfaceType, ushort slot) - { - RuntimeImports.RhpFallbackFailFast(); - return default; - } - } -} diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/CompilerServices/RuntimeFeature.cs b/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/CompilerServices/RuntimeFeature.cs new file mode 100644 index 00000000000000..4e658bc1f61689 --- /dev/null +++ b/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/CompilerServices/RuntimeFeature.cs @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime.CompilerServices +{ + public static partial class RuntimeFeature + { + /// + /// Name of the Portable PDB feature. + /// + public const string PortablePdb = nameof(PortablePdb); + + /// + /// Indicates that this version of runtime supports default interface method implementations. + /// + public const string DefaultImplementationsOfInterfaces = nameof(DefaultImplementationsOfInterfaces); + + /// + /// Indicates that this version of runtime supports the Unmanaged calling convention value. + /// + public const string UnmanagedSignatureCallingConvention = nameof(UnmanagedSignatureCallingConvention); + + /// + /// Indicates that this version of runtime supports covariant returns in overrides of methods declared in classes. + /// + public const string CovariantReturnsOfClasses = nameof(CovariantReturnsOfClasses); + + /// + /// Represents a runtime feature where types can define ref fields. + /// + public const string ByRefFields = nameof(ByRefFields); + + /// + /// Represents a runtime feature where byref-like types can be used in Generic parameters. + /// + public const string ByRefLikeGenerics = nameof(ByRefLikeGenerics); + + /// + /// Indicates that this version of runtime supports virtual static members of interfaces. + /// + public const string VirtualStaticsInInterfaces = nameof(VirtualStaticsInInterfaces); + + /// + /// Indicates that this version of runtime supports and as numeric types. + /// + public const string NumericIntPtr = nameof(NumericIntPtr); + } +} diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/InteropServices/IDynamicInterfaceCastable.cs b/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/InteropServices/IDynamicInterfaceCastable.cs new file mode 100644 index 00000000000000..4d9b8a9a54cb9a --- /dev/null +++ b/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/InteropServices/IDynamicInterfaceCastable.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Internal.Runtime; + +namespace System.Runtime.InteropServices +{ + public unsafe partial interface IDynamicInterfaceCastable + { + internal static IntPtr GetDynamicInterfaceImplementation(object instance, MethodTable* interfaceType, ushort slot) + { + RuntimeImports.RhpFallbackFailFast(); + return default; + } + } +} diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/System/RuntimeTypeHandle.cs b/src/coreclr/nativeaot/Test.CoreLib/src/System/RuntimeTypeHandle.cs index 9adaed61c4cc86..e4bb6b9b17467a 100644 --- a/src/coreclr/nativeaot/Test.CoreLib/src/System/RuntimeTypeHandle.cs +++ b/src/coreclr/nativeaot/Test.CoreLib/src/System/RuntimeTypeHandle.cs @@ -5,6 +5,8 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using Internal.Runtime; + namespace System { [StructLayout(LayoutKind.Sequential)] @@ -17,6 +19,11 @@ internal RuntimeTypeHandle(IntPtr value) _value = value; } + unsafe internal RuntimeTypeHandle(MethodTable* value) + :this((IntPtr)value) + { + } + [Intrinsic] internal static unsafe IntPtr ToIntPtr(RuntimeTypeHandle handle) { diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj b/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj index 956b3ecbf04e8e..0b82467b1a942e 100644 --- a/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj +++ b/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj @@ -209,11 +209,14 @@ System\Runtime\CompilerServices\Unsafe.cs - + + Common\System\Runtime\InteropServices\IDynamicInterfaceCastable.cs + + @@ -222,6 +225,7 @@ + diff --git a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs index 2728cb113d3a89..ceb7b6b71141b3 100644 --- a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs +++ b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs @@ -218,6 +218,8 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType public virtual bool CanReferenceConstructedTypeOrCanonicalFormOfType(TypeDesc type) => true; public virtual TypeDesc[] GetImplementingClasses(TypeDesc type) => null; + + public virtual bool CanHaveDynamicInterfaceImplementations(TypeDesc type) => true; #endif } } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs index ecd3df3a3915c8..c32e6215bd5049 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs @@ -308,11 +308,20 @@ public ISymbolNode ComputeConstantLookup(ReadyToRunHelperId lookupKind, object t { var type = (TypeDesc)targetOfLookup; - // We counter-intuitively ask for a constructed type symbol. This is needed due to IDynamicInterfaceCastable. - // If this cast happens with an object that implements IDynamicIntefaceCastable, user code will - // see a RuntimeTypeHandle representing this interface. if (type.IsInterface) - return NodeFactory.MaximallyConstructableType(type); + { + // We counter-intuitively ask for a constructed type symbol. This is needed due to IDynamicInterfaceCastable. + // If this cast happens with an object that implements IDynamicInterfaceCastable, user code will + // see a RuntimeTypeHandle representing this interface. + if (NodeFactory.DevirtualizationManager.CanHaveDynamicInterfaceImplementations(type)) + { + return NodeFactory.MaximallyConstructableType(type); + } + else + { + return NecessaryTypeSymbolIfPossible(type); + } + } if (type.IsNullable) type = type.Instantiation[0]; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/InterfaceDispatchCellNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/InterfaceDispatchCellNode.cs index e0bf93690edf8f..f206358d283644 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/InterfaceDispatchCellNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/InterfaceDispatchCellNode.cs @@ -50,6 +50,20 @@ public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) public override bool StaticDependenciesAreComputed => true; + private IEETypeNode GetInterfaceTypeNode(NodeFactory factory) + { + // If this dispatch cell is ever used with an object that implements IDynamicIntefaceCastable, user code will + // see a RuntimeTypeHandle representing this interface. + if (factory.DevirtualizationManager.CanHaveDynamicInterfaceImplementations(_targetMethod.OwningType)) + { + return factory.ConstructedTypeSymbol(_targetMethod.OwningType); + } + else + { + return factory.NecessaryTypeSymbol(_targetMethod.OwningType); + } + } + public override IEnumerable GetStaticDependencies(NodeFactory factory) { DependencyList result = new DependencyList(); @@ -63,10 +77,7 @@ public override IEnumerable GetStaticDependencies(NodeFacto result.Add(factory.InitialInterfaceDispatchStub, "Initial interface dispatch stub"); - // We counter-intuitively ask for a constructed type symbol. This is needed due to IDynamicInterfaceCastable. - // If this dispatch cell is ever used with an object that implements IDynamicIntefaceCastable, user code will - // see a RuntimeTypeHandle representing this interface. - result.Add(factory.ConstructedTypeSymbol(_targetMethod.OwningType), "Interface type"); + result.Add(GetInterfaceTypeNode(factory), "Interface type"); return result; } @@ -75,10 +86,7 @@ public override void EncodeData(ref ObjectDataBuilder objData, NodeFactory facto { objData.EmitPointerReloc(factory.InitialInterfaceDispatchStub); - // We counter-intuitively ask for a constructed type symbol. This is needed due to IDynamicInterfaceCastable. - // If this dispatch cell is ever used with an object that implements IDynamicIntefaceCastable, user code will - // see a RuntimeTypeHandle representing this interface. - IEETypeNode interfaceType = factory.ConstructedTypeSymbol(_targetMethod.OwningType); + IEETypeNode interfaceType = GetInterfaceTypeNode(factory); if (factory.Target.SupportsRelativePointers) { if (interfaceType.RepresentsIndirectionCell) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs index 309772d6e5ef72..bc3f6ef3945523 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs @@ -150,6 +150,7 @@ ILScanResults IILScanner.Scan() _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.CheckInstanceInterface), "Not tracked by scanner"); _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.CheckInstanceClass), "Not tracked by scanner"); _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.IsInstanceOfException), "Not tracked by scanner"); + _dependencyGraph.AddRoot(_nodeFactory.MethodEntrypoint(_nodeFactory.TypeSystemContext.GetHelperEntryPoint("ThrowHelpers", "ThrowFeatureBodyRemoved")), "Substitution for methods removed based on scanning"); _dependencyGraph.ComputeMarkedNodes(); @@ -276,6 +277,34 @@ public ReadOnlyFieldPolicy GetReadOnlyFieldPolicy() return new ScannedReadOnlyPolicy(MarkedNodes); } + public BodyAndFieldSubstitutions GetBodyAndFieldSubstitutions() + { + Dictionary bodySubstitutions = []; + + bool hasIDynamicInterfaceCastableType = false; + + foreach (var type in ConstructedEETypes) + { + if (type.IsIDynamicInterfaceCastable) + { + hasIDynamicInterfaceCastableType = true; + break; + } + } + + if (!hasIDynamicInterfaceCastableType) + { + // We can't easily trim out some of the IDynamicInterfaceCastable infrastructure because + // the callers do type checks based on flags on the MethodTable instead of an actual type cast. + // Trim out the logic that we can't do easily here. + TypeDesc iDynamicInterfaceCastableType = _factory.TypeSystemContext.SystemModule.GetKnownType("System.Runtime.InteropServices", "IDynamicInterfaceCastable"); + MethodDesc getDynamicInterfaceImplementationMethod = iDynamicInterfaceCastableType.GetKnownMethod("GetDynamicInterfaceImplementation", null); + bodySubstitutions.Add(getDynamicInterfaceImplementationMethod, BodySubstitution.ThrowingBody); + } + + return new BodyAndFieldSubstitutions(bodySubstitutions, []); + } + public TypeMapManager GetTypeMapManager() { return new ScannedTypeMapManager(_factory); @@ -450,10 +479,12 @@ private sealed class ScannedDevirtualizationManager : DevirtualizationManager private HashSet _disqualifiedTypes = new(); private HashSet _overriddenMethods = new(); private HashSet _generatedVirtualMethods = new(); + private readonly bool _canHaveDynamicInterfaceImplementations; public ScannedDevirtualizationManager(NodeFactory factory, ImmutableArray> markedNodes) { var vtables = new Dictionary>(); + var dynamicInterfaceCastableImplementationTargets = new HashSet(); foreach (var node in markedNodes) { @@ -493,7 +524,7 @@ public ScannedDevirtualizationManager(NodeFactory factory, ImmutableArray BuildVTable(NodeFactory factory, TypeDesc currentType, T _overriddenMethods.Add(baseVtable[i].GetCanonMethodTarget(CanonicalFormKind.Specific)); } } + + _canHaveDynamicInterfaceImplementations |= type.IsIDynamicInterfaceCastable; } } } + + if (_canHaveDynamicInterfaceImplementations) + { + _disqualifiedTypes.UnionWith(dynamicInterfaceCastableImplementationTargets); + } } private static bool CanAssumeWholeProgramViewOnTypeUse(NodeFactory factory, TypeDesc implementingType, DefType baseType) @@ -780,6 +818,8 @@ public override TypeDesc[] GetImplementingClasses(TypeDesc type) } return null; } + + public override bool CanHaveDynamicInterfaceImplementations(TypeDesc type) => _canHaveDynamicInterfaceImplementations; } private sealed class ScannedInliningPolicy : IInliningPolicy diff --git a/src/coreclr/tools/aot/ILCompiler/Program.cs b/src/coreclr/tools/aot/ILCompiler/Program.cs index 1e301684b7721b..0cf9f83308e207 100644 --- a/src/coreclr/tools/aot/ILCompiler/Program.cs +++ b/src/coreclr/tools/aot/ILCompiler/Program.cs @@ -529,6 +529,10 @@ void RunScanner() interopStubManager = scanResults.GetInteropStubManager(interopStateManager, pinvokePolicy); + substitutions.AppendFrom(scanResults.GetBodyAndFieldSubstitutions()); + + substitutionProvider = new SubstitutionProvider(logger, featureSwitches, substitutions); + ilProvider = new SubstitutedILProvider(unsubstitutedILProvider, substitutionProvider, devirtualizationManager, metadataManager); // Use a more precise IL provider that uses whole program analysis for dead branch elimination diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/IDynamicInterfaceCastable.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/IDynamicInterfaceCastable.cs index e4b327da1cfee2..f7b87ef6a791bb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/IDynamicInterfaceCastable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/IDynamicInterfaceCastable.cs @@ -10,7 +10,7 @@ namespace System.Runtime.InteropServices /// Implementation of this interface on a value type will be ignored. Only non-value types are allowed /// to participate in a type cast failure through this interface. /// - public interface IDynamicInterfaceCastable + public partial interface IDynamicInterfaceCastable { /// /// Called when an implementing class instance is cast to an interface type that