File: Compiler\DependencyAnalysis\ReadyToRun\DelayLoadHelperImport.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.Collections.Generic;
using System.Diagnostics;

using Internal.Text;
using Internal.TypeSystem;
using Internal.ReadyToRunConstants;

namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
    /// <summary>
    /// This class represents a single indirection cell used to call delay load helpers.
    /// </summary>
    public class DelayLoadHelperImport : Import
    {
        private readonly ReadyToRunHelper _helper;

        private readonly bool _useVirtualCall;
        private readonly bool _useJumpableStub;

        private readonly ISymbolNode _delayLoadHelper;

        public bool UseVirtualCall => _useVirtualCall;
        public bool UseJumpableStub => _useJumpableStub;
        public ReadyToRunHelper HelperId => _helper;

        public DelayLoadHelperImport(
            NodeFactory factory, 
            ImportSectionNode importSectionNode, 
            ReadyToRunHelper helper, 
            Signature instanceSignature, 
            bool useVirtualCall = false, 
            bool useJumpableStub = false,
            MethodDesc callingMethod = null)
            : base(importSectionNode, instanceSignature, callingMethod)
        {
            _helper = helper;
            _useVirtualCall = useVirtualCall;
            _useJumpableStub = useJumpableStub;
            if (factory.Target.Architecture == TargetArchitecture.Wasm32)
            {
                if (instanceSignature is GenericLookupSignature)
                {
                    // Generic lookups are resolved via eager fixups and don't need import thunks
                    _delayLoadHelper = null;
                }
                else
                {
                    _delayLoadHelper = factory.WasmImportThunkPortableEntrypoint(this);
                }
            }
            else
            {
                _delayLoadHelper = factory.ImportThunk(helper, importSectionNode, useVirtualCall, useJumpableStub);
            }
        }

        public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
        {
            sb.Append("DelayLoadHelperImport("u8);
            if (_useVirtualCall)
            {
                sb.Append("[VSD] "u8);
            }
            if (_useJumpableStub)
            {
                sb.Append("[JMP] "u8);
            }
            sb.Append(_helper.ToString());
            sb.Append(") -> "u8);
            ImportSignature.AppendMangledName(nameMangler, sb);
            if (CallingMethod != null)
            {
                sb.Append(" @ "u8);
                sb.Append(nameMangler.GetMangledMethodName(CallingMethod));
            }
        }

        public override int ClassCode => 667823013;

        public override void EncodeData(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly)
        {
            if (_delayLoadHelper is not null)
            {
                // This needs to be an empty target pointer since it will be filled in with Module*
                // when loaded by CoreCLR
                dataBuilder.EmitReloc(_delayLoadHelper,
                    factory.Target.PointerSize == 4 ? RelocType.IMAGE_REL_BASED_HIGHLOW : RelocType.IMAGE_REL_BASED_DIR64, factory.Target.CodeDelta);
            }
            else
            {
                // Eager fixups don't need a delay load helper thunk — emit a zero pointer
                dataBuilder.EmitNaturalInt(0);
            }

            if (Table.EntrySize == (factory.Target.PointerSize * 2))
            {
                dataBuilder.EmitNaturalInt(0);
            }
            else
            {
                Debug.Assert(Table.EntrySize == factory.Target.PointerSize);
            }
        }

        public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
        {
            if (_delayLoadHelper is not null)
            {
                return new DependencyListEntry[]
                {
                    new DependencyListEntry(_delayLoadHelper, "Delay load helper thunk for ready-to-run fixup import"),
                    new DependencyListEntry(ImportSignature, "Signature for ready-to-run fixup import"),
                };
            }

            return new DependencyListEntry[]
            {
                new DependencyListEntry(ImportSignature, "Signature for ready-to-run fixup import"),
            };
        }

        public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
        {
            DelayLoadHelperImport otherNode = (DelayLoadHelperImport)other;
            int result = _useJumpableStub.CompareTo(otherNode._useJumpableStub);
            if (result != 0)
                return result;

            result = _useVirtualCall.CompareTo(otherNode._useVirtualCall);
            if (result != 0)
                return result;

            result = _helper.CompareTo(otherNode._helper);
            if (result != 0)
                return result;

            return base.CompareToImpl(other, comparer);
        }
    }
}