diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DynamicallyAccessedMembersBinder.cs b/src/coreclr/tools/Common/Compiler/Dataflow/DynamicallyAccessedMembersBinder.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DynamicallyAccessedMembersBinder.cs rename to src/coreclr/tools/Common/Compiler/Dataflow/DynamicallyAccessedMembersBinder.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/EcmaExtensions.cs b/src/coreclr/tools/Common/Compiler/Dataflow/EcmaExtensions.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/EcmaExtensions.cs rename to src/coreclr/tools/Common/Compiler/Dataflow/EcmaExtensions.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericParameterProxy.cs b/src/coreclr/tools/Common/Compiler/Dataflow/GenericParameterProxy.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericParameterProxy.cs rename to src/coreclr/tools/Common/Compiler/Dataflow/GenericParameterProxy.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodProxy.cs b/src/coreclr/tools/Common/Compiler/Dataflow/MethodProxy.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodProxy.cs rename to src/coreclr/tools/Common/Compiler/Dataflow/MethodProxy.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ParameterProxy.cs b/src/coreclr/tools/Common/Compiler/Dataflow/ParameterProxy.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ParameterProxy.cs rename to src/coreclr/tools/Common/Compiler/Dataflow/ParameterProxy.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeExtensions.cs b/src/coreclr/tools/Common/Compiler/Dataflow/TypeExtensions.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeExtensions.cs rename to src/coreclr/tools/Common/Compiler/Dataflow/TypeExtensions.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeProxy.cs b/src/coreclr/tools/Common/Compiler/Dataflow/TypeProxy.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeProxy.cs rename to src/coreclr/tools/Common/Compiler/Dataflow/TypeProxy.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/EventPseudoDesc.cs b/src/coreclr/tools/Common/Compiler/EventPseudoDesc.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/EventPseudoDesc.cs rename to src/coreclr/tools/Common/Compiler/EventPseudoDesc.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSettings.cs b/src/coreclr/tools/Common/Compiler/FeatureSettings.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSettings.cs rename to src/coreclr/tools/Common/Compiler/FeatureSettings.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessLinkerXmlBase.cs b/src/coreclr/tools/Common/Compiler/ProcessLinkerXmlBase.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessLinkerXmlBase.cs rename to src/coreclr/tools/Common/Compiler/ProcessLinkerXmlBase.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/PropertyPseudoDesc.cs b/src/coreclr/tools/Common/Compiler/PropertyPseudoDesc.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/PropertyPseudoDesc.cs rename to src/coreclr/tools/Common/Compiler/PropertyPseudoDesc.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/PseudoDescExtensions.cs b/src/coreclr/tools/Common/Compiler/PseudoDescExtensions.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/PseudoDescExtensions.cs rename to src/coreclr/tools/Common/Compiler/PseudoDescExtensions.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/BodySubstitutionParser.cs b/src/coreclr/tools/Common/Compiler/ReferenceSource/BodySubstitutionParser.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/BodySubstitutionParser.cs rename to src/coreclr/tools/Common/Compiler/ReferenceSource/BodySubstitutionParser.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/DescriptorMarker.cs b/src/coreclr/tools/Common/Compiler/ReferenceSource/DescriptorMarker.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/DescriptorMarker.cs rename to src/coreclr/tools/Common/Compiler/ReferenceSource/DescriptorMarker.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/FeatureSettings.cs b/src/coreclr/tools/Common/Compiler/ReferenceSource/FeatureSettings.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/FeatureSettings.cs rename to src/coreclr/tools/Common/Compiler/ReferenceSource/FeatureSettings.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/GenericParameterProxy.cs b/src/coreclr/tools/Common/Compiler/ReferenceSource/GenericParameterProxy.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/GenericParameterProxy.cs rename to src/coreclr/tools/Common/Compiler/ReferenceSource/GenericParameterProxy.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/LinkAttributesParser.cs b/src/coreclr/tools/Common/Compiler/ReferenceSource/LinkAttributesParser.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/LinkAttributesParser.cs rename to src/coreclr/tools/Common/Compiler/ReferenceSource/LinkAttributesParser.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodProxy.cs b/src/coreclr/tools/Common/Compiler/ReferenceSource/MethodProxy.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/MethodProxy.cs rename to src/coreclr/tools/Common/Compiler/ReferenceSource/MethodProxy.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ParameterProxy.cs b/src/coreclr/tools/Common/Compiler/ReferenceSource/ParameterProxy.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/ParameterProxy.cs rename to src/coreclr/tools/Common/Compiler/ReferenceSource/ParameterProxy.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/ProcessLinkerXmlBase.cs b/src/coreclr/tools/Common/Compiler/ReferenceSource/ProcessLinkerXmlBase.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/ProcessLinkerXmlBase.cs rename to src/coreclr/tools/Common/Compiler/ReferenceSource/ProcessLinkerXmlBase.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/README.md b/src/coreclr/tools/Common/Compiler/ReferenceSource/README.md similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/README.md rename to src/coreclr/tools/Common/Compiler/ReferenceSource/README.md diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/TypePreserve.cs b/src/coreclr/tools/Common/Compiler/ReferenceSource/TypePreserve.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/TypePreserve.cs rename to src/coreclr/tools/Common/Compiler/ReferenceSource/TypePreserve.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/TypeProxy.cs b/src/coreclr/tools/Common/Compiler/ReferenceSource/TypeProxy.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReferenceSource/TypeProxy.cs rename to src/coreclr/tools/Common/Compiler/ReferenceSource/TypeProxy.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreserve.cs b/src/coreclr/tools/Common/Compiler/TypePreserve.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreserve.cs rename to src/coreclr/tools/Common/Compiler/TypePreserve.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index 3069685c02fe6f..66fd2256b6d6cb 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -265,6 +265,13 @@ + + + + + + + @@ -303,6 +310,7 @@ + @@ -310,8 +318,13 @@ + + + + + @@ -319,7 +332,6 @@ - @@ -341,13 +353,10 @@ - - - @@ -356,10 +365,8 @@ - - @@ -369,8 +376,6 @@ - - @@ -409,9 +414,7 @@ - - @@ -569,7 +572,6 @@ - @@ -578,10 +580,8 @@ - - diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/EffectiveVisibility.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/EffectiveVisibility.cs new file mode 100644 index 00000000000000..92e2b234c0f13a --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/EffectiveVisibility.cs @@ -0,0 +1,95 @@ +// 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.Diagnostics; +using System.Reflection; +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace ILCompiler +{ + public enum EffectiveVisibility + { + Private, + Public, + Family, + Assembly, + FamilyAndAssembly, + FamilyOrAssembly, + } + + public static class EffectiveVisibilityExtensions + { + private static EffectiveVisibility ToEffectiveVisibility(this TypeAttributes typeAttributes) + { + return (typeAttributes & TypeAttributes.VisibilityMask) switch + { + TypeAttributes.Public or TypeAttributes.NestedPublic => EffectiveVisibility.Public, + TypeAttributes.NotPublic => EffectiveVisibility.Assembly, + TypeAttributes.NestedPrivate => EffectiveVisibility.Private, + TypeAttributes.NestedAssembly => EffectiveVisibility.Assembly, + TypeAttributes.NestedFamily => EffectiveVisibility.Family, + TypeAttributes.NestedFamANDAssem => EffectiveVisibility.FamilyAndAssembly, + TypeAttributes.NestedFamORAssem => EffectiveVisibility.FamilyOrAssembly, + _ => throw new UnreachableException() + }; + } + private static EffectiveVisibility ToEffectiveVisibility(this MethodAttributes typeAttributes) + { + return (typeAttributes & MethodAttributes.MemberAccessMask) switch + { + // PrivateScope == Compiler-Controlled in the ECMA spec. A member with this accessibility + // is only accessible through a MemberDef, not a MemberRef. + // As a result, it's only accessible within the current assembly, which is effectively the same rules as + // Family for our case. + MethodAttributes.PrivateScope => EffectiveVisibility.Assembly, + MethodAttributes.Public => EffectiveVisibility.Public, + MethodAttributes.Private => EffectiveVisibility.Private, + MethodAttributes.Assembly => EffectiveVisibility.Assembly, + MethodAttributes.Family => EffectiveVisibility.Family, + MethodAttributes.FamANDAssem => EffectiveVisibility.FamilyAndAssembly, + MethodAttributes.FamORAssem => EffectiveVisibility.FamilyOrAssembly, + _ => throw new UnreachableException() + }; + } + + private static EffectiveVisibility ConstrainToVisibility(this EffectiveVisibility visibility, EffectiveVisibility enclosingVisibility) + { + return (visibility, enclosingVisibility) switch + { + (_, _) when visibility == enclosingVisibility => visibility, + (_, EffectiveVisibility.Private) => EffectiveVisibility.Private, + (EffectiveVisibility.Private, _) => EffectiveVisibility.Private, + (EffectiveVisibility.Public, _) => enclosingVisibility, + (_, EffectiveVisibility.Public) => visibility, + (EffectiveVisibility.FamilyOrAssembly, _) => enclosingVisibility, + (_, EffectiveVisibility.FamilyOrAssembly) => visibility, + (EffectiveVisibility.Family, EffectiveVisibility.Assembly) => EffectiveVisibility.FamilyAndAssembly, + (EffectiveVisibility.Family, EffectiveVisibility.FamilyAndAssembly) => EffectiveVisibility.FamilyAndAssembly, + (EffectiveVisibility.Assembly, EffectiveVisibility.Family) => EffectiveVisibility.FamilyAndAssembly, + (EffectiveVisibility.Assembly, EffectiveVisibility.FamilyAndAssembly) => EffectiveVisibility.FamilyAndAssembly, + (EffectiveVisibility.FamilyAndAssembly, EffectiveVisibility.Family) => EffectiveVisibility.FamilyAndAssembly, + (EffectiveVisibility.FamilyAndAssembly, EffectiveVisibility.Assembly) => EffectiveVisibility.FamilyAndAssembly, + _ => throw new UnreachableException(), + }; + } + + public static bool IsExposedOutsideOfThisAssembly(this EffectiveVisibility visibility, bool anyInternalsVisibleTo) + { + return visibility is EffectiveVisibility.Public or EffectiveVisibility.Family + || (anyInternalsVisibleTo && visibility is EffectiveVisibility.Assembly or EffectiveVisibility.FamilyOrAssembly); + } + + public static EffectiveVisibility GetEffectiveVisibility(this EcmaMethod method) + { + EffectiveVisibility visibility = method.Attributes.ToEffectiveVisibility(); + + for (EcmaType type = (EcmaType)method.OwningType; type is not null; type = (EcmaType)type.ContainingType) + { + visibility = visibility.ConstrainToVisibility(type.Attributes.ToEffectiveVisibility()); + } + return visibility; + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunLibraryRootProvider.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunLibraryRootProvider.cs index daacba4ef35f6d..838cf6e9df6c00 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunLibraryRootProvider.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunLibraryRootProvider.cs @@ -6,92 +6,39 @@ using Internal.TypeSystem.Ecma; using Internal.TypeSystem; using Internal.JitInterface; +using System.Reflection.Metadata; namespace ILCompiler { /// - /// Provides compilation group for a library that compiles everything in the input IL module. + /// Roots all methods in the input IL module. /// - public class ReadyToRunRootProvider : ICompilationRootProvider + public class ReadyToRunLibraryRootProvider : ICompilationRootProvider { private EcmaModule _module; - private IEnumerable _profileData; - private readonly bool _profileDrivenPartialNGen; - public ReadyToRunRootProvider(EcmaModule module, ProfileDataManager profileDataManager, bool profileDrivenPartialNGen) + public ReadyToRunLibraryRootProvider(EcmaModule module) { _module = module; - _profileData = profileDataManager.GetMethodsForModuleDesc(module); - _profileDrivenPartialNGen = profileDrivenPartialNGen; } public void AddCompilationRoots(IRootingServiceProvider rootProvider) { - foreach (var method in _profileData) + foreach (MetadataType type in _module.GetAllTypes()) { - try + MetadataType typeWithMethods = type; + if (type.HasInstantiation) { - // Validate that this method is fully instantiated - if (method.OwningType.IsGenericDefinition || method.OwningType.ContainsSignatureVariables()) - { - continue; - } - - if (method.IsGenericMethodDefinition) - { - continue; - } - - bool containsSignatureVariables = false; - foreach (TypeDesc t in method.Instantiation) - { - if (t.IsGenericDefinition) - { - containsSignatureVariables = true; - break; - } - - if (t.ContainsSignatureVariables()) - { - containsSignatureVariables = true; - break; - } - } - if (containsSignatureVariables) + typeWithMethods = InstantiateIfPossible(type); + if (typeWithMethods == null) continue; - - if (!CorInfoImpl.ShouldSkipCompilation(method)) - { - CheckCanGenerateMethod(method); - rootProvider.AddCompilationRoot(method, rootMinimalDependencies: true, reason: "Profile triggered method"); - } - } - catch (TypeSystemException) - { - // Individual methods can fail to load types referenced in their signatures. - // Skip them in library mode since they're not going to be callable. - continue; } - } - if (!_profileDrivenPartialNGen) - { - foreach (MetadataType type in _module.GetAllTypes()) - { - MetadataType typeWithMethods = type; - if (type.HasInstantiation) - { - typeWithMethods = InstantiateIfPossible(type); - if (typeWithMethods == null) - continue; - } - - RootMethods(typeWithMethods, "Library module method", rootProvider); - } + RootMethods(typeWithMethods, "Library module method", rootProvider); } } - private void RootMethods(TypeDesc type, string reason, IRootingServiceProvider rootProvider) + private void RootMethods(MetadataType type, string reason, IRootingServiceProvider rootProvider) { foreach (MethodDesc method in type.GetAllMethods()) { @@ -192,7 +139,7 @@ private static Instantiation GetInstantiationThatMeetsConstraints(Instantiation return new Instantiation(args); } - private static InstantiatedType InstantiateIfPossible(MetadataType type) + public static InstantiatedType InstantiateIfPossible(MetadataType type) { Instantiation inst = GetInstantiationThatMeetsConstraints(type.Instantiation); if (inst.IsNull) @@ -203,7 +150,7 @@ private static InstantiatedType InstantiateIfPossible(MetadataType type) return type.MakeInstantiatedType(inst); } - private static MethodDesc InstantiateIfPossible(MethodDesc method) + public static MethodDesc InstantiateIfPossible(MethodDesc method) { Instantiation inst = GetInstantiationThatMeetsConstraints(method.Instantiation); if (inst.IsNull) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunProfilingRootProvider.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunProfilingRootProvider.cs new file mode 100644 index 00000000000000..bde2aa94d93ad3 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunProfilingRootProvider.cs @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Internal.JitInterface; +using Internal.TypeSystem.Ecma; +using Internal.TypeSystem; + +namespace ILCompiler +{ + /// + /// Roots all methods in the profile data in the module. + /// + public class ReadyToRunProfilingRootProvider : ICompilationRootProvider + { + private EcmaModule _module; + private IEnumerable _profileData; + + public ReadyToRunProfilingRootProvider(EcmaModule module, ProfileDataManager profileDataManager) + { + _module = module; + _profileData = profileDataManager.GetMethodsForModuleDesc(module); + } + + public void AddCompilationRoots(IRootingServiceProvider rootProvider) + { + foreach (var method in _profileData) + { + try + { + // Validate that this method is fully instantiated + if (method.OwningType.IsGenericDefinition || method.OwningType.ContainsSignatureVariables()) + { + continue; + } + + if (method.IsGenericMethodDefinition) + { + continue; + } + + bool containsSignatureVariables = false; + foreach (TypeDesc t in method.Instantiation) + { + if (t.IsGenericDefinition) + { + containsSignatureVariables = true; + break; + } + + if (t.ContainsSignatureVariables()) + { + containsSignatureVariables = true; + break; + } + } + if (containsSignatureVariables) + continue; + + if (!CorInfoImpl.ShouldSkipCompilation(method)) + { + ReadyToRunLibraryRootProvider.CheckCanGenerateMethod(method); + rootProvider.AddCompilationRoot(method, rootMinimalDependencies: true, reason: "Profile triggered method"); + } + } + catch (TypeSystemException) + { + // Individual methods can fail to load types referenced in their signatures. + // Skip them in library mode since they're not going to be callable. + continue; + } + } + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunVisibilityRootProvider.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunVisibilityRootProvider.cs new file mode 100644 index 00000000000000..4766937ce694b7 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunVisibilityRootProvider.cs @@ -0,0 +1,162 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; + +using Internal.TypeSystem.Ecma; +using Internal.TypeSystem; +using Internal.JitInterface; +using System.Reflection.Metadata; + +namespace ILCompiler +{ + /// + /// Roots all possibly-visible methods in the input IL module. + /// + public class ReadyToRunVisibilityRootProvider : ICompilationRootProvider + { + private EcmaModule _module; + + public ReadyToRunVisibilityRootProvider(EcmaModule module) + { + _module = module; + } + + public void AddCompilationRoots(IRootingServiceProvider rootProvider) + { + foreach (MetadataType type in _module.GetAllTypes()) + { + MetadataType typeWithMethods = type; + if (type.HasInstantiation) + { + typeWithMethods = ReadyToRunLibraryRootProvider.InstantiateIfPossible(type); + if (typeWithMethods == null) + continue; + } + + RootMethods(typeWithMethods, "Library module method", rootProvider, ((EcmaAssembly)_module.Assembly).HasAssemblyCustomAttribute("System.Runtime.CompilerServices", "InternalsVisibleToAttribute")); + } + + if (_module.EntryPoint is not null) + { + rootProvider.AddCompilationRoot(_module.EntryPoint, rootMinimalDependencies: false, $"{_module.Assembly.GetName()} Main Method"); + } + } + + private void RootMethods(MetadataType type, string reason, IRootingServiceProvider rootProvider, bool anyInternalsVisibleTo) + { + MethodImplRecord[] methodImplRecords = GetAllMethodImplRecordsForType((EcmaType)type.GetTypeDefinition()); + foreach (MethodDesc method in type.GetAllMethods()) + { + // Skip methods with no IL + if (method.IsAbstract) + continue; + + if (method.IsInternalCall) + continue; + + // If the method is not visible outside the assembly, then do not root the method. + // It will be rooted by any callers that require it and do not inline it. + if (!method.IsStaticConstructor + && method.GetTypicalMethodDefinition() is EcmaMethod ecma + && !ecma.GetEffectiveVisibility().IsExposedOutsideOfThisAssembly(anyInternalsVisibleTo)) + { + // If a method itself is not visible outside the assembly, but it implements a method that is, + // we want to root it as it could be called from outside the assembly. + // Since instance method overriding does not always require a MethodImpl record (it can be omitted when both the name and signature match) + // we will also root any methods that are virtual and do not have any MethodImpl records as it is difficult to determine all methods a method + // overrides or implements and we don't need to be perfect here. + bool anyMethodImplRecordsForMethod = false; + bool implementsOrOverridesVisibleMethod = false; + foreach (var record in methodImplRecords) + { + if (record.Body == ecma) + { + anyMethodImplRecordsForMethod = true; + implementsOrOverridesVisibleMethod = record.Decl.GetTypicalMethodDefinition() is EcmaMethod decl + && decl.GetEffectiveVisibility().IsExposedOutsideOfThisAssembly(anyInternalsVisibleTo); + if (implementsOrOverridesVisibleMethod) + { + break; + } + } + } + if (anyMethodImplRecordsForMethod && !implementsOrOverridesVisibleMethod) + { + continue; + } + if (!anyMethodImplRecordsForMethod && !method.IsVirtual) + { + continue; + } + } + + MethodDesc methodToRoot = method; + if (method.HasInstantiation) + { + methodToRoot = ReadyToRunLibraryRootProvider.InstantiateIfPossible(method); + + if (methodToRoot == null) + continue; + } + + try + { + if (!CorInfoImpl.ShouldSkipCompilation(method)) + { + ReadyToRunLibraryRootProvider.CheckCanGenerateMethod(methodToRoot); + rootProvider.AddCompilationRoot(methodToRoot, rootMinimalDependencies: false, reason: reason); + } + } + catch (TypeSystemException) + { + // Individual methods can fail to load types referenced in their signatures. + // Skip them in library mode since they're not going to be callable. + continue; + } + } + } + + private MethodImplRecord[] GetAllMethodImplRecordsForType(EcmaType type) + { + ArrayBuilder records = default; + MetadataReader metadataReader = type.MetadataReader; + TypeDefinition definition = metadataReader.GetTypeDefinition(type.Handle); + + foreach (var methodImplHandle in definition.GetMethodImplementations()) + { + MethodImplementation methodImpl = metadataReader.GetMethodImplementation(methodImplHandle); + + records.Add(new MethodImplRecord( + _module.GetMethod(methodImpl.MethodDeclaration), + _module.GetMethod(methodImpl.MethodBody) + )); + } + return records.ToArray(); + } + + /// + /// Determine if the visibility-based root provider should be used for the given module. + /// + /// The module + /// true if the module should use the visibility-based root provider; otherwise, false. + /// + /// We will use a visibility-based root provider for modules that are marked as trimmable. + /// Trimmable assemblies are less likely to use private reflection, which the visibility-based root provider + /// doesn't track well. + /// + public static bool UseVisibilityBasedRootProvider(EcmaModule module) + { + EcmaAssembly assembly = (EcmaAssembly)module.Assembly; + + foreach (var assemblyMetadata in assembly.GetDecodedCustomAttributes("System.Reflection", "AssemblyMetadataAttribute")) + { + if ((string)assemblyMetadata.FixedArguments[0].Value == "IsTrimmable") + { + return bool.TryParse((string)assemblyMetadata.FixedArguments[1].Value, out bool isTrimmable) && isTrimmable; + } + } + return false; + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunXmlRootProvider.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunXmlRootProvider.cs new file mode 100644 index 00000000000000..13ba5a4aeaa029 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunXmlRootProvider.cs @@ -0,0 +1,213 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; +using System.Text; +using System.Threading.Tasks; +using System.Xml.XPath; +using Internal.JitInterface; +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace ILCompiler +{ + public class ReadyToRunXmlRootProvider : ICompilationRootProvider + { + private readonly TypeSystemContext _context; + private readonly Stream _documentStream; + private readonly ManifestResource _resource; + private readonly ModuleDesc _owningModule; + private readonly string _xmlDocumentLocation; + + public ReadyToRunXmlRootProvider(Stream documentStream, ManifestResource resource, ModuleDesc owningModule, string xmlDocumentLocation) + { + _context = owningModule.Context; + _documentStream = documentStream; + _resource = resource; + _owningModule = owningModule; + _xmlDocumentLocation = xmlDocumentLocation; + } + + public void AddCompilationRoots(IRootingServiceProvider rootProvider) + { + CompilationRootProvider root = new CompilationRootProvider(rootProvider, _context, _documentStream, _resource, _owningModule, _xmlDocumentLocation); + root.ProcessXml(); + } + + public static bool TryCreateRootProviderFromEmbeddedDescriptorFile(EcmaModule module, out ReadyToRunXmlRootProvider provider) + { + PEMemoryBlock resourceDirectory = module.PEReader.GetSectionData(module.PEReader.PEHeaders.CorHeader.ResourcesDirectory.RelativeVirtualAddress); + + foreach (var resourceHandle in module.MetadataReader.ManifestResources) + { + ManifestResource resource = module.MetadataReader.GetManifestResource(resourceHandle); + + // Don't try to process linked resources or resources in other assemblies + if (!resource.Implementation.IsNil) + { + continue; + } + + string resourceName = module.MetadataReader.GetString(resource.Name); + if (resourceName == "ILLink.Descriptors.xml") + { + BlobReader reader = resourceDirectory.GetReader((int)resource.Offset, resourceDirectory.Length - (int)resource.Offset); + int length = (int)reader.ReadUInt32(); + + UnmanagedMemoryStream ms; + unsafe + { + ms = new UnmanagedMemoryStream(reader.CurrentPointer, length); + } + + provider = new ReadyToRunXmlRootProvider(ms, resource, module, "resource " + resourceName + " in " + module.ToString()); + return true; + } + } + provider = null; + return false; + } + + private class CompilationRootProvider : ProcessLinkerXmlBase + { + private const string NamespaceElementName = "namespace"; + private const string _preserve = "preserve"; + private readonly IRootingServiceProvider _rootingServiceProvider; + + public CompilationRootProvider(IRootingServiceProvider provider, TypeSystemContext context, Stream documentStream, ManifestResource resource, ModuleDesc owningModule, string xmlDocumentLocation) + : base(context, documentStream, resource, owningModule, xmlDocumentLocation, ImmutableDictionary.Empty) + { + _rootingServiceProvider = provider; + } + + public void ProcessXml() => ProcessXml(false); + + protected override void ProcessAssembly(ModuleDesc assembly, XPathNavigator nav, bool warnOnUnresolvedTypes) + { + if (GetTypePreserve(nav) == TypePreserve.All) + { + foreach (var type in assembly.GetAllTypes()) + { + PreserveMethodsOnType(type); + } + } + else + { + ProcessTypes(assembly, nav, warnOnUnresolvedTypes); + ProcessNamespaces(assembly, nav); + } + } + + private void PreserveMethodsOnType(TypeDesc type) + { + MetadataType typeWithMethods = (MetadataType)type; + if (type.HasInstantiation) + { + typeWithMethods = ReadyToRunLibraryRootProvider.InstantiateIfPossible(typeWithMethods); + if (typeWithMethods == null) + return; + } + + foreach (MethodDesc method in typeWithMethods.GetAllMethods()) + { + RootMethod(method); + } + } + + private void RootMethod(MethodDesc method) + { + // Skip methods with no IL + if (method.IsAbstract) + return; + + if (method.IsInternalCall) + return; + + MethodDesc methodToRoot = method; + if (method.HasInstantiation) + { + methodToRoot = ReadyToRunLibraryRootProvider.InstantiateIfPossible(method); + + if (methodToRoot == null) + return; + } + + try + { + if (!CorInfoImpl.ShouldSkipCompilation(method)) + { + ReadyToRunLibraryRootProvider.CheckCanGenerateMethod(methodToRoot); + _rootingServiceProvider.AddCompilationRoot(methodToRoot, rootMinimalDependencies: false, reason: "Linker XML descriptor"); + } + } + catch (TypeSystemException) + { + // Individual methods can fail to load types referenced in their signatures. + // Skip them in library mode since they're not going to be callable. + return; + } + } + + private void ProcessNamespaces(ModuleDesc assembly, XPathNavigator nav) + { + foreach (XPathNavigator namespaceNav in nav.SelectChildren(NamespaceElementName, XmlNamespace)) + { + if (!ShouldProcessElement(namespaceNav)) + continue; + + string fullname = GetFullName(namespaceNav); + foreach (DefType type in assembly.GetAllTypes()) + { + if (type.Namespace != fullname) + continue; + + ProcessType(type, nav); + } + } + } + + protected override void ProcessType(TypeDesc type, XPathNavigator nav) + { + TypePreserve preserve = GetTypePreserve(nav); + if (preserve == TypePreserve.All || preserve == TypePreserve.Methods) + { + PreserveMethodsOnType(type); + } + else + { + ProcessTypeChildren(type, nav); + } + } + + protected override void ProcessMethod(TypeDesc type, MethodDesc method, XPathNavigator nav, object customData) + { + MetadataType typeWithMethods = (MetadataType)type; + if (type.HasInstantiation) + { + InstantiatedType instantiated = ReadyToRunLibraryRootProvider.InstantiateIfPossible(typeWithMethods); + method = method.Context.GetMethodForInstantiatedType(method, instantiated); + } + + RootMethod(method); + } + + private static TypePreserve GetTypePreserve(XPathNavigator nav) + { + string attribute = GetAttribute(nav, _preserve); + if (string.IsNullOrEmpty(attribute)) + return nav.HasChildren ? TypePreserve.Nothing : TypePreserve.All; + + if (Enum.TryParse(attribute, true, out TypePreserve result)) + return result; + return TypePreserve.Nothing; + } + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index ea9930f54e39f7..9d30f81815b9d8 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -16,12 +16,18 @@ false Debug;Release;Checked false + $(NoWarn);CS8524 + + + all + contentfiles + @@ -55,6 +61,13 @@ + + + + + + + @@ -94,6 +107,7 @@ + @@ -101,8 +115,13 @@ + + + + + @@ -110,6 +129,16 @@ + + + + + + + + + + @@ -117,6 +146,8 @@ + + @@ -198,6 +229,7 @@ + @@ -220,6 +252,7 @@ + diff --git a/src/coreclr/tools/aot/crossgen2/Program.cs b/src/coreclr/tools/aot/crossgen2/Program.cs index c09d42c7afd1ac..5c568c6d8b7cb4 100644 --- a/src/coreclr/tools/aot/crossgen2/Program.cs +++ b/src/coreclr/tools/aot/crossgen2/Program.cs @@ -513,10 +513,24 @@ private void RunSingleCompilation(Dictionary inFilePaths, Instru // For normal compilations add compilation roots. foreach (var module in rootingModules) { - compilationRoots.Add(new ReadyToRunRootProvider( - module, - profileDataManager, - profileDrivenPartialNGen: partial)); + compilationRoots.Add(new ReadyToRunProfilingRootProvider(module, profileDataManager)); + // If we're doing partial precompilation, only use profile data. + if (!partial) + { + if (ReadyToRunVisibilityRootProvider.UseVisibilityBasedRootProvider(module)) + { + compilationRoots.Add(new ReadyToRunVisibilityRootProvider(module)); + + if (ReadyToRunXmlRootProvider.TryCreateRootProviderFromEmbeddedDescriptorFile(module, out ReadyToRunXmlRootProvider xmlProvider)) + { + compilationRoots.Add(xmlProvider); + } + } + else + { + compilationRoots.Add(new ReadyToRunLibraryRootProvider(module)); + } + } if (!_command.CompositeOrInputBubble) { diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/DataTypeImplementation.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/DataTypeImplementation.cs index f4f3c6489b9398..f683cd5e35136b 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/DataTypeImplementation.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/DataTypeImplementation.cs @@ -1113,7 +1113,7 @@ internal override RestrictionFlags ValidRestrictionFlags XsdSimpleValue simpleValue = (XsdSimpleValue)unionTypedValue; values.Add(new XmlAtomicValue(simpleValue.XmlType, simpleValue.TypedValue, nsmgr)); } - array = values.ToArray(typeof(XmlAtomicValue)); + array = ToArray(values, typeof(XmlAtomicValue[])); } else { //Variety == List or Atomic