File: Compiler\DependencyAnalysis\ExternalReferencesTableNode.cs
Web Access
Project: src\src\runtime\src\coreclr\tools\aot\ILCompiler.Compiler\ILCompiler.Compiler.csproj (ILCompiler.Compiler)
// 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 Internal.Text;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler.DependencyAnalysis
{
    /// <summary>
    /// Represents a node that points to various symbols and can be sequentially addressed.
    /// </summary>
    public sealed class ExternalReferencesTableNode : ObjectNode, ISymbolDefinitionNode
    {
        private readonly string _blobName;
        private readonly NodeFactory _nodeFactory;

        private Dictionary<SymbolAndDelta, uint> _insertedSymbolsDictionary = new Dictionary<SymbolAndDelta, uint>();
        private List<SymbolAndDelta> _insertedSymbols = new List<SymbolAndDelta>();

        public ExternalReferencesTableNode(string blobName, NodeFactory nodeFactory)
        {
            _blobName = blobName;
            _nodeFactory = nodeFactory;
        }

        public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
        {
            sb.Append(nameMangler.CompilationUnitPrefix).Append("__external_" + _blobName + "_references");
        }
        public int Offset => 0;
        public override bool IsShareable => false;

        /// <summary>
        /// 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.
        /// </summary>
        public uint GetIndex(ISymbolNode symbol, int delta = 0)
        {
#if DEBUG
            if (_nodeFactory.MarkingComplete)
            {
                var node = symbol as ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<NodeFactory>;
                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 GetSection(NodeFactory factory)
        {
            if (factory.Target.IsWindows || factory.Target.SupportsRelativePointers)
                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<byte>(), Array.Empty<Relocation>(), 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);
            builder.RequireInitialAlignment(factory.Target.SupportsRelativePointers ? 4 : factory.Target.PointerSize);

            foreach (SymbolAndDelta symbolAndDelta in _insertedSymbols)
            {
                if (factory.Target.SupportsRelativePointers)
                {
                    // 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
                {
                    builder.EmitPointerReloc(symbolAndDelta.Symbol, symbolAndDelta.Delta);
                }
            }

            builder.AddSymbol(this);

            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);
        }

        private struct SymbolAndDelta : IEquatable<SymbolAndDelta>
        {
            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();
            }
        }
    }
}