From 1a6224cb0412c7fb9d9af6c9e528395e0a82afd7 Mon Sep 17 00:00:00 2001 From: TomasMatousek Date: Wed, 18 Jun 2014 18:46:57 -0700 Subject: [PATCH] PEWriter metadata sizes fif. The PEWriter used to calculate sizes of metadata tables, rows and columns 3 times during emit. Under certain circumstances the result of the first one was different from the other two which might have lead to writing invalid values to PE headers. This change factors various sizes related to metadata tables to a separate class that is immutable, calculated once and then passed around. (changeset 1281677) --- .../Emitter/EditAndContinue/EmitHelpers.cs | 7 +- Src/Compilers/Core/Source/CodeAnalysis.csproj | 1 + .../Emit/EditAndContinue/DeltaPeWriter.cs | 27 +- .../BitArithmeticUtilities.cs | 29 + .../Core/Source/PEWriter/ClrHeader.cs | 8 +- .../Source/PEWriter/CustomDebugInfoWriter.cs | 2 +- .../Core/Source/PEWriter/FullPeWriter.cs | 5 +- .../Core/Source/PEWriter/MetadataSizes.cs | 260 +++++ .../Core/Source/PEWriter/PeWriter.cs | 943 +++++++----------- .../Emit/EditAndContinue/EmitHelpers.vb | 5 +- 10 files changed, 688 insertions(+), 599 deletions(-) create mode 100644 Src/Compilers/Core/Source/PEWriter/MetadataSizes.cs diff --git a/Src/Compilers/CSharp/Source/Emitter/EditAndContinue/EmitHelpers.cs b/Src/Compilers/CSharp/Source/Emitter/EditAndContinue/EmitHelpers.cs index 9d95dfc6c68..fd4feaa0d92 100644 --- a/Src/Compilers/CSharp/Source/Emitter/EditAndContinue/EmitHelpers.cs +++ b/Src/Compilers/CSharp/Source/Emitter/EditAndContinue/EmitHelpers.cs @@ -96,14 +96,15 @@ internal static class EmitHelpers definitionMap, changes, cancellationToken); - - writer.WriteMetadataAndIL(metadataStream, ilStream); + + Cci.MetadataSizes metadataSizes; + writer.WriteMetadataAndIL(metadataStream, ilStream, out metadataSizes); writer.GetMethodTokens(updatedMethodTokens); return new EmitDifferenceResult( success: true, diagnostics: diagnostics.ToReadOnlyAndFree(), - baseline: writer.GetDelta(baseline, compilation, encId)); + baseline: writer.GetDelta(baseline, compilation, encId, metadataSizes)); } catch (Cci.PdbWritingException e) { diff --git a/Src/Compilers/Core/Source/CodeAnalysis.csproj b/Src/Compilers/Core/Source/CodeAnalysis.csproj index 6b743e15f58..5a4e08c293e 100644 --- a/Src/Compilers/Core/Source/CodeAnalysis.csproj +++ b/Src/Compilers/Core/Source/CodeAnalysis.csproj @@ -378,6 +378,7 @@ + diff --git a/Src/Compilers/Core/Source/Emit/EditAndContinue/DeltaPeWriter.cs b/Src/Compilers/Core/Source/Emit/EditAndContinue/DeltaPeWriter.cs index 58e7b86347d..3d2b67915e1 100644 --- a/Src/Compilers/Core/Source/Emit/EditAndContinue/DeltaPeWriter.cs +++ b/Src/Compilers/Core/Source/Emit/EditAndContinue/DeltaPeWriter.cs @@ -105,10 +105,11 @@ internal MethodLocals(ImmutableArray definitions, ImmutableArr this.localMap = new Dictionary(); } - private ImmutableArray GetDeltaTableSizes() + private ImmutableArray GetDeltaTableSizes(ImmutableArray rowCounts) { var sizes = new int[MetadataTokens.TableCount]; - this.GetTableSizes(sizes); + + rowCounts.CopyTo(sizes); sizes[(int)TableIndex.TypeRef] = this.typeRefIndex.Rows.Count; sizes[(int)TableIndex.TypeDef] = this.typeDefs.GetAdded().Count; @@ -131,10 +132,7 @@ private ImmutableArray GetDeltaTableSizes() return ImmutableArray.Create(sizes); } - internal EmitBaseline GetDelta( - EmitBaseline baseline, - Microsoft.CodeAnalysis.Compilation compilation, - Guid encId) + internal EmitBaseline GetDelta(EmitBaseline baseline, Compilation compilation, Guid encId, MetadataSizes metadataSizes) { Debug.Assert(this.unalignedStringStreamLength > 0); // OnSerializedMetadataTables should have been called. @@ -150,7 +148,7 @@ private ImmutableArray GetDeltaTableSizes() } var previousTableSizes = this.previousGeneration.TableEntriesAdded; - var deltaTableSizes = this.GetDeltaTableSizes(); + var deltaTableSizes = this.GetDeltaTableSizes(metadataSizes.RowCounts); var tableSizes = new int[MetadataTokens.TableCount]; for (int i = 0; i < tableSizes.Length; i++) @@ -656,13 +654,13 @@ protected override void OnBeforeHeapsAligned() this.unalignedStringStreamLength = this.stringWriter.BaseStream.Length; } - protected override void PopulateEncLogTableRows(List table) + protected override void PopulateEncLogTableRows(List table, ImmutableArray rowCounts) { // The EncLog table is a log of all the operations needed // to update the previous metadata. That means all // new references must be added to the EncLog. var previousSizes = this.previousGeneration.TableSizes; - var deltaSizes = this.GetDeltaTableSizes(); + var deltaSizes = this.GetDeltaTableSizes(rowCounts); PopulateEncLogTableRows(table, TableIndex.AssemblyRef, previousSizes, deltaSizes); PopulateEncLogTableRows(table, TableIndex.ModuleRef, previousSizes, deltaSizes); @@ -787,7 +785,7 @@ private static void PopulateEncLogTableRows(List table, uint tokenTyp } } - protected override void PopulateEncMapTableRows(List table) + protected override void PopulateEncMapTableRows(List table, ImmutableArray rowCounts) { // The EncMap table maps from offset in each table in the delta // metadata to token. As such, the EncMap is a concatenated @@ -795,7 +793,7 @@ protected override void PopulateEncMapTableRows(List table) // and, within each table, sorted by row. var tokens = ArrayBuilder.GetInstance(); var previousSizes = this.previousGeneration.TableSizes; - var deltaSizes = this.GetDeltaTableSizes(); + var deltaSizes = this.GetDeltaTableSizes(rowCounts); AddReferencedTokens(tokens, TableIndex.AssemblyRef, previousSizes, deltaSizes); AddReferencedTokens(tokens, TableIndex.ModuleRef, previousSizes, deltaSizes); @@ -883,15 +881,14 @@ protected override void PopulateEncMapTableRows(List table) TableIndex.GenericParamConstraint, }; - var tableSizes = new int[MetadataTokens.TableCount]; - this.GetTableSizes(tableSizes); - for (uint i = 0; i < tableSizes.Length; i++) + for (int i = 0; i < rowCounts.Length; i++) { if (handledTables.Contains((TableIndex)i)) { continue; } - Debug.Assert(tableSizes[i] == 0); + + Debug.Assert(rowCounts[i] == 0); } #endif } diff --git a/Src/Compilers/Core/Source/InternalUtilities/BitArithmeticUtilities.cs b/Src/Compilers/Core/Source/InternalUtilities/BitArithmeticUtilities.cs index 4cfa1271b91..fed87262bd3 100644 --- a/Src/Compilers/Core/Source/InternalUtilities/BitArithmeticUtilities.cs +++ b/Src/Compilers/Core/Source/InternalUtilities/BitArithmeticUtilities.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Diagnostics; + namespace Roslyn.Utilities { internal static class BitArithmeticUtilities @@ -43,5 +45,32 @@ public static int CountBits(ulong v) return (int)v; } } + + internal static uint Align(uint position, uint alignment) + { + Debug.Assert(CountBits(alignment) == 1); + + uint result = position & ~(alignment - 1); + if (result == position) + { + return result; + } + + return result + alignment; + } + + internal static int Align(int position, int alignment) + { + Debug.Assert(position >= 0 && alignment >= 0); + Debug.Assert(CountBits(alignment) == 1); + + int result = position & ~(alignment - 1); + if (result == position) + { + return result; + } + + return result + alignment; + } } } \ No newline at end of file diff --git a/Src/Compilers/Core/Source/PEWriter/ClrHeader.cs b/Src/Compilers/Core/Source/PEWriter/ClrHeader.cs index 356b8d31a39..55641447274 100644 --- a/Src/Compilers/Core/Source/PEWriter/ClrHeader.cs +++ b/Src/Compilers/Core/Source/PEWriter/ClrHeader.cs @@ -1,15 +1,15 @@ // Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Cci = Microsoft.Cci; +using System.Reflection.PortableExecutable; namespace Microsoft.Cci { - internal class ClrHeader + internal sealed class CorHeader { internal ushort MajorRuntimeVersion; internal ushort MinorRuntimeVersion; - internal DirectoryEntry MetaData; - internal uint Flags; + internal DirectoryEntry MetadataDirectory; + internal CorFlags Flags; internal uint EntryPointToken; internal DirectoryEntry Resources; internal DirectoryEntry StrongNameSignature; diff --git a/Src/Compilers/Core/Source/PEWriter/CustomDebugInfoWriter.cs b/Src/Compilers/Core/Source/PEWriter/CustomDebugInfoWriter.cs index 17d5e741772..738dd547431 100644 --- a/Src/Compilers/Core/Source/PEWriter/CustomDebugInfoWriter.cs +++ b/Src/Compilers/Core/Source/PEWriter/CustomDebugInfoWriter.cs @@ -293,7 +293,7 @@ private void SerializeNamespaceScopeMetadata(IMethodBody methodBody, ArrayBuilde cmw.WriteByte(0); // kind: UsingInfo cmw.Align(4); - cmw.WriteUint(streamLength = PeWriter.Aligned((uint)usingCounts.Count * 2 + 10, 4)); + cmw.WriteUint(streamLength = BitArithmeticUtilities.Align((uint)usingCounts.Count * 2 + 10, 4)); cmw.WriteUshort((ushort)usingCounts.Count); foreach (ushort uc in usingCounts) { diff --git a/Src/Compilers/Core/Source/PEWriter/FullPeWriter.cs b/Src/Compilers/Core/Source/PEWriter/FullPeWriter.cs index e764a9ae9a0..332ddd96876 100644 --- a/Src/Compilers/Core/Source/PEWriter/FullPeWriter.cs +++ b/Src/Compilers/Core/Source/PEWriter/FullPeWriter.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis; using EmitContext = Microsoft.CodeAnalysis.Emit.EmitContext; @@ -295,11 +296,11 @@ internal FullReferenceIndexer(PeWriter peWriter) } } - protected override void PopulateEncLogTableRows(List table) + protected override void PopulateEncLogTableRows(List table, ImmutableArray rowCounts) { } - protected override void PopulateEncMapTableRows(List table) + protected override void PopulateEncMapTableRows(List table, ImmutableArray rowCounts) { } diff --git a/Src/Compilers/Core/Source/PEWriter/MetadataSizes.cs b/Src/Compilers/Core/Source/PEWriter/MetadataSizes.cs new file mode 100644 index 00000000000..95cf0997ba9 --- /dev/null +++ b/Src/Compilers/Core/Source/PEWriter/MetadataSizes.cs @@ -0,0 +1,260 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Immutable; +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; +using Roslyn.Utilities; + +namespace Microsoft.Cci +{ + using BitArithmeticUtilities; + + internal sealed class MetadataSizes + { + private const int StreamAlignment = 4; + + private readonly bool isMinimalDelta; + + public readonly byte BlobIndexSize; + public readonly byte StringIndexSize; + public readonly byte GuidIndexSize; + public readonly byte CustomAttributeTypeCodedIndexSize; + public readonly byte DeclSecurityCodedIndexSize; + public readonly byte EventDefIndexSize; + public readonly byte FieldDefIndexSize; + public readonly byte GenericParamIndexSize; + public readonly byte HasConstantCodedIndexSize; + public readonly byte HasCustomAttributeCodedIndexSize; + public readonly byte HasFieldMarshalCodedIndexSize; + public readonly byte HasSemanticsCodedIndexSize; + public readonly byte ImplementationCodedIndexSize; + public readonly byte MemberForwardedCodedIndexSize; + public readonly byte MemberRefParentCodedIndexSize; + public readonly byte MethodDefIndexSize; + public readonly byte MethodDefOrRefCodedIndexSize; + public readonly byte ModuleRefIndexSize; + public readonly byte ParameterIndexSize; + public readonly byte PropertyDefIndexSize; + public readonly byte ResolutionScopeCodedIndexSize; + public readonly byte TypeDefIndexSize; + public readonly byte TypeDefOrRefCodedIndexSize; + public readonly byte TypeOrMethodDefCodedIndexSize; + + /// + /// Table row counts. + /// + public readonly ImmutableArray RowCounts; + + /// + /// Exact (unaligned) heap sizes. + /// + public readonly ImmutableArray HeapSizes; + + /// + /// Overall size of metadata stream storage (stream headers, streams: heaps + tables). + /// + public readonly int MetadataStreamStorageSize; + + /// + /// The size of metadata stream (#- or #~). Aligned. + /// + public readonly int MetadataTableStreamSize; + + public MetadataSizes(ImmutableArray rowCounts, ImmutableArray heapSizes, bool isMinimalDelta) + { + const byte large = 4; + const byte small = 2; + + this.RowCounts = rowCounts; + this.HeapSizes = heapSizes; + this.isMinimalDelta = isMinimalDelta; + + this.BlobIndexSize = (isMinimalDelta || heapSizes[(int)HeapIndex.Blob] > ushort.MaxValue) ? large : small; + this.StringIndexSize = (isMinimalDelta || heapSizes[(int)HeapIndex.String] > ushort.MaxValue) ? large : small; + this.GuidIndexSize = (isMinimalDelta || heapSizes[(int)HeapIndex.Guid] > ushort.MaxValue) ? large : small; + + this.CustomAttributeTypeCodedIndexSize = this.GetIndexByteSize(3, TableIndex.MethodDef, TableIndex.MemberRef); + this.DeclSecurityCodedIndexSize = this.GetIndexByteSize(2, TableIndex.MethodDef, TableIndex.TypeDef); + this.EventDefIndexSize = this.GetIndexByteSize(0, TableIndex.Event); + this.FieldDefIndexSize = this.GetIndexByteSize(0, TableIndex.Field); + this.GenericParamIndexSize = this.GetIndexByteSize(0, TableIndex.GenericParam); + this.HasConstantCodedIndexSize = this.GetIndexByteSize(2, TableIndex.Field, TableIndex.Param, TableIndex.Property); + + this.HasCustomAttributeCodedIndexSize = this.GetIndexByteSize(5, + TableIndex.MethodDef, + TableIndex.Field, + TableIndex.TypeRef, + TableIndex.TypeDef, + TableIndex.Param, + TableIndex.InterfaceImpl, + TableIndex.MemberRef, + TableIndex.Module, + TableIndex.DeclSecurity, + TableIndex.Property, + TableIndex.Event, + TableIndex.StandAloneSig, + TableIndex.ModuleRef, + TableIndex.TypeSpec, + TableIndex.Assembly, + TableIndex.AssemblyRef, + TableIndex.File, + TableIndex.ExportedType, + TableIndex.ManifestResource, + TableIndex.GenericParam, + TableIndex.GenericParamConstraint, + TableIndex.MethodSpec); + + this.HasFieldMarshalCodedIndexSize = this.GetIndexByteSize(1, TableIndex.Field, TableIndex.Param); + this.HasSemanticsCodedIndexSize = this.GetIndexByteSize(1, TableIndex.Event, TableIndex.Property); + this.ImplementationCodedIndexSize = this.GetIndexByteSize(2, TableIndex.File, TableIndex.AssemblyRef, TableIndex.ExportedType); + this.MemberForwardedCodedIndexSize = this.GetIndexByteSize(1, TableIndex.Field, TableIndex.MethodDef); + this.MemberRefParentCodedIndexSize = this.GetIndexByteSize(3, TableIndex.TypeDef, TableIndex.TypeRef, TableIndex.ModuleRef, TableIndex.MethodDef, TableIndex.TypeSpec); + this.MethodDefIndexSize = this.GetIndexByteSize(0, TableIndex.MethodDef); + this.MethodDefOrRefCodedIndexSize = this.GetIndexByteSize(1, TableIndex.MethodDef, TableIndex.MemberRef); + this.ModuleRefIndexSize = this.GetIndexByteSize(0, TableIndex.ModuleRef); + this.ParameterIndexSize = this.GetIndexByteSize(0, TableIndex.Param); + this.PropertyDefIndexSize = this.GetIndexByteSize(0, TableIndex.Property); + this.ResolutionScopeCodedIndexSize = this.GetIndexByteSize(2, TableIndex.Module, TableIndex.ModuleRef, TableIndex.AssemblyRef, TableIndex.TypeRef); + this.TypeDefIndexSize = this.GetIndexByteSize(0, TableIndex.TypeDef); + this.TypeDefOrRefCodedIndexSize = this.GetIndexByteSize(2, TableIndex.TypeDef, TableIndex.TypeRef, TableIndex.TypeSpec); + this.TypeOrMethodDefCodedIndexSize = this.GetIndexByteSize(1, TableIndex.TypeDef, TableIndex.MethodDef); + + int size = this.CalculateTableStreamHeaderSize(); + + size += GetTableSize(TableIndex.Module, 2 + 3 * this.GuidIndexSize + this.StringIndexSize); + size += GetTableSize(TableIndex.TypeRef, this.ResolutionScopeCodedIndexSize + this.StringIndexSize + this.StringIndexSize); + size += GetTableSize(TableIndex.TypeDef, 4 + this.StringIndexSize + this.StringIndexSize + this.TypeDefOrRefCodedIndexSize + this.FieldDefIndexSize + this.MethodDefIndexSize); + Debug.Assert(RowCounts[(int)TableIndex.FieldPtr] == 0); + size += GetTableSize(TableIndex.Field, 2 + this.StringIndexSize + this.BlobIndexSize); + Debug.Assert(RowCounts[(int)TableIndex.MethodPtr] == 0); + size += GetTableSize(TableIndex.MethodDef, 8 + this.StringIndexSize + this.BlobIndexSize + this.ParameterIndexSize); + Debug.Assert(RowCounts[(int)TableIndex.ParamPtr] == 0); + size += GetTableSize(TableIndex.Param, 4 + this.StringIndexSize); + size += GetTableSize(TableIndex.InterfaceImpl, this.TypeDefIndexSize + this.TypeDefOrRefCodedIndexSize); + size += GetTableSize(TableIndex.MemberRef, this.MemberRefParentCodedIndexSize + this.StringIndexSize + this.BlobIndexSize); + size += GetTableSize(TableIndex.Constant, 2 + this.HasConstantCodedIndexSize + this.BlobIndexSize); + size += GetTableSize(TableIndex.CustomAttribute, this.HasCustomAttributeCodedIndexSize + this.CustomAttributeTypeCodedIndexSize + this.BlobIndexSize); + size += GetTableSize(TableIndex.FieldMarshal, this.HasFieldMarshalCodedIndexSize + this.BlobIndexSize); + size += GetTableSize(TableIndex.DeclSecurity, 2 + this.DeclSecurityCodedIndexSize + this.BlobIndexSize); + size += GetTableSize(TableIndex.ClassLayout, 6 + this.TypeDefIndexSize); + size += GetTableSize(TableIndex.FieldLayout, 4 + this.FieldDefIndexSize); + size += GetTableSize(TableIndex.StandAloneSig, this.BlobIndexSize); + size += GetTableSize(TableIndex.EventMap, this.TypeDefIndexSize + this.EventDefIndexSize); + Debug.Assert(RowCounts[(int)TableIndex.EventPtr] == 0); + size += GetTableSize(TableIndex.Event, 2 + this.StringIndexSize + this.TypeDefOrRefCodedIndexSize); + size += GetTableSize(TableIndex.PropertyMap, this.TypeDefIndexSize + this.PropertyDefIndexSize); + Debug.Assert(RowCounts[(int)TableIndex.PropertyPtr] == 0); + size += GetTableSize(TableIndex.Property, 2 + this.StringIndexSize + this.BlobIndexSize); + size += GetTableSize(TableIndex.MethodSemantics, 2 + this.MethodDefIndexSize + this.HasSemanticsCodedIndexSize); + size += GetTableSize(TableIndex.MethodImpl, 0 + this.TypeDefIndexSize + this.MethodDefOrRefCodedIndexSize + this.MethodDefOrRefCodedIndexSize); + size += GetTableSize(TableIndex.ModuleRef, 0 + this.StringIndexSize); + size += GetTableSize(TableIndex.TypeSpec, 0 + this.BlobIndexSize); + size += GetTableSize(TableIndex.ImplMap, 2 + this.MemberForwardedCodedIndexSize + this.StringIndexSize + this.ModuleRefIndexSize); + size += GetTableSize(TableIndex.FieldRva, 4 + this.FieldDefIndexSize); + size += GetTableSize(TableIndex.EncLog, 8); + size += GetTableSize(TableIndex.EncMap, 4); + size += GetTableSize(TableIndex.Assembly, 16 + this.BlobIndexSize + this.StringIndexSize + this.StringIndexSize); + Debug.Assert(RowCounts[(int)TableIndex.AssemblyProcessor] == 0); + Debug.Assert(RowCounts[(int)TableIndex.AssemblyOS] == 0); + size += GetTableSize(TableIndex.AssemblyRef, 12 + this.BlobIndexSize + this.StringIndexSize + this.StringIndexSize + this.BlobIndexSize); + Debug.Assert(RowCounts[(int)TableIndex.AssemblyRefProcessor] == 0); + Debug.Assert(RowCounts[(int)TableIndex.AssemblyRefOS] == 0); + size += GetTableSize(TableIndex.File, 4 + this.StringIndexSize + this.BlobIndexSize); + size += GetTableSize(TableIndex.ExportedType, 8 + this.StringIndexSize + this.StringIndexSize + this.ImplementationCodedIndexSize); + size += GetTableSize(TableIndex.ManifestResource, 8 + this.StringIndexSize + this.ImplementationCodedIndexSize); + size += GetTableSize(TableIndex.NestedClass, this.TypeDefIndexSize + this.TypeDefIndexSize); + size += GetTableSize(TableIndex.GenericParam, 4 + this.TypeOrMethodDefCodedIndexSize + this.StringIndexSize); + size += GetTableSize(TableIndex.MethodSpec, this.MethodDefOrRefCodedIndexSize + this.BlobIndexSize); + size += GetTableSize(TableIndex.GenericParamConstraint, this.GenericParamIndexSize + this.TypeDefOrRefCodedIndexSize); + + // +1 for terminating 0 byte + size = Align(size + 1, StreamAlignment); + + this.MetadataTableStreamSize = size; + + size += GetAlignedHeapSize(HeapIndex.String); + size += GetAlignedHeapSize(HeapIndex.UserString); + size += GetAlignedHeapSize(HeapIndex.Guid); + size += GetAlignedHeapSize(HeapIndex.Blob); + + this.MetadataStreamStorageSize = size; + } + + /// + /// Metadata header size. + /// Includes: + /// - metadata storage signature + /// - storage header + /// - stream headers + /// + public int MetadataHeaderSize + { + get + { + return this.isMinimalDelta ? 124 : 108; + } + } + + /// + /// Total size of metadata (header and all streams). + /// + public int MetadataSize + { + get + { + return MetadataHeaderSize + MetadataStreamStorageSize; + } + } + + public int GetAlignedHeapSize(HeapIndex index) + { + return Align(HeapSizes[(int)index], StreamAlignment); + } + + private int GetTableSize(TableIndex index, int rowSize) + { + return RowCounts[(int)index] * rowSize; + } + + internal int CalculateTableStreamHeaderSize() + { + int result = sizeof(int) + // Reserved + sizeof(short) + // Version (major, minor) + sizeof(byte) + // Heap index sizes + sizeof(byte) + // Bit width of RowId + sizeof(long) + // Valid table mask + sizeof(long); // Sorted table mask + + foreach (int rowCount in RowCounts) + { + if (rowCount > 0) + { + // present table row count + result += sizeof(int); + } + } + + return result; + } + + private byte GetIndexByteSize(int discriminatingBits, params TableIndex[] tables) + { + const int BitsPerShort = 16; + return (byte)(isMinimalDelta || IndexDoesNotFit(BitsPerShort - discriminatingBits, tables) ? 4 : 2); + } + + private bool IndexDoesNotFit(int numberOfBits, params TableIndex[] tables) + { + int maxIndex = (1 << numberOfBits) - 1; + foreach (TableIndex table in tables) + { + if (RowCounts[(int)table] > maxIndex) + { + return true; + } + } + + return false; + } + } +} diff --git a/Src/Compilers/Core/Source/PEWriter/PeWriter.cs b/Src/Compilers/Core/Source/PEWriter/PeWriter.cs index 6013fa44d95..20591736ca9 100644 --- a/Src/Compilers/Core/Source/PEWriter/PeWriter.cs +++ b/Src/Compilers/Core/Source/PEWriter/PeWriter.cs @@ -11,6 +11,7 @@ using System.Reflection.Emit; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; using System.Runtime.InteropServices; using System.Text; using System.Threading; @@ -21,6 +22,8 @@ namespace Microsoft.Cci { + using BitArithmeticUtilities; + internal abstract class PeWriter { /// @@ -443,12 +446,12 @@ protected virtual void OnBeforeHeapsAligned() /// /// Populate EncLog table. /// - protected abstract void PopulateEncLogTableRows(List table); + protected abstract void PopulateEncLogTableRows(List table, ImmutableArray rowCounts); /// /// Populate EncMap table. /// - protected abstract void PopulateEncMapTableRows(List table); + protected abstract void PopulateEncMapTableRows(List table, ImmutableArray rowCounts); // If true, it is allowed to have methods not have bodies (for emitting metadata-only // assembly) @@ -465,8 +468,6 @@ protected virtual void OnBeforeHeapsAligned() private uint[] pseudoSymbolTokenToTokenMap; private List pseudoStringTokenToTokenMap; - private readonly ClrHeader clrHeader = new ClrHeader(); - private readonly bool emitRuntimeStartupStub; private readonly BinaryWriter coverageDataWriter = new BinaryWriter(new MemoryStream()); private readonly SectionHeader coverSection = new SectionHeader(); @@ -505,34 +506,6 @@ protected virtual void OnBeforeHeapsAligned() // A map of method body to RVA. private readonly Dictionary possiblyDuplicateMethodBodies; - private byte blobIndexSize; - private byte stringIndexSize; - private byte guidIndexSize; - - private byte customAttributeTypeCodedIndexSize; - private byte declSecurityCodedIndexSize; - private byte eventDefIndexSize; - private byte fieldDefIndexSize; - private byte genericParamIndexSize; - private byte hasConstantCodedIndexSize; - private byte hasCustomAttributeCodedIndexSize; - private byte hasFieldMarshalCodedIndexSize; - private byte hasSemanticsCodedIndexSize; - private byte implementationCodedIndexSize; - private byte memberForwardedCodedIndexSize; - private byte memberRefParentCodedIndexSize; - private byte methodDefIndexSize; - private byte methodDefOrRefCodedIndexSize; - private byte moduleRefIndexSize; - private byte parameterIndexSize; - private byte propertyDefIndexSize; - private byte resolutionScopeCodedIndexSize; - private byte typeDefIndexSize; - private byte typeDefOrRefCodedIndexSize; - private byte typeOrMethodDefCodedIndexSize; - - private readonly uint[] tableSizes = new uint[MetadataTokens.TableCount]; - private readonly NtHeader ntHeader = new NtHeader(); private readonly PdbWriter pdbWriter; private readonly BinaryWriter rdataWriter = new BinaryWriter(new MemoryStream()); @@ -721,6 +694,7 @@ internal void WritePeToStream(Stream peStream) uint moduleVersionIdOffsetInMetadataStream; int mappedFieldDataStreamRva; + MetadataSizes metadataSizes; SerializeMetadataAndIL( metadataWriter, @@ -728,18 +702,20 @@ internal void WritePeToStream(Stream peStream) mappedFieldDataWriter, separateMethodIL: false, moduleVersionIdOffsetInMetadataStream: out moduleVersionIdOffsetInMetadataStream, - mappedFieldDataStreamRva: out mappedFieldDataStreamRva); + mappedFieldDataStreamRva: out mappedFieldDataStreamRva, + metadataSizes: out metadataSizes); // fill in header fields. - FillInNtHeader((int)ilBuffer.Length, mappedFieldDataStreamRva); - FillInClrHeader((int)ilBuffer.Length); + FillInNtHeader(metadataSizes, (int)ilBuffer.Length, mappedFieldDataStreamRva); + var corHeader = CreateCorHeader(metadataSizes, (int)ilBuffer.Length); // write to pe stream. long positionOfHeaderTimestamp; WriteHeaders(peStream, out positionOfHeaderTimestamp); + long startOfMetadataStream; long positionOfDebugTableTimestamp; - WriteTextSection(peStream, metadataBuffer, ilBuffer, mappedFieldDataBuffer, out startOfMetadataStream, out positionOfDebugTableTimestamp); + WriteTextSection(peStream, corHeader, metadataBuffer, ilBuffer, mappedFieldDataBuffer, out startOfMetadataStream, out positionOfDebugTableTimestamp); WriteRdataSection(peStream); WriteSdataSection(peStream); WriteCoverSection(peStream); @@ -754,7 +730,7 @@ internal void WritePeToStream(Stream peStream) } } - internal void WriteMetadataAndIL(Stream metadataStream, Stream ilStream) + internal void WriteMetadataAndIL(Stream metadataStream, Stream ilStream, out MetadataSizes metadataSizes) { // Extract information from object model into tables, indices and streams CreateIndices(); @@ -786,7 +762,8 @@ internal void WriteMetadataAndIL(Stream metadataStream, Stream ilStream) mappedFieldDataWriter, separateMethodIL: true, moduleVersionIdOffsetInMetadataStream: out moduleVersionIdOffsetInMetadataStream, - mappedFieldDataStreamRva: out mappedFieldDataStreamRva); + mappedFieldDataStreamRva: out mappedFieldDataStreamRva, + metadataSizes: out metadataSizes); ilBuffer.WriteTo(ilStream); metadataBuffer.WriteTo(metadataStream); @@ -874,17 +851,6 @@ private static byte[] ComputeSerializedGuidFromData(Stream stream, out byte[] ti return guidData; } - internal static uint Aligned(uint position, uint alignment) - { - uint result = position & ~(alignment - 1); - if (result == position) - { - return result; - } - - return result + alignment; - } - private uint ComputeStrongNameSignatureSize() { IAssembly assembly = this.module.AsAssembly; @@ -907,18 +873,18 @@ private uint ComputeStrongNameSignatureSize() return keySize < 128 + 32 ? 128u : keySize - 32; } - private uint ComputeOffsetToDebugTable(int ilStreamLength) + private uint ComputeOffsetToDebugTable(MetadataSizes metadataSizes, int ilStreamLength) { uint result = this.ComputeOffsetToMetadata(ilStreamLength); - result += this.ComputeSizeOfMetadata(); - result += Aligned(this.resourceWriter.BaseStream.Length, 4); + result += (uint)metadataSizes.MetadataSize; + result += Align(this.resourceWriter.BaseStream.Length, 4); result += this.ComputeStrongNameSignatureSize(); // size of strong name hash return result; } - private uint ComputeOffsetToImportTable(int ilStreamLength) + private uint ComputeOffsetToImportTable(MetadataSizes metadataSizes, int ilStreamLength) { - uint result = this.ComputeOffsetToDebugTable(ilStreamLength); + uint result = this.ComputeOffsetToDebugTable(metadataSizes, ilStreamLength); result += this.ComputeSizeOfDebugTable(result); result += 0; // TODO: size of unmanaged export stubs (when and if these are ever supported). return result; @@ -929,7 +895,7 @@ private uint ComputeOffsetToMetadata(int ilStreamLength) uint result = 0; result += this.sizeOfImportAddressTable; result += 72; // size of CLR header - result += Aligned((uint)ilStreamLength, 4); + result += Align((uint)ilStreamLength, 4); return result; } @@ -946,69 +912,63 @@ private uint ComputeSizeOfDebugTable(uint offsetToMetadata) return 0x1c + (uint)this.debugDirectory.Data.Length; } - private uint ComputeSizeOfMetadata() - { - uint result = this.MetadataHeaderSize; - result += Aligned(this.ComputeSizeOfMetadataTablesStream(), 4); - result += Aligned(this.stringWriter.BaseStream.Length, 4); - result += Aligned(this.userStringWriter.BaseStream.Length, 4); - result += Aligned(this.guidWriter.BaseStream.Length, 4); - result += Aligned(this.blobWriter.BaseStream.Length, 4); - return result; - } - - private uint ComputeSizeOfMetadataTablesStream() - { - this.ComputeColumnSizes(); - uint result = this.ComputeSizeOfTablesHeader(); - result += this.tableSizes[(byte)TableIndex.Module] * (2u + 3u * this.guidIndexSize + this.stringIndexSize); - result += this.tableSizes[(byte)TableIndex.TypeRef] * (0u + this.resolutionScopeCodedIndexSize + this.stringIndexSize + this.stringIndexSize); - result += this.tableSizes[(byte)TableIndex.TypeDef] * (4u + this.stringIndexSize + this.stringIndexSize + this.typeDefOrRefCodedIndexSize + this.fieldDefIndexSize + this.methodDefIndexSize); - Debug.Assert(this.tableSizes[(byte)TableIndex.FieldPtr] == 0); - result += this.tableSizes[(byte)TableIndex.Field] * (2u + this.stringIndexSize + this.blobIndexSize); - Debug.Assert(this.tableSizes[(byte)TableIndex.MethodPtr] == 0); - result += this.tableSizes[(byte)TableIndex.MethodDef] * (8u + this.stringIndexSize + this.blobIndexSize + this.parameterIndexSize); - Debug.Assert(this.tableSizes[(byte)TableIndex.ParamPtr] == 0); - result += this.tableSizes[(byte)TableIndex.Param] * (4u + this.stringIndexSize); - result += this.tableSizes[(byte)TableIndex.InterfaceImpl] * (0u + this.typeDefIndexSize + this.typeDefOrRefCodedIndexSize); - result += this.tableSizes[(byte)TableIndex.MemberRef] * (0u + this.memberRefParentCodedIndexSize + this.stringIndexSize + this.blobIndexSize); - result += this.tableSizes[(byte)TableIndex.Constant] * (2u + this.hasConstantCodedIndexSize + this.blobIndexSize); - result += this.tableSizes[(byte)TableIndex.CustomAttribute] * (0u + this.hasCustomAttributeCodedIndexSize + this.customAttributeTypeCodedIndexSize + this.blobIndexSize); - result += this.tableSizes[(byte)TableIndex.FieldMarshal] * (0u + this.hasFieldMarshalCodedIndexSize + this.blobIndexSize); - result += this.tableSizes[(byte)TableIndex.DeclSecurity] * (2u + this.declSecurityCodedIndexSize + this.blobIndexSize); - result += this.tableSizes[(byte)TableIndex.ClassLayout] * (6u + this.typeDefIndexSize); - result += this.tableSizes[(byte)TableIndex.FieldLayout] * (4u + this.fieldDefIndexSize); - result += this.tableSizes[(byte)TableIndex.StandAloneSig] * (0u + this.blobIndexSize); - result += this.tableSizes[(byte)TableIndex.EventMap] * (0u + this.typeDefIndexSize + this.eventDefIndexSize); - Debug.Assert(this.tableSizes[(byte)TableIndex.EventPtr] == 0); - result += this.tableSizes[(byte)TableIndex.Event] * (2u + this.stringIndexSize + this.typeDefOrRefCodedIndexSize); - result += this.tableSizes[(byte)TableIndex.PropertyMap] * (0u + this.typeDefIndexSize + this.propertyDefIndexSize); - Debug.Assert(this.tableSizes[(byte)TableIndex.PropertyPtr] == 0); - result += this.tableSizes[(byte)TableIndex.Property] * (2u + this.stringIndexSize + this.blobIndexSize); - result += this.tableSizes[(byte)TableIndex.MethodSemantics] * (2u + this.methodDefIndexSize + this.hasSemanticsCodedIndexSize); - result += this.tableSizes[(byte)TableIndex.MethodImpl] * (0u + this.typeDefIndexSize + this.methodDefOrRefCodedIndexSize + this.methodDefOrRefCodedIndexSize); - result += this.tableSizes[(byte)TableIndex.ModuleRef] * (0u + this.stringIndexSize); - result += this.tableSizes[(byte)TableIndex.TypeSpec] * (0u + this.blobIndexSize); - result += this.tableSizes[(byte)TableIndex.ImplMap] * (2u + this.memberForwardedCodedIndexSize + this.stringIndexSize + this.moduleRefIndexSize); - result += this.tableSizes[(byte)TableIndex.FieldRva] * (4u + this.fieldDefIndexSize); - result += this.tableSizes[(byte)TableIndex.EncLog] * (8u); - result += this.tableSizes[(byte)TableIndex.EncMap] * (4u); - result += this.tableSizes[(byte)TableIndex.Assembly] * (16u + this.blobIndexSize + this.stringIndexSize + this.stringIndexSize); - Debug.Assert(this.tableSizes[(byte)TableIndex.AssemblyProcessor] == 0); - Debug.Assert(this.tableSizes[(byte)TableIndex.AssemblyOS] == 0); - result += this.tableSizes[(byte)TableIndex.AssemblyRef] * (12u + this.blobIndexSize + this.stringIndexSize + this.stringIndexSize + this.blobIndexSize); - Debug.Assert(this.tableSizes[(byte)TableIndex.AssemblyRefProcessor] == 0); - Debug.Assert(this.tableSizes[(byte)TableIndex.AssemblyRefOS] == 0); - result += this.tableSizes[(byte)TableIndex.File] * (4u + this.stringIndexSize + this.blobIndexSize); - result += this.tableSizes[(byte)TableIndex.ExportedType] * (8u + this.stringIndexSize + this.stringIndexSize + this.implementationCodedIndexSize); - result += this.tableSizes[(byte)TableIndex.ManifestResource] * (8u + this.stringIndexSize + this.implementationCodedIndexSize); - result += this.tableSizes[(byte)TableIndex.NestedClass] * (0u + this.typeDefIndexSize + this.typeDefIndexSize); - result += this.tableSizes[(byte)TableIndex.GenericParam] * (4u + this.typeOrMethodDefCodedIndexSize + this.stringIndexSize); - result += this.tableSizes[(byte)TableIndex.MethodSpec] * (0u + this.methodDefOrRefCodedIndexSize + this.blobIndexSize); - result += this.tableSizes[(byte)TableIndex.GenericParamConstraint] * (0u + this.genericParamIndexSize + this.typeDefOrRefCodedIndexSize); - return result + 1; + private ImmutableArray CalculateRowCounts() + { + var rowCounts = new int[MetadataTokens.TableCount]; + + rowCounts[(int)TableIndex.Assembly] = (this.module.AsAssembly != null) ? 1 : 0; + rowCounts[(int)TableIndex.AssemblyRef] = this.assemblyRefTable.Count; + rowCounts[(int)TableIndex.ClassLayout] = this.classLayoutTable.Count; + rowCounts[(int)TableIndex.Constant] = this.constantTable.Count; + rowCounts[(int)TableIndex.CustomAttribute] = this.customAttributeTable.Count; + rowCounts[(int)TableIndex.TypeRef] = this.typeRefTable.Count; + rowCounts[(int)TableIndex.DeclSecurity] = this.declSecurityTable.Count; + rowCounts[(int)TableIndex.EncLog] = this.encLogTable.Count; + rowCounts[(int)TableIndex.EncMap] = this.encMapTable.Count; + rowCounts[(int)TableIndex.EventMap] = this.eventMapTable.Count; + rowCounts[(int)TableIndex.Event] = this.eventTable.Count; + rowCounts[(int)TableIndex.ExportedType] = this.exportedTypeTable.Count; + rowCounts[(int)TableIndex.FieldLayout] = this.fieldLayoutTable.Count; + rowCounts[(int)TableIndex.FieldMarshal] = this.fieldMarshalTable.Count; + rowCounts[(int)TableIndex.FieldRva] = this.fieldRvaTable.Count; + rowCounts[(int)TableIndex.Field] = this.fieldDefTable.Count; + rowCounts[(int)TableIndex.File] = this.fileTable.Count; + rowCounts[(int)TableIndex.GenericParamConstraint] = this.genericParamConstraintTable.Count; + rowCounts[(int)TableIndex.GenericParam] = this.genericParamTable.Count; + rowCounts[(int)TableIndex.ImplMap] = this.implMapTable.Count; + rowCounts[(int)TableIndex.InterfaceImpl] = this.interfaceImplTable.Count; + rowCounts[(int)TableIndex.ManifestResource] = this.manifestResourceTable.Count; + rowCounts[(int)TableIndex.MemberRef] = this.memberRefTable.Count; + rowCounts[(int)TableIndex.MethodImpl] = this.methodImplTable.Count; + rowCounts[(int)TableIndex.MethodSemantics] = this.methodSemanticsTable.Count; + rowCounts[(int)TableIndex.MethodSpec] = this.methodSpecTable.Count; + rowCounts[(int)TableIndex.MethodDef] = this.methodTable.Length; + rowCounts[(int)TableIndex.ModuleRef] = this.moduleRefTable.Count; + rowCounts[(int)TableIndex.Module] = 1; + rowCounts[(int)TableIndex.NestedClass] = this.nestedClassTable.Count; + rowCounts[(int)TableIndex.Param] = this.paramTable.Count; + rowCounts[(int)TableIndex.PropertyMap] = this.propertyMapTable.Count; + rowCounts[(int)TableIndex.Property] = this.propertyTable.Count; + rowCounts[(int)TableIndex.StandAloneSig] = this.GetStandAloneSignatures().Count; + rowCounts[(int)TableIndex.TypeDef] = this.typeDefTable.Count; + rowCounts[(int)TableIndex.TypeRef] = this.typeRefTable.Count; + rowCounts[(int)TableIndex.TypeSpec] = this.typeSpecTable.Count; + + return ImmutableArray.CreateRange(rowCounts); + } + + private ImmutableArray CalculateHeapSizes() + { + var heapSizes = new int[MetadataTokens.HeapCount]; + + heapSizes[(int)HeapIndex.UserString] = (int)this.userStringWriter.BaseStream.Length; + heapSizes[(int)HeapIndex.String] = (int)this.stringWriter.BaseStream.Length; + heapSizes[(int)HeapIndex.Blob] = (int)this.blobWriter.BaseStream.Length; + heapSizes[(int)HeapIndex.Guid] = (int)this.guidWriter.BaseStream.Length; + + return ImmutableArray.CreateRange(heapSizes); } - + private uint ComputeSizeOfPeHeaders() { ushort numberOfSections = 1; // .text @@ -1031,15 +991,15 @@ private uint ComputeSizeOfPeHeaders() return sizeOfPeHeaders; } - private uint ComputeSizeOfTextSection(int ilStreamLength, int mappedFieldDataLength) + private uint ComputeSizeOfTextSection(MetadataSizes metadataSizes, int ilStreamLength, int mappedFieldDataLength) { - uint textSectionLength = this.ComputeOffsetToImportTable(ilStreamLength); + uint textSectionLength = this.ComputeOffsetToImportTable(metadataSizes, ilStreamLength); if (this.emitRuntimeStartupStub) { textSectionLength += !this.module.Requires64bits ? 66u : 70u; //size of import table textSectionLength += 14; //size of name table - textSectionLength = Aligned(textSectionLength, !this.module.Requires64bits ? 4u : 8u); //optional padding to make startup stub's target address align on word or double word boundary + textSectionLength = Align(textSectionLength, !this.module.Requires64bits ? 4u : 8u); //optional padding to make startup stub's target address align on word or double word boundary textSectionLength += !this.module.Requires64bits ? 8u : 16u; //fixed size of runtime startup stub } @@ -1055,8 +1015,8 @@ private uint ComputeSizeOfWin32Resources() uint result = 0; if (this.win32ResourceWriter.BaseStream.Length > 0) { - result += Aligned(this.win32ResourceWriter.BaseStream.Length, 4); - } // result += Aligned(this.win32ResourceWriter.BaseStream.Length+1, 8); + result += Align(this.win32ResourceWriter.BaseStream.Length, 4); + } // result += Align(this.win32ResourceWriter.BaseStream.Length+1, 8); return result; } @@ -1326,38 +1286,40 @@ private void CreateInitialFileRefIndex() } } - private void FillInClrHeader(int ilStreamLength) + private CorHeader CreateCorHeader(MetadataSizes metadataSizes, int ilStreamLength) { - ClrHeader clrHeader = this.clrHeader; - clrHeader.CodeManagerTable.RelativeVirtualAddress = 0; - clrHeader.CodeManagerTable.Size = 0; + CorHeader corHeader = new CorHeader(); + corHeader.CodeManagerTable.RelativeVirtualAddress = 0; + corHeader.CodeManagerTable.Size = 0; IMethodReference entryPoint = this.module.EntryPoint; if (entryPoint == null || entryPoint.GetResolvedMethod(Context) == null) { - clrHeader.EntryPointToken = 0; + corHeader.EntryPointToken = 0; } else { - clrHeader.EntryPointToken = this.GetMethodToken(entryPoint); + corHeader.EntryPointToken = this.GetMethodToken(entryPoint); } - clrHeader.ExportAddressTableJumps.RelativeVirtualAddress = 0; - clrHeader.ExportAddressTableJumps.Size = 0; - clrHeader.Flags = this.GetClrHeaderFlags(); - clrHeader.MajorRuntimeVersion = 2; - clrHeader.MetaData.RelativeVirtualAddress = this.textSection.RelativeVirtualAddress + this.ComputeOffsetToMetadata(ilStreamLength); - clrHeader.MetaData.Size = this.ComputeSizeOfMetadata(); - clrHeader.MinorRuntimeVersion = 5; - clrHeader.Resources.RelativeVirtualAddress = clrHeader.MetaData.RelativeVirtualAddress + clrHeader.MetaData.Size; - clrHeader.Resources.Size = Aligned(this.resourceWriter.BaseStream.Length, 4); - clrHeader.StrongNameSignature.RelativeVirtualAddress = clrHeader.Resources.RelativeVirtualAddress + clrHeader.Resources.Size; - clrHeader.StrongNameSignature.Size = this.ComputeStrongNameSignatureSize(); - clrHeader.VTableFixups.RelativeVirtualAddress = 0; - clrHeader.VTableFixups.Size = 0; + corHeader.ExportAddressTableJumps.RelativeVirtualAddress = 0; + corHeader.ExportAddressTableJumps.Size = 0; + corHeader.Flags = this.GetCorHeaderFlags(); + corHeader.MajorRuntimeVersion = 2; + corHeader.MetadataDirectory.RelativeVirtualAddress = this.textSection.RelativeVirtualAddress + this.ComputeOffsetToMetadata(ilStreamLength); + corHeader.MetadataDirectory.Size = (uint)metadataSizes.MetadataSize; + corHeader.MinorRuntimeVersion = 5; + corHeader.Resources.RelativeVirtualAddress = corHeader.MetadataDirectory.RelativeVirtualAddress + corHeader.MetadataDirectory.Size; + corHeader.Resources.Size = Align(this.resourceWriter.BaseStream.Length, 4); + corHeader.StrongNameSignature.RelativeVirtualAddress = corHeader.Resources.RelativeVirtualAddress + corHeader.Resources.Size; + corHeader.StrongNameSignature.Size = this.ComputeStrongNameSignatureSize(); + corHeader.VTableFixups.RelativeVirtualAddress = 0; + corHeader.VTableFixups.Size = 0; + + return corHeader; } - private void FillInNtHeader(int ilStreamLength, int mappedFieldDataStreamRva) + private void FillInNtHeader(MetadataSizes metadataSizes, int ilStreamLength, int mappedFieldDataStreamRva) { bool use32bitAddresses = !this.module.Requires64bits; NtHeader ntHeader = this.ntHeader; @@ -1367,8 +1329,8 @@ private void FillInNtHeader(int ilStreamLength, int mappedFieldDataStreamRva) ntHeader.PointerToSymbolTable = 0; ntHeader.SizeOfCode = this.textSection.SizeOfRawData; ntHeader.SizeOfInitializedData = this.rdataSection.SizeOfRawData + this.coverSection.SizeOfRawData + this.sdataSection.SizeOfRawData + this.tlsSection.SizeOfRawData + this.resourceSection.SizeOfRawData + this.relocSection.SizeOfRawData; - ntHeader.SizeOfHeaders = Aligned(this.ComputeSizeOfPeHeaders(), this.module.FileAlignment); - ntHeader.SizeOfImage = Aligned(this.relocSection.RelativeVirtualAddress + this.relocSection.VirtualSize, 0x2000); + ntHeader.SizeOfHeaders = Align(this.ComputeSizeOfPeHeaders(), this.module.FileAlignment); + ntHeader.SizeOfImage = Align(this.relocSection.RelativeVirtualAddress + this.relocSection.VirtualSize, 0x2000); ntHeader.SizeOfUninitializedData = 0; // In the PE File Header this is a "Time/Date Stamp" whose description is "Time and date @@ -1382,7 +1344,7 @@ private void FillInNtHeader(int ilStreamLength, int mappedFieldDataStreamRva) ntHeader.CliHeaderTable.RelativeVirtualAddress = this.textSection.RelativeVirtualAddress + ntHeader.ImportAddressTable.Size; ntHeader.CliHeaderTable.Size = 72; - ntHeader.ImportTable.RelativeVirtualAddress = this.textSection.RelativeVirtualAddress + this.ComputeOffsetToImportTable(ilStreamLength); + ntHeader.ImportTable.RelativeVirtualAddress = this.textSection.RelativeVirtualAddress + this.ComputeOffsetToImportTable(metadataSizes, ilStreamLength); if (!this.emitRuntimeStartupStub) { @@ -1403,7 +1365,7 @@ private void FillInNtHeader(int ilStreamLength, int mappedFieldDataStreamRva) ntHeader.CertificateTable.Size = 0; ntHeader.CopyrightTable.RelativeVirtualAddress = 0; ntHeader.CopyrightTable.Size = 0; - ntHeader.DebugTable.RelativeVirtualAddress = this.pdbWriter == null ? 0u : this.textSection.RelativeVirtualAddress + this.ComputeOffsetToDebugTable(ilStreamLength); + ntHeader.DebugTable.RelativeVirtualAddress = this.pdbWriter == null ? 0u : this.textSection.RelativeVirtualAddress + this.ComputeOffsetToDebugTable(metadataSizes, ilStreamLength); ntHeader.DebugTable.Size = this.pdbWriter == null ? 0u : 0x1c; // Only the size of the fixed part of the debug table goes here. ntHeader.DelayImportTable.RelativeVirtualAddress = 0; ntHeader.DelayImportTable.Size = 0; @@ -1423,20 +1385,20 @@ private void FillInNtHeader(int ilStreamLength, int mappedFieldDataStreamRva) ntHeader.ThreadLocalStorageTable.Size = this.tlsSection.SizeOfRawData; } - private void FillInSectionHeaders(int ilStreamLength, int mappedFieldDataLength) + private void FillInSectionHeaders(MetadataSizes metadataSizes, int ilStreamLength, int mappedFieldDataLength) { uint sizeOfPeHeaders = this.ComputeSizeOfPeHeaders(); - uint sizeOfTextSection = this.ComputeSizeOfTextSection(ilStreamLength, mappedFieldDataLength); + uint sizeOfTextSection = this.ComputeSizeOfTextSection(metadataSizes, ilStreamLength, mappedFieldDataLength); this.textSection.Characteristics = 0x60000020; // section is read + execute + code this.textSection.Name = ".text"; this.textSection.NumberOfLinenumbers = 0; this.textSection.NumberOfRelocations = 0; this.textSection.PointerToLinenumbers = 0; - this.textSection.PointerToRawData = Aligned(sizeOfPeHeaders, this.module.FileAlignment); + this.textSection.PointerToRawData = Align(sizeOfPeHeaders, this.module.FileAlignment); this.textSection.PointerToRelocations = 0; - this.textSection.RelativeVirtualAddress = Aligned(sizeOfPeHeaders, 0x2000); - this.textSection.SizeOfRawData = Aligned(sizeOfTextSection, this.module.FileAlignment); + this.textSection.RelativeVirtualAddress = Align(sizeOfPeHeaders, 0x2000); + this.textSection.SizeOfRawData = Align(sizeOfTextSection, this.module.FileAlignment); this.textSection.VirtualSize = sizeOfTextSection; this.rdataSection.Characteristics = 0x40000040; // section is read + initialized @@ -1446,8 +1408,8 @@ private void FillInSectionHeaders(int ilStreamLength, int mappedFieldDataLength) this.rdataSection.PointerToLinenumbers = 0; this.rdataSection.PointerToRawData = this.textSection.PointerToRawData + this.textSection.SizeOfRawData; this.rdataSection.PointerToRelocations = 0; - this.rdataSection.RelativeVirtualAddress = Aligned(this.textSection.RelativeVirtualAddress + this.textSection.VirtualSize, 0x2000); - this.rdataSection.SizeOfRawData = Aligned(this.rdataWriter.BaseStream.Length, this.module.FileAlignment); + this.rdataSection.RelativeVirtualAddress = Align(this.textSection.RelativeVirtualAddress + this.textSection.VirtualSize, 0x2000); + this.rdataSection.SizeOfRawData = Align(this.rdataWriter.BaseStream.Length, this.module.FileAlignment); this.rdataSection.VirtualSize = this.rdataWriter.BaseStream.Length; this.sdataSection.Characteristics = 0xC0000040; // section is write + read + initialized @@ -1457,8 +1419,8 @@ private void FillInSectionHeaders(int ilStreamLength, int mappedFieldDataLength) this.sdataSection.PointerToLinenumbers = 0; this.sdataSection.PointerToRawData = this.rdataSection.PointerToRawData + this.rdataSection.SizeOfRawData; this.sdataSection.PointerToRelocations = 0; - this.sdataSection.RelativeVirtualAddress = Aligned(this.rdataSection.RelativeVirtualAddress + this.rdataSection.VirtualSize, 0x2000); - this.sdataSection.SizeOfRawData = Aligned(this.sdataWriter.BaseStream.Length, this.module.FileAlignment); + this.sdataSection.RelativeVirtualAddress = Align(this.rdataSection.RelativeVirtualAddress + this.rdataSection.VirtualSize, 0x2000); + this.sdataSection.SizeOfRawData = Align(this.sdataWriter.BaseStream.Length, this.module.FileAlignment); this.sdataSection.VirtualSize = this.sdataWriter.BaseStream.Length; this.coverSection.Characteristics = 0xC8000040; // section is not paged + write + read + initialized @@ -1468,8 +1430,8 @@ private void FillInSectionHeaders(int ilStreamLength, int mappedFieldDataLength) this.coverSection.PointerToLinenumbers = 0; this.coverSection.PointerToRawData = this.sdataSection.PointerToRawData + this.sdataSection.SizeOfRawData; this.coverSection.PointerToRelocations = 0; - this.coverSection.RelativeVirtualAddress = Aligned(this.sdataSection.RelativeVirtualAddress + this.sdataSection.VirtualSize, 0x2000); - this.coverSection.SizeOfRawData = Aligned(this.coverageDataWriter.BaseStream.Length, this.module.FileAlignment); + this.coverSection.RelativeVirtualAddress = Align(this.sdataSection.RelativeVirtualAddress + this.sdataSection.VirtualSize, 0x2000); + this.coverSection.SizeOfRawData = Align(this.coverageDataWriter.BaseStream.Length, this.module.FileAlignment); this.coverSection.VirtualSize = this.coverageDataWriter.BaseStream.Length; this.tlsSection.Characteristics = 0xC0000040; // section is write + read + initialized @@ -1479,8 +1441,8 @@ private void FillInSectionHeaders(int ilStreamLength, int mappedFieldDataLength) this.tlsSection.PointerToLinenumbers = 0; this.tlsSection.PointerToRawData = this.coverSection.PointerToRawData + this.coverSection.SizeOfRawData; this.tlsSection.PointerToRelocations = 0; - this.tlsSection.RelativeVirtualAddress = Aligned(this.coverSection.RelativeVirtualAddress + this.coverSection.VirtualSize, 0x2000); - this.tlsSection.SizeOfRawData = Aligned(this.tlsDataWriter.BaseStream.Length, this.module.FileAlignment); + this.tlsSection.RelativeVirtualAddress = Align(this.coverSection.RelativeVirtualAddress + this.coverSection.VirtualSize, 0x2000); + this.tlsSection.SizeOfRawData = Align(this.tlsDataWriter.BaseStream.Length, this.module.FileAlignment); this.tlsSection.VirtualSize = this.tlsDataWriter.BaseStream.Length; this.resourceSection.Characteristics = 0x40000040; // section is read + initialized @@ -1490,9 +1452,9 @@ private void FillInSectionHeaders(int ilStreamLength, int mappedFieldDataLength) this.resourceSection.PointerToLinenumbers = 0; this.resourceSection.PointerToRawData = this.tlsSection.PointerToRawData + this.tlsSection.SizeOfRawData; this.resourceSection.PointerToRelocations = 0; - this.resourceSection.RelativeVirtualAddress = Aligned(this.tlsSection.RelativeVirtualAddress + this.tlsSection.VirtualSize, 0x2000); + this.resourceSection.RelativeVirtualAddress = Align(this.tlsSection.RelativeVirtualAddress + this.tlsSection.VirtualSize, 0x2000); uint sizeOfWin32Resources = this.ComputeSizeOfWin32Resources(); - this.resourceSection.SizeOfRawData = Aligned(sizeOfWin32Resources, this.module.FileAlignment); + this.resourceSection.SizeOfRawData = Align(sizeOfWin32Resources, this.module.FileAlignment); this.resourceSection.VirtualSize = sizeOfWin32Resources; this.relocSection.Characteristics = 0x42000040; // section is read + discardable + initialized @@ -1502,7 +1464,7 @@ private void FillInSectionHeaders(int ilStreamLength, int mappedFieldDataLength) this.relocSection.PointerToLinenumbers = 0; this.relocSection.PointerToRawData = this.resourceSection.PointerToRawData + this.resourceSection.SizeOfRawData; this.relocSection.PointerToRelocations = 0; - this.relocSection.RelativeVirtualAddress = Aligned(this.resourceSection.RelativeVirtualAddress + this.resourceSection.VirtualSize, 0x2000); + this.relocSection.RelativeVirtualAddress = Align(this.resourceSection.RelativeVirtualAddress + this.resourceSection.VirtualSize, 0x2000); if (!this.emitRuntimeStartupStub) { @@ -1631,25 +1593,32 @@ private uint GetBlobIndex(string str) return this.GetBlobIndex(byteArray); } - private uint GetClrHeaderFlags() + private CorFlags GetCorHeaderFlags() { - uint result = 0; + CorFlags result = 0; if (this.module.ILOnly) - result |= 1; + { + result |= CorFlags.ILOnly; + } if (this.module.Requires32bits) - result |= 2; + { + result |= CorFlags.Requires32Bit; + } if (this.module.StrongNameSigned) - result |= 8; + { + result |= CorFlags.StrongNameSigned; + } if (this.module.TrackDebugData) - result |= 0x10000; + { + result |= CorFlags.TrackDebugData; + } if (this.module.Prefers32bits) { - result |= 0x20000; - result |= 2; + result |= CorFlags.Requires32Bit | CorFlags.Prefers32Bit; } return result; @@ -3008,12 +2977,7 @@ private void SerializeCustomModifier(ICustomModifier customModifier, BinaryWrite writer.WriteCompressedUInt(this.GetTypeDefOrRefCodedIndex(customModifier.GetModifier(Context), true)); } - private uint MetadataHeaderSize - { - get { return (uint)(this.IsMinimalDelta ? 124 : 108); } - } - - private void SerializeMetadataHeader(BinaryWriter writer, uint tableStreamLength) + private void SerializeMetadataHeader(BinaryWriter writer, MetadataSizes metadataSizes) { uint startOffset = writer.BaseStream.Position; @@ -3041,27 +3005,27 @@ private void SerializeMetadataHeader(BinaryWriter writer, uint tableStreamLength writer.WriteUshort((ushort)(this.IsMinimalDelta ? 6 : 5)); // number of streams 32 // Stream headers - uint offsetFromStartOfMetadata = this.MetadataHeaderSize; - SerializeStreamHeader(ref offsetFromStartOfMetadata, tableStreamLength, (this.CompressMetadataStream ? "#~" : "#-"), writer); - SerializeStreamHeader(ref offsetFromStartOfMetadata, this.stringWriter.BaseStream.Length, "#Strings", writer); - SerializeStreamHeader(ref offsetFromStartOfMetadata, this.userStringWriter.BaseStream.Length, "#US", writer); - SerializeStreamHeader(ref offsetFromStartOfMetadata, this.guidWriter.BaseStream.Length, "#GUID", writer); - SerializeStreamHeader(ref offsetFromStartOfMetadata, this.blobWriter.BaseStream.Length, "#Blob", writer); + int offsetFromStartOfMetadata = metadataSizes.MetadataHeaderSize; + SerializeStreamHeader(ref offsetFromStartOfMetadata, metadataSizes.MetadataTableStreamSize, (this.CompressMetadataStream ? "#~" : "#-"), writer); + SerializeStreamHeader(ref offsetFromStartOfMetadata, metadataSizes.GetAlignedHeapSize(HeapIndex.String), "#Strings", writer); + SerializeStreamHeader(ref offsetFromStartOfMetadata, metadataSizes.GetAlignedHeapSize(HeapIndex.UserString), "#US", writer); + SerializeStreamHeader(ref offsetFromStartOfMetadata, metadataSizes.GetAlignedHeapSize(HeapIndex.Guid), "#GUID", writer); + SerializeStreamHeader(ref offsetFromStartOfMetadata, metadataSizes.GetAlignedHeapSize(HeapIndex.Blob), "#Blob", writer); if (this.IsMinimalDelta) { SerializeStreamHeader(ref offsetFromStartOfMetadata, 0, "#JTD", writer); } uint endOffset = writer.BaseStream.Position; - Debug.Assert(endOffset - startOffset == MetadataHeaderSize); + Debug.Assert(endOffset - startOffset == metadataSizes.MetadataHeaderSize); } - private static void SerializeStreamHeader(ref uint offsetFromStartOfMetadata, uint sizeOfStreamHeap, string streamName, BinaryWriter writer) + private static void SerializeStreamHeader(ref int offsetFromStartOfMetadata, int alignedStreamSize, string streamName, BinaryWriter writer) { // 4 for the first uint (offset), 4 for the second uint (padded size), length of stream name + 1 for null terminator (then padded) - uint sizeOfStreamHeader = 8 + Aligned((uint)streamName.Length + 1, 4); - writer.WriteUint(offsetFromStartOfMetadata); - writer.WriteUint(Aligned(sizeOfStreamHeap, 4)); + int sizeOfStreamHeader = 8 + Align(streamName.Length + 1, 4); + writer.WriteInt(offsetFromStartOfMetadata); + writer.WriteInt(alignedStreamSize); foreach (char ch in streamName) { writer.WriteByte((byte)ch); @@ -3073,21 +3037,18 @@ private static void SerializeStreamHeader(ref uint offsetFromStartOfMetadata, ui writer.WriteByte(0); } - offsetFromStartOfMetadata += sizeOfStreamHeap; + offsetFromStartOfMetadata += alignedStreamSize; } - private void SerializeMetadata(BinaryWriter metadataWriter, int methodBodyStreamRva, int mappedFieldDataStreamRva, bool separateMethodIL, out uint moduleVersionIdOffset) + private void SerializeMetadata(BinaryWriter metadataWriter, MetadataSizes metadataSizes, int methodBodyStreamRva, int mappedFieldDataStreamRva, bool separateMethodIL, out uint moduleVersionIdOffset) { uint metadataStartOffset = metadataWriter.BaseStream.Position; - uint metadataTablesStartOffset = metadataStartOffset + MetadataHeaderSize; // Leave space for the metadata header. We need to fill in the sizes of all tables and heaps. // It's easier to write it at the end then to precalculate the sizes. - metadataWriter.BaseStream.Position = metadataTablesStartOffset; - this.SerializeMetadataTables(metadataWriter, methodBodyStreamRva, mappedFieldDataStreamRva, separateMethodIL); - - uint metadataTablesEndOffset = metadataWriter.BaseStream.Position; - + metadataWriter.BaseStream.Position = metadataStartOffset + (uint)metadataSizes.MetadataHeaderSize; + this.SerializeMetadataTables(metadataWriter, metadataSizes, methodBodyStreamRva, mappedFieldDataStreamRva, separateMethodIL); + this.stringWriter.BaseStream.WriteTo(metadataWriter.BaseStream); this.userStringWriter.BaseStream.WriteTo(metadataWriter.BaseStream); @@ -3101,7 +3062,7 @@ private void SerializeMetadata(BinaryWriter metadataWriter, int methodBodyStream // write header at the start of the metadata stream: metadataWriter.BaseStream.Position = 0; - this.SerializeMetadataHeader(metadataWriter, tableStreamLength: metadataTablesEndOffset - metadataTablesStartOffset); + this.SerializeMetadataHeader(metadataWriter, metadataSizes); metadataWriter.BaseStream.Position = metadataSize; } @@ -3117,125 +3078,52 @@ private uint GetModuleVersionGuidOffsetInMetadataStream(uint guidHeapOffsetInMet return guidHeapOffsetInMetadataStream + moduleVersionOffsetInGuidTable; } - private void SerializeMetadataTables(BinaryWriter writer, int methodBodyStreamRva, int mappedFieldDataStreamRva, bool separateMethodIL) - { - this.SerializeTablesHeader(writer); - this.SerializeModuleTable(writer); - this.SerializeTypeRefTable(writer); - this.SerializeTypeDefTable(writer); - this.SerializeFieldTable(writer); - this.SerializeMethodTable(writer, methodBodyStreamRva, separateMethodIL); - this.SerializeParamTable(writer); - this.SerializeInterfaceImplTable(writer); - this.SerializeMemberRefTable(writer); - this.SerializeConstantTable(writer); - this.SerializeCustomAttributeTable(writer); - this.SerializeFieldMarshalTable(writer); - this.SerializeDeclSecurityTable(writer); - this.SerializeClassLayoutTable(writer); - this.SerializeFieldLayoutTable(writer); - this.SerializeStandAloneSigTable(writer); - this.SerializeEventMapTable(writer); - this.SerializeEventTable(writer); - this.SerializePropertyMapTable(writer); - this.SerializePropertyTable(writer); - this.SerializeMethodSemanticsTable(writer); - this.SerializeMethodImplTable(writer); - this.SerializeModuleRefTable(writer); - this.SerializeTypeSpecTable(writer); - this.SerializeImplMapTable(writer); - this.SerializeFieldRvaTable(writer, mappedFieldDataStreamRva); + private void SerializeMetadataTables(BinaryWriter writer, MetadataSizes metadataSizes, int methodBodyStreamRva, int mappedFieldDataStreamRva, bool separateMethodIL) + { + uint startPosition = writer.BaseStream.Position; + + this.SerializeTablesHeader(writer, metadataSizes); + this.SerializeModuleTable(writer, metadataSizes); + this.SerializeTypeRefTable(writer, metadataSizes); + this.SerializeTypeDefTable(writer, metadataSizes); + this.SerializeFieldTable(writer, metadataSizes); + this.SerializeMethodTable(writer, metadataSizes, methodBodyStreamRva, separateMethodIL); + this.SerializeParamTable(writer, metadataSizes); + this.SerializeInterfaceImplTable(writer, metadataSizes); + this.SerializeMemberRefTable(writer, metadataSizes); + this.SerializeConstantTable(writer, metadataSizes); + this.SerializeCustomAttributeTable(writer, metadataSizes); + this.SerializeFieldMarshalTable(writer, metadataSizes); + this.SerializeDeclSecurityTable(writer, metadataSizes); + this.SerializeClassLayoutTable(writer, metadataSizes); + this.SerializeFieldLayoutTable(writer, metadataSizes); + this.SerializeStandAloneSigTable(writer, metadataSizes); + this.SerializeEventMapTable(writer, metadataSizes); + this.SerializeEventTable(writer, metadataSizes); + this.SerializePropertyMapTable(writer, metadataSizes); + this.SerializePropertyTable(writer, metadataSizes); + this.SerializeMethodSemanticsTable(writer, metadataSizes); + this.SerializeMethodImplTable(writer, metadataSizes); + this.SerializeModuleRefTable(writer, metadataSizes); + this.SerializeTypeSpecTable(writer, metadataSizes); + this.SerializeImplMapTable(writer, metadataSizes); + this.SerializeFieldRvaTable(writer, metadataSizes, mappedFieldDataStreamRva); this.SerializeEncLogTable(writer); this.SerializeEncMapTable(writer); - this.SerializeAssemblyTable(writer); - this.SerializeAssemblyRefTable(writer); - this.SerializeFileTable(writer); - this.SerializeExportedTypeTable(writer); - this.SerializeManifestResourceTable(writer); - this.SerializeNestedClassTable(writer); - this.SerializeGenericParamTable(writer); - this.SerializeMethodSpecTable(writer); - this.SerializeGenericParamConstraintTable(writer); + this.SerializeAssemblyTable(writer, metadataSizes); + this.SerializeAssemblyRefTable(writer, metadataSizes); + this.SerializeFileTable(writer, metadataSizes); + this.SerializeExportedTypeTable(writer, metadataSizes); + this.SerializeManifestResourceTable(writer, metadataSizes); + this.SerializeNestedClassTable(writer, metadataSizes); + this.SerializeGenericParamTable(writer, metadataSizes); + this.SerializeMethodSpecTable(writer, metadataSizes); + this.SerializeGenericParamConstraintTable(writer, metadataSizes); writer.WriteByte(0); writer.Align(4); - } - private void ComputeColumnSizes() - { - const byte large = 4; - const byte small = 2; - - // TODO (tomat): reuse values from metadata reader? - - this.blobIndexSize = (IsMinimalDelta || this.blobWriter.BaseStream.Length > ushort.MaxValue) ? large : small; - this.stringIndexSize = (IsMinimalDelta || this.stringWriter.BaseStream.Length > ushort.MaxValue) ? large : small; - this.guidIndexSize = (IsMinimalDelta || this.guidWriter.BaseStream.Length > ushort.MaxValue) ? large : small; - - this.customAttributeTypeCodedIndexSize = this.GetIndexByteSize(3, TableIndex.MethodDef, TableIndex.MemberRef); - this.declSecurityCodedIndexSize = this.GetIndexByteSize(2, TableIndex.MethodDef, TableIndex.TypeDef); - this.eventDefIndexSize = this.GetIndexByteSize(0, TableIndex.Event); - this.fieldDefIndexSize = this.GetIndexByteSize(0, TableIndex.Field); - this.genericParamIndexSize = this.GetIndexByteSize(0, TableIndex.GenericParam); - this.hasConstantCodedIndexSize = this.GetIndexByteSize(2, TableIndex.Field, TableIndex.Param, TableIndex.Property); - - this.hasCustomAttributeCodedIndexSize = this.GetIndexByteSize(5, - TableIndex.MethodDef, - TableIndex.Field, - TableIndex.TypeRef, - TableIndex.TypeDef, - TableIndex.Param, - TableIndex.InterfaceImpl, - TableIndex.MemberRef, - TableIndex.Module, - TableIndex.DeclSecurity, - TableIndex.Property, - TableIndex.Event, - TableIndex.StandAloneSig, - TableIndex.ModuleRef, - TableIndex.TypeSpec, - TableIndex.Assembly, - TableIndex.AssemblyRef, - TableIndex.File, - TableIndex.ExportedType, - TableIndex.ManifestResource, - TableIndex.GenericParam, - TableIndex.GenericParamConstraint, - TableIndex.MethodSpec); - - this.hasFieldMarshalCodedIndexSize = this.GetIndexByteSize(1, TableIndex.Field, TableIndex.Param); - this.hasSemanticsCodedIndexSize = this.GetIndexByteSize(1, TableIndex.Event, TableIndex.Property); - this.implementationCodedIndexSize = this.GetIndexByteSize(2, TableIndex.File, TableIndex.AssemblyRef, TableIndex.ExportedType); - this.memberForwardedCodedIndexSize = this.GetIndexByteSize(1, TableIndex.Field, TableIndex.MethodDef); - this.memberRefParentCodedIndexSize = this.GetIndexByteSize(3, TableIndex.TypeDef, TableIndex.TypeRef, TableIndex.ModuleRef, TableIndex.MethodDef, TableIndex.TypeSpec); - this.methodDefIndexSize = this.GetIndexByteSize(0, TableIndex.MethodDef); - this.methodDefOrRefCodedIndexSize = this.GetIndexByteSize(1, TableIndex.MethodDef, TableIndex.MemberRef); - this.moduleRefIndexSize = this.GetIndexByteSize(0, TableIndex.ModuleRef); - this.parameterIndexSize = this.GetIndexByteSize(0, TableIndex.Param); - this.propertyDefIndexSize = this.GetIndexByteSize(0, TableIndex.Property); - this.resolutionScopeCodedIndexSize = this.GetIndexByteSize(2, TableIndex.Module, TableIndex.ModuleRef, TableIndex.AssemblyRef, TableIndex.TypeRef); - this.typeDefIndexSize = this.GetIndexByteSize(0, TableIndex.TypeDef); - this.typeDefOrRefCodedIndexSize = this.GetIndexByteSize(2, TableIndex.TypeDef, TableIndex.TypeRef, TableIndex.TypeSpec); - this.typeOrMethodDefCodedIndexSize = this.GetIndexByteSize(1, TableIndex.TypeDef, TableIndex.MethodDef); - } - - private byte GetIndexByteSize(int discriminatingBits, params TableIndex[] tables) - { - const int BitsPerShort = 16; - return (byte)(IsMinimalDelta || IndexDoesNotFit(BitsPerShort - discriminatingBits, tables) ? 4 : 2); - } - - private bool IndexDoesNotFit(int numberOfBits, params TableIndex[] tables) - { - uint maxIndex = (uint)(1 << numberOfBits) - 1; - foreach (TableIndex table in tables) - { - if (this.tableSizes[(uint)table] > maxIndex) - { - return true; - } - } - - return false; + uint endPosition = writer.BaseStream.Position; + Debug.Assert(metadataSizes.MetadataTableStreamSize == endPosition - startPosition); } private void SerializeMetadataAndIL( @@ -3244,7 +3132,8 @@ private bool IndexDoesNotFit(int numberOfBits, params TableIndex[] tables) BinaryWriter mappedFieldDataWriter, bool separateMethodIL, out uint moduleVersionIdOffsetInMetadataStream, - out int mappedFieldDataStreamRva) + out int mappedFieldDataStreamRva, + out MetadataSizes metadataSizes) { uint[] methodBodyRvas = SerializeMethodBodies(ilWriter); @@ -3255,14 +3144,18 @@ private bool IndexDoesNotFit(int numberOfBits, params TableIndex[] tables) PopulateTables(methodBodyRvas, mappedFieldDataWriter); + var rowCounts = CalculateRowCounts(); + int mappedFieldDataLength = (int)mappedFieldDataWriter.BaseStream.Length; int ilStreamLength = (int)ilWriter.BaseStream.Length; // Do this as soon as table rows are done and before we need to final size of string table SerializeStringHeap(); + metadataSizes = new MetadataSizes(rowCounts, CalculateHeapSizes(), IsMinimalDelta); + // Do this here so that tables and win32 resources can contain actual RVAs without the need for fixups. - FillInSectionHeaders(ilStreamLength, mappedFieldDataLength); + FillInSectionHeaders(metadataSizes, ilStreamLength, mappedFieldDataLength); // Align heaps this.OnBeforeHeapsAligned(); @@ -3276,7 +3169,7 @@ private bool IndexDoesNotFit(int numberOfBits, params TableIndex[] tables) Debug.Assert(mappedFieldDataLength % MappedFieldDataAlignment == 0); mappedFieldDataStreamRva = (int)(this.textSection.RelativeVirtualAddress + this.textSection.VirtualSize - mappedFieldDataLength); - SerializeMetadata(metadataWriter, methodBodyStreamRva, mappedFieldDataStreamRva, separateMethodIL, moduleVersionIdOffset: out moduleVersionIdOffsetInMetadataStream); + SerializeMetadata(metadataWriter, metadataSizes, methodBodyStreamRva, mappedFieldDataStreamRva, separateMethodIL, moduleVersionIdOffset: out moduleVersionIdOffsetInMetadataStream); } private void PopulateTables(uint[] methodBodyRvas, BinaryWriter mappedFieldDataWriter) @@ -3310,7 +3203,6 @@ private void PopulateTables(uint[] methodBodyRvas, BinaryWriter mappedFieldDataW this.PopulateParamTableRows(); this.PopulatePropertyMapTableRows(); this.PopulatePropertyTableRows(); - this.PopulateStandAloneSigTableRows(); this.PopulateTypeDefTableRows(); this.PopulateTypeRefTableRows(); this.PopulateTypeSpecTableRows(); @@ -3318,8 +3210,11 @@ private void PopulateTables(uint[] methodBodyRvas, BinaryWriter mappedFieldDataW // This table is populated after the others because it depends on the order of the entries of the generic parameter table. this.PopulateCustomAttributeTableRows(); - this.PopulateEncLogTableRows(); - this.PopulateEncMapRows(); + ImmutableArray rowCounts = CalculateRowCounts(); + Debug.Assert(rowCounts[(int)TableIndex.EncLog] == 0 && rowCounts[(int)TableIndex.EncMap] == 0); + + this.PopulateEncLogTableRows(this.encLogTable, rowCounts); + this.PopulateEncMapTableRows(this.encMapTable, rowCounts); } private struct AssemblyRefTableRow @@ -3358,8 +3253,6 @@ private void PopulateAssemblyRefTableRows() r.ContentType = assemblyRef.ContentType; this.assemblyRefTable.Add(r); } - - this.tableSizes[(uint)TableIndex.AssemblyRef] = (uint)this.assemblyRefTable.Count; } private static readonly Version NullVersion = new Version(0, 0, 0, 0); @@ -3414,7 +3307,6 @@ private void PopulateAssemblyTableRows() this.assemblyKey = (IteratorHelper.EnumerableIsNotEmpty(assembly.PublicKey)) ? this.GetBlobIndex(new List(assembly.PublicKey).ToArray()) : 0; this.assemblyName = this.GetStringIndexForPathAndCheckLength(assembly.Name, assembly); this.assemblyCulture = (assembly.Culture != null) ? this.GetStringIndex(assembly.Culture) : StringIdx.Empty; - this.tableSizes[(uint)TableIndex.Assembly] = 1; } private uint assemblyKey; @@ -3437,8 +3329,6 @@ private void PopulateClassLayoutTableRows() r.Parent = typeDefIndex; this.classLayoutTable.Add(r); } - - this.tableSizes[(uint)TableIndex.ClassLayout] = (uint)this.classLayoutTable.Count; } private struct ClassLayoutRow { public ushort PackingSize; public uint ClassSize; public uint Parent; } @@ -3487,8 +3377,6 @@ private void PopulateConstantTableRows() { this.constantTable.Sort(new ConstantRowComparer()); } - - this.tableSizes[(uint)TableIndex.Constant] = (uint)this.constantTable.Count; } private class ConstantRowComparer : Comparer @@ -3563,7 +3451,6 @@ private void PopulateCustomAttributeTableRows() this.AddCustomAttributesToTable(sortedGenericParameterList, 19, this.GetGenericParameterIndex); this.customAttributeTable.Sort(new CustomAttributeRowComparer()); - this.tableSizes[(uint)TableIndex.CustomAttribute] = (uint)this.customAttributeTable.Count; } private void AddAssemblyAttributesToTable() @@ -3621,7 +3508,6 @@ private uint GetDummyAssemblyAttributeParent(bool isSecurity, bool allowMultiple r.Name = this.GetStringIndex(dummyAssemblyAttributeParentName + dummyAssemblyAttributeParentQualifier[iS, iM]); r.Namespace = this.GetStringIndex(dummyAssemblyAttributeParentNamespace); this.typeRefTable.Add(r); - this.tableSizes[(uint)TableIndex.TypeRef] = (uint)this.typeRefTable.Count; dummyAssemblyAttributeParent[iS, iM] = ((uint)this.typeRefTable.Count << 5) | 2; } return dummyAssemblyAttributeParent[iS, iM]; @@ -3726,7 +3612,6 @@ private void PopulateDeclSecurityTableRows() } this.declSecurityTable.Sort(new DeclSecurityRowComparer()); - this.tableSizes[(uint)TableIndex.DeclSecurity] = (uint)this.declSecurityTable.Count; } private void PopulateDeclSecurityTableRowsFor(uint parent, IEnumerable attributes) @@ -3776,22 +3661,10 @@ private struct DeclSecurityRow { public ushort Action; public uint Parent; publi private readonly List declSecurityTable = new List(); - private void PopulateEncLogTableRows() - { - this.PopulateEncLogTableRows(this.encLogTable); - this.tableSizes[(uint)TableIndex.EncLog] = (uint)this.encLogTable.Count; - } - protected struct EncLogRow { public uint Token; public EncFuncCode FuncCode; } private readonly List encLogTable = new List(); - - private void PopulateEncMapRows() - { - this.PopulateEncMapTableRows(this.encMapTable); - this.tableSizes[(uint)TableIndex.EncMap] = (uint)this.encMapTable.Count; - } - + protected struct EncMapRow { public uint Token; } private readonly List encMapTable = new List(); @@ -3799,7 +3672,6 @@ protected struct EncMapRow { public uint Token; } private void PopulateEventMapTableRows() { this.PopulateEventMapTableRows(this.eventMapTable); - this.tableSizes[(uint)TableIndex.EventMap] = (uint)this.eventMapTable.Count; } protected struct EventMapRow { public uint Parent; public uint EventList; } @@ -3819,8 +3691,6 @@ private void PopulateEventTableRows() r.EventType = this.GetTypeDefOrRefCodedIndex(eventDef.GetType(Context), true); this.eventTable.Add(r); } - - this.tableSizes[(uint)TableIndex.Event] = (uint)this.eventTable.Count; } private struct EventRow { public ushort EventFlags; public StringIdx Name; public uint EventType; } @@ -3891,8 +3761,6 @@ private void PopulateExportedTypeTableRows() this.exportedTypeTable.Add(r); } } - - this.tableSizes[(uint)TableIndex.ExportedType] = (uint)this.exportedTypeTable.Count; } private struct ExportedTypeRow { public TypeFlags Flags; public uint TypeDefId; public StringIdx TypeName; public StringIdx TypeNamespace; public uint Implementation; } @@ -3914,8 +3782,6 @@ private void PopulateFieldLayoutTableRows() r.Field = fieldDefIndex; this.fieldLayoutTable.Add(r); } - - this.tableSizes[(uint)TableIndex.FieldLayout] = (uint)this.fieldLayoutTable.Count; } private struct FieldLayoutRow { public uint Offset; public uint Field; } @@ -3979,8 +3845,6 @@ private void PopulateFieldMarshalTableRows() { this.fieldMarshalTable.Sort(new FieldMarshalRowComparer()); } - - this.tableSizes[(uint)TableIndex.FieldMarshal] = (uint)this.fieldMarshalTable.Count; } private class FieldMarshalRowComparer : Comparer @@ -4014,8 +3878,6 @@ private void PopulateFieldRvaTableRows(BinaryWriter mappedFieldDataWriter) r.Field = fieldIndex; this.fieldRvaTable.Add(r); } - - this.tableSizes[(uint)TableIndex.FieldRva] = (uint)this.fieldRvaTable.Count; } private struct FieldRvaRow { public uint Offset; public uint Field; } @@ -4041,8 +3903,6 @@ private void PopulateFieldTableRows() r.Signature = this.GetFieldSignatureIndex(fieldDef); this.fieldDefTable.Add(r); } - - this.tableSizes[(uint)TableIndex.Field] = (uint)this.fieldDefTable.Count; } private struct FieldDefRow { public ushort Flags; public StringIdx Name; public uint Signature; } @@ -4068,8 +3928,6 @@ private void PopulateFileTableRows() r.HashValue = this.GetBlobIndex(fileReference.GetHashValue(hashAlgorithm).ToArray()); this.fileTable.Add(r); } - - this.tableSizes[(uint)TableIndex.File] = (uint)this.fileTable.Count; } private struct FileTableRow { public uint Flags; public StringIdx FileName; public uint HashValue; } @@ -4090,8 +3948,6 @@ private void PopulateGenericParamConstraintTableRows() this.genericParamConstraintTable.Add(r); } } - - this.tableSizes[(uint)TableIndex.GenericParamConstraint] = (uint)this.genericParamConstraintTable.Count; } private struct GenericParamConstraintRow { public uint Owner; public uint Constraint; } @@ -4120,7 +3976,6 @@ private void PopulateGenericParamTableRows() } this.genericParamTable.Sort(new GenericParamRowComparer()); - this.tableSizes[(uint)TableIndex.GenericParam] = (uint)this.genericParamTable.Count; } private class GenericParamRowComparer : Comparer @@ -4169,8 +4024,6 @@ private void PopulateImplMapTableRows() r.ImportScope = this.GetModuleRefIndex(data.ModuleName); this.implMapTable.Add(r); } - - this.tableSizes[(uint)TableIndex.ImplMap] = (uint)this.implMapTable.Count; } private struct ImplMapRow { public ushort MappingFlags; public uint MemberForwarded; public StringIdx ImportName; public uint ImportScope; } @@ -4190,8 +4043,6 @@ private void PopulateInterfaceImplTableRows() this.interfaceImplTable.Add(r); } } - - this.tableSizes[(uint)TableIndex.InterfaceImpl] = (uint)this.interfaceImplTable.Count; } private struct InterfaceImplRow { public uint Class; public uint Interface; } @@ -4221,8 +4072,6 @@ private void PopulateManifestResourceTableRows() this.manifestResourceTable.Add(r); } - - this.tableSizes[(uint)TableIndex.ManifestResource] = (uint)this.manifestResourceTable.Count; } private struct ManifestResourceRow { public uint Offset; public uint Flags; public StringIdx Name; public uint Implementation; } @@ -4242,8 +4091,6 @@ private void PopulateMemberRefTableRows() r.Signature = this.GetMemberRefSignatureIndex(memberRef); this.memberRefTable.Add(r); } - - this.tableSizes[(uint)TableIndex.MemberRef] = (uint)this.memberRefTable.Count; } private struct MemberRefRow { public uint Class; public StringIdx Name; public uint Signature; } @@ -4262,8 +4109,6 @@ private void PopulateMethodImplTableRows() r.MethodDecl = this.GetMethodDefOrRefCodedIndex(methodImplementation.ImplementedMethod); this.methodImplTable.Add(r); } - - this.tableSizes[(uint)TableIndex.MethodImpl] = (uint)this.methodImplTable.Count; } private struct MethodImplRow { public uint Class; public uint MethodBody; public uint MethodDecl; } @@ -4337,8 +4182,6 @@ private void PopulateMethodSemanticsTableRows() { this.methodSemanticsTable.Sort(new MethodSemanticsRowComparer()); } - - this.tableSizes[(uint)TableIndex.MethodSemantics] = (uint)this.methodSemanticsTable.Count; } private class MethodSemanticsRowComparer : Comparer @@ -4371,8 +4214,6 @@ private void PopulateMethodSpecTableRows() r.Instantiation = this.GetGenericMethodInstanceIndex(genericMethodInstanceReference); this.methodSpecTable.Add(r); } - - this.tableSizes[(uint)TableIndex.MethodSpec] = (uint)this.methodSpecTable.Count; } private struct MethodSpecRow { public uint Method; public uint Instantiation; } @@ -4399,8 +4240,6 @@ private void PopulateMethodTableRows(uint[] methodBodyRvas) i++; } - - this.tableSizes[(uint)TableIndex.MethodDef] = (uint)this.methodTable.Length; } private struct MethodRow { public uint Rva; public ushort ImplFlags; public ushort Flags; public StringIdx Name; public uint Signature; public uint ParamList; } @@ -4418,8 +4257,6 @@ private void PopulateModuleRefTableRows() r.Name = this.GetStringIndexForPathAndCheckLength(moduleName); this.moduleRefTable.Add(r); } - - this.tableSizes[(uint)TableIndex.ModuleRef] = (uint)this.moduleRefTable.Count; } private struct ModuleRefRow { public StringIdx Name; } @@ -4435,7 +4272,6 @@ private void PopulateModuleTableRows() r.EncId = this.GetGuidIndex(this.EncId); r.EncBaseId = this.GetGuidIndex(this.EncBaseId); this.moduleRow = r; - this.tableSizes[(uint)TableIndex.Module] = 1; } private struct ModuleRow { public ushort Generation; public StringIdx Name; public uint ModuleVersionId; public uint EncId; public uint EncBaseId; } @@ -4458,8 +4294,6 @@ private void PopulateNestedClassTableRows() r.EnclosingClass = this.GetTypeDefIndex(nestedTypeDef.ContainingTypeDefinition); this.nestedClassTable.Add(r); } - - this.tableSizes[(uint)TableIndex.NestedClass] = (uint)this.nestedClassTable.Count; } private struct NestedClassRow { public uint NestedClass; public uint EnclosingClass; } @@ -4479,8 +4313,6 @@ private void PopulateParamTableRows() r.Name = this.GetStringIndexForNameAndCheckLength(parDef.Name, parDef); this.paramTable.Add(r); } - - this.tableSizes[(uint)TableIndex.Param] = (uint)this.paramTable.Count; } private struct ParamRow { public ushort Flags; public ushort Sequence; public StringIdx Name; } @@ -4490,7 +4322,6 @@ private struct ParamRow { public ushort Flags; public ushort Sequence; public St private void PopulatePropertyMapTableRows() { this.PopulatePropertyMapTableRows(this.propertyMapTable); - this.tableSizes[(uint)TableIndex.PropertyMap] = (uint)this.propertyMapTable.Count; } protected struct PropertyMapRow { public uint Parent; public uint PropertyList; } @@ -4510,19 +4341,12 @@ private void PopulatePropertyTableRows() r.Type = this.GetPropertySignatureIndex(propertyDef); this.propertyTable.Add(r); } - - this.tableSizes[(uint)TableIndex.Property] = (uint)this.propertyTable.Count; } private struct PropertyRow { public ushort PropFlags; public StringIdx Name; public uint Type; } private readonly List propertyTable = new List(); - private void PopulateStandAloneSigTableRows() - { - this.tableSizes[(uint)TableIndex.StandAloneSig] = (uint)this.GetStandAloneSignatures().Count; - } - private void PopulateTypeDefTableRows() { var typeDefs = this.GetTypeDefs(); @@ -4546,8 +4370,6 @@ private void PopulateTypeDefTableRows() this.typeDefTable.Add(r); } - - this.tableSizes[(uint)TableIndex.TypeDef] = (uint)this.typeDefTable.Count; } private struct TypeDefRow { public uint Flags; public StringIdx Name; public StringIdx Namespace; public uint Extends; public uint FieldList; public uint MethodList; } @@ -4594,8 +4416,6 @@ private void PopulateTypeRefTableRows() this.typeRefTable.Add(r); } - - this.tableSizes[(uint)TableIndex.TypeRef] = (uint)this.typeRefTable.Count; } private struct TypeRefRow { public uint ResolutionScope; public StringIdx Name; public StringIdx Namespace; } @@ -4613,28 +4433,28 @@ private void PopulateTypeSpecTableRows() r.Signature = this.GetTypeSpecSignatureIndex(typeSpec); this.typeSpecTable.Add(r); } - - this.tableSizes[(uint)TableIndex.TypeSpec] = (uint)this.typeSpecTable.Count; } private struct TypeSpecRow { public uint Signature; } private readonly List typeSpecTable = new List(); - private void SerializeTablesHeader(BinaryWriter writer) + private void SerializeTablesHeader(BinaryWriter writer, MetadataSizes metadataSizes) { + uint startPosition = writer.BaseStream.Position; + HeapSizeFlag heapSizes = 0; - if (this.stringIndexSize > 2) + if (metadataSizes.StringIndexSize > 2) { heapSizes |= HeapSizeFlag.StringHeapLarge; } - if (this.guidIndexSize > 2) + if (metadataSizes.GuidIndexSize > 2) { heapSizes |= HeapSizeFlag.GuidHeapLarge; } - if (this.blobIndexSize > 2) + if (metadataSizes.BlobIndexSize > 2) { heapSizes |= HeapSizeFlag.BlobHeapLarge; } @@ -4646,7 +4466,7 @@ private void SerializeTablesHeader(BinaryWriter writer) ulong validTables = 0; ulong sortedTables = 0; - this.ComputeValidAndSortedMasks(out validTables, out sortedTables); + ComputeValidAndSortedMasks(metadataSizes, out validTables, out sortedTables); writer.WriteUint(0); // reserved writer.WriteByte(this.module.MetadataFormatMajorVersion); @@ -4655,39 +4475,20 @@ private void SerializeTablesHeader(BinaryWriter writer) writer.WriteByte(1); // reserved writer.WriteUlong(validTables); writer.WriteUlong(sortedTables); - this.SerializeTableSizes(writer); - } + SerializeRowCounts(writer, metadataSizes); - internal void GetTableSizes(int[] sizes) - { - for (int i = 0; i < this.tableSizes.Length; i++) - { - sizes[i] = (int)this.tableSizes[i]; - } - } - - private uint ComputeSizeOfTablesHeader() - { - uint result = 4 + 4 + 8 + 8; - foreach (uint tableSize in this.tableSizes) - { - if (tableSize > 0) - { - result += 4; - } - } - - return result; + uint endPosition = writer.BaseStream.Position; + Debug.Assert(metadataSizes.CalculateTableStreamHeaderSize() == endPosition - startPosition); } - private void ComputeValidAndSortedMasks(out ulong validTables, out ulong sortedTables) + private static void ComputeValidAndSortedMasks(MetadataSizes metadataSizes, out ulong validTables, out ulong sortedTables) { validTables = 0; ulong validBit = 1; - foreach (uint tableSize in this.tableSizes) + foreach (int rowCount in metadataSizes.RowCounts) { - if (tableSize > 0) + if (rowCount > 0) { validTables |= validBit; } @@ -4698,13 +4499,13 @@ private void ComputeValidAndSortedMasks(out ulong validTables, out ulong sortedT sortedTables = 0x16003301fa00/* & validTables*/; } - private void SerializeTableSizes(BinaryWriter writer) + private static void SerializeRowCounts(BinaryWriter writer, MetadataSizes tableSizes) { - foreach (uint tableSize in this.tableSizes) + foreach (int rowCount in tableSizes.RowCounts) { - if (tableSize > 0) + if (rowCount > 0) { - writer.WriteUint(tableSize); + writer.WriteInt(rowCount); } } } @@ -4782,13 +4583,13 @@ private static void SerializeMetadataConstantValue(object value, BinaryWriter wr } } - private void SerializeModuleTable(BinaryWriter writer) + private void SerializeModuleTable(BinaryWriter writer, MetadataSizes metadataSizes) { - writer.WriteUshort(this.moduleRow.Generation); // generation (Edit & Continue) - SerializeIndex(writer, this.moduleRow.Name, this.stringIndexSize); - SerializeIndex(writer, this.moduleRow.ModuleVersionId, this.guidIndexSize); // module version id GUID index - SerializeIndex(writer, this.moduleRow.EncId, this.guidIndexSize); // Edit & Continue Id GUID - SerializeIndex(writer, this.moduleRow.EncBaseId, this.guidIndexSize); // Edit & Continue Base Id GUID + writer.WriteUshort(this.moduleRow.Generation); + SerializeIndex(writer, this.moduleRow.Name, metadataSizes.StringIndexSize); + SerializeIndex(writer, this.moduleRow.ModuleVersionId, metadataSizes.GuidIndexSize); + SerializeIndex(writer, this.moduleRow.EncId, metadataSizes.GuidIndexSize); + SerializeIndex(writer, this.moduleRow.EncBaseId, metadataSizes.GuidIndexSize); } private void SerializeEncLogTable(BinaryWriter writer) @@ -4808,36 +4609,36 @@ private void SerializeEncMapTable(BinaryWriter writer) } } - private void SerializeTypeRefTable(BinaryWriter writer) + private void SerializeTypeRefTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (TypeRefRow typeRef in this.typeRefTable) { - SerializeIndex(writer, typeRef.ResolutionScope, this.resolutionScopeCodedIndexSize); - this.SerializeIndex(writer, typeRef.Name, this.stringIndexSize); - this.SerializeIndex(writer, typeRef.Namespace, this.stringIndexSize); + SerializeIndex(writer, typeRef.ResolutionScope, metadataSizes.ResolutionScopeCodedIndexSize); + this.SerializeIndex(writer, typeRef.Name, metadataSizes.StringIndexSize); + this.SerializeIndex(writer, typeRef.Namespace, metadataSizes.StringIndexSize); } } - private void SerializeTypeDefTable(BinaryWriter writer) + private void SerializeTypeDefTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (TypeDefRow typeDef in this.typeDefTable) { writer.WriteUint(typeDef.Flags); - this.SerializeIndex(writer, typeDef.Name, this.stringIndexSize); - this.SerializeIndex(writer, typeDef.Namespace, this.stringIndexSize); - SerializeIndex(writer, typeDef.Extends, this.typeDefOrRefCodedIndexSize); - SerializeIndex(writer, typeDef.FieldList, this.fieldDefIndexSize); - SerializeIndex(writer, typeDef.MethodList, this.methodDefIndexSize); + this.SerializeIndex(writer, typeDef.Name, metadataSizes.StringIndexSize); + this.SerializeIndex(writer, typeDef.Namespace, metadataSizes.StringIndexSize); + SerializeIndex(writer, typeDef.Extends, metadataSizes.TypeDefOrRefCodedIndexSize); + SerializeIndex(writer, typeDef.FieldList, metadataSizes.FieldDefIndexSize); + SerializeIndex(writer, typeDef.MethodList, metadataSizes.MethodDefIndexSize); } } - private void SerializeFieldTable(BinaryWriter writer) + private void SerializeFieldTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (FieldDefRow fieldDef in this.fieldDefTable) { writer.WriteUshort(fieldDef.Flags); - this.SerializeIndex(writer, fieldDef.Name, this.stringIndexSize); - SerializeIndex(writer, fieldDef.Signature, this.blobIndexSize); + this.SerializeIndex(writer, fieldDef.Name, metadataSizes.StringIndexSize); + SerializeIndex(writer, fieldDef.Signature, metadataSizes.BlobIndexSize); } } @@ -4859,7 +4660,7 @@ private static void SerializeIndex(BinaryWriter writer, uint index, byte indexSi } } - private void SerializeMethodTable(BinaryWriter writer, int methodBodyStreamRva, bool separateMethodIL) + private void SerializeMethodTable(BinaryWriter writer, MetadataSizes metadataSizes, int methodBodyStreamRva, bool separateMethodIL) { foreach (MethodRow method in this.methodTable) { @@ -4880,203 +4681,203 @@ private void SerializeMethodTable(BinaryWriter writer, int methodBodyStreamRva, writer.WriteUshort(method.ImplFlags); writer.WriteUshort(method.Flags); - this.SerializeIndex(writer, method.Name, this.stringIndexSize); - SerializeIndex(writer, method.Signature, this.blobIndexSize); - SerializeIndex(writer, method.ParamList, this.parameterIndexSize); + this.SerializeIndex(writer, method.Name, metadataSizes.StringIndexSize); + SerializeIndex(writer, method.Signature, metadataSizes.BlobIndexSize); + SerializeIndex(writer, method.ParamList, metadataSizes.ParameterIndexSize); } } - private void SerializeParamTable(BinaryWriter writer) + private void SerializeParamTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (ParamRow param in this.paramTable) { writer.WriteUshort(param.Flags); writer.WriteUshort(param.Sequence); - this.SerializeIndex(writer, param.Name, this.stringIndexSize); + this.SerializeIndex(writer, param.Name, metadataSizes.StringIndexSize); } } - private void SerializeInterfaceImplTable(BinaryWriter writer) + private void SerializeInterfaceImplTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (InterfaceImplRow interfaceImpl in this.interfaceImplTable) { - SerializeIndex(writer, interfaceImpl.Class, this.typeDefIndexSize); - SerializeIndex(writer, interfaceImpl.Interface, this.typeDefOrRefCodedIndexSize); + SerializeIndex(writer, interfaceImpl.Class, metadataSizes.TypeDefIndexSize); + SerializeIndex(writer, interfaceImpl.Interface, metadataSizes.TypeDefOrRefCodedIndexSize); } } - private void SerializeMemberRefTable(BinaryWriter writer) + private void SerializeMemberRefTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (MemberRefRow memberRef in this.memberRefTable) { - SerializeIndex(writer, memberRef.Class, this.memberRefParentCodedIndexSize); - SerializeIndex(writer, memberRef.Name, this.stringIndexSize); - SerializeIndex(writer, memberRef.Signature, this.blobIndexSize); + SerializeIndex(writer, memberRef.Class, metadataSizes.MemberRefParentCodedIndexSize); + SerializeIndex(writer, memberRef.Name, metadataSizes.StringIndexSize); + SerializeIndex(writer, memberRef.Signature, metadataSizes.BlobIndexSize); } } - private void SerializeConstantTable(BinaryWriter writer) + private void SerializeConstantTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (ConstantRow constant in this.constantTable) { writer.WriteByte(constant.Type); writer.WriteByte(0); - SerializeIndex(writer, constant.Parent, this.hasConstantCodedIndexSize); - SerializeIndex(writer, constant.Value, this.blobIndexSize); + SerializeIndex(writer, constant.Parent, metadataSizes.HasConstantCodedIndexSize); + SerializeIndex(writer, constant.Value, metadataSizes.BlobIndexSize); } } - private void SerializeCustomAttributeTable(BinaryWriter writer) + private void SerializeCustomAttributeTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (CustomAttributeRow customAttribute in this.customAttributeTable) { - SerializeIndex(writer, customAttribute.Parent, this.hasCustomAttributeCodedIndexSize); - SerializeIndex(writer, customAttribute.Type, this.customAttributeTypeCodedIndexSize); - SerializeIndex(writer, customAttribute.Value, this.blobIndexSize); + SerializeIndex(writer, customAttribute.Parent, metadataSizes.HasCustomAttributeCodedIndexSize); + SerializeIndex(writer, customAttribute.Type, metadataSizes.CustomAttributeTypeCodedIndexSize); + SerializeIndex(writer, customAttribute.Value, metadataSizes.BlobIndexSize); } } - private void SerializeFieldMarshalTable(BinaryWriter writer) + private void SerializeFieldMarshalTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (FieldMarshalRow fieldMarshal in this.fieldMarshalTable) { - SerializeIndex(writer, fieldMarshal.Parent, this.hasFieldMarshalCodedIndexSize); - SerializeIndex(writer, fieldMarshal.NativeType, this.blobIndexSize); + SerializeIndex(writer, fieldMarshal.Parent, metadataSizes.HasFieldMarshalCodedIndexSize); + SerializeIndex(writer, fieldMarshal.NativeType, metadataSizes.BlobIndexSize); } } - private void SerializeDeclSecurityTable(BinaryWriter writer) + private void SerializeDeclSecurityTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (DeclSecurityRow declSecurity in this.declSecurityTable) { writer.WriteUshort(declSecurity.Action); - SerializeIndex(writer, declSecurity.Parent, this.declSecurityCodedIndexSize); - SerializeIndex(writer, declSecurity.PermissionSet, this.blobIndexSize); + SerializeIndex(writer, declSecurity.Parent, metadataSizes.DeclSecurityCodedIndexSize); + SerializeIndex(writer, declSecurity.PermissionSet, metadataSizes.BlobIndexSize); } } - private void SerializeClassLayoutTable(BinaryWriter writer) + private void SerializeClassLayoutTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (ClassLayoutRow classLayout in this.classLayoutTable) { writer.WriteUshort(classLayout.PackingSize); writer.WriteUint(classLayout.ClassSize); - SerializeIndex(writer, classLayout.Parent, this.typeDefIndexSize); + SerializeIndex(writer, classLayout.Parent, metadataSizes.TypeDefIndexSize); } } - private void SerializeFieldLayoutTable(BinaryWriter writer) + private void SerializeFieldLayoutTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (FieldLayoutRow fieldLayout in this.fieldLayoutTable) { writer.WriteUint(fieldLayout.Offset); - SerializeIndex(writer, fieldLayout.Field, this.fieldDefIndexSize); + SerializeIndex(writer, fieldLayout.Field, metadataSizes.FieldDefIndexSize); } } - private void SerializeStandAloneSigTable(BinaryWriter writer) + private void SerializeStandAloneSigTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (uint blobIndex in this.GetStandAloneSignatures()) { - SerializeIndex(writer, blobIndex, this.blobIndexSize); + SerializeIndex(writer, blobIndex, metadataSizes.BlobIndexSize); } } - private void SerializeEventMapTable(BinaryWriter writer) + private void SerializeEventMapTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (EventMapRow eventMap in this.eventMapTable) { - SerializeIndex(writer, eventMap.Parent, this.typeDefIndexSize); - SerializeIndex(writer, eventMap.EventList, this.eventDefIndexSize); + SerializeIndex(writer, eventMap.Parent, metadataSizes.TypeDefIndexSize); + SerializeIndex(writer, eventMap.EventList, metadataSizes.EventDefIndexSize); } } - private void SerializeEventTable(BinaryWriter writer) + private void SerializeEventTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (EventRow eventRow in this.eventTable) { writer.WriteUshort(eventRow.EventFlags); - SerializeIndex(writer, eventRow.Name, this.stringIndexSize); - SerializeIndex(writer, eventRow.EventType, this.typeDefOrRefCodedIndexSize); + SerializeIndex(writer, eventRow.Name, metadataSizes.StringIndexSize); + SerializeIndex(writer, eventRow.EventType, metadataSizes.TypeDefOrRefCodedIndexSize); } } - private void SerializePropertyMapTable(BinaryWriter writer) + private void SerializePropertyMapTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (PropertyMapRow propertyMap in this.propertyMapTable) { - SerializeIndex(writer, propertyMap.Parent, this.typeDefIndexSize); - SerializeIndex(writer, propertyMap.PropertyList, this.propertyDefIndexSize); + SerializeIndex(writer, propertyMap.Parent, metadataSizes.TypeDefIndexSize); + SerializeIndex(writer, propertyMap.PropertyList, metadataSizes.PropertyDefIndexSize); } } - private void SerializePropertyTable(BinaryWriter writer) + private void SerializePropertyTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (PropertyRow property in this.propertyTable) { writer.WriteUshort(property.PropFlags); - this.SerializeIndex(writer, property.Name, this.stringIndexSize); - SerializeIndex(writer, property.Type, this.blobIndexSize); + this.SerializeIndex(writer, property.Name, metadataSizes.StringIndexSize); + SerializeIndex(writer, property.Type, metadataSizes.BlobIndexSize); } } - private void SerializeMethodSemanticsTable(BinaryWriter writer) + private void SerializeMethodSemanticsTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (MethodSemanticsRow methodSemantic in this.methodSemanticsTable) { writer.WriteUshort(methodSemantic.Semantic); - SerializeIndex(writer, methodSemantic.Method, this.methodDefIndexSize); - SerializeIndex(writer, methodSemantic.Association, this.hasSemanticsCodedIndexSize); + SerializeIndex(writer, methodSemantic.Method, metadataSizes.MethodDefIndexSize); + SerializeIndex(writer, methodSemantic.Association, metadataSizes.HasSemanticsCodedIndexSize); } } - private void SerializeMethodImplTable(BinaryWriter writer) + private void SerializeMethodImplTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (MethodImplRow methodImpl in this.methodImplTable) { - SerializeIndex(writer, methodImpl.Class, this.typeDefIndexSize); - SerializeIndex(writer, methodImpl.MethodBody, this.methodDefOrRefCodedIndexSize); - SerializeIndex(writer, methodImpl.MethodDecl, this.methodDefOrRefCodedIndexSize); + SerializeIndex(writer, methodImpl.Class, metadataSizes.TypeDefIndexSize); + SerializeIndex(writer, methodImpl.MethodBody, metadataSizes.MethodDefOrRefCodedIndexSize); + SerializeIndex(writer, methodImpl.MethodDecl, metadataSizes.MethodDefOrRefCodedIndexSize); } } - private void SerializeModuleRefTable(BinaryWriter writer) + private void SerializeModuleRefTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (ModuleRefRow moduleRef in this.moduleRefTable) { - this.SerializeIndex(writer, moduleRef.Name, this.stringIndexSize); + this.SerializeIndex(writer, moduleRef.Name, metadataSizes.StringIndexSize); } } - private void SerializeTypeSpecTable(BinaryWriter writer) + private void SerializeTypeSpecTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (TypeSpecRow typeSpec in this.typeSpecTable) { - SerializeIndex(writer, typeSpec.Signature, this.blobIndexSize); + SerializeIndex(writer, typeSpec.Signature, metadataSizes.BlobIndexSize); } } - private void SerializeImplMapTable(BinaryWriter writer) + private void SerializeImplMapTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (ImplMapRow implMap in this.implMapTable) { writer.WriteUshort(implMap.MappingFlags); - SerializeIndex(writer, implMap.MemberForwarded, this.memberForwardedCodedIndexSize); - this.SerializeIndex(writer, implMap.ImportName, this.stringIndexSize); - SerializeIndex(writer, implMap.ImportScope, this.moduleRefIndexSize); + SerializeIndex(writer, implMap.MemberForwarded, metadataSizes.MemberForwardedCodedIndexSize); + this.SerializeIndex(writer, implMap.ImportName, metadataSizes.StringIndexSize); + SerializeIndex(writer, implMap.ImportScope, metadataSizes.ModuleRefIndexSize); } } - private void SerializeFieldRvaTable(BinaryWriter writer, int mappedFieldDataStreamRva) + private void SerializeFieldRvaTable(BinaryWriter writer, MetadataSizes metadataSizes, int mappedFieldDataStreamRva) { foreach (FieldRvaRow fieldRva in this.fieldRvaTable) { writer.WriteUint((uint)mappedFieldDataStreamRva + fieldRva.Offset); - SerializeIndex(writer, fieldRva.Field, this.fieldDefIndexSize); + SerializeIndex(writer, fieldRva.Field, metadataSizes.FieldDefIndexSize); } } - private void SerializeAssemblyTable(BinaryWriter writer) + private void SerializeAssemblyTable(BinaryWriter writer, MetadataSizes metadataSizes) { IAssembly assembly = this.module.AsAssembly; if (assembly == null) @@ -5090,12 +4891,12 @@ private void SerializeAssemblyTable(BinaryWriter writer) writer.WriteUshort((ushort)assembly.Version.Build); writer.WriteUshort((ushort)assembly.Version.Revision); writer.WriteUint(assembly.Flags); - SerializeIndex(writer, this.assemblyKey, this.blobIndexSize); - this.SerializeIndex(writer, this.assemblyName, this.stringIndexSize); - this.SerializeIndex(writer, this.assemblyCulture, this.stringIndexSize); + SerializeIndex(writer, this.assemblyKey, metadataSizes.BlobIndexSize); + this.SerializeIndex(writer, this.assemblyName, metadataSizes.StringIndexSize); + this.SerializeIndex(writer, this.assemblyCulture, metadataSizes.StringIndexSize); } - private void SerializeAssemblyRefTable(BinaryWriter writer) + private void SerializeAssemblyRefTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (AssemblyRefTableRow assemblyRef in this.assemblyRefTable) { @@ -5115,81 +4916,81 @@ private void SerializeAssemblyRefTable(BinaryWriter writer) writer.WriteUint(flags); - SerializeIndex(writer, assemblyRef.PublicKeyToken, this.blobIndexSize); - this.SerializeIndex(writer, assemblyRef.Name, this.stringIndexSize); - this.SerializeIndex(writer, assemblyRef.Culture, this.stringIndexSize); - SerializeIndex(writer, 0, this.blobIndexSize); // hash of referenced assembly. Omitted. + SerializeIndex(writer, assemblyRef.PublicKeyToken, metadataSizes.BlobIndexSize); + this.SerializeIndex(writer, assemblyRef.Name, metadataSizes.StringIndexSize); + this.SerializeIndex(writer, assemblyRef.Culture, metadataSizes.StringIndexSize); + SerializeIndex(writer, 0, metadataSizes.BlobIndexSize); // hash of referenced assembly. Omitted. } } - private void SerializeFileTable(BinaryWriter writer) + private void SerializeFileTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (FileTableRow fileReference in this.fileTable) { writer.WriteUint(fileReference.Flags); - this.SerializeIndex(writer, fileReference.FileName, this.stringIndexSize); - SerializeIndex(writer, fileReference.HashValue, this.blobIndexSize); + this.SerializeIndex(writer, fileReference.FileName, metadataSizes.StringIndexSize); + SerializeIndex(writer, fileReference.HashValue, metadataSizes.BlobIndexSize); } } - private void SerializeExportedTypeTable(BinaryWriter writer) + private void SerializeExportedTypeTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (ExportedTypeRow exportedType in this.exportedTypeTable) { writer.WriteUint((uint)exportedType.Flags); writer.WriteUint(exportedType.TypeDefId); - this.SerializeIndex(writer, exportedType.TypeName, this.stringIndexSize); - this.SerializeIndex(writer, exportedType.TypeNamespace, this.stringIndexSize); - SerializeIndex(writer, exportedType.Implementation, this.implementationCodedIndexSize); + this.SerializeIndex(writer, exportedType.TypeName, metadataSizes.StringIndexSize); + this.SerializeIndex(writer, exportedType.TypeNamespace, metadataSizes.StringIndexSize); + SerializeIndex(writer, exportedType.Implementation, metadataSizes.ImplementationCodedIndexSize); } } - private void SerializeManifestResourceTable(BinaryWriter writer) + private void SerializeManifestResourceTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (ManifestResourceRow manifestResource in this.manifestResourceTable) { writer.WriteUint(manifestResource.Offset); writer.WriteUint(manifestResource.Flags); - this.SerializeIndex(writer, manifestResource.Name, this.stringIndexSize); - SerializeIndex(writer, manifestResource.Implementation, this.implementationCodedIndexSize); + this.SerializeIndex(writer, manifestResource.Name, metadataSizes.StringIndexSize); + SerializeIndex(writer, manifestResource.Implementation, metadataSizes.ImplementationCodedIndexSize); } } - private void SerializeNestedClassTable(BinaryWriter writer) + private void SerializeNestedClassTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (NestedClassRow nestedClass in this.nestedClassTable) { - SerializeIndex(writer, nestedClass.NestedClass, this.typeDefIndexSize); - SerializeIndex(writer, nestedClass.EnclosingClass, this.typeDefIndexSize); + SerializeIndex(writer, nestedClass.NestedClass, metadataSizes.TypeDefIndexSize); + SerializeIndex(writer, nestedClass.EnclosingClass, metadataSizes.TypeDefIndexSize); } } - private void SerializeGenericParamTable(BinaryWriter writer) + private void SerializeGenericParamTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (GenericParamRow genericParam in this.genericParamTable) { writer.WriteUshort(genericParam.Number); writer.WriteUshort(genericParam.Flags); - SerializeIndex(writer, genericParam.Owner, this.typeOrMethodDefCodedIndexSize); - this.SerializeIndex(writer, genericParam.Name, this.stringIndexSize); + SerializeIndex(writer, genericParam.Owner, metadataSizes.TypeOrMethodDefCodedIndexSize); + this.SerializeIndex(writer, genericParam.Name, metadataSizes.StringIndexSize); } } - private void SerializeMethodSpecTable(BinaryWriter writer) + private void SerializeMethodSpecTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (MethodSpecRow methodSpec in this.methodSpecTable) { - SerializeIndex(writer, methodSpec.Method, this.methodDefOrRefCodedIndexSize); - SerializeIndex(writer, methodSpec.Instantiation, this.blobIndexSize); + SerializeIndex(writer, methodSpec.Method, metadataSizes.MethodDefOrRefCodedIndexSize); + SerializeIndex(writer, methodSpec.Instantiation, metadataSizes.BlobIndexSize); } } - private void SerializeGenericParamConstraintTable(BinaryWriter writer) + private void SerializeGenericParamConstraintTable(BinaryWriter writer, MetadataSizes metadataSizes) { foreach (GenericParamConstraintRow genericParamConstraint in this.genericParamConstraintTable) { - SerializeIndex(writer, genericParamConstraint.Owner, this.genericParamIndexSize); - SerializeIndex(writer, genericParamConstraint.Constraint, this.typeDefOrRefCodedIndexSize); + SerializeIndex(writer, genericParamConstraint.Owner, metadataSizes.GenericParamIndexSize); + SerializeIndex(writer, genericParamConstraint.Constraint, metadataSizes.TypeDefOrRefCodedIndexSize); } } @@ -7055,7 +6856,7 @@ private static void WriteSectionHeader(SectionHeader sectionHeader, BinaryWriter writer.WriteUint(sectionHeader.Characteristics); } - private void WriteTextSection(Stream peStream, MemoryStream metadataStream, MemoryStream ilStream, MemoryStream mappedFieldDataStream, out long startOfMetadata, out long positionOfTimestamp) + private void WriteTextSection(Stream peStream, CorHeader corHeader, MemoryStream metadataStream, MemoryStream ilStream, MemoryStream mappedFieldDataStream, out long startOfMetadata, out long positionOfTimestamp) { peStream.Position = this.textSection.PointerToRawData; if (this.emitRuntimeStartupStub) @@ -7063,14 +6864,14 @@ private void WriteTextSection(Stream peStream, MemoryStream metadataStream, Memo this.WriteImportAddressTable(peStream); } - this.WriteClrHeader(peStream); - this.WriteIL(peStream, ilStream); + WriteCorHeader(peStream, corHeader); + WriteIL(peStream, ilStream); startOfMetadata = peStream.Position; - this.WriteMetadata(peStream, metadataStream); + WriteMetadata(peStream, metadataStream); this.WriteManagedResources(peStream); - this.WriteSpaceForHash(peStream); + WriteSpaceForHash(peStream, (int)corHeader.StrongNameSignature.Size); this.WriteDebugTable(peStream, out positionOfTimestamp); if (this.emitRuntimeStartupStub) @@ -7080,7 +6881,7 @@ private void WriteTextSection(Stream peStream, MemoryStream metadataStream, Memo this.WriteRuntimeStartupStub(peStream); } - this.WriteMappedFieldData(peStream, mappedFieldDataStream); + WriteMappedFieldData(peStream, mappedFieldDataStream); } private void WriteImportAddressTable(Stream peStream) @@ -7165,32 +6966,31 @@ private void WriteNameTable(Stream peStream) writer.BaseStream.WriteTo(peStream); } - private void WriteClrHeader(Stream peStream) + private static void WriteCorHeader(Stream peStream, CorHeader corHeader) { BinaryWriter writer = new BinaryWriter(new MemoryStream(72)); - ClrHeader clrHeader = this.clrHeader; writer.WriteUint(72); // Number of bytes in this header 4 - writer.WriteUshort(clrHeader.MajorRuntimeVersion); // 6 - writer.WriteUshort(clrHeader.MinorRuntimeVersion); // 8 - writer.WriteUint(clrHeader.MetaData.RelativeVirtualAddress); // 12 - writer.WriteUint(clrHeader.MetaData.Size); // 16 - writer.WriteUint(clrHeader.Flags); // 20 - writer.WriteUint(clrHeader.EntryPointToken); // 24 - writer.WriteUint(clrHeader.Resources.Size == 0 ? 0u : clrHeader.Resources.RelativeVirtualAddress); // 28 - writer.WriteUint(clrHeader.Resources.Size); // 32 - writer.WriteUint(clrHeader.StrongNameSignature.Size == 0 ? 0u : clrHeader.StrongNameSignature.RelativeVirtualAddress); // 36 - writer.WriteUint(clrHeader.StrongNameSignature.Size); // 40 - writer.WriteUint(clrHeader.CodeManagerTable.RelativeVirtualAddress); // 44 - writer.WriteUint(clrHeader.CodeManagerTable.Size); // 48 - writer.WriteUint(clrHeader.VTableFixups.RelativeVirtualAddress); // 52 - writer.WriteUint(clrHeader.VTableFixups.Size); // 56 - writer.WriteUint(clrHeader.ExportAddressTableJumps.RelativeVirtualAddress); // 60 - writer.WriteUint(clrHeader.ExportAddressTableJumps.Size); // 64 + writer.WriteUshort(corHeader.MajorRuntimeVersion); // 6 + writer.WriteUshort(corHeader.MinorRuntimeVersion); // 8 + writer.WriteUint(corHeader.MetadataDirectory.RelativeVirtualAddress); // 12 + writer.WriteUint(corHeader.MetadataDirectory.Size); // 16 + writer.WriteUint((uint)corHeader.Flags); // 20 + writer.WriteUint(corHeader.EntryPointToken); // 24 + writer.WriteUint(corHeader.Resources.Size == 0 ? 0u : corHeader.Resources.RelativeVirtualAddress); // 28 + writer.WriteUint(corHeader.Resources.Size); // 32 + writer.WriteUint(corHeader.StrongNameSignature.Size == 0 ? 0u : corHeader.StrongNameSignature.RelativeVirtualAddress); // 36 + writer.WriteUint(corHeader.StrongNameSignature.Size); // 40 + writer.WriteUint(corHeader.CodeManagerTable.RelativeVirtualAddress); // 44 + writer.WriteUint(corHeader.CodeManagerTable.Size); // 48 + writer.WriteUint(corHeader.VTableFixups.RelativeVirtualAddress); // 52 + writer.WriteUint(corHeader.VTableFixups.Size); // 56 + writer.WriteUint(corHeader.ExportAddressTableJumps.RelativeVirtualAddress); // 60 + writer.WriteUint(corHeader.ExportAddressTableJumps.Size); // 64 writer.WriteUlong(0); // 72 writer.BaseStream.WriteTo(peStream); } - private void WriteIL(Stream peStream, MemoryStream ilStream) + private static void WriteIL(Stream peStream, MemoryStream ilStream) { ilStream.WriteTo(peStream); while (peStream.Position % 4 != 0) @@ -7199,7 +6999,7 @@ private void WriteIL(Stream peStream, MemoryStream ilStream) } } - private void WriteMappedFieldData(Stream peStream, MemoryStream dataStream) + private static void WriteMappedFieldData(Stream peStream, MemoryStream dataStream) { dataStream.WriteTo(peStream); while (peStream.Position % 4 != 0) @@ -7208,17 +7008,16 @@ private void WriteMappedFieldData(Stream peStream, MemoryStream dataStream) } } - private void WriteSpaceForHash(Stream peStream) + private static void WriteSpaceForHash(Stream peStream, int strongNameSignatureSize) { - uint size = this.clrHeader.StrongNameSignature.Size; - while (size > 0) + while (strongNameSignatureSize > 0) { peStream.WriteByte(0); - size--; + strongNameSignatureSize--; } } - private void WriteMetadata(Stream peStream, MemoryStream metadataStream) + private static void WriteMetadata(Stream peStream, MemoryStream metadataStream) { metadataStream.WriteTo(peStream); while (peStream.Position % 4 != 0) @@ -7272,7 +7071,7 @@ private void WriteRuntimeStartupStub(Stream peStream) if (!this.module.Requires64bits) { //emit 0's (nops) to pad the entry point code so that the target address is aligned on a 4 byte boundary. - for (uint i = 0, n = (uint)(Aligned((uint)peStream.Position, 4) - peStream.Position); i < n; i++) writer.WriteByte(0); + for (uint i = 0, n = (uint)(Align((uint)peStream.Position, 4) - peStream.Position); i < n; i++) writer.WriteByte(0); writer.WriteUshort(0); writer.WriteByte(0xff); writer.WriteByte(0x25); //4 @@ -7281,7 +7080,7 @@ private void WriteRuntimeStartupStub(Stream peStream) else { //emit 0's (nops) to pad the entry point code so that the target address is aligned on a 8 byte boundary. - for (uint i = 0, n = (uint)(Aligned((uint)peStream.Position, 8) - peStream.Position); i < n; i++) writer.WriteByte(0); + for (uint i = 0, n = (uint)(Align((uint)peStream.Position, 8) - peStream.Position); i < n; i++) writer.WriteByte(0); writer.WriteUint(0); writer.WriteUshort(0); writer.WriteByte(0xff); diff --git a/Src/Compilers/VisualBasic/Source/Emit/EditAndContinue/EmitHelpers.vb b/Src/Compilers/VisualBasic/Source/Emit/EditAndContinue/EmitHelpers.vb index ec8820d26d6..c7399c53a53 100644 --- a/Src/Compilers/VisualBasic/Source/Emit/EditAndContinue/EmitHelpers.vb +++ b/Src/Compilers/VisualBasic/Source/Emit/EditAndContinue/EmitHelpers.vb @@ -86,13 +86,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit changes, cancellationToken) - writer.WriteMetadataAndIL(metadataStream, ilStream) + Dim metadataSizes As Cci.MetadataSizes = Nothing + writer.WriteMetadataAndIL(metadataStream, ilStream, metadataSizes) writer.GetMethodTokens(updatedMethodTokens) Return New EmitDifferenceResult( success:=True, diagnostics:=diagnostics.ToReadOnlyAndFree(), - baseline:=writer.GetDelta(baseline, compilation, encId)) + baseline:=writer.GetDelta(baseline, compilation, encId, metadataSizes)) Catch e As Cci.PdbWritingException diagnostics.Add(ERRID.ERR_PDBWritingFailed, Location.None, e.Message) -- GitLab