| | | 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 | | |
| | | 4 | | using System.Collections.Immutable; |
| | | 5 | | using System.Diagnostics; |
| | | 6 | | using System.Numerics; |
| | | 7 | | using System.Reflection.Internal; |
| | | 8 | | |
| | | 9 | | namespace 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> |
| | 0 | 82 | | public ImmutableArray<int> HeapSizes { get; } |
| | | 83 | | |
| | | 84 | | /// <summary> |
| | | 85 | | /// Table row counts. |
| | | 86 | | /// </summary> |
| | 0 | 87 | | public ImmutableArray<int> RowCounts { get; } |
| | | 88 | | |
| | | 89 | | /// <summary> |
| | | 90 | | /// External table row counts. |
| | | 91 | | /// </summary> |
| | 0 | 92 | | 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 | | |
| | 0 | 121 | | internal MetadataSizes( |
| | 0 | 122 | | ImmutableArray<int> rowCounts, |
| | 0 | 123 | | ImmutableArray<int> externalRowCounts, |
| | 0 | 124 | | ImmutableArray<int> heapSizes, |
| | 0 | 125 | | int metadataVersionByteCount, |
| | 0 | 126 | | bool isStandaloneDebugMetadata) |
| | 0 | 127 | | { |
| | 0 | 128 | | Debug.Assert(rowCounts.Length == MetadataTokens.TableCount); |
| | 0 | 129 | | Debug.Assert(externalRowCounts.Length == MetadataTokens.TableCount); |
| | 0 | 130 | | Debug.Assert(heapSizes.Length == MetadataTokens.HeapCount); |
| | | 131 | | |
| | 0 | 132 | | RowCounts = rowCounts; |
| | 0 | 133 | | ExternalRowCounts = externalRowCounts; |
| | 0 | 134 | | HeapSizes = heapSizes; |
| | | 135 | | |
| | | 136 | | // +1 for NUL terminator |
| | 0 | 137 | | MetadataVersionPaddedLength = BitArithmetic.Align(metadataVersionByteCount + 1, 4); |
| | | 138 | | |
| | 0 | 139 | | PresentTablesMask = ComputeNonEmptyTableMask(rowCounts); |
| | 0 | 140 | | 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. |
| | 0 | 145 | | bool isEncDelta = IsPresent(TableIndex.EncLog) || IsPresent(TableIndex.EncMap); |
| | 0 | 146 | | bool isCompressed = !isEncDelta; |
| | | 147 | | |
| | 0 | 148 | | IsEncDelta = isEncDelta; |
| | 0 | 149 | | IsCompressed = isCompressed; |
| | | 150 | | |
| | 0 | 151 | | BlobReferenceIsSmall = isCompressed && heapSizes[(int)HeapIndex.Blob] <= ushort.MaxValue; |
| | 0 | 152 | | StringReferenceIsSmall = isCompressed && heapSizes[(int)HeapIndex.String] <= ushort.MaxValue; |
| | 0 | 153 | | GuidReferenceIsSmall = isCompressed && heapSizes[(int)HeapIndex.Guid] <= ushort.MaxValue; |
| | | 154 | | |
| | | 155 | | // table can either be present or external, it can't be both: |
| | 0 | 156 | | Debug.Assert((PresentTablesMask & ExternalTablesMask) == 0); |
| | | 157 | | |
| | 0 | 158 | | CustomAttributeTypeCodedIndexIsSmall = IsReferenceSmall(3, TableIndex.MethodDef, TableIndex.MemberRef); |
| | 0 | 159 | | DeclSecurityCodedIndexIsSmall = IsReferenceSmall(2, TableIndex.MethodDef, TableIndex.TypeDef); |
| | 0 | 160 | | EventDefReferenceIsSmall = IsReferenceSmall(0, TableIndex.Event); |
| | 0 | 161 | | FieldDefReferenceIsSmall = IsReferenceSmall(0, TableIndex.Field); |
| | 0 | 162 | | GenericParamReferenceIsSmall = IsReferenceSmall(0, TableIndex.GenericParam); |
| | 0 | 163 | | HasConstantCodedIndexIsSmall = IsReferenceSmall(2, TableIndex.Field, TableIndex.Param, TableIndex.Property); |
| | | 164 | | |
| | 0 | 165 | | HasCustomAttributeCodedIndexIsSmall = IsReferenceSmall(5, |
| | 0 | 166 | | TableIndex.MethodDef, |
| | 0 | 167 | | TableIndex.Field, |
| | 0 | 168 | | TableIndex.TypeRef, |
| | 0 | 169 | | TableIndex.TypeDef, |
| | 0 | 170 | | TableIndex.Param, |
| | 0 | 171 | | TableIndex.InterfaceImpl, |
| | 0 | 172 | | TableIndex.MemberRef, |
| | 0 | 173 | | TableIndex.Module, |
| | 0 | 174 | | TableIndex.DeclSecurity, |
| | 0 | 175 | | TableIndex.Property, |
| | 0 | 176 | | TableIndex.Event, |
| | 0 | 177 | | TableIndex.StandAloneSig, |
| | 0 | 178 | | TableIndex.ModuleRef, |
| | 0 | 179 | | TableIndex.TypeSpec, |
| | 0 | 180 | | TableIndex.Assembly, |
| | 0 | 181 | | TableIndex.AssemblyRef, |
| | 0 | 182 | | TableIndex.File, |
| | 0 | 183 | | TableIndex.ExportedType, |
| | 0 | 184 | | TableIndex.ManifestResource, |
| | 0 | 185 | | TableIndex.GenericParam, |
| | 0 | 186 | | TableIndex.GenericParamConstraint, |
| | 0 | 187 | | TableIndex.MethodSpec); |
| | | 188 | | |
| | 0 | 189 | | HasFieldMarshalCodedIndexIsSmall = IsReferenceSmall(1, TableIndex.Field, TableIndex.Param); |
| | 0 | 190 | | HasSemanticsCodedIndexIsSmall = IsReferenceSmall(1, TableIndex.Event, TableIndex.Property); |
| | 0 | 191 | | ImplementationCodedIndexIsSmall = IsReferenceSmall(2, TableIndex.File, TableIndex.AssemblyRef, TableIndex.Ex |
| | 0 | 192 | | MemberForwardedCodedIndexIsSmall = IsReferenceSmall(1, TableIndex.Field, TableIndex.MethodDef); |
| | 0 | 193 | | MemberRefParentCodedIndexIsSmall = IsReferenceSmall(3, TableIndex.TypeDef, TableIndex.TypeRef, TableIndex.Mo |
| | 0 | 194 | | MethodDefReferenceIsSmall = IsReferenceSmall(0, TableIndex.MethodDef); |
| | 0 | 195 | | MethodDefOrRefCodedIndexIsSmall = IsReferenceSmall(1, TableIndex.MethodDef, TableIndex.MemberRef); |
| | 0 | 196 | | ModuleRefReferenceIsSmall = IsReferenceSmall(0, TableIndex.ModuleRef); |
| | 0 | 197 | | ParameterReferenceIsSmall = IsReferenceSmall(0, TableIndex.Param); |
| | 0 | 198 | | PropertyDefReferenceIsSmall = IsReferenceSmall(0, TableIndex.Property); |
| | 0 | 199 | | ResolutionScopeCodedIndexIsSmall = IsReferenceSmall(2, TableIndex.Module, TableIndex.ModuleRef, TableIndex.A |
| | 0 | 200 | | TypeDefReferenceIsSmall = IsReferenceSmall(0, TableIndex.TypeDef); |
| | 0 | 201 | | TypeDefOrRefCodedIndexIsSmall = IsReferenceSmall(2, TableIndex.TypeDef, TableIndex.TypeRef, TableIndex.TypeS |
| | 0 | 202 | | TypeOrMethodDefCodedIndexIsSmall = IsReferenceSmall(1, TableIndex.TypeDef, TableIndex.MethodDef); |
| | | 203 | | |
| | 0 | 204 | | DocumentReferenceIsSmall = IsReferenceSmall(0, TableIndex.Document); |
| | 0 | 205 | | LocalVariableReferenceIsSmall = IsReferenceSmall(0, TableIndex.LocalVariable); |
| | 0 | 206 | | LocalConstantReferenceIsSmall = IsReferenceSmall(0, TableIndex.LocalConstant); |
| | 0 | 207 | | ImportScopeReferenceIsSmall = IsReferenceSmall(0, TableIndex.ImportScope); |
| | | 208 | | |
| | 0 | 209 | | HasCustomDebugInformationCodedIndexIsSmall = IsReferenceSmall(5, |
| | 0 | 210 | | TableIndex.MethodDef, |
| | 0 | 211 | | TableIndex.Field, |
| | 0 | 212 | | TableIndex.TypeRef, |
| | 0 | 213 | | TableIndex.TypeDef, |
| | 0 | 214 | | TableIndex.Param, |
| | 0 | 215 | | TableIndex.InterfaceImpl, |
| | 0 | 216 | | TableIndex.MemberRef, |
| | 0 | 217 | | TableIndex.Module, |
| | 0 | 218 | | TableIndex.DeclSecurity, |
| | 0 | 219 | | TableIndex.Property, |
| | 0 | 220 | | TableIndex.Event, |
| | 0 | 221 | | TableIndex.StandAloneSig, |
| | 0 | 222 | | TableIndex.ModuleRef, |
| | 0 | 223 | | TableIndex.TypeSpec, |
| | 0 | 224 | | TableIndex.Assembly, |
| | 0 | 225 | | TableIndex.AssemblyRef, |
| | 0 | 226 | | TableIndex.File, |
| | 0 | 227 | | TableIndex.ExportedType, |
| | 0 | 228 | | TableIndex.ManifestResource, |
| | 0 | 229 | | TableIndex.GenericParam, |
| | 0 | 230 | | TableIndex.GenericParamConstraint, |
| | 0 | 231 | | TableIndex.MethodSpec, |
| | 0 | 232 | | TableIndex.Document, |
| | 0 | 233 | | TableIndex.LocalScope, |
| | 0 | 234 | | TableIndex.LocalVariable, |
| | 0 | 235 | | TableIndex.LocalConstant, |
| | 0 | 236 | | TableIndex.ImportScope); |
| | | 237 | | |
| | 0 | 238 | | int size = CalculateTableStreamHeaderSize(); |
| | | 239 | | |
| | | 240 | | const byte small = 2; |
| | | 241 | | const byte large = 4; |
| | | 242 | | |
| | 0 | 243 | | byte blobReferenceSize = BlobReferenceIsSmall ? small : large; |
| | 0 | 244 | | byte stringReferenceSize = StringReferenceIsSmall ? small : large; |
| | 0 | 245 | | byte guidReferenceSize = GuidReferenceIsSmall ? small : large; |
| | 0 | 246 | | byte customAttributeTypeCodedIndexSize = CustomAttributeTypeCodedIndexIsSmall ? small : large; |
| | 0 | 247 | | byte declSecurityCodedIndexSize = DeclSecurityCodedIndexIsSmall ? small : large; |
| | 0 | 248 | | byte eventDefReferenceSize = EventDefReferenceIsSmall ? small : large; |
| | 0 | 249 | | byte fieldDefReferenceSize = FieldDefReferenceIsSmall ? small : large; |
| | 0 | 250 | | byte genericParamReferenceSize = GenericParamReferenceIsSmall ? small : large; |
| | 0 | 251 | | byte hasConstantCodedIndexSize = HasConstantCodedIndexIsSmall ? small : large; |
| | 0 | 252 | | byte hasCustomAttributeCodedIndexSize = HasCustomAttributeCodedIndexIsSmall ? small : large; |
| | 0 | 253 | | byte hasFieldMarshalCodedIndexSize = HasFieldMarshalCodedIndexIsSmall ? small : large; |
| | 0 | 254 | | byte hasSemanticsCodedIndexSize = HasSemanticsCodedIndexIsSmall ? small : large; |
| | 0 | 255 | | byte implementationCodedIndexSize = ImplementationCodedIndexIsSmall ? small : large; |
| | 0 | 256 | | byte memberForwardedCodedIndexSize = MemberForwardedCodedIndexIsSmall ? small : large; |
| | 0 | 257 | | byte memberRefParentCodedIndexSize = MemberRefParentCodedIndexIsSmall ? small : large; |
| | 0 | 258 | | byte methodDefReferenceSize = MethodDefReferenceIsSmall ? small : large; |
| | 0 | 259 | | byte methodDefOrRefCodedIndexSize = MethodDefOrRefCodedIndexIsSmall ? small : large; |
| | 0 | 260 | | byte moduleRefReferenceSize = ModuleRefReferenceIsSmall ? small : large; |
| | 0 | 261 | | byte parameterReferenceSize = ParameterReferenceIsSmall ? small : large; |
| | 0 | 262 | | byte propertyDefReferenceSize = PropertyDefReferenceIsSmall ? small : large; |
| | 0 | 263 | | byte resolutionScopeCodedIndexSize = ResolutionScopeCodedIndexIsSmall ? small : large; |
| | 0 | 264 | | byte typeDefReferenceSize = TypeDefReferenceIsSmall ? small : large; |
| | 0 | 265 | | byte typeDefOrRefCodedIndexSize = TypeDefOrRefCodedIndexIsSmall ? small : large; |
| | 0 | 266 | | byte typeOrMethodDefCodedIndexSize = TypeOrMethodDefCodedIndexIsSmall ? small : large; |
| | 0 | 267 | | byte documentReferenceSize = DocumentReferenceIsSmall ? small : large; |
| | 0 | 268 | | byte localVariableReferenceSize = LocalVariableReferenceIsSmall ? small : large; |
| | 0 | 269 | | byte localConstantReferenceSize = LocalConstantReferenceIsSmall ? small : large; |
| | 0 | 270 | | byte importScopeReferenceSize = ImportScopeReferenceIsSmall ? small : large; |
| | 0 | 271 | | byte hasCustomDebugInformationCodedIndexSize = HasCustomDebugInformationCodedIndexIsSmall ? small : large; |
| | | 272 | | |
| | 0 | 273 | | size += GetTableSize(TableIndex.Module, 2 + 3 * guidReferenceSize + stringReferenceSize); |
| | 0 | 274 | | size += GetTableSize(TableIndex.TypeRef, resolutionScopeCodedIndexSize + stringReferenceSize + stringReferen |
| | 0 | 275 | | size += GetTableSize(TableIndex.TypeDef, 4 + stringReferenceSize + stringReferenceSize + typeDefOrRefCodedIn |
| | 0 | 276 | | Debug.Assert(rowCounts[(int)TableIndex.FieldPtr] == 0); |
| | 0 | 277 | | size += GetTableSize(TableIndex.Field, 2 + stringReferenceSize + blobReferenceSize); |
| | 0 | 278 | | Debug.Assert(rowCounts[(int)TableIndex.MethodPtr] == 0); |
| | 0 | 279 | | size += GetTableSize(TableIndex.MethodDef, 8 + stringReferenceSize + blobReferenceSize + parameterReferenceS |
| | 0 | 280 | | Debug.Assert(rowCounts[(int)TableIndex.ParamPtr] == 0); |
| | 0 | 281 | | size += GetTableSize(TableIndex.Param, 4 + stringReferenceSize); |
| | 0 | 282 | | size += GetTableSize(TableIndex.InterfaceImpl, typeDefReferenceSize + typeDefOrRefCodedIndexSize); |
| | 0 | 283 | | size += GetTableSize(TableIndex.MemberRef, memberRefParentCodedIndexSize + stringReferenceSize + blobReferen |
| | 0 | 284 | | size += GetTableSize(TableIndex.Constant, 2 + hasConstantCodedIndexSize + blobReferenceSize); |
| | 0 | 285 | | size += GetTableSize(TableIndex.CustomAttribute, hasCustomAttributeCodedIndexSize + customAttributeTypeCoded |
| | 0 | 286 | | size += GetTableSize(TableIndex.FieldMarshal, hasFieldMarshalCodedIndexSize + blobReferenceSize); |
| | 0 | 287 | | size += GetTableSize(TableIndex.DeclSecurity, 2 + declSecurityCodedIndexSize + blobReferenceSize); |
| | 0 | 288 | | size += GetTableSize(TableIndex.ClassLayout, 6 + typeDefReferenceSize); |
| | 0 | 289 | | size += GetTableSize(TableIndex.FieldLayout, 4 + fieldDefReferenceSize); |
| | 0 | 290 | | size += GetTableSize(TableIndex.StandAloneSig, blobReferenceSize); |
| | 0 | 291 | | size += GetTableSize(TableIndex.EventMap, typeDefReferenceSize + eventDefReferenceSize); |
| | 0 | 292 | | Debug.Assert(rowCounts[(int)TableIndex.EventPtr] == 0); |
| | 0 | 293 | | size += GetTableSize(TableIndex.Event, 2 + stringReferenceSize + typeDefOrRefCodedIndexSize); |
| | 0 | 294 | | size += GetTableSize(TableIndex.PropertyMap, typeDefReferenceSize + propertyDefReferenceSize); |
| | 0 | 295 | | Debug.Assert(rowCounts[(int)TableIndex.PropertyPtr] == 0); |
| | 0 | 296 | | size += GetTableSize(TableIndex.Property, 2 + stringReferenceSize + blobReferenceSize); |
| | 0 | 297 | | size += GetTableSize(TableIndex.MethodSemantics, 2 + methodDefReferenceSize + hasSemanticsCodedIndexSize); |
| | 0 | 298 | | size += GetTableSize(TableIndex.MethodImpl, typeDefReferenceSize + methodDefOrRefCodedIndexSize + methodDefO |
| | 0 | 299 | | size += GetTableSize(TableIndex.ModuleRef, stringReferenceSize); |
| | 0 | 300 | | size += GetTableSize(TableIndex.TypeSpec, blobReferenceSize); |
| | 0 | 301 | | size += GetTableSize(TableIndex.ImplMap, 2 + memberForwardedCodedIndexSize + stringReferenceSize + moduleRef |
| | 0 | 302 | | size += GetTableSize(TableIndex.FieldRva, 4 + fieldDefReferenceSize); |
| | 0 | 303 | | size += GetTableSize(TableIndex.EncLog, 8); |
| | 0 | 304 | | size += GetTableSize(TableIndex.EncMap, 4); |
| | 0 | 305 | | size += GetTableSize(TableIndex.Assembly, 16 + blobReferenceSize + stringReferenceSize + stringReferenceSize |
| | 0 | 306 | | Debug.Assert(rowCounts[(int)TableIndex.AssemblyProcessor] == 0); |
| | 0 | 307 | | Debug.Assert(rowCounts[(int)TableIndex.AssemblyOS] == 0); |
| | 0 | 308 | | size += GetTableSize(TableIndex.AssemblyRef, 12 + blobReferenceSize + stringReferenceSize + stringReferenceS |
| | 0 | 309 | | Debug.Assert(rowCounts[(int)TableIndex.AssemblyRefProcessor] == 0); |
| | 0 | 310 | | Debug.Assert(rowCounts[(int)TableIndex.AssemblyRefOS] == 0); |
| | 0 | 311 | | size += GetTableSize(TableIndex.File, 4 + stringReferenceSize + blobReferenceSize); |
| | 0 | 312 | | size += GetTableSize(TableIndex.ExportedType, 8 + stringReferenceSize + stringReferenceSize + implementation |
| | 0 | 313 | | size += GetTableSize(TableIndex.ManifestResource, 8 + stringReferenceSize + implementationCodedIndexSize); |
| | 0 | 314 | | size += GetTableSize(TableIndex.NestedClass, typeDefReferenceSize + typeDefReferenceSize); |
| | 0 | 315 | | size += GetTableSize(TableIndex.GenericParam, 4 + typeOrMethodDefCodedIndexSize + stringReferenceSize); |
| | 0 | 316 | | size += GetTableSize(TableIndex.MethodSpec, methodDefOrRefCodedIndexSize + blobReferenceSize); |
| | 0 | 317 | | size += GetTableSize(TableIndex.GenericParamConstraint, genericParamReferenceSize + typeDefOrRefCodedIndexSi |
| | | 318 | | |
| | 0 | 319 | | size += GetTableSize(TableIndex.Document, blobReferenceSize + guidReferenceSize + blobReferenceSize + guidRe |
| | 0 | 320 | | size += GetTableSize(TableIndex.MethodDebugInformation, documentReferenceSize + blobReferenceSize); |
| | 0 | 321 | | size += GetTableSize(TableIndex.LocalScope, methodDefReferenceSize + importScopeReferenceSize + localVariabl |
| | 0 | 322 | | size += GetTableSize(TableIndex.LocalVariable, 2 + 2 + stringReferenceSize); |
| | 0 | 323 | | size += GetTableSize(TableIndex.LocalConstant, stringReferenceSize + blobReferenceSize); |
| | 0 | 324 | | size += GetTableSize(TableIndex.ImportScope, importScopeReferenceSize + blobReferenceSize); |
| | 0 | 325 | | size += GetTableSize(TableIndex.StateMachineMethod, methodDefReferenceSize + methodDefReferenceSize); |
| | 0 | 326 | | size += GetTableSize(TableIndex.CustomDebugInformation, hasCustomDebugInformationCodedIndexSize + guidRefere |
| | | 327 | | |
| | | 328 | | // +1 for terminating 0 byte |
| | 0 | 329 | | size = BitArithmetic.Align(size + 1, StreamAlignment); |
| | | 330 | | |
| | 0 | 331 | | MetadataTableStreamSize = size; |
| | | 332 | | |
| | 0 | 333 | | size += GetAlignedHeapSize(HeapIndex.String); |
| | 0 | 334 | | size += GetAlignedHeapSize(HeapIndex.UserString); |
| | 0 | 335 | | size += GetAlignedHeapSize(HeapIndex.Guid); |
| | 0 | 336 | | size += GetAlignedHeapSize(HeapIndex.Blob); |
| | | 337 | | |
| | 0 | 338 | | StandalonePdbStreamSize = isStandaloneDebugMetadata ? CalculateStandalonePdbStreamSize() : 0; |
| | 0 | 339 | | size += StandalonePdbStreamSize; |
| | | 340 | | |
| | 0 | 341 | | MetadataStreamStorageSize = size; |
| | 0 | 342 | | } |
| | | 343 | | |
| | 0 | 344 | | internal bool IsStandaloneDebugMetadata => StandalonePdbStreamSize > 0; |
| | | 345 | | |
| | 0 | 346 | | 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 |
| | 0 | 358 | | { |
| | | 359 | | const int RegularStreamHeaderSizes = 76; |
| | | 360 | | const int EncDeltaMarkerStreamHeaderSize = 16; |
| | | 361 | | const int StandalonePdbStreamHeaderSize = 16; |
| | | 362 | | |
| | 0 | 363 | | Debug.Assert(RegularStreamHeaderSizes == |
| | 0 | 364 | | GetMetadataStreamHeaderSize("#~"u8) + |
| | 0 | 365 | | GetMetadataStreamHeaderSize("#Strings"u8) + |
| | 0 | 366 | | GetMetadataStreamHeaderSize("#US"u8) + |
| | 0 | 367 | | GetMetadataStreamHeaderSize("#GUID"u8) + |
| | 0 | 368 | | GetMetadataStreamHeaderSize("#Blob"u8)); |
| | | 369 | | |
| | 0 | 370 | | Debug.Assert(EncDeltaMarkerStreamHeaderSize == GetMetadataStreamHeaderSize("#JTD"u8)); |
| | 0 | 371 | | Debug.Assert(StandalonePdbStreamHeaderSize == GetMetadataStreamHeaderSize("#Pdb"u8)); |
| | | 372 | | |
| | 0 | 373 | | return |
| | 0 | 374 | | sizeof(uint) + // signature |
| | 0 | 375 | | sizeof(ushort) + // major version |
| | 0 | 376 | | sizeof(ushort) + // minor version |
| | 0 | 377 | | sizeof(uint) + // reserved |
| | 0 | 378 | | sizeof(uint) + // padded metadata version length |
| | 0 | 379 | | MetadataVersionPaddedLength + // metadata version |
| | 0 | 380 | | sizeof(ushort) + // storage header: reserved |
| | 0 | 381 | | sizeof(ushort) + // stream count |
| | 0 | 382 | | (IsStandaloneDebugMetadata ? StandalonePdbStreamHeaderSize : 0) + |
| | 0 | 383 | | RegularStreamHeaderSizes + |
| | 0 | 384 | | (IsEncDelta ? EncDeltaMarkerStreamHeaderSize : 0); |
| | 0 | 385 | | } |
| | | 386 | | } |
| | | 387 | | |
| | | 388 | | internal static int GetMetadataStreamHeaderSize(ReadOnlySpan<byte> streamName) |
| | 0 | 389 | | { |
| | 0 | 390 | | return |
| | 0 | 391 | | sizeof(int) + // offset |
| | 0 | 392 | | sizeof(int) + // size |
| | 0 | 393 | | BitArithmetic.Align(streamName.Length + 1, 4); // zero-terminated name, padding |
| | 0 | 394 | | } |
| | | 395 | | |
| | | 396 | | /// <summary> |
| | | 397 | | /// Total size of metadata (header and all streams). |
| | | 398 | | /// </summary> |
| | 0 | 399 | | internal int MetadataSize => MetadataHeaderSize + MetadataStreamStorageSize; |
| | | 400 | | |
| | | 401 | | /// <summary> |
| | | 402 | | /// Returns aligned size of the specified heap. |
| | | 403 | | /// </summary> |
| | | 404 | | public int GetAlignedHeapSize(HeapIndex index) |
| | 0 | 405 | | { |
| | 0 | 406 | | int i = (int)index; |
| | 0 | 407 | | if (i < 0 || i > HeapSizes.Length) |
| | 0 | 408 | | { |
| | 0 | 409 | | Throw.ArgumentOutOfRange(nameof(index)); |
| | | 410 | | } |
| | | 411 | | |
| | 0 | 412 | | return BitArithmetic.Align(HeapSizes[i], StreamAlignment); |
| | 0 | 413 | | } |
| | | 414 | | |
| | | 415 | | internal int CalculateTableStreamHeaderSize() |
| | 0 | 416 | | { |
| | 0 | 417 | | int result = sizeof(int) + // Reserved |
| | 0 | 418 | | sizeof(short) + // Version (major, minor) |
| | 0 | 419 | | sizeof(byte) + // Heap index sizes |
| | 0 | 420 | | sizeof(byte) + // Bit width of RowId |
| | 0 | 421 | | sizeof(long) + // Valid table mask |
| | 0 | 422 | | sizeof(long); // Sorted table mask |
| | | 423 | | |
| | | 424 | | // present table row counts |
| | 0 | 425 | | for (int i = 0; i < RowCounts.Length; i++) |
| | 0 | 426 | | { |
| | 0 | 427 | | if (((1UL << i) & PresentTablesMask) != 0) |
| | 0 | 428 | | { |
| | 0 | 429 | | result += sizeof(int); |
| | 0 | 430 | | } |
| | 0 | 431 | | } |
| | | 432 | | |
| | 0 | 433 | | return result; |
| | 0 | 434 | | } |
| | | 435 | | |
| | | 436 | | internal const int PdbIdSize = 20; |
| | | 437 | | |
| | | 438 | | internal int CalculateStandalonePdbStreamSize() |
| | 0 | 439 | | { |
| | 0 | 440 | | int result = |
| | 0 | 441 | | PdbIdSize + // PDB ID |
| | 0 | 442 | | sizeof(int) + // EntryPoint |
| | 0 | 443 | | sizeof(long) + // ReferencedTypeSystemTables |
| | 0 | 444 | | BitOperations.PopCount(ExternalTablesMask) * sizeof(int); // External row counts |
| | | 445 | | |
| | 0 | 446 | | Debug.Assert(result % StreamAlignment == 0); |
| | 0 | 447 | | return result; |
| | 0 | 448 | | } |
| | | 449 | | |
| | | 450 | | private static ulong ComputeNonEmptyTableMask(ImmutableArray<int> rowCounts) |
| | 0 | 451 | | { |
| | 0 | 452 | | ulong mask = 0; |
| | 0 | 453 | | for (int i = 0; i < rowCounts.Length; i++) |
| | 0 | 454 | | { |
| | 0 | 455 | | if (rowCounts[i] > 0) |
| | 0 | 456 | | { |
| | 0 | 457 | | mask |= (1UL << i); |
| | 0 | 458 | | } |
| | 0 | 459 | | } |
| | | 460 | | |
| | 0 | 461 | | return mask; |
| | 0 | 462 | | } |
| | | 463 | | |
| | | 464 | | private int GetTableSize(TableIndex index, int rowSize) |
| | 0 | 465 | | { |
| | 0 | 466 | | return RowCounts[(int)index] * rowSize; |
| | 0 | 467 | | } |
| | | 468 | | |
| | | 469 | | private bool IsReferenceSmall(int tagBitSize, params TableIndex[] tables) |
| | 0 | 470 | | { |
| | | 471 | | const int smallBitCount = 16; |
| | 0 | 472 | | return IsCompressed && ReferenceFits(smallBitCount - tagBitSize, tables); |
| | 0 | 473 | | } |
| | | 474 | | |
| | | 475 | | private bool ReferenceFits(int bitCount, TableIndex[] tables) |
| | 0 | 476 | | { |
| | 0 | 477 | | int maxIndex = (1 << bitCount) - 1; |
| | 0 | 478 | | foreach (TableIndex table in tables) |
| | 0 | 479 | | { |
| | | 480 | | // table can be either local or external, but not both: |
| | 0 | 481 | | Debug.Assert(RowCounts[(int)table] == 0 || ExternalRowCounts[(int)table] == 0); |
| | | 482 | | |
| | 0 | 483 | | if (RowCounts[(int)table] + ExternalRowCounts[(int)table] > maxIndex) |
| | 0 | 484 | | { |
| | 0 | 485 | | return false; |
| | | 486 | | } |
| | 0 | 487 | | } |
| | | 488 | | |
| | 0 | 489 | | return true; |
| | 0 | 490 | | } |
| | | 491 | | } |
| | | 492 | | } |
| | | 493 | | |