| File: Compiler\DependencyAnalysis\FatFunctionPointerNode.cs | Web Access |
| Project: 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 Internal.Text; using Internal.TypeSystem; using Debug = System.Diagnostics.Debug; namespace ILCompiler.DependencyAnalysis { /// <summary> /// Represents a fat function pointer - a data structure that captures a pointer to a canonical /// method body along with the instantiation context the canonical body requires. /// Pointers to these structures can be created by e.g. ldftn/ldvirtftn of a method with a canonical body. /// </summary> public class FatFunctionPointerNode : DehydratableObjectNode, IMethodNode, ISymbolDefinitionNode { private readonly bool _isUnboxingStub; private readonly bool _isAddressTaken; public bool IsUnboxingStub => _isUnboxingStub; public FatFunctionPointerNode(MethodDesc methodRepresented, bool isUnboxingStub, bool addressTaken) { // We should not create these for methods that don't have a canonical method body Debug.Assert(methodRepresented.GetCanonMethodTarget(CanonicalFormKind.Specific) != methodRepresented); Method = methodRepresented; _isUnboxingStub = isUnboxingStub; _isAddressTaken = addressTaken; } public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { string prefix = $"__fat{(_isUnboxingStub ? "unbox" : "")}{(_isAddressTaken ? "addresstaken" : "")}pointer_"; sb.Append(prefix).Append(nameMangler.GetMangledMethodName(Method)); } int ISymbolDefinitionNode.Offset => 0; int ISymbolNode.Offset => Method.Context.Target.Architecture == TargetArchitecture.Wasm32 ? 1 << 31 : 2; public override bool IsShareable => true; public MethodDesc Method { get; } protected override ObjectNodeSection GetDehydratedSection(NodeFactory factory) { if (factory.Target.IsWindows) return ObjectNodeSection.ReadOnlyDataSection; else return ObjectNodeSection.DataSection; } public override bool StaticDependenciesAreComputed => true; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); protected override ObjectData GetDehydratableData(NodeFactory factory, bool relocsOnly = false) { var builder = new ObjectDataBuilder(factory, relocsOnly); // These need to be aligned the same as method bodies because they show up in same contexts // (macOS ARM64 has even stricter alignment requirement for the linker, so round up to pointer size) Debug.Assert(factory.Target.MinimumFunctionAlignment <= factory.Target.PointerSize); builder.RequireInitialAlignment(factory.Target.PointerSize); builder.AddSymbol(this); MethodDesc canonMethod = Method.GetCanonMethodTarget(CanonicalFormKind.Specific); // Pointer to the canonical body of the method ISymbolNode target = _isAddressTaken ? factory.AddressTakenMethodEntrypoint(canonMethod, _isUnboxingStub) : factory.MethodEntrypoint(canonMethod, _isUnboxingStub); builder.EmitPointerReloc(target); // Find out what's the context to use ISortableSymbolNode contextParameter; if (canonMethod.RequiresInstMethodDescArg()) { contextParameter = factory.MethodGenericDictionary(Method); } else { Debug.Assert(canonMethod.RequiresInstMethodTableArg()); // Ask for a constructed type symbol because we need the vtable to get to the dictionary contextParameter = factory.ConstructedTypeSymbol(Method.OwningType); } // The next entry is a pointer to the context to be used for the canonical method builder.EmitPointerReloc(contextParameter); return builder.ToObjectData(); } public override int ClassCode => 190463489; public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { var compare = _isUnboxingStub.CompareTo(((FatFunctionPointerNode)other)._isUnboxingStub); if (compare != 0) return compare; compare = _isAddressTaken.CompareTo(((FatFunctionPointerNode)other)._isAddressTaken); if (compare != 0) return compare; return comparer.Compare(Method, ((FatFunctionPointerNode)other).Method); } } }