| File: Compiler\ReadyToRunXmlRootProvider.cs | Web Access |
| Project: src\runtime\src\coreclr\tools\aot\ILCompiler.ReadyToRun\ILCompiler.ReadyToRun.csproj (ILCompiler.ReadyToRun) |
// 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 ILCompiler.Dataflow; 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; private InstructionSetSupport _instructionSetSupport; public CompilationRootProvider(IRootingServiceProvider provider, TypeSystemContext context, Stream documentStream, ManifestResource resource, ModuleDesc owningModule, string xmlDocumentLocation) : base(null , context, documentStream, resource, owningModule, xmlDocumentLocation, ImmutableDictionary<string, bool>.Empty) { _rootingServiceProvider = provider; _instructionSetSupport = ((ReadyToRunCompilerContext)owningModule.Context).InstructionSetSupport; } 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(_instructionSetSupport, 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.StringEquals(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); if (instantiated is null) return; 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; } } } }