File: Compiler\DependencyAnalysis\AddressTakenMethodNode.cs
Web Access
Project: src\src\runtime\src\coreclr\tools\aot\ILCompiler.Compiler\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.Collections.Generic;
using System.Diagnostics;

using ILCompiler.DependencyAnalysisFramework;

using Internal.Text;
using Internal.TypeSystem;

namespace ILCompiler.DependencyAnalysis
{
    /// <summary>
    /// Represents a method with address taken. Under normal circumstances, this node is not emitted
    /// into the object file and instead references to it are replaced to refer to the underlying method body.
    /// This is achieved through <see cref="ShouldSkipEmittingObjectNode(NodeFactory)"/> and <see cref="NodeForLinkage(NodeFactory)"/>.
    /// However, if the underlying method body got folded together with another method due to identical method body folding
    /// optimization, this node is not skipped and instead emits a jump stub. The purpose of the jump stub is to provide a
    /// unique code address for the address taken method.
    /// </summary>
    internal sealed class AddressTakenMethodNode : JumpStubNode, IMethodNode, ISymbolNodeWithLinkage
    {
        private readonly IMethodNode _methodNode;

        public IMethodNode RealBody => _methodNode;

        public AddressTakenMethodNode(IMethodNode methodNode)
            : base(methodNode)
        {
            _methodNode = methodNode;
        }

        public MethodDesc Method => _methodNode.Method;

        protected override string GetName(NodeFactory factory)
        {
            return "Address taken method: " + _methodNode.GetMangledName(factory.NameMangler);
        }

        public override bool ShouldSkipEmittingObjectNode(NodeFactory factory)
        {
            return factory.ObjectInterner.GetDeduplicatedSymbol(factory, RealBody) == RealBody;
        }

        public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) => null;
        public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context) => null;
        public override bool InterestingForDynamicDependencyAnalysis => false;
        public override bool HasDynamicDependencies => false;
        public override bool HasConditionalStaticDependencies => false;

        public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
        {
            // We use the same mangled name as the underlying real method body.
            // This is okay since this node will go out of the way if the real body is marked
            // and part of the graph.
            _methodNode.AppendMangledName(nameMangler, sb);
        }

        public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
        {
            return comparer.Compare(_methodNode, ((AddressTakenMethodNode)other)._methodNode);
        }

        public ISymbolNode NodeForLinkage(NodeFactory factory)
        {
            // If someone refers to this node but the target method still has a unique body,
            // refer to the target method.
            return factory.ObjectInterner.GetDeduplicatedSymbol(factory, RealBody) == RealBody ? RealBody : this;
        }

        public override bool RepresentsIndirectionCell
        {
            get
            {
                Debug.Assert(!_methodNode.RepresentsIndirectionCell);
                return false;
            }
        }

        public override int ClassCode => 0xfab0355;

        public override bool IsShareable => ((ObjectNode)_methodNode).IsShareable;
    }
}