| File: Compiler\DependencyAnalysis\ReadyToRun\CopiedFieldRvaNode.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.Collections.Immutable; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; using Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using Debug = System.Diagnostics.Debug; namespace ILCompiler.DependencyAnalysis.ReadyToRun { public class CopiedFieldRvaNode : ObjectNode, ISymbolDefinitionNode, IObjectNodeWithAlignment { private int _rva; private EcmaModule _module; public CopiedFieldRvaNode(EcmaModule module, int rva) { _rva = rva; _module = module; } public override ObjectNodeSection GetSection(NodeFactory factory) { return ObjectNodeSection.ReadOnlyDataSection; } public override bool IsShareable => false; public override int ClassCode => 223495; public override bool StaticDependenciesAreComputed => true; public int Offset => 0; // Keep this in sync with the alignment applied in GetData: the RVA blob is at least // pointer-aligned, raised to the largest packing size among the fields that share this RVA. public int GetAlignment(NodeFactory factory) { int requiredAlignment = factory.Target.PointerSize; foreach (EcmaField field in GetFieldsAtRva()) { requiredAlignment = Math.Max(requiredAlignment, (field.FieldType as MetadataType)?.GetClassLayout().PackingSize ?? 1); } return requiredAlignment; } // Enumerates the fields whose FieldRVA entry points at this node's RVA. The ECMA-335 // FieldRVA table (II.22.18) has an RVA column (a fixed 4-byte constant) followed by a // Field column that indexes the Field table; that index is 2 bytes when the Field table // is "small" (< 2^16 rows) and 4 bytes otherwise. So the row size tells us the index width. private unsafe List<EcmaField> GetFieldsAtRva() { MetadataReader metadataReader = _module.MetadataReader; int rowCount = metadataReader.GetTableRowCount(TableIndex.FieldRva); bool smallFieldIndex = (metadataReader.GetTableRowSize(TableIndex.FieldRva) - sizeof(int)) == sizeof(ushort); BlobReader metadataBlob = new BlobReader(_module.PEReader.GetMetadata().Pointer, _module.PEReader.GetMetadata().Length); metadataBlob.Offset = metadataReader.GetTableMetadataOffset(TableIndex.FieldRva); List<EcmaField> fields = new List<EcmaField>(); for (int i = 1; i <= rowCount; i++) { int currentFieldRva = metadataBlob.ReadInt32(); int currentFieldRid = smallFieldIndex ? metadataBlob.ReadUInt16() : metadataBlob.ReadInt32(); if (currentFieldRva == _rva) { fields.Add(_module.GetField(MetadataTokens.FieldDefinitionHandle(currentFieldRid))); } } return fields; } public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { if (relocsOnly) { return new ObjectData( data: Array.Empty<byte>(), relocs: Array.Empty<Relocation>(), alignment: 1, definedSymbols: new ISymbolDefinitionNode[] { this }); } ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); byte[] rvaData = GetRvaData(factory.Target.PointerSize); builder.RequireInitialAlignment(GetAlignment(factory)); builder.AddSymbol(this); builder.EmitBytes(rvaData); return builder.ToObjectData(); } private byte[] GetRvaData(int targetPointerSize) { int size = 0; foreach (EcmaField field in GetFieldsAtRva()) { Debug.Assert(field.HasRva); // Handle overlapping fields sharing the RVA by reusing the blob and keeping the largest size. size = Math.Max(size, field.FieldType.GetElementSize().AsInt); } Debug.Assert(size > 0); PEMemoryBlock block = _module.PEReader.GetSectionData(_rva); if (block.Length < size) throw new BadImageFormatException(); byte[] result = new byte[AlignmentHelper.AlignUp(size, targetPointerSize)]; block.GetContent(0, size).CopyTo(result); return result; } protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix); sb.Append($"_FieldRvaData_{_module.Assembly.GetName().Name}_{_rva}"); } public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { int result = _module.CompareTo(((CopiedFieldRvaNode)other)._module); if (result != 0) return result; return _rva - ((CopiedFieldRvaNode)other)._rva; } } }