File: Compiler\DependencyAnalysis\ReadyToRun\MethodEntryPointTableNode.cs
Web Access
Project: src\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.Diagnostics;
using System.IO;
using System.Reflection.Metadata.Ecma335;

using Internal.JitInterface;
using Internal.NativeFormat;
using Internal.Text;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;

namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
    public class MethodEntryPointTableNode : ModuleSpecificHeaderTableNode
    {
        private struct EntryPoint
        {
            public static EntryPoint Null = new EntryPoint(-1, null);

            public readonly int MethodIndex;
            public readonly MethodWithGCInfo Method;

            public bool IsNull => (MethodIndex < 0);
            
            public EntryPoint(int methodIndex, MethodWithGCInfo method)
            {
                MethodIndex = methodIndex;
                Method = method;
            }
        }

        public MethodEntryPointTableNode(EcmaModule module) : base(module)
        {
        }

        protected override string ModuleSpecificName => "__ReadyToRunMethodEntryPointTable__";

        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            if (relocsOnly)
            {
                return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, Array.Empty<ISymbolDefinitionNode>());
            }

            List<EntryPoint> ridToEntryPoint = new List<EntryPoint>();

            foreach (MethodWithGCInfo method in factory.EnumerateCompiledMethods(_module, CompiledMethodCategory.NonInstantiated))
            {
                Debug.Assert(method.Method is EcmaMethod);
                EcmaMethod ecmaMethod = (EcmaMethod)method.Method;
                Debug.Assert(ecmaMethod.Module == _module);

                // Strip away the token type bits, keep just the low 24 bits RID
                uint rid = SignatureBuilder.RidFromToken((mdToken)MetadataTokens.GetToken(ecmaMethod.Handle));
                Debug.Assert(rid != 0);
                rid--;

                while (ridToEntryPoint.Count <= rid)
                {
                    ridToEntryPoint.Add(EntryPoint.Null);
                }

                int methodIndex = factory.RuntimeFunctionsTable.GetIndex(method);
                ridToEntryPoint[(int)rid] = new EntryPoint(methodIndex, method);
            }

            NativeWriter writer = new NativeWriter();

            Section arraySection = writer.NewSection();
            VertexArray vertexArray = new VertexArray(arraySection);
            arraySection.Place(vertexArray);

            Dictionary<byte[], BlobVertex> uniqueFixups = new Dictionary<byte[], BlobVertex>(ByteArrayComparer.Instance);

            for (int rid = 0; rid < ridToEntryPoint.Count; rid++)
            {
                EntryPoint entryPoint = ridToEntryPoint[rid];
                if (!entryPoint.IsNull)
                {
                    byte[] fixups = entryPoint.Method.GetFixupBlob(factory);

                    BlobVertex fixupBlobVertex = null;
                    if (fixups != null && !uniqueFixups.TryGetValue(fixups, out fixupBlobVertex))
                    {
                        fixupBlobVertex = new BlobVertex(fixups);
                        uniqueFixups.Add(fixups, fixupBlobVertex);
                    }
                    EntryPointVertex entryPointVertex = new EntryPointVertex((uint)entryPoint.MethodIndex, fixupBlobVertex);
                    vertexArray.Set(rid, entryPointVertex);
                }
            }

            vertexArray.ExpandLayout();

            MemoryStream arrayContent = new MemoryStream();
            writer.Save(arrayContent);
            return new ObjectData(
                data: arrayContent.ToArray(),
                relocs: null,
                alignment: 8,
                definedSymbols: new ISymbolDefinitionNode[] { this });
        }

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