| | | 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.Diagnostics; |
| | | 5 | | |
| | | 6 | | namespace System.Reflection.Metadata.Ecma335 |
| | | 7 | | { |
| | | 8 | | internal enum MetadataStreamKind |
| | | 9 | | { |
| | | 10 | | Illegal, |
| | | 11 | | Compressed, |
| | | 12 | | Uncompressed, |
| | | 13 | | } |
| | | 14 | | |
| | | 15 | | [Flags] |
| | | 16 | | internal enum TableMask : ulong |
| | | 17 | | { |
| | | 18 | | Module = 1UL << TableIndex.Module, |
| | | 19 | | TypeRef = 1UL << TableIndex.TypeRef, |
| | | 20 | | TypeDef = 1UL << TableIndex.TypeDef, |
| | | 21 | | FieldPtr = 1UL << TableIndex.FieldPtr, |
| | | 22 | | Field = 1UL << TableIndex.Field, |
| | | 23 | | MethodPtr = 1UL << TableIndex.MethodPtr, |
| | | 24 | | MethodDef = 1UL << TableIndex.MethodDef, |
| | | 25 | | ParamPtr = 1UL << TableIndex.ParamPtr, |
| | | 26 | | Param = 1UL << TableIndex.Param, |
| | | 27 | | InterfaceImpl = 1UL << TableIndex.InterfaceImpl, |
| | | 28 | | MemberRef = 1UL << TableIndex.MemberRef, |
| | | 29 | | Constant = 1UL << TableIndex.Constant, |
| | | 30 | | CustomAttribute = 1UL << TableIndex.CustomAttribute, |
| | | 31 | | FieldMarshal = 1UL << TableIndex.FieldMarshal, |
| | | 32 | | DeclSecurity = 1UL << TableIndex.DeclSecurity, |
| | | 33 | | ClassLayout = 1UL << TableIndex.ClassLayout, |
| | | 34 | | FieldLayout = 1UL << TableIndex.FieldLayout, |
| | | 35 | | StandAloneSig = 1UL << TableIndex.StandAloneSig, |
| | | 36 | | EventMap = 1UL << TableIndex.EventMap, |
| | | 37 | | EventPtr = 1UL << TableIndex.EventPtr, |
| | | 38 | | Event = 1UL << TableIndex.Event, |
| | | 39 | | PropertyMap = 1UL << TableIndex.PropertyMap, |
| | | 40 | | PropertyPtr = 1UL << TableIndex.PropertyPtr, |
| | | 41 | | Property = 1UL << TableIndex.Property, |
| | | 42 | | MethodSemantics = 1UL << TableIndex.MethodSemantics, |
| | | 43 | | MethodImpl = 1UL << TableIndex.MethodImpl, |
| | | 44 | | ModuleRef = 1UL << TableIndex.ModuleRef, |
| | | 45 | | TypeSpec = 1UL << TableIndex.TypeSpec, |
| | | 46 | | ImplMap = 1UL << TableIndex.ImplMap, |
| | | 47 | | FieldRva = 1UL << TableIndex.FieldRva, |
| | | 48 | | EnCLog = 1UL << TableIndex.EncLog, |
| | | 49 | | EnCMap = 1UL << TableIndex.EncMap, |
| | | 50 | | Assembly = 1UL << TableIndex.Assembly, |
| | | 51 | | // AssemblyProcessor = 1UL << TableIndices.AssemblyProcessor, |
| | | 52 | | // AssemblyOS = 1UL << TableIndices.AssemblyOS, |
| | | 53 | | AssemblyRef = 1UL << TableIndex.AssemblyRef, |
| | | 54 | | // AssemblyRefProcessor = 1UL << TableIndices.AssemblyRefProcessor, |
| | | 55 | | // AssemblyRefOS = 1UL << TableIndices.AssemblyRefOS, |
| | | 56 | | File = 1UL << TableIndex.File, |
| | | 57 | | ExportedType = 1UL << TableIndex.ExportedType, |
| | | 58 | | ManifestResource = 1UL << TableIndex.ManifestResource, |
| | | 59 | | NestedClass = 1UL << TableIndex.NestedClass, |
| | | 60 | | GenericParam = 1UL << TableIndex.GenericParam, |
| | | 61 | | MethodSpec = 1UL << TableIndex.MethodSpec, |
| | | 62 | | GenericParamConstraint = 1UL << TableIndex.GenericParamConstraint, |
| | | 63 | | |
| | | 64 | | Document = 1UL << TableIndex.Document, |
| | | 65 | | MethodDebugInformation = 1UL << TableIndex.MethodDebugInformation, |
| | | 66 | | LocalScope = 1UL << TableIndex.LocalScope, |
| | | 67 | | LocalVariable = 1UL << TableIndex.LocalVariable, |
| | | 68 | | LocalConstant = 1UL << TableIndex.LocalConstant, |
| | | 69 | | ImportScope = 1UL << TableIndex.ImportScope, |
| | | 70 | | StateMachineMethod = 1UL << TableIndex.StateMachineMethod, |
| | | 71 | | CustomDebugInformation = 1UL << TableIndex.CustomDebugInformation, |
| | | 72 | | |
| | | 73 | | PtrTables = |
| | | 74 | | FieldPtr |
| | | 75 | | | MethodPtr |
| | | 76 | | | ParamPtr |
| | | 77 | | | EventPtr |
| | | 78 | | | PropertyPtr, |
| | | 79 | | |
| | | 80 | | EncTables = |
| | | 81 | | EnCLog |
| | | 82 | | | EnCMap, |
| | | 83 | | |
| | | 84 | | TypeSystemTables = |
| | | 85 | | PtrTables |
| | | 86 | | | EncTables |
| | | 87 | | | Module |
| | | 88 | | | TypeRef |
| | | 89 | | | TypeDef |
| | | 90 | | | Field |
| | | 91 | | | MethodDef |
| | | 92 | | | Param |
| | | 93 | | | InterfaceImpl |
| | | 94 | | | MemberRef |
| | | 95 | | | Constant |
| | | 96 | | | CustomAttribute |
| | | 97 | | | FieldMarshal |
| | | 98 | | | DeclSecurity |
| | | 99 | | | ClassLayout |
| | | 100 | | | FieldLayout |
| | | 101 | | | StandAloneSig |
| | | 102 | | | EventMap |
| | | 103 | | | Event |
| | | 104 | | | PropertyMap |
| | | 105 | | | Property |
| | | 106 | | | MethodSemantics |
| | | 107 | | | MethodImpl |
| | | 108 | | | ModuleRef |
| | | 109 | | | TypeSpec |
| | | 110 | | | ImplMap |
| | | 111 | | | FieldRva |
| | | 112 | | | Assembly |
| | | 113 | | | AssemblyRef |
| | | 114 | | | File |
| | | 115 | | | ExportedType |
| | | 116 | | | ManifestResource |
| | | 117 | | | NestedClass |
| | | 118 | | | GenericParam |
| | | 119 | | | MethodSpec |
| | | 120 | | | GenericParamConstraint, |
| | | 121 | | |
| | | 122 | | DebugTables = |
| | | 123 | | Document |
| | | 124 | | | MethodDebugInformation |
| | | 125 | | | LocalScope |
| | | 126 | | | LocalVariable |
| | | 127 | | | LocalConstant |
| | | 128 | | | ImportScope |
| | | 129 | | | StateMachineMethod |
| | | 130 | | | CustomDebugInformation, |
| | | 131 | | |
| | | 132 | | AllTables = |
| | | 133 | | TypeSystemTables | |
| | | 134 | | DebugTables, |
| | | 135 | | |
| | | 136 | | ValidPortablePdbExternalTables = |
| | | 137 | | TypeSystemTables & ~PtrTables & ~EncTables |
| | | 138 | | } |
| | | 139 | | |
| | | 140 | | internal enum HeapSizes : byte |
| | | 141 | | { |
| | | 142 | | StringHeapLarge = 0x01, // 4 byte uint indexes used for string heap offsets |
| | | 143 | | GuidHeapLarge = 0x02, // 4 byte uint indexes used for GUID heap offsets |
| | | 144 | | BlobHeapLarge = 0x04, // 4 byte uint indexes used for Blob heap offsets |
| | | 145 | | ExtraData = 0x40, // Indicates that there is an extra 4 bytes of data immediately after the row counts |
| | | 146 | | } |
| | | 147 | | |
| | | 148 | | internal enum StringKind : byte |
| | | 149 | | { |
| | | 150 | | Plain = (byte)(StringHandleType.String >> HeapHandleType.OffsetBitCount), |
| | | 151 | | Virtual = (byte)(StringHandleType.VirtualString >> HeapHandleType.OffsetBitCount), |
| | | 152 | | WinRTPrefixed = (byte)(StringHandleType.WinRTPrefixedString >> HeapHandleType.OffsetBitCount), |
| | | 153 | | DotTerminated = (byte)(StringHandleType.DotTerminatedString >> HeapHandleType.OffsetBitCount), |
| | | 154 | | } |
| | | 155 | | |
| | | 156 | | internal static class StringHandleType |
| | | 157 | | { |
| | | 158 | | // The 3 high bits above the offset that specify the full string type (including virtual bit) |
| | | 159 | | internal const uint TypeMask = ~(HeapHandleType.OffsetMask); |
| | | 160 | | |
| | | 161 | | // The string type bits excluding the virtual bit. |
| | | 162 | | internal const uint NonVirtualTypeMask = TypeMask & ~(HeapHandleType.VirtualBit); |
| | | 163 | | |
| | | 164 | | // NUL-terminated UTF8 string on a #String heap. |
| | | 165 | | internal const uint String = (0 << HeapHandleType.OffsetBitCount); |
| | | 166 | | |
| | | 167 | | // String on #String heap whose terminator is NUL and '.', whichever comes first. |
| | | 168 | | internal const uint DotTerminatedString = (1 << HeapHandleType.OffsetBitCount); |
| | | 169 | | |
| | | 170 | | // Reserved values that can be used for future strings: |
| | | 171 | | internal const uint ReservedString1 = (2 << HeapHandleType.OffsetBitCount); |
| | | 172 | | internal const uint ReservedString2 = (3 << HeapHandleType.OffsetBitCount); |
| | | 173 | | |
| | | 174 | | // Virtual string identified by a virtual index |
| | | 175 | | internal const uint VirtualString = HeapHandleType.VirtualBit | (0 << HeapHandleType.OffsetBitCount); |
| | | 176 | | |
| | | 177 | | // Virtual string whose value is a "<WinRT>" prefixed string found at the specified heap offset. |
| | | 178 | | internal const uint WinRTPrefixedString = HeapHandleType.VirtualBit | (1 << HeapHandleType.OffsetBitCount); |
| | | 179 | | |
| | | 180 | | // Reserved virtual strings that can be used in future: |
| | | 181 | | internal const uint ReservedVirtualString1 = HeapHandleType.VirtualBit | (2 << HeapHandleType.OffsetBitCount); |
| | | 182 | | internal const uint ReservedVirtualString2 = HeapHandleType.VirtualBit | (3 << HeapHandleType.OffsetBitCount); |
| | | 183 | | } |
| | | 184 | | |
| | | 185 | | internal static class HeapHandleType |
| | | 186 | | { |
| | | 187 | | // Heap offset values are limited to 29 bits (max compressed integer) |
| | | 188 | | internal const int OffsetBitCount = 29; |
| | | 189 | | internal const uint OffsetMask = (1 << OffsetBitCount) - 1; |
| | | 190 | | internal const uint VirtualBit = 0x80000000; |
| | | 191 | | |
| | | 192 | | internal static bool IsValidHeapOffset(uint offset) |
| | 0 | 193 | | { |
| | 0 | 194 | | return (offset & ~OffsetMask) == 0; |
| | 0 | 195 | | } |
| | | 196 | | } |
| | | 197 | | |
| | | 198 | | /// <summary> |
| | | 199 | | /// These constants are all in the byte range and apply to the interpretation of <see cref="Handle.VType"/>, |
| | | 200 | | /// </summary> |
| | | 201 | | internal static class HandleType |
| | | 202 | | { |
| | | 203 | | internal const uint Module = (uint)TableIndex.Module; |
| | | 204 | | internal const uint TypeRef = (uint)TableIndex.TypeRef; |
| | | 205 | | internal const uint TypeDef = (uint)TableIndex.TypeDef; |
| | | 206 | | internal const uint FieldDef = (uint)TableIndex.Field; |
| | | 207 | | internal const uint MethodDef = (uint)TableIndex.MethodDef; |
| | | 208 | | internal const uint ParamDef = (uint)TableIndex.Param; |
| | | 209 | | internal const uint InterfaceImpl = (uint)TableIndex.InterfaceImpl; |
| | | 210 | | internal const uint MemberRef = (uint)TableIndex.MemberRef; |
| | | 211 | | internal const uint Constant = (uint)TableIndex.Constant; |
| | | 212 | | internal const uint CustomAttribute = (uint)TableIndex.CustomAttribute; |
| | | 213 | | internal const uint DeclSecurity = (uint)TableIndex.DeclSecurity; |
| | | 214 | | internal const uint Signature = (uint)TableIndex.StandAloneSig; |
| | | 215 | | internal const uint EventMap = (uint)TableIndex.EventMap; |
| | | 216 | | internal const uint Event = (uint)TableIndex.Event; |
| | | 217 | | internal const uint PropertyMap = (uint)TableIndex.PropertyMap; |
| | | 218 | | internal const uint Property = (uint)TableIndex.Property; |
| | | 219 | | internal const uint MethodSemantics = (uint)TableIndex.MethodSemantics; |
| | | 220 | | internal const uint MethodImpl = (uint)TableIndex.MethodImpl; |
| | | 221 | | internal const uint ModuleRef = (uint)TableIndex.ModuleRef; |
| | | 222 | | internal const uint TypeSpec = (uint)TableIndex.TypeSpec; |
| | | 223 | | internal const uint Assembly = (uint)TableIndex.Assembly; |
| | | 224 | | internal const uint AssemblyRef = (uint)TableIndex.AssemblyRef; |
| | | 225 | | internal const uint File = (uint)TableIndex.File; |
| | | 226 | | internal const uint ExportedType = (uint)TableIndex.ExportedType; |
| | | 227 | | internal const uint ManifestResource = (uint)TableIndex.ManifestResource; |
| | | 228 | | internal const uint NestedClass = (uint)TableIndex.NestedClass; |
| | | 229 | | internal const uint GenericParam = (uint)TableIndex.GenericParam; |
| | | 230 | | internal const uint MethodSpec = (uint)TableIndex.MethodSpec; |
| | | 231 | | internal const uint GenericParamConstraint = (uint)TableIndex.GenericParamConstraint; |
| | | 232 | | |
| | | 233 | | // debug tables: |
| | | 234 | | internal const uint Document = (uint)TableIndex.Document; |
| | | 235 | | internal const uint MethodDebugInformation = (uint)TableIndex.MethodDebugInformation; |
| | | 236 | | internal const uint LocalScope = (uint)TableIndex.LocalScope; |
| | | 237 | | internal const uint LocalVariable = (uint)TableIndex.LocalVariable; |
| | | 238 | | internal const uint LocalConstant = (uint)TableIndex.LocalConstant; |
| | | 239 | | internal const uint ImportScope = (uint)TableIndex.ImportScope; |
| | | 240 | | internal const uint AsyncMethod = (uint)TableIndex.StateMachineMethod; |
| | | 241 | | internal const uint CustomDebugInformation = (uint)TableIndex.CustomDebugInformation; |
| | | 242 | | |
| | | 243 | | internal const uint UserString = 0x70; // #UserString heap |
| | | 244 | | |
| | | 245 | | // The following values never appear in a token stored in metadata, |
| | | 246 | | // they are just helper values to identify the type of a handle. |
| | | 247 | | // Note, however, that even though they do not come from the spec, |
| | | 248 | | // they are surfaced as public constants via HandleKind enum and |
| | | 249 | | // therefore cannot change! |
| | | 250 | | |
| | | 251 | | internal const uint Blob = 0x71; // #Blob heap |
| | | 252 | | internal const uint Guid = 0x72; // #Guid heap |
| | | 253 | | |
| | | 254 | | // #String heap and its modifications |
| | | 255 | | // |
| | | 256 | | // Multiple values are reserved for string handles so that we can encode special |
| | | 257 | | // handling with more than just the virtual bit. See StringHandleType for how |
| | | 258 | | // the two extra bits are actually interpreted. The extra String1,2,3 values here are |
| | | 259 | | // not used directly, but serve as a reminder that they are not available for use |
| | | 260 | | // by another handle type. |
| | | 261 | | internal const uint String = 0x78; |
| | | 262 | | internal const uint String1 = 0x79; |
| | | 263 | | internal const uint String2 = 0x7a; |
| | | 264 | | internal const uint String3 = 0x7b; |
| | | 265 | | |
| | | 266 | | // Namespace handles also have offsets into the #String heap (when non-virtual) |
| | | 267 | | // to their full name. However, this is an implementation detail and they are |
| | | 268 | | // surfaced with first-class HandleKind.Namespace and strongly-typed NamespaceHandle. |
| | | 269 | | internal const uint Namespace = 0x7c; |
| | | 270 | | |
| | | 271 | | internal const uint HeapMask = 0x70; |
| | | 272 | | internal const uint TypeMask = 0x7F; |
| | | 273 | | |
| | | 274 | | /// <summary> |
| | | 275 | | /// Use the highest bit to mark tokens that are virtual (synthesized). |
| | | 276 | | /// We create virtual tokens to represent projected WinMD entities. |
| | | 277 | | /// </summary> |
| | | 278 | | internal const uint VirtualBit = 0x80; |
| | | 279 | | |
| | | 280 | | /// <summary> |
| | | 281 | | /// In the case of string handles, the two lower bits that (in addition to the |
| | | 282 | | /// virtual bit not included in this mask) encode how to obtain the string value. |
| | | 283 | | /// </summary> |
| | | 284 | | internal const uint NonVirtualStringTypeMask = 0x03; |
| | | 285 | | } |
| | | 286 | | |
| | | 287 | | internal static class TokenTypeIds |
| | | 288 | | { |
| | | 289 | | internal const uint Module = HandleType.Module << RowIdBitCount; |
| | | 290 | | internal const uint TypeRef = HandleType.TypeRef << RowIdBitCount; |
| | | 291 | | internal const uint TypeDef = HandleType.TypeDef << RowIdBitCount; |
| | | 292 | | internal const uint FieldDef = HandleType.FieldDef << RowIdBitCount; |
| | | 293 | | internal const uint MethodDef = HandleType.MethodDef << RowIdBitCount; |
| | | 294 | | internal const uint ParamDef = HandleType.ParamDef << RowIdBitCount; |
| | | 295 | | internal const uint InterfaceImpl = HandleType.InterfaceImpl << RowIdBitCount; |
| | | 296 | | internal const uint MemberRef = HandleType.MemberRef << RowIdBitCount; |
| | | 297 | | internal const uint Constant = HandleType.Constant << RowIdBitCount; |
| | | 298 | | internal const uint CustomAttribute = HandleType.CustomAttribute << RowIdBitCount; |
| | | 299 | | internal const uint DeclSecurity = HandleType.DeclSecurity << RowIdBitCount; |
| | | 300 | | internal const uint Signature = HandleType.Signature << RowIdBitCount; |
| | | 301 | | internal const uint EventMap = HandleType.EventMap << RowIdBitCount; |
| | | 302 | | internal const uint Event = HandleType.Event << RowIdBitCount; |
| | | 303 | | internal const uint PropertyMap = HandleType.PropertyMap << RowIdBitCount; |
| | | 304 | | internal const uint Property = HandleType.Property << RowIdBitCount; |
| | | 305 | | internal const uint MethodSemantics = HandleType.MethodSemantics << RowIdBitCount; |
| | | 306 | | internal const uint MethodImpl = HandleType.MethodImpl << RowIdBitCount; |
| | | 307 | | internal const uint ModuleRef = HandleType.ModuleRef << RowIdBitCount; |
| | | 308 | | internal const uint TypeSpec = HandleType.TypeSpec << RowIdBitCount; |
| | | 309 | | internal const uint Assembly = HandleType.Assembly << RowIdBitCount; |
| | | 310 | | internal const uint AssemblyRef = HandleType.AssemblyRef << RowIdBitCount; |
| | | 311 | | internal const uint File = HandleType.File << RowIdBitCount; |
| | | 312 | | internal const uint ExportedType = HandleType.ExportedType << RowIdBitCount; |
| | | 313 | | internal const uint ManifestResource = HandleType.ManifestResource << RowIdBitCount; |
| | | 314 | | internal const uint NestedClass = HandleType.NestedClass << RowIdBitCount; |
| | | 315 | | internal const uint GenericParam = HandleType.GenericParam << RowIdBitCount; |
| | | 316 | | internal const uint MethodSpec = HandleType.MethodSpec << RowIdBitCount; |
| | | 317 | | internal const uint GenericParamConstraint = HandleType.GenericParamConstraint << RowIdBitCount; |
| | | 318 | | |
| | | 319 | | // debug tables: |
| | | 320 | | internal const uint Document = HandleType.Document << RowIdBitCount; |
| | | 321 | | internal const uint MethodDebugInformation = HandleType.MethodDebugInformation << RowIdBitCount; |
| | | 322 | | internal const uint LocalScope = HandleType.LocalScope << RowIdBitCount; |
| | | 323 | | internal const uint LocalVariable = HandleType.LocalVariable << RowIdBitCount; |
| | | 324 | | internal const uint LocalConstant = HandleType.LocalConstant << RowIdBitCount; |
| | | 325 | | internal const uint ImportScope = HandleType.ImportScope << RowIdBitCount; |
| | | 326 | | internal const uint AsyncMethod = HandleType.AsyncMethod << RowIdBitCount; |
| | | 327 | | internal const uint CustomDebugInformation = HandleType.CustomDebugInformation << RowIdBitCount; |
| | | 328 | | |
| | | 329 | | internal const uint UserString = HandleType.UserString << RowIdBitCount; |
| | | 330 | | |
| | | 331 | | internal const int RowIdBitCount = 24; |
| | | 332 | | internal const uint RIDMask = (1 << RowIdBitCount) - 1; |
| | | 333 | | internal const uint TypeMask = HandleType.TypeMask << RowIdBitCount; |
| | | 334 | | |
| | | 335 | | /// <summary> |
| | | 336 | | /// Use the highest bit to mark tokens that are virtual (synthesized). |
| | | 337 | | /// We create virtual tokens to represent projected WinMD entities. |
| | | 338 | | /// </summary> |
| | | 339 | | internal const uint VirtualBit = 0x80000000; |
| | | 340 | | |
| | | 341 | | /// <summary> |
| | | 342 | | /// Returns true if the token value can escape the metadata reader. |
| | | 343 | | /// We don't allow virtual tokens and heap tokens other than UserString to escape |
| | | 344 | | /// since the token type ids are internal to the reader and not specified by ECMA spec. |
| | | 345 | | /// |
| | | 346 | | /// Spec (Partition III, 1.9 Metadata tokens): |
| | | 347 | | /// Many CIL instructions are followed by a "metadata token". This is a 4-byte value, that specifies a row in a |
| | | 348 | | /// metadata table, or a starting byte offset in the User String heap. |
| | | 349 | | /// |
| | | 350 | | /// For example, a value of 0x02 specifies the TypeDef table; a value of 0x70 specifies the User |
| | | 351 | | /// String heap.The value corresponds to the number assigned to that metadata table (see Partition II for the fu |
| | | 352 | | /// list of tables) or to 0x70 for the User String heap.The least-significant 3 bytes specify the target row wit |
| | | 353 | | /// metadata table, or starting byte offset within the User String heap. |
| | | 354 | | /// </summary> |
| | | 355 | | internal static bool IsEntityOrUserStringToken(uint vToken) |
| | | 356 | | { |
| | | 357 | | return (vToken & TypeMask) <= UserString; |
| | | 358 | | } |
| | | 359 | | |
| | | 360 | | internal static bool IsEntityToken(uint vToken) |
| | | 361 | | { |
| | | 362 | | return (vToken & TypeMask) < UserString; |
| | | 363 | | } |
| | | 364 | | |
| | | 365 | | internal static bool IsValidRowId(uint rowId) |
| | | 366 | | { |
| | | 367 | | return (rowId & ~RIDMask) == 0; |
| | | 368 | | } |
| | | 369 | | |
| | | 370 | | internal static bool IsValidRowId(int rowId) |
| | | 371 | | { |
| | | 372 | | return (rowId & ~RIDMask) == 0; |
| | | 373 | | } |
| | | 374 | | } |
| | | 375 | | } |
| | | 376 | | |