File: Compiler\DependencyAnalysis\ReadyToRun\InstanceEntryPointTableNode.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.Linq;
using System.Reflection.Metadata.Ecma335;
using ILCompiler.ReadyToRun.TypeSystem;
using Internal;
using Internal.JitInterface;
using Internal.NativeFormat;
using Internal.Runtime;
using Internal.Text;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;

namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
    public class InstanceEntryPointTableNode : HeaderTableNode, ISignatureEmitter
    {
        private readonly NodeFactory _factory;
        private bool _materializedSignature;

        public InstanceEntryPointTableNode(NodeFactory factory)
        {
            _factory = factory;
            _factory.ManifestMetadataTable.RegisterEmitter(this);
        }

        public void MaterializeSignature()
        {
            if (!_materializedSignature)
            {
                if (_factory.CompilationModuleGroup.IsInputBubble)
                {
                    foreach (MethodWithGCInfo method in _factory.EnumerateCompiledMethods(null, CompiledMethodCategory.Instantiated))
                    {
                        if (method.Method is AsyncResumptionStub)
                            continue;

                        BuildSignatureForMethod(method, _factory);
                    }
                }

                _materializedSignature = true;
            }
        }

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

        public static byte[] BuildSignatureForMethodDefinedInModule(MethodDesc method, NodeFactory factory)
        {
            EcmaMethod typicalMethod = (EcmaMethod)method.GetPrimaryMethodDesc().GetTypicalMethodDefinition();

            ModuleToken moduleToken;
            if (factory.CompilationModuleGroup.VersionsWithMethodBody(typicalMethod))
            {
                moduleToken = new ModuleToken(typicalMethod.Module, typicalMethod.Handle);
            }
            else
            {
                MutableModule manifestMetadata = factory.ManifestMetadataTable._mutableModule;
                var handle = manifestMetadata.TryGetExistingEntityHandle(typicalMethod);
                Debug.Assert(handle.HasValue);
                moduleToken = new ModuleToken(factory.ManifestMetadataTable._mutableModule, handle.Value);
            }

            ArraySignatureBuilder signatureBuilder = new ArraySignatureBuilder();
            signatureBuilder.EmitMethodSignature(
                new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false, genericContextObject: null),
                enforceDefEncoding: true,
                enforceOwningType: moduleToken.Module is EcmaModule ? factory.CompilationModuleGroup.EnforceOwningType((EcmaModule)moduleToken.Module) : true,
                factory.SignatureContext,
                isInstantiatingStub: false);

            return signatureBuilder.ToArray();
        }

        private byte[] BuildSignatureForMethod(MethodWithGCInfo method, NodeFactory factory)
        {
            return BuildSignatureForMethodDefinedInModule(method.Method, factory);
        }

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

            NativeWriter hashtableWriter = new NativeWriter();

            Section hashtableSection = hashtableWriter.NewSection();
            VertexHashtable vertexHashtable = new VertexHashtable();
            hashtableSection.Place(vertexHashtable);

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

            foreach (MethodWithGCInfo method in factory.EnumerateCompiledMethods(null, CompiledMethodCategory.Instantiated))
            {
                // Resumption stubs are discovered via READYTORUN_FIXUP_ResumptionStubEntryPoint fixups
                // on their parent async variant methods, so they do not need entries in the InstanceEntryPointTable.
                if (method.Method is AsyncResumptionStub)
                    continue;

                Debug.Assert(method.Method.HasInstantiation || method.Method.OwningType.HasInstantiation || method.Method.IsAsyncVariant());

                int methodIndex = factory.RuntimeFunctionsTable.GetIndex(method);

                byte[] signature = BuildSignatureForMethod(method, factory);
                BlobVertex signatureBlob;
                if (!uniqueSignatures.TryGetValue(signature, out signatureBlob))
                {
                    signatureBlob = new BlobVertex(signature);
                    uniqueSignatures.Add(signature, signatureBlob);
                }

                byte[] fixup = method.GetFixupBlob(factory);
                BlobVertex fixupBlob = null;
                if (fixup != null && !uniqueFixups.TryGetValue(fixup, out fixupBlob))
                {
                    fixupBlob = new BlobVertex(fixup);
                    uniqueFixups.Add(fixup, fixupBlob);
                }

                EntryPointVertex entryPointVertex = new EntryPointWithBlobVertex((uint)methodIndex, fixupBlob, signatureBlob);
                hashtableSection.Place(entryPointVertex);
                vertexHashtable.Append(unchecked((uint)method.Method.GetHashCode()), entryPointVertex);
            }

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

        public override int ClassCode => -348722540;
    }
}