| File: Compiler\DependencyAnalysis\ExactMethodInstantiationsNode.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 System; using System.Diagnostics; using Internal.Text; using Internal.TypeSystem; using Internal.NativeFormat; using Internal.Runtime; namespace ILCompiler.DependencyAnalysis { /// <summary> /// Hashtable of all exact (non-canonical) generic method instantiations compiled in the module. /// </summary> public sealed class ExactMethodInstantiationsNode : ObjectNode, ISymbolDefinitionNode { private ExternalReferencesTableNode _externalReferences; public ExactMethodInstantiationsNode(ExternalReferencesTableNode externalReferences) { _externalReferences = externalReferences; } public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix).Append("__exact_method_instantiations"u8); } public int Offset => 0; public override bool IsShareable => false; public override ObjectNodeSection GetSection(NodeFactory factory) => _externalReferences.GetSection(factory); public override bool StaticDependenciesAreComputed => true; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // Dependencies for this node are tracked by the method code nodes if (relocsOnly) return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this }); // Ensure the native layout data has been saved, in order to get valid Vertex offsets for the signature Vertices factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory); NativeWriter nativeWriter = new NativeWriter(); VertexHashtable hashtable = new VertexHashtable(); Section nativeSection = nativeWriter.NewSection(); nativeSection.Place(hashtable); foreach (MethodDesc method in factory.MetadataManager.GetExactMethodHashtableEntries()) { // Get the method pointer vertex bool getUnboxingStub = method.OwningType.IsValueType && !method.Signature.IsStatic; // TODO-SIZE: we need address taken entrypoint only if this was a target of a delegate IMethodNode methodEntryPointNode = factory.AddressTakenMethodEntrypoint(method, getUnboxingStub); Vertex methodPointer = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(methodEntryPointNode)); // Get native layout vertices for the declaring type ISymbolNode declaringTypeNode = factory.NecessaryTypeSymbol(method.OwningType); Vertex declaringType = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(declaringTypeNode)); // Get a vertex sequence for the method instantiation args if any VertexSequence arguments = new VertexSequence(); foreach (var arg in method.Instantiation) { ISymbolNode argNode = factory.NecessaryTypeSymbol(arg); arguments.Append(nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(argNode))); } int flags = 0; MethodDesc methodForMetadata = GetMethodForMetadata(method, out bool isAsyncVariant, out bool isReturnDroppingAsyncThunk); if (isAsyncVariant) flags |= GenericMethodsHashtableConstants.IsAsyncVariant; // Same flag as the other hashtable! Readers are shared. if (isReturnDroppingAsyncThunk) flags |= GenericMethodsHashtableConstants.IsReturnDroppingAsyncThunk; int token = factory.MetadataManager.GetMetadataHandleForMethod(factory, methodForMetadata); int flagsAndToken = (token & MetadataManager.MetadataOffsetMask) | flags; // Get the vertex for the completed method signature Vertex methodSignature = nativeWriter.GetTuple(declaringType, nativeWriter.GetUnsignedConstant((uint)flagsAndToken), arguments); // Make the generic method entry vertex Vertex entry = nativeWriter.GetTuple(methodSignature, methodPointer); // Add to the hash table, hashed by the containing type's hashcode uint hashCode = (uint)method.OwningType.GetHashCode(); hashtable.Append(hashCode, nativeSection.Place(entry)); } byte[] streamBytes = nativeWriter.Save(); return new ObjectData(streamBytes, Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this }); } public static void GetExactMethodInstantiationDependenciesForMethod(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) { dependencies ??= new DependencyList(); // Method entry point dependency bool getUnboxingStub = method.OwningType.IsValueType && !method.Signature.IsStatic; // TODO-SIZE: we need address taken entrypoint only if this was a target of a delegate IMethodNode methodEntryPointNode = factory.AddressTakenMethodEntrypoint(method, getUnboxingStub); dependencies.Add(new DependencyListEntry(methodEntryPointNode, "Exact method instantiation entry")); // Get native layout dependencies for the declaring type dependencies.Add(new DependencyListEntry(factory.NecessaryTypeSymbol(method.OwningType), "Exact method instantiation entry")); // Get native layout dependencies for the method instantiation args foreach (var arg in method.Instantiation) dependencies.Add(new DependencyListEntry(factory.NecessaryTypeSymbol(arg), "Exact method instantiation entry")); factory.MetadataManager.GetNativeLayoutMetadataDependencies(ref dependencies, factory, GetMethodForMetadata(method, out _, out _)); } private static MethodDesc GetMethodForMetadata(MethodDesc method, out bool isAsyncVariant, out bool isReturnDroppingAsyncThunk) { MethodDesc result = method.GetTypicalMethodDefinition(); if (result is ReturnDroppingAsyncThunk rdThunk) { isAsyncVariant = false; isReturnDroppingAsyncThunk = true; return rdThunk.AsyncVariantTarget.Target; } if (result is AsyncMethodVariant asyncVariant) { isAsyncVariant = true; isReturnDroppingAsyncThunk = false; return asyncVariant.Target; } isAsyncVariant = false; isReturnDroppingAsyncThunk = false; return result; } protected internal override int Phase => (int)ObjectNodePhase.Ordered; public override int ClassCode => (int)ObjectNodeOrder.ExactMethodInstantiationsNode; } }