| File: Compiler\DependencyAnalysis\ReadyToRun\ReadyToRunHeaderNode.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.Collections.Generic; using System.Diagnostics; using Internal.Runtime; using Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using Internal.ReadyToRunConstants; using ILCompiler.DependencyAnalysisFramework; using System.Threading.Tasks; namespace ILCompiler.DependencyAnalysis.ReadyToRun { public abstract class HeaderTableNode : ObjectNode, ISymbolDefinitionNode { public abstract void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb); public int Offset => 0; public override bool IsShareable => false; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public override bool StaticDependenciesAreComputed => true; public override ObjectNodeSection GetSection(NodeFactory factory) { if (factory.Target.IsWindows) return ObjectNodeSection.ReadOnlyDataSection; else return ObjectNodeSection.DataSection; } } public abstract class ModuleSpecificHeaderTableNode : HeaderTableNode { protected readonly EcmaModule _module; public ModuleSpecificHeaderTableNode(EcmaModule module) { _module = module; } public sealed override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { ModuleSpecificHeaderTableNode otherModuleSpecificHeaderTableNode = (ModuleSpecificHeaderTableNode)other; if (_module == null) { Debug.Assert(otherModuleSpecificHeaderTableNode._module != null); return -1; } else if (otherModuleSpecificHeaderTableNode._module == null) { return 1; } return _module.Assembly.GetName().Name.CompareTo(otherModuleSpecificHeaderTableNode._module.Assembly.GetName().Name); } protected abstract string ModuleSpecificName { get; } public sealed override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix); if (_module != null) { sb.Append(ModuleSpecificName); sb.Append(_module.Assembly.GetName().Name); } else { sb.Append(ModuleSpecificName); } } } public abstract class ReadyToRunHeaderNode : ObjectNode, ISymbolDefinitionNode { struct HeaderItem { public HeaderItem(ReadyToRunSectionType id, DependencyNodeCore<NodeFactory> node, ISymbolNode startSymbol) { Id = id; Node = node; StartSymbol = startSymbol; } public readonly ReadyToRunSectionType Id; public readonly DependencyNodeCore<NodeFactory> Node; public readonly ISymbolNode StartSymbol; } private readonly List<HeaderItem> _items = new List<HeaderItem>(); private readonly ReadyToRunFlags _flags; private readonly Task<(bool canSkipValidation, string[] reasons)> _shouldAddSkipTypeValidationFlag; public ReadyToRunHeaderNode(ReadyToRunFlags flags, EcmaModule moduleToCheckForSkipTypeValidation) { if (moduleToCheckForSkipTypeValidation != null) { _shouldAddSkipTypeValidationFlag = TypeValidationChecker.CanSkipValidation(moduleToCheckForSkipTypeValidation); } else { _shouldAddSkipTypeValidationFlag = Task.FromResult((false, new string[0])); } _flags = flags; } public void Add(ReadyToRunSectionType id, DependencyNodeCore<NodeFactory> node, ISymbolNode startSymbol) { _items.Add(new HeaderItem(id, node, startSymbol)); } public void Add<T>(ReadyToRunSectionType id, T node) where T : DependencyNodeCore<NodeFactory>, ISymbolNode { Add(id, node, node); } public int Offset => 0; public override bool IsShareable => false; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); protected abstract void AppendMangledHeaderName(NameMangler nameMangler, Utf8StringBuilder sb); public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) => AppendMangledHeaderName(nameMangler, sb); public override bool StaticDependenciesAreComputed => true; // For R2R, we can put the header in the read-only section on non-Windows as well. Since we emit a PE image // and do our own mapping, we don't need it to be writeable for the OS loader to handle absolute pointer relocs. // Our R2R PE images group read-only data into the .text section, so this doesn't result in more work to map. public override ObjectNodeSection GetSection(NodeFactory factory) => ObjectNodeSection.ReadOnlyDataSection; public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); builder.RequireInitialPointerAlignment(); builder.AddSymbol(this); EmitHeaderPrefix(ref builder); // Don't bother sorting if we're not emitting the contents if (!relocsOnly) _items.MergeSort((x, y) => Comparer<int>.Default.Compare((int)x.Id, (int)y.Id)); // ReadyToRunHeader.Flags int flagsInt = (int)_flags; if (!relocsOnly) { if (_shouldAddSkipTypeValidationFlag.Result.canSkipValidation) { flagsInt |= (int)ReadyToRunFlags.READYTORUN_FLAG_SkipTypeValidation; } else { if (factory.OptimizationFlags.TypeValidation == TypeValidationRule.AutomaticWithLogging) { // If we are in automatic with logging mode, we reach here when we are unable to enable // skip validation. When logging is enabled, write out the reasons we found for // not doing so. foreach (string reason in _shouldAddSkipTypeValidationFlag.Result.reasons) System.Console.WriteLine(reason); } } } builder.EmitInt(flagsInt); // ReadyToRunHeader.NumberOfSections ObjectDataBuilder.Reservation sectionCountReservation = builder.ReserveInt(); int count = 0; foreach (var item in _items) { // Skip empty entries if (!relocsOnly && item.Node is ObjectNode on && on.ShouldSkipEmittingObjectNode(factory)) continue; builder.EmitInt((int)item.Id); // DelayLoadMethodCallThunks symbols are PCode, but the header entry encodes a data RVA. // Remove the target code delta so the RVA does not include the ARM Thumb bit. int rvaDelta = item.Id == ReadyToRunSectionType.DelayLoadMethodCallThunks ? -factory.Target.CodeDelta : 0; builder.EmitReloc(item.StartSymbol, RelocType.IMAGE_REL_BASED_ADDR32NB, rvaDelta); // The header entry for the runtime functions table should not include the 4 byte 0xffffffff sentinel // value in the covered range. For WASM, also excludes the trailing min table index. int delta = item.Id == ReadyToRunSectionType.RuntimeFunctions ? factory.RuntimeFunctionsTable.SentinelSizeAdjustment : 0; builder.EmitReloc(item.StartSymbol, RelocType.IMAGE_REL_SYMBOL_SIZE, delta); count++; } builder.EmitInt(sectionCountReservation, count); return builder.ToObjectData(); } protected abstract void EmitHeaderPrefix(ref ObjectDataBuilder builder); protected internal override int Phase => (int)ObjectNodePhase.Ordered; } public class GlobalHeaderNode : ReadyToRunHeaderNode { public GlobalHeaderNode(ReadyToRunFlags flags, EcmaModule moduleToCheckForSkipValidation) : base(flags, moduleToCheckForSkipValidation) { } protected override void AppendMangledHeaderName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix); sb.Append("__ReadyToRunHeader"u8); } protected override void EmitHeaderPrefix(ref ObjectDataBuilder builder) { // ReadyToRunHeader.Magic builder.EmitInt((int)(ReadyToRunHeaderConstants.Signature)); // ReadyToRunHeader.MajorVersion builder.EmitShort((short)(ReadyToRunHeaderConstants.CurrentMajorVersion)); builder.EmitShort((short)(ReadyToRunHeaderConstants.CurrentMinorVersion)); } public override int ClassCode => (int)ObjectNodeOrder.GlobalHeaderNode; } public class AssemblyHeaderNode : ReadyToRunHeaderNode { private readonly int _index; public AssemblyHeaderNode(ReadyToRunFlags flags, int index) : base(flags, null) { _index = index; } protected override void EmitHeaderPrefix(ref ObjectDataBuilder builder) { } public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { return _index - ((AssemblyHeaderNode)other)._index; } protected override void AppendMangledHeaderName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix); sb.Append("__ReadyToRunAssemblyHeader__"u8); sb.Append(_index.ToString()); } public override int ClassCode => (int)ObjectNodeOrder.ReadyToRunAssemblyHeaderNode; } }