| File: Compiler\DependencyAnalysis\ReadyToRun\GCRefMapNode.cs | Web Access |
| Project: 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; using System.Collections.Generic; using System.Diagnostics; using Internal.Text; namespace ILCompiler.DependencyAnalysis.ReadyToRun { public class GCRefMapNode : ObjectNode, ISymbolDefinitionNode { /// <summary> /// Number of GC ref map records to represent with a single lookup pointer /// </summary> public const int GCREFMAP_LOOKUP_STRIDE = 1024; private readonly ImportSectionNode _importSection; private readonly List<IMethodNode> _methods; public GCRefMapNode(ImportSectionNode importSection) { _importSection = importSection; _methods = new List<IMethodNode>(); } public override ObjectNodeSection GetSection(NodeFactory factory) => ObjectNodeSection.ReadOnlyDataSection; public override bool IsShareable => false; public override int ClassCode => 555444333; public override bool StaticDependenciesAreComputed => true; public int Offset => 0; public bool IsEmpty => _methods.Count == 0; public void AddImport(Import import) { lock (_methods) { _methods.Add(import as IMethodNode); } } public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append("GCRefMap->"u8); sb.Append(_importSection.Name); } public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { if (_methods.Count == 0 || relocsOnly) { return new ObjectData( data: Array.Empty<byte>(), relocs: Array.Empty<Relocation>(), alignment: 1, definedSymbols: new ISymbolDefinitionNode[] { this }); } _methods.MergeSort(CompilerComparer.Instance); GCRefMapBuilder builder = new GCRefMapBuilder(factory.Target, relocsOnly); builder.Builder.RequireInitialAlignment(4); builder.Builder.AddSymbol(this); // First, emit the initial ref map offset and reserve the offset map entries int offsetCount = _methods.Count / GCREFMAP_LOOKUP_STRIDE; builder.Builder.EmitInt((offsetCount + 1) * sizeof(int)); ObjectDataBuilder.Reservation[] offsets = new ObjectDataBuilder.Reservation[offsetCount]; for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++) { offsets[offsetIndex] = builder.Builder.ReserveInt(); } // Next, generate the actual method GC ref maps and update the offset map int nextOffsetIndex = 0; int nextMethodIndex = GCREFMAP_LOOKUP_STRIDE - 1; for (int methodIndex = 0; methodIndex < _methods.Count; methodIndex++) { IMethodNode methodNode = _methods[methodIndex]; if (methodNode == null) { // Flush an empty GC ref map block to prevent // the indexed records from falling out of sync with methods builder.Flush(); } else { bool isStub = false; if (methodNode is DelayLoadHelperImport methodImport) { MethodFixupSignature signature = (MethodFixupSignature)methodImport.ImportSignature.Target; isStub = signature.IsUnboxingStub || signature.IsInstantiatingStub; } builder.GetCallRefMap(methodNode.Method, isStub); } if (methodIndex >= nextMethodIndex) { builder.Builder.EmitInt(offsets[nextOffsetIndex], builder.Builder.CountBytes); nextOffsetIndex++; nextMethodIndex += GCREFMAP_LOOKUP_STRIDE; } } Debug.Assert(nextOffsetIndex == offsets.Length); return builder.Builder.ToObjectData(); } protected override string GetName(NodeFactory factory) { Utf8StringBuilder sb = new Utf8StringBuilder(); AppendMangledName(factory.NameMangler, sb); return sb.ToString(); } public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { return comparer.Compare(_importSection, ((GCRefMapNode)other)._importSection); } } }