// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using Internal.Text; using Internal.TypeSystem; using Internal.Runtime; using Debug = System.Diagnostics.Debug; namespace ILCompiler.DependencyAnalysis { /// /// Represents a node that points to various symbols and can be sequentially addressed. /// public sealed class ExternalReferencesTableNode : ObjectNode, ISymbolDefinitionNode { private readonly ObjectAndOffsetSymbolNode _endSymbol; private readonly string _blobName; private readonly NodeFactory _nodeFactory; private Dictionary _insertedSymbolsDictionary = new Dictionary(); private List _insertedSymbols = new List(); public ExternalReferencesTableNode(string blobName, NodeFactory nodeFactory) { _blobName = blobName; _endSymbol = new ObjectAndOffsetSymbolNode(this, 0, "__external_" + blobName + "_references_End", true); _nodeFactory = nodeFactory; } public ISymbolDefinitionNode EndSymbol => _endSymbol; public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix).Append("__external_" + _blobName + "_references"); } public int Offset => 0; public override bool IsShareable => false; /// /// Adds a new entry to the table. Thread safety: not thread safe. Expected to be called at the final /// object data emission phase from a single thread. /// public uint GetIndex(ISymbolNode symbol, int delta = 0) { #if DEBUG if (_nodeFactory.MarkingComplete) { var node = symbol as ILCompiler.DependencyAnalysisFramework.DependencyNodeCore; if (node != null) Debug.Assert(node.Marked); } #endif SymbolAndDelta key = new SymbolAndDelta(symbol, delta); uint index; if (!_insertedSymbolsDictionary.TryGetValue(key, out index)) { index = (uint)_insertedSymbols.Count; _insertedSymbolsDictionary[key] = index; _insertedSymbols.Add(key); } return index; } public override ObjectNodeSection Section { get { if (_nodeFactory.Target.IsWindows) return ObjectNodeSection.ReadOnlyDataSection; else return ObjectNodeSection.DataSection; } } public override bool StaticDependenciesAreComputed => true; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) return new ObjectData(Array.Empty(), Array.Empty(), 1, new ISymbolDefinitionNode[] { this }); // Zero out the dictionary so that we AV if someone tries to insert after we're done. _insertedSymbolsDictionary = null; var builder = new ObjectDataBuilder(factory, relocsOnly); foreach (SymbolAndDelta symbolAndDelta in _insertedSymbols) { if (factory.Target.Abi == TargetAbi.CoreRT) { // TODO: set low bit if the linkage of the symbol is IAT_PVALUE. builder.EmitReloc(symbolAndDelta.Symbol, RelocType.IMAGE_REL_BASED_RELPTR32, symbolAndDelta.Delta); } else { Debug.Assert(factory.Target.Abi == TargetAbi.ProjectN); int delta = symbolAndDelta.Delta; if (symbolAndDelta.Symbol.RepresentsIndirectionCell) { delta = (int)((uint)delta | IndirectionConstants.RVAPointsToIndirection); } builder.EmitReloc(symbolAndDelta.Symbol, RelocType.IMAGE_REL_BASED_ADDR32NB, delta); } } _endSymbol.SetSymbolOffset(builder.CountBytes); builder.AddSymbol(this); builder.AddSymbol(_endSymbol); return builder.ToObjectData(); } protected internal override int Phase => (int)ObjectNodePhase.Ordered; public override int ClassCode => (int)ObjectNodeOrder.ExternalReferencesTableNode; public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { return string.Compare(_blobName, ((ExternalReferencesTableNode)other)._blobName); } struct SymbolAndDelta : IEquatable { public readonly ISymbolNode Symbol; public readonly int Delta; public SymbolAndDelta(ISymbolNode symbol, int delta) { Symbol = symbol; Delta = delta; } public bool Equals(SymbolAndDelta other) { return Symbol == other.Symbol && Delta == other.Delta; } public override bool Equals(object obj) { return Equals((SymbolAndDelta)obj); } public override int GetHashCode() { return Symbol.GetHashCode(); } } } }