File: Compiler\DependencyAnalysis\ReadyToRun\WasmImportThunkPortableEntrypoint.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 ILCompiler.DependencyAnalysis.Wasm;
using Internal.ReadyToRunConstants;
using Internal.Text;
using Internal.JitInterface;
using Internal.TypeSystem;
using System.Diagnostics;

namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
    public class WasmImportThunkPortableEntrypoint : ObjectNode, ISymbolDefinitionNode, ISortableSymbolNode
    {
        private readonly DelayLoadHelperImport _import;

        public bool UseVirtualCall => _import.UseVirtualCall;
        public bool UseJumpableStub => _import.UseJumpableStub;
        public ReadyToRunHelper HelperId => _import.HelperId;

        public WasmImportThunkPortableEntrypoint(NodeFactory factory, DelayLoadHelperImport import)
        {
            Debug.Assert(!import.UseVirtualCall); // We don't currently support these for WASM, so detect them early so we can diagnose issues faster.
            Debug.Assert(import.HelperId != ReadyToRunHelper.GetString);
            _import = import;
            Debug.Assert(import.Signature is MethodFixupSignature || import.Signature is GenericLookupSignature);
        }

        public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
        {
            sb.Append("WasmImportThunkPortableEntrypoint->"u8);
            _import.AppendMangledName(nameMangler, sb);
        }

        protected override string GetName(NodeFactory factory)
        {
            Utf8StringBuilder sb = new Utf8StringBuilder();
            AppendMangledName(factory.NameMangler, sb);
            return sb.ToString();
        }

        public int Offset => 0;

        public override bool StaticDependenciesAreComputed => true;

        public override bool IsShareable => false;

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

        public override int ClassCode => 1738294057;

        public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
        {
            WasmImportThunkPortableEntrypoint otherNode = (WasmImportThunkPortableEntrypoint)other;
            return comparer.Compare(_import, otherNode._import);
        }

        private static readonly WasmSignature _genericLookupSignature32Bit = new WasmSignature(
            new WasmFuncType(
                new WasmResultType(new[] { WasmValueType.I32, WasmValueType.I32 }),
                new WasmResultType(new[] { WasmValueType.I32 })),
            "iii");
        private static readonly WasmSignature _genericLookupSignature64Bit = new WasmSignature(
            new WasmFuncType(
                new WasmResultType(new[] { WasmValueType.I64, WasmValueType.I64 }),
                new WasmResultType(new[] { WasmValueType.I64 })),
            "lll");

        public override ObjectData GetData(NodeFactory factory, System.Boolean relocsOnly = false)
        {
            // The layout of this matches READYTORUN_IMPORT_THUNK_PORTABLE_ENTRYPOINT

            ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);
            builder.AddSymbol(this);
            WasmSignature wasmSignature;

            RelocType tableIndexPointerRelocType = factory.Target.PointerSize == 4 ? RelocType.WASM_TABLE_INDEX_I32 : RelocType.WASM_TABLE_INDEX_I64;

            if (_import.Signature is GenericLookupSignature)
            {
                wasmSignature = factory.Target.PointerSize == 4 ? _genericLookupSignature32Bit : _genericLookupSignature64Bit;
            }
            else
            {
                MethodDesc method = ((MethodFixupSignature)(_import.Signature)).Method;
                // The import thunk always uses managed calling convention ($sp + PE entrypoint)
                // even if the underlying method is UnmanagedCallersOnly, because the thunk is
                // called from R2R-generated managed code.
                WasmLowering.LoweringFlags flags = WasmLowering.GetLoweringFlags(method) & ~WasmLowering.LoweringFlags.IsUnmanagedCallersOnly;
                wasmSignature = WasmLowering.GetSignature(method.Signature, flags);
            }
            builder.EmitReloc(factory.WasmImportThunk(wasmSignature, HelperId, _import.Table, UseVirtualCall, UseJumpableStub), tableIndexPointerRelocType);
            builder.EmitReloc(_import, RelocType.IMAGE_REL_BASED_ADDR32NB);
            if (factory.Target.PointerSize == 8)
            {
                builder.EmitUInt(0); // Padding to make the structure the same size on 32 and 64 bit
            }

            return builder.ToObjectData();
        }
    }
}