File: Compiler\DependencyAnalysis\UnboxingStubMapNode.cs
Web Access
Project: 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 Internal.Text;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler.DependencyAnalysis
{
    /// <summary>
    /// UnboxingStubMap - WASM-only table that maps unboxing stubs to their targets. The layout is:
    /// uint simpleCount, uint instantiatingCount, followed by simpleCount pairs of (stub, target)
    /// function table indices for simple unboxing stubs and instantiatingCount pairs of (stub, target)
    /// function table indices for unboxing and instantiating stubs.
    /// </summary>
    public sealed class UnboxingStubMapNode : ObjectNode, ISymbolDefinitionNode
    {
        public override bool IsShareable => false;

        public override ObjectNodeSection GetSection(NodeFactory factory) => ObjectNodeSection.ReadOnlyDataSection;

        public override bool StaticDependenciesAreComputed => true;

        public int Offset => 0;

        protected internal override int Phase => (int)ObjectNodePhase.Ordered;
        public override int ClassCode => (int)ObjectNodeOrder.UnboxingStubMapNode;

        public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
        {
            sb.Append(nameMangler.CompilationUnitPrefix).Append("_unboxing_stub_map"u8);
        }

        protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);

        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // The data emission relies on the set of compiled methods which is incomplete during
            // dependency tracking. This node doesn't keep anything alive - it only describes stubs
            // that were generated for other reasons.
            if (relocsOnly)
            {
                return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
            }

            ObjectDataBuilder objData = new ObjectDataBuilder(factory, relocsOnly);
            objData.RequireInitialPointerAlignment();
            objData.AddSymbol(this);

            ObjectDataBuilder.Reservation simpleCountReservation = objData.ReserveInt();
            ObjectDataBuilder.Reservation instantiatingCountReservation = objData.ReserveInt();

            int simpleCount = 0;
            foreach (UnboxingStubNode stub in factory.MetadataManager.GetUnboxingStubs())
            {
                if (!stub.IsInstantiating)
                {
                    EmitPair(ref objData, factory, stub);
                    simpleCount++;
                }
            }

            int instantiatingCount = 0;
            foreach (UnboxingStubNode stub in factory.MetadataManager.GetUnboxingStubs())
            {
                if (stub.IsInstantiating)
                {
                    EmitPair(ref objData, factory, stub);
                    instantiatingCount++;
                }
            }

            objData.EmitInt(simpleCountReservation, simpleCount);
            objData.EmitInt(instantiatingCountReservation, instantiatingCount);

            return objData.ToObjectData();
        }

        private static void EmitPair(ref ObjectDataBuilder objData, NodeFactory factory, UnboxingStubNode stub)
        {
            var target = factory.MethodEntrypoint(stub.Method);
            Debug.Assert(stub.Marked && target.Marked);
            objData.EmitReloc(stub, RelocType.WASM_TABLE_INDEX_I32);
            objData.EmitReloc(target, RelocType.WASM_TABLE_INDEX_I32);
        }
    }
}