|
// 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 Internal.ReadyToRunConstants;
namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
public class ImportSectionNode : EmbeddedObjectNode
{
private class ImportTable : ArrayOfEmbeddedDataNode<Import>
{
private byte _alignment;
public ImportTable(string symbol, byte alignment) : base(symbol, nodeSorter: new EmbeddedObjectNodeComparer(CompilerComparer.Instance))
{
_alignment = alignment;
}
public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => false;
public override int ClassCode => (int)ObjectNodeOrder.ImportSectionNode;
protected override int GetAlignmentRequirement(NodeFactory factory)
{
return _alignment;
}
}
private readonly ImportTable _imports;
// TODO: annoying - today there's no way to put signature RVA's into R/O data section
private readonly ArrayOfEmbeddedPointersNode<Signature> _signatures;
// TODO: annoying - cannot enumerate the ArrayOfEmbeddedPointersNode so we must keep a copy.
private readonly List<Signature> _signatureList;
private readonly GCRefMapNode _gcRefMap;
private readonly ReadyToRunImportSectionType _type;
private readonly ReadyToRunImportSectionFlags _flags;
private readonly byte _entrySize;
private readonly string _name;
private readonly bool _emitPrecode;
private bool _materializedSignature;
public ImportSectionNode(string name, ReadyToRunImportSectionType importType, ReadyToRunImportSectionFlags flags, byte entrySize, bool emitPrecode, bool emitGCRefMap)
{
_name = name;
_type = importType;
_flags = flags;
_entrySize = entrySize;
_emitPrecode = emitPrecode;
_imports = new ImportTable(_name + "_ImportBegin", entrySize);
_signatures = new ArrayOfEmbeddedPointersNode<Signature>(_name + "_SigBegin", new EmbeddedObjectNodeComparer(CompilerComparer.Instance));
_signatureList = new List<Signature>();
_gcRefMap = emitGCRefMap ? new GCRefMapNode(this) : null;
}
public void MaterializeSignature(NodeFactory r2rFactory)
{
if (!_materializedSignature)
{
_signatureList.MergeSortAllowDuplicates(new SortableDependencyNode.ObjectNodeComparer(CompilerComparer.Instance));
foreach (Signature signature in _signatureList)
{
signature.GetData(r2rFactory, relocsOnly: false);
}
_materializedSignature = true;
}
}
public void AddImport(NodeFactory factory, Import import)
{
if (_materializedSignature)
{
throw new Exception("Cannot call AddImport after MaterializeSignature");
}
_imports.AddEmbeddedObject(import);
_signatures.AddEmbeddedObject(import.ImportSignature);
lock (_signatureList)
{
_signatureList.Add(import.ImportSignature.Target);
}
_gcRefMap?.AddImport(import);
}
public string Name => _name;
public bool EmitPrecode => _emitPrecode;
public bool IsEager => (_flags & ReadyToRunImportSectionFlags.Eager) != 0;
public override bool StaticDependenciesAreComputed => true;
protected internal override int Phase => (int)ObjectNodePhase.Ordered;
public override int ClassCode => (int)ObjectNodeOrder.ImportSectionNode;
public override void EncodeData(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly)
{
if (!_imports.ShouldSkipEmittingObjectNode(factory))
{
dataBuilder.EmitReloc(_imports, RelocType.IMAGE_REL_BASED_ADDR32NB, 0);
}
else
{
dataBuilder.EmitUInt(0);
}
if (!relocsOnly)
{
dataBuilder.EmitReloc(_imports, RelocType.IMAGE_REL_SYMBOL_SIZE);
dataBuilder.EmitShort((short)_flags);
dataBuilder.EmitByte((byte)_type);
dataBuilder.EmitByte(_entrySize);
}
if (!_signatures.ShouldSkipEmittingObjectNode(factory))
{
dataBuilder.EmitReloc(_signatures, RelocType.IMAGE_REL_BASED_ADDR32NB, 0);
}
else
{
dataBuilder.EmitUInt(0);
}
// If we emit an Rva for an empty gcrefmap, it will have no size header and be impossible for r2rdump to read correctly
if (_gcRefMap?.IsEmpty == false)
{
// This indirectly generates the AuxiliaryDataRva by emitting a placeholder 0 which will be replaced later
dataBuilder.EmitReloc(_gcRefMap, RelocType.IMAGE_REL_BASED_ADDR32NB, 0);
}
else
{
dataBuilder.EmitUInt(0);
}
}
public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context)
{
yield return new DependencyListEntry(_imports, "Import section fixup data");
yield return new DependencyListEntry(_signatures, "Import section signatures");
if (_gcRefMap != null)
{
yield return new DependencyListEntry(_gcRefMap, "GC ref map");
}
}
protected override string GetName(NodeFactory context)
{
return _name;
}
public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
{
return _name.CompareTo(((ImportSectionNode)other)._name);
}
public int EntrySize => _entrySize;
}
}
|