< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 286
Coverable lines: 286
Total lines: 493
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 92
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)0%68680%
IsPresent(...)100%110%
GetMetadataStreamHeaderSize(...)100%110%
GetAlignedHeapSize(...)0%440%
CalculateTableStreamHeaderSize()0%440%
CalculateStandalonePdbStreamSize()100%110%
ComputeNonEmptyTableMask(...)0%440%
GetTableSize(...)100%110%
IsReferenceSmall(...)0%220%
ReferenceFits(...)0%660%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataSizes.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Collections.Immutable;
 5using System.Diagnostics;
 6using System.Numerics;
 7using System.Reflection.Internal;
 8
 9namespace System.Reflection.Metadata.Ecma335
 10{
 11    /// <summary>
 12    /// Provides information on sizes of various metadata structures.
 13    /// </summary>
 14    public sealed class MetadataSizes
 15    {
 16        private const int StreamAlignment = 4;
 17
 18        // Call the length of the string (including the terminator) m (we require m <= 255);
 19        internal const int MaxMetadataVersionByteCount = 0xff - 1;
 20
 21        internal readonly int MetadataVersionPaddedLength;
 22
 23        internal const ulong SortedTypeSystemTables =
 24            1UL << (int)TableIndex.InterfaceImpl |
 25            1UL << (int)TableIndex.Constant |
 26            1UL << (int)TableIndex.CustomAttribute |
 27            1UL << (int)TableIndex.FieldMarshal |
 28            1UL << (int)TableIndex.DeclSecurity |
 29            1UL << (int)TableIndex.ClassLayout |
 30            1UL << (int)TableIndex.FieldLayout |
 31            1UL << (int)TableIndex.MethodSemantics |
 32            1UL << (int)TableIndex.MethodImpl |
 33            1UL << (int)TableIndex.ImplMap |
 34            1UL << (int)TableIndex.FieldRva |
 35            1UL << (int)TableIndex.NestedClass |
 36            1UL << (int)TableIndex.GenericParam |
 37            1UL << (int)TableIndex.GenericParamConstraint;
 38
 39        internal const ulong SortedDebugTables =
 40            1UL << (int)TableIndex.LocalScope |
 41            1UL << (int)TableIndex.StateMachineMethod |
 42            1UL << (int)TableIndex.CustomDebugInformation;
 43
 44        internal readonly bool IsEncDelta;
 45        internal readonly bool IsCompressed;
 46
 47        internal readonly bool BlobReferenceIsSmall;
 48        internal readonly bool StringReferenceIsSmall;
 49        internal readonly bool GuidReferenceIsSmall;
 50        internal readonly bool CustomAttributeTypeCodedIndexIsSmall;
 51        internal readonly bool DeclSecurityCodedIndexIsSmall;
 52        internal readonly bool EventDefReferenceIsSmall;
 53        internal readonly bool FieldDefReferenceIsSmall;
 54        internal readonly bool GenericParamReferenceIsSmall;
 55        internal readonly bool HasConstantCodedIndexIsSmall;
 56        internal readonly bool HasCustomAttributeCodedIndexIsSmall;
 57        internal readonly bool HasFieldMarshalCodedIndexIsSmall;
 58        internal readonly bool HasSemanticsCodedIndexIsSmall;
 59        internal readonly bool ImplementationCodedIndexIsSmall;
 60        internal readonly bool MemberForwardedCodedIndexIsSmall;
 61        internal readonly bool MemberRefParentCodedIndexIsSmall;
 62        internal readonly bool MethodDefReferenceIsSmall;
 63        internal readonly bool MethodDefOrRefCodedIndexIsSmall;
 64        internal readonly bool ModuleRefReferenceIsSmall;
 65        internal readonly bool ParameterReferenceIsSmall;
 66        internal readonly bool PropertyDefReferenceIsSmall;
 67        internal readonly bool ResolutionScopeCodedIndexIsSmall;
 68        internal readonly bool TypeDefReferenceIsSmall;
 69        internal readonly bool TypeDefOrRefCodedIndexIsSmall;
 70        internal readonly bool TypeOrMethodDefCodedIndexIsSmall;
 71
 72        internal readonly bool DocumentReferenceIsSmall;
 73        internal readonly bool LocalVariableReferenceIsSmall;
 74        internal readonly bool LocalConstantReferenceIsSmall;
 75        internal readonly bool ImportScopeReferenceIsSmall;
 76        internal readonly bool HasCustomDebugInformationCodedIndexIsSmall;
 77
 78        /// <summary>
 79        /// Exact (unaligned) heap sizes.
 80        /// </summary>
 81        /// <remarks>Use <see cref="GetAlignedHeapSize(HeapIndex)"/> to get an aligned heap size.</remarks>
 082        public ImmutableArray<int> HeapSizes { get; }
 83
 84        /// <summary>
 85        /// Table row counts.
 86        /// </summary>
 087        public ImmutableArray<int> RowCounts { get; }
 88
 89        /// <summary>
 90        /// External table row counts.
 91        /// </summary>
 092        public ImmutableArray<int> ExternalRowCounts { get; }
 93
 94        /// <summary>
 95        /// Non-empty tables that are emitted into the metadata table stream.
 96        /// </summary>
 97        internal readonly ulong PresentTablesMask;
 98
 99        /// <summary>
 100        /// Non-empty tables stored in an external metadata table stream that might be referenced from the metadata tabl
 101        /// </summary>
 102        internal readonly ulong ExternalTablesMask;
 103
 104        /// <summary>
 105        /// Overall size of metadata stream storage (stream headers, table stream, heaps, additional streams).
 106        /// Aligned to <see cref="StreamAlignment"/>.
 107        /// </summary>
 108        internal readonly int MetadataStreamStorageSize;
 109
 110        /// <summary>
 111        /// The size of metadata stream (#- or #~). Aligned.
 112        /// Aligned to <see cref="StreamAlignment"/>.
 113        /// </summary>
 114        internal readonly int MetadataTableStreamSize;
 115
 116        /// <summary>
 117        /// The size of #Pdb stream. Aligned.
 118        /// </summary>
 119        internal readonly int StandalonePdbStreamSize;
 120
 0121        internal MetadataSizes(
 0122            ImmutableArray<int> rowCounts,
 0123            ImmutableArray<int> externalRowCounts,
 0124            ImmutableArray<int> heapSizes,
 0125            int metadataVersionByteCount,
 0126            bool isStandaloneDebugMetadata)
 0127        {
 0128            Debug.Assert(rowCounts.Length == MetadataTokens.TableCount);
 0129            Debug.Assert(externalRowCounts.Length == MetadataTokens.TableCount);
 0130            Debug.Assert(heapSizes.Length == MetadataTokens.HeapCount);
 131
 0132            RowCounts = rowCounts;
 0133            ExternalRowCounts = externalRowCounts;
 0134            HeapSizes = heapSizes;
 135
 136            // +1 for NUL terminator
 0137            MetadataVersionPaddedLength = BitArithmetic.Align(metadataVersionByteCount + 1, 4);
 138
 0139            PresentTablesMask = ComputeNonEmptyTableMask(rowCounts);
 0140            ExternalTablesMask = ComputeNonEmptyTableMask(externalRowCounts);
 141
 142            // Auto-detect EnC delta from presence of EnC tables.
 143            // EnC delta tables are stored as uncompressed metadata table stream, other metadata use compressed stream.
 144            // We could support uncompress non-EnC metadata in future if we needed to.
 0145            bool isEncDelta = IsPresent(TableIndex.EncLog) || IsPresent(TableIndex.EncMap);
 0146            bool isCompressed = !isEncDelta;
 147
 0148            IsEncDelta = isEncDelta;
 0149            IsCompressed = isCompressed;
 150
 0151            BlobReferenceIsSmall = isCompressed && heapSizes[(int)HeapIndex.Blob] <= ushort.MaxValue;
 0152            StringReferenceIsSmall = isCompressed && heapSizes[(int)HeapIndex.String] <= ushort.MaxValue;
 0153            GuidReferenceIsSmall = isCompressed && heapSizes[(int)HeapIndex.Guid] <= ushort.MaxValue;
 154
 155            // table can either be present or external, it can't be both:
 0156            Debug.Assert((PresentTablesMask & ExternalTablesMask) == 0);
 157
 0158            CustomAttributeTypeCodedIndexIsSmall = IsReferenceSmall(3, TableIndex.MethodDef, TableIndex.MemberRef);
 0159            DeclSecurityCodedIndexIsSmall = IsReferenceSmall(2, TableIndex.MethodDef, TableIndex.TypeDef);
 0160            EventDefReferenceIsSmall = IsReferenceSmall(0, TableIndex.Event);
 0161            FieldDefReferenceIsSmall = IsReferenceSmall(0, TableIndex.Field);
 0162            GenericParamReferenceIsSmall = IsReferenceSmall(0, TableIndex.GenericParam);
 0163            HasConstantCodedIndexIsSmall = IsReferenceSmall(2, TableIndex.Field, TableIndex.Param, TableIndex.Property);
 164
 0165            HasCustomAttributeCodedIndexIsSmall = IsReferenceSmall(5,
 0166                TableIndex.MethodDef,
 0167                TableIndex.Field,
 0168                TableIndex.TypeRef,
 0169                TableIndex.TypeDef,
 0170                TableIndex.Param,
 0171                TableIndex.InterfaceImpl,
 0172                TableIndex.MemberRef,
 0173                TableIndex.Module,
 0174                TableIndex.DeclSecurity,
 0175                TableIndex.Property,
 0176                TableIndex.Event,
 0177                TableIndex.StandAloneSig,
 0178                TableIndex.ModuleRef,
 0179                TableIndex.TypeSpec,
 0180                TableIndex.Assembly,
 0181                TableIndex.AssemblyRef,
 0182                TableIndex.File,
 0183                TableIndex.ExportedType,
 0184                TableIndex.ManifestResource,
 0185                TableIndex.GenericParam,
 0186                TableIndex.GenericParamConstraint,
 0187                TableIndex.MethodSpec);
 188
 0189            HasFieldMarshalCodedIndexIsSmall = IsReferenceSmall(1, TableIndex.Field, TableIndex.Param);
 0190            HasSemanticsCodedIndexIsSmall = IsReferenceSmall(1, TableIndex.Event, TableIndex.Property);
 0191            ImplementationCodedIndexIsSmall = IsReferenceSmall(2, TableIndex.File, TableIndex.AssemblyRef, TableIndex.Ex
 0192            MemberForwardedCodedIndexIsSmall = IsReferenceSmall(1, TableIndex.Field, TableIndex.MethodDef);
 0193            MemberRefParentCodedIndexIsSmall = IsReferenceSmall(3, TableIndex.TypeDef, TableIndex.TypeRef, TableIndex.Mo
 0194            MethodDefReferenceIsSmall = IsReferenceSmall(0, TableIndex.MethodDef);
 0195            MethodDefOrRefCodedIndexIsSmall = IsReferenceSmall(1, TableIndex.MethodDef, TableIndex.MemberRef);
 0196            ModuleRefReferenceIsSmall = IsReferenceSmall(0, TableIndex.ModuleRef);
 0197            ParameterReferenceIsSmall = IsReferenceSmall(0, TableIndex.Param);
 0198            PropertyDefReferenceIsSmall = IsReferenceSmall(0, TableIndex.Property);
 0199            ResolutionScopeCodedIndexIsSmall = IsReferenceSmall(2, TableIndex.Module, TableIndex.ModuleRef, TableIndex.A
 0200            TypeDefReferenceIsSmall = IsReferenceSmall(0, TableIndex.TypeDef);
 0201            TypeDefOrRefCodedIndexIsSmall = IsReferenceSmall(2, TableIndex.TypeDef, TableIndex.TypeRef, TableIndex.TypeS
 0202            TypeOrMethodDefCodedIndexIsSmall = IsReferenceSmall(1, TableIndex.TypeDef, TableIndex.MethodDef);
 203
 0204            DocumentReferenceIsSmall = IsReferenceSmall(0, TableIndex.Document);
 0205            LocalVariableReferenceIsSmall = IsReferenceSmall(0, TableIndex.LocalVariable);
 0206            LocalConstantReferenceIsSmall = IsReferenceSmall(0, TableIndex.LocalConstant);
 0207            ImportScopeReferenceIsSmall = IsReferenceSmall(0, TableIndex.ImportScope);
 208
 0209            HasCustomDebugInformationCodedIndexIsSmall = IsReferenceSmall(5,
 0210                TableIndex.MethodDef,
 0211                TableIndex.Field,
 0212                TableIndex.TypeRef,
 0213                TableIndex.TypeDef,
 0214                TableIndex.Param,
 0215                TableIndex.InterfaceImpl,
 0216                TableIndex.MemberRef,
 0217                TableIndex.Module,
 0218                TableIndex.DeclSecurity,
 0219                TableIndex.Property,
 0220                TableIndex.Event,
 0221                TableIndex.StandAloneSig,
 0222                TableIndex.ModuleRef,
 0223                TableIndex.TypeSpec,
 0224                TableIndex.Assembly,
 0225                TableIndex.AssemblyRef,
 0226                TableIndex.File,
 0227                TableIndex.ExportedType,
 0228                TableIndex.ManifestResource,
 0229                TableIndex.GenericParam,
 0230                TableIndex.GenericParamConstraint,
 0231                TableIndex.MethodSpec,
 0232                TableIndex.Document,
 0233                TableIndex.LocalScope,
 0234                TableIndex.LocalVariable,
 0235                TableIndex.LocalConstant,
 0236                TableIndex.ImportScope);
 237
 0238            int size = CalculateTableStreamHeaderSize();
 239
 240            const byte small = 2;
 241            const byte large = 4;
 242
 0243            byte blobReferenceSize = BlobReferenceIsSmall ? small : large;
 0244            byte stringReferenceSize = StringReferenceIsSmall ? small : large;
 0245            byte guidReferenceSize = GuidReferenceIsSmall ? small : large;
 0246            byte customAttributeTypeCodedIndexSize = CustomAttributeTypeCodedIndexIsSmall ? small : large;
 0247            byte declSecurityCodedIndexSize = DeclSecurityCodedIndexIsSmall ? small : large;
 0248            byte eventDefReferenceSize = EventDefReferenceIsSmall ? small : large;
 0249            byte fieldDefReferenceSize = FieldDefReferenceIsSmall ? small : large;
 0250            byte genericParamReferenceSize = GenericParamReferenceIsSmall ? small : large;
 0251            byte hasConstantCodedIndexSize = HasConstantCodedIndexIsSmall ? small : large;
 0252            byte hasCustomAttributeCodedIndexSize = HasCustomAttributeCodedIndexIsSmall ? small : large;
 0253            byte hasFieldMarshalCodedIndexSize = HasFieldMarshalCodedIndexIsSmall ? small : large;
 0254            byte hasSemanticsCodedIndexSize = HasSemanticsCodedIndexIsSmall ? small : large;
 0255            byte implementationCodedIndexSize = ImplementationCodedIndexIsSmall ? small : large;
 0256            byte memberForwardedCodedIndexSize = MemberForwardedCodedIndexIsSmall ? small : large;
 0257            byte memberRefParentCodedIndexSize = MemberRefParentCodedIndexIsSmall ? small : large;
 0258            byte methodDefReferenceSize = MethodDefReferenceIsSmall ? small : large;
 0259            byte methodDefOrRefCodedIndexSize = MethodDefOrRefCodedIndexIsSmall ? small : large;
 0260            byte moduleRefReferenceSize = ModuleRefReferenceIsSmall ? small : large;
 0261            byte parameterReferenceSize = ParameterReferenceIsSmall ? small : large;
 0262            byte propertyDefReferenceSize = PropertyDefReferenceIsSmall ? small : large;
 0263            byte resolutionScopeCodedIndexSize = ResolutionScopeCodedIndexIsSmall ? small : large;
 0264            byte typeDefReferenceSize = TypeDefReferenceIsSmall ? small : large;
 0265            byte typeDefOrRefCodedIndexSize = TypeDefOrRefCodedIndexIsSmall ? small : large;
 0266            byte typeOrMethodDefCodedIndexSize = TypeOrMethodDefCodedIndexIsSmall ? small : large;
 0267            byte documentReferenceSize = DocumentReferenceIsSmall ? small : large;
 0268            byte localVariableReferenceSize = LocalVariableReferenceIsSmall ? small : large;
 0269            byte localConstantReferenceSize = LocalConstantReferenceIsSmall ? small : large;
 0270            byte importScopeReferenceSize = ImportScopeReferenceIsSmall ? small : large;
 0271            byte hasCustomDebugInformationCodedIndexSize = HasCustomDebugInformationCodedIndexIsSmall ? small : large;
 272
 0273            size += GetTableSize(TableIndex.Module, 2 + 3 * guidReferenceSize + stringReferenceSize);
 0274            size += GetTableSize(TableIndex.TypeRef, resolutionScopeCodedIndexSize + stringReferenceSize + stringReferen
 0275            size += GetTableSize(TableIndex.TypeDef, 4 + stringReferenceSize + stringReferenceSize + typeDefOrRefCodedIn
 0276            Debug.Assert(rowCounts[(int)TableIndex.FieldPtr] == 0);
 0277            size += GetTableSize(TableIndex.Field, 2 + stringReferenceSize + blobReferenceSize);
 0278            Debug.Assert(rowCounts[(int)TableIndex.MethodPtr] == 0);
 0279            size += GetTableSize(TableIndex.MethodDef, 8 + stringReferenceSize + blobReferenceSize + parameterReferenceS
 0280            Debug.Assert(rowCounts[(int)TableIndex.ParamPtr] == 0);
 0281            size += GetTableSize(TableIndex.Param, 4 + stringReferenceSize);
 0282            size += GetTableSize(TableIndex.InterfaceImpl, typeDefReferenceSize + typeDefOrRefCodedIndexSize);
 0283            size += GetTableSize(TableIndex.MemberRef, memberRefParentCodedIndexSize + stringReferenceSize + blobReferen
 0284            size += GetTableSize(TableIndex.Constant, 2 + hasConstantCodedIndexSize + blobReferenceSize);
 0285            size += GetTableSize(TableIndex.CustomAttribute, hasCustomAttributeCodedIndexSize + customAttributeTypeCoded
 0286            size += GetTableSize(TableIndex.FieldMarshal, hasFieldMarshalCodedIndexSize + blobReferenceSize);
 0287            size += GetTableSize(TableIndex.DeclSecurity, 2 + declSecurityCodedIndexSize + blobReferenceSize);
 0288            size += GetTableSize(TableIndex.ClassLayout, 6 + typeDefReferenceSize);
 0289            size += GetTableSize(TableIndex.FieldLayout, 4 + fieldDefReferenceSize);
 0290            size += GetTableSize(TableIndex.StandAloneSig, blobReferenceSize);
 0291            size += GetTableSize(TableIndex.EventMap, typeDefReferenceSize + eventDefReferenceSize);
 0292            Debug.Assert(rowCounts[(int)TableIndex.EventPtr] == 0);
 0293            size += GetTableSize(TableIndex.Event, 2 + stringReferenceSize + typeDefOrRefCodedIndexSize);
 0294            size += GetTableSize(TableIndex.PropertyMap, typeDefReferenceSize + propertyDefReferenceSize);
 0295            Debug.Assert(rowCounts[(int)TableIndex.PropertyPtr] == 0);
 0296            size += GetTableSize(TableIndex.Property, 2 + stringReferenceSize + blobReferenceSize);
 0297            size += GetTableSize(TableIndex.MethodSemantics, 2 + methodDefReferenceSize + hasSemanticsCodedIndexSize);
 0298            size += GetTableSize(TableIndex.MethodImpl, typeDefReferenceSize + methodDefOrRefCodedIndexSize + methodDefO
 0299            size += GetTableSize(TableIndex.ModuleRef, stringReferenceSize);
 0300            size += GetTableSize(TableIndex.TypeSpec, blobReferenceSize);
 0301            size += GetTableSize(TableIndex.ImplMap, 2 + memberForwardedCodedIndexSize + stringReferenceSize + moduleRef
 0302            size += GetTableSize(TableIndex.FieldRva, 4 + fieldDefReferenceSize);
 0303            size += GetTableSize(TableIndex.EncLog, 8);
 0304            size += GetTableSize(TableIndex.EncMap, 4);
 0305            size += GetTableSize(TableIndex.Assembly, 16 + blobReferenceSize + stringReferenceSize + stringReferenceSize
 0306            Debug.Assert(rowCounts[(int)TableIndex.AssemblyProcessor] == 0);
 0307            Debug.Assert(rowCounts[(int)TableIndex.AssemblyOS] == 0);
 0308            size += GetTableSize(TableIndex.AssemblyRef, 12 + blobReferenceSize + stringReferenceSize + stringReferenceS
 0309            Debug.Assert(rowCounts[(int)TableIndex.AssemblyRefProcessor] == 0);
 0310            Debug.Assert(rowCounts[(int)TableIndex.AssemblyRefOS] == 0);
 0311            size += GetTableSize(TableIndex.File, 4 + stringReferenceSize + blobReferenceSize);
 0312            size += GetTableSize(TableIndex.ExportedType, 8 + stringReferenceSize + stringReferenceSize + implementation
 0313            size += GetTableSize(TableIndex.ManifestResource, 8 + stringReferenceSize + implementationCodedIndexSize);
 0314            size += GetTableSize(TableIndex.NestedClass, typeDefReferenceSize + typeDefReferenceSize);
 0315            size += GetTableSize(TableIndex.GenericParam, 4 + typeOrMethodDefCodedIndexSize + stringReferenceSize);
 0316            size += GetTableSize(TableIndex.MethodSpec, methodDefOrRefCodedIndexSize + blobReferenceSize);
 0317            size += GetTableSize(TableIndex.GenericParamConstraint, genericParamReferenceSize + typeDefOrRefCodedIndexSi
 318
 0319            size += GetTableSize(TableIndex.Document, blobReferenceSize + guidReferenceSize + blobReferenceSize + guidRe
 0320            size += GetTableSize(TableIndex.MethodDebugInformation, documentReferenceSize + blobReferenceSize);
 0321            size += GetTableSize(TableIndex.LocalScope, methodDefReferenceSize + importScopeReferenceSize + localVariabl
 0322            size += GetTableSize(TableIndex.LocalVariable, 2 + 2 + stringReferenceSize);
 0323            size += GetTableSize(TableIndex.LocalConstant, stringReferenceSize + blobReferenceSize);
 0324            size += GetTableSize(TableIndex.ImportScope, importScopeReferenceSize + blobReferenceSize);
 0325            size += GetTableSize(TableIndex.StateMachineMethod, methodDefReferenceSize + methodDefReferenceSize);
 0326            size += GetTableSize(TableIndex.CustomDebugInformation, hasCustomDebugInformationCodedIndexSize + guidRefere
 327
 328            // +1 for terminating 0 byte
 0329            size = BitArithmetic.Align(size + 1, StreamAlignment);
 330
 0331            MetadataTableStreamSize = size;
 332
 0333            size += GetAlignedHeapSize(HeapIndex.String);
 0334            size += GetAlignedHeapSize(HeapIndex.UserString);
 0335            size += GetAlignedHeapSize(HeapIndex.Guid);
 0336            size += GetAlignedHeapSize(HeapIndex.Blob);
 337
 0338            StandalonePdbStreamSize = isStandaloneDebugMetadata ? CalculateStandalonePdbStreamSize() : 0;
 0339            size += StandalonePdbStreamSize;
 340
 0341            MetadataStreamStorageSize = size;
 0342        }
 343
 0344        internal bool IsStandaloneDebugMetadata => StandalonePdbStreamSize > 0;
 345
 0346        internal bool IsPresent(TableIndex table) => (PresentTablesMask & (1UL << (int)table)) != 0;
 347
 348        /// <summary>
 349        /// Metadata header size.
 350        /// Includes:
 351        /// - metadata storage signature
 352        /// - storage header
 353        /// - stream headers
 354        /// </summary>
 355        internal int MetadataHeaderSize
 356        {
 357            get
 0358            {
 359                const int RegularStreamHeaderSizes = 76;
 360                const int EncDeltaMarkerStreamHeaderSize = 16;
 361                const int StandalonePdbStreamHeaderSize = 16;
 362
 0363                Debug.Assert(RegularStreamHeaderSizes ==
 0364                    GetMetadataStreamHeaderSize("#~"u8) +
 0365                    GetMetadataStreamHeaderSize("#Strings"u8) +
 0366                    GetMetadataStreamHeaderSize("#US"u8) +
 0367                    GetMetadataStreamHeaderSize("#GUID"u8) +
 0368                    GetMetadataStreamHeaderSize("#Blob"u8));
 369
 0370                Debug.Assert(EncDeltaMarkerStreamHeaderSize == GetMetadataStreamHeaderSize("#JTD"u8));
 0371                Debug.Assert(StandalonePdbStreamHeaderSize == GetMetadataStreamHeaderSize("#Pdb"u8));
 372
 0373                return
 0374                    sizeof(uint) +                 // signature
 0375                    sizeof(ushort) +               // major version
 0376                    sizeof(ushort) +               // minor version
 0377                    sizeof(uint) +                 // reserved
 0378                    sizeof(uint) +                 // padded metadata version length
 0379                    MetadataVersionPaddedLength +  // metadata version
 0380                    sizeof(ushort) +               // storage header: reserved
 0381                    sizeof(ushort) +               // stream count
 0382                    (IsStandaloneDebugMetadata ? StandalonePdbStreamHeaderSize : 0) +
 0383                    RegularStreamHeaderSizes +
 0384                    (IsEncDelta ? EncDeltaMarkerStreamHeaderSize : 0);
 0385            }
 386        }
 387
 388        internal static int GetMetadataStreamHeaderSize(ReadOnlySpan<byte> streamName)
 0389        {
 0390            return
 0391                sizeof(int) + // offset
 0392                sizeof(int) + // size
 0393                BitArithmetic.Align(streamName.Length + 1, 4); // zero-terminated name, padding
 0394        }
 395
 396        /// <summary>
 397        /// Total size of metadata (header and all streams).
 398        /// </summary>
 0399        internal int MetadataSize => MetadataHeaderSize + MetadataStreamStorageSize;
 400
 401        /// <summary>
 402        /// Returns aligned size of the specified heap.
 403        /// </summary>
 404        public int GetAlignedHeapSize(HeapIndex index)
 0405        {
 0406            int i = (int)index;
 0407            if (i < 0 || i > HeapSizes.Length)
 0408            {
 0409                Throw.ArgumentOutOfRange(nameof(index));
 410            }
 411
 0412            return BitArithmetic.Align(HeapSizes[i], StreamAlignment);
 0413        }
 414
 415        internal int CalculateTableStreamHeaderSize()
 0416        {
 0417            int result = sizeof(int) +        // Reserved
 0418                         sizeof(short) +      // Version (major, minor)
 0419                         sizeof(byte) +       // Heap index sizes
 0420                         sizeof(byte) +       // Bit width of RowId
 0421                         sizeof(long) +       // Valid table mask
 0422                         sizeof(long);        // Sorted table mask
 423
 424            // present table row counts
 0425            for (int i = 0; i < RowCounts.Length; i++)
 0426            {
 0427                if (((1UL << i) & PresentTablesMask) != 0)
 0428                {
 0429                    result += sizeof(int);
 0430                }
 0431            }
 432
 0433            return result;
 0434        }
 435
 436        internal const int PdbIdSize = 20;
 437
 438        internal int CalculateStandalonePdbStreamSize()
 0439        {
 0440            int result =
 0441                PdbIdSize +                                                         // PDB ID
 0442                sizeof(int) +                                                       // EntryPoint
 0443                sizeof(long) +                                                      // ReferencedTypeSystemTables
 0444                BitOperations.PopCount(ExternalTablesMask) * sizeof(int); // External row counts
 445
 0446            Debug.Assert(result % StreamAlignment == 0);
 0447            return result;
 0448        }
 449
 450        private static ulong ComputeNonEmptyTableMask(ImmutableArray<int> rowCounts)
 0451        {
 0452            ulong mask = 0;
 0453            for (int i = 0; i < rowCounts.Length; i++)
 0454            {
 0455                if (rowCounts[i] > 0)
 0456                {
 0457                    mask |= (1UL << i);
 0458                }
 0459            }
 460
 0461            return mask;
 0462        }
 463
 464        private int GetTableSize(TableIndex index, int rowSize)
 0465        {
 0466            return RowCounts[(int)index] * rowSize;
 0467        }
 468
 469        private bool IsReferenceSmall(int tagBitSize, params TableIndex[] tables)
 0470        {
 471            const int smallBitCount = 16;
 0472            return IsCompressed && ReferenceFits(smallBitCount - tagBitSize, tables);
 0473        }
 474
 475        private bool ReferenceFits(int bitCount, TableIndex[] tables)
 0476        {
 0477            int maxIndex = (1 << bitCount) - 1;
 0478            foreach (TableIndex table in tables)
 0479            {
 480                // table can be either local or external, but not both:
 0481                Debug.Assert(RowCounts[(int)table] == 0 || ExternalRowCounts[(int)table] == 0);
 482
 0483                if (RowCounts[(int)table] + ExternalRowCounts[(int)table] > maxIndex)
 0484                {
 0485                    return false;
 486                }
 0487            }
 488
 0489            return true;
 0490        }
 491    }
 492}
 493