From 1b47b264282bb720976413326fefa687864c0e41 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 28 Aug 2025 09:30:19 -0700 Subject: [PATCH 01/17] signature parsing and GetFieldDescData cDAC API --- .../design/datacontracts/RuntimeTypeSystem.md | 100 ++++++++ docs/design/datacontracts/SignatureDecoder.md | 217 ++++++++++++++++++ src/coreclr/vm/binder.h | 9 +- src/coreclr/vm/datadescriptor/contracts.jsonc | 3 +- .../vm/datadescriptor/datadescriptor.inc | 15 ++ src/coreclr/vm/field.h | 10 + .../ContractRegistry.cs | 4 + .../Contracts/IRuntimeTypeSystem.cs | 13 ++ .../Contracts/ISignatureDecoder.cs | 19 ++ .../DataType.cs | 2 + .../Constants.cs | 3 + .../Contracts/EcmaMetadata_1.cs | 24 +- .../Contracts/RuntimeTypeSystem_1.cs | 88 ++++++- .../Signature/SignatureTypeProvider.cs | 177 ++++++++++++++ .../Contracts/SignatureDecoderFactory.cs | 18 ++ .../Contracts/SignatureDecoder_1.cs | 67 ++++++ .../Data/CoreLibBinder.cs | 18 ++ .../Data/FieldDesc.cs | 20 ++ .../EcmaMetadataUtils.cs | 8 +- .../CachingContractRegistry.cs | 2 + .../Legacy/ISOSDacInterface.cs | 18 +- .../Legacy/SOSDacImpl.cs | 97 +++++++- 22 files changed, 921 insertions(+), 11 deletions(-) create mode 100644 docs/design/datacontracts/SignatureDecoder.md create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ISignatureDecoder.cs create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoderFactory.cs create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoder_1.cs create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/FieldDesc.cs diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 86fe79087fb690..a7c094fa1db0cf 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -282,6 +282,17 @@ internal partial struct RuntimeTypeSystem_1 } ``` +### FieldDesc +```csharp +TargetPointer GetMTOfEnclosingClass(TargetPointer fieldDescPointer); +uint GetFieldDescMemberDef(TargetPointer fieldDescPointer); +bool IsFieldDescThreadStatic(TargetPointer fieldDescPointer); +bool IsFieldDescStatic(TargetPointer fieldDescPointer); +uint GetFieldDescType(TargetPointer fieldDescPointer); +uint GetFieldDescOffset(TargetPointer fieldDescPointer, FieldDefinition fieldDef); +TargetPointer GetFieldDescNextField(TargetPointer fieldDescPointer); +``` + Internally the contract has a `MethodTable_1` struct that depends on the `MethodTable` data descriptor ```csharp @@ -1384,4 +1395,93 @@ Getting a MethodDesc for a certain slot in a MethodTable return GetMethodDescForEntrypoint(pCode); } + + TypeHandle IRuntimeTypeSystem.GetMethodTable(TypeHandle typeHandle) + { + if (typeHandle.IsTypeDesc()) + { + Data.TypeDesc typeDesc = target.ProcessedData.GetOrAdd(typeHandle.TypeDescAddress()); + CorElementType elemType = (CorElementType)(typeDesc.TypeAndFlags & 0xFF); + switch (elemType) + { + case CorElementType.Ptr: + case CorElementType.FnPtr: + TargetPointer coreLib = target.ReadGlobalPointer(Constants.Globals.CoreLib); + TargetPointer classes = target.ReadPointer(coreLib + /* CoreLibData::Classes offset */); + TargetPointer typeHandlePtr = target.ReadPointer(classes + (ulong)CorElementType.U * (ulong)target.PointerSize); + return GetTypeHandle(typeHandlePtr); + case CorElementType.ValueType: + return GetTypeHandle(target.ReadPointer(typeHandle.TypeDescAddress() + /* ParamTypeDesc::TypeArg offset */)); + default: + return new TypeHandle(TargetPointer.Null); + } + } + return typeHandle; + } ``` + +### FieldDesc + +The version 1 FieldDesc APIs depend on the following data descriptors: +| Data Descriptor Name | Field | Meaning | +| --- | --- | --- | +| `FieldDesc` | `MTOfEnclosingClass` | Pointer to method table of enclosing class | +| `FieldDesc` | `DWord1` | The FD's flags and token | +| `FieldDesc` | `DWord2` | The FD's kind and offset | + +```csharp +internal enum FieldDescFlags1 : uint +{ + TokenMask = 0xffffff, + IsStatic = 0x1000000, + IsThreadStatic = 0x2000000, +} + +internal enum FieldDescFlags2 : uint +{ + TypeMask = 0xf8000000, + OffsetMask = 0x07ffffff, +} + +TargetPointer GetMTOfEnclosingClass(TargetPointer fieldDescPointer) +{ + return target.ReadPointer(fieldDescPointer + /* FieldDesc::MTOfEnclosingClass offset */); +} + +uint GetFieldDescMemberDef(TargetPointer fieldDescPointer) +{ + uint DWord1 = target.Read(fieldDescPointer + /* FieldDesc::DWord1 offset */); + return EcmaMetadataUtils.CreateFieldDef(DWord1 & (uint)FieldDescFlags1.TokenMask); +} + +bool IsFieldDescThreadStatic(TargetPointer fieldDescPointer) +{ + uint DWord1 = target.Read(fieldDescPointer + /* FieldDesc::DWord1 offset */); + return (DWord1 & (uint)FieldDescFlags1.IsThreadStatic) != 0; +} + +bool IsFieldDescStatic(TargetPointer fieldDescPointer) +{ + uint DWord1 = target.Read(fieldDescPointer + /* FieldDesc::DWord1 offset */); + return (DWord1 & (uint)FieldDescFlags1.IsStatic) != 0; +} + +uint GetFieldDescType(TargetPointer fieldDescPointer) +{ + uint DWord2 = target.Read(fieldDescPointer + /* FieldDesc::DWord2 offset */); + return (DWord2 & (uint)FieldDescFlags2.TypeMask) >> 27; +} + +uint GetFieldDescOffset(TargetPointer fieldDescPointer) +{ + uint DWord2 = target.Read(fieldDescPointer + /* FieldDesc::DWord2 offset */); + if (DWord2 == _target.ReadGlobal("FieldOffsetBigRVA")) + { + return (uint)fieldDef.GetRelativeVirtualAddress(); + } + return DWord2 & (uint)FieldDescFlags2.OffsetMask; +} + +TargetPointer GetFieldDescNextField(TargetPointer fieldDescPointer) + => fieldDescPointer + _target.GetTypeInfo(DataType.FieldDesc).Size!.Value; +``` \ No newline at end of file diff --git a/docs/design/datacontracts/SignatureDecoder.md b/docs/design/datacontracts/SignatureDecoder.md new file mode 100644 index 00000000000000..7a08124b0a1e64 --- /dev/null +++ b/docs/design/datacontracts/SignatureDecoder.md @@ -0,0 +1,217 @@ +# Contract SignatureDecoder + +This contract encapsulates signature decoding in the cDAC. + +## APIs of contract + +```csharp +TypeHandle DecodeFieldSignature(BlobHandle blobHandle, ModuleHandle moduleHandle, TypeHandle ctx); +``` + +## Version 1 + +In version 1 of the SignatureDecoder contract we take advantage of the System.Reflection.Metadata signature decoding. We implement a SignatureTypeProvider that inherits from System.Reflection.Metadata ISignatureTypeProvider. + +Data descriptors used: +| Data Descriptor Name | Field | Meaning | +| --- | --- | --- | +| CoreLibBinder | Classes | MTs for primitive types | +| ILCodeVersionNode | TypeDefToMethodTableMap | Mapping table | +| ILCodeVersionNode | TypeRefToMethodTableMap | Mapping table | + +Global variables used: +| Global Name | Type | Purpose | +| --- | --- | --- | +| CoreLib | TargetPointer | pointer to the `CoreLibBinder` | +| PredefinedArrayTypes | TargetPointer | pointer to the cache of primitive-type array MTs | +| ObjectMethodTable | TargetPointer | pointer to the MT of `object` | +| StringMethodTable | TargetPointer | pointer to the MT of `string` | + +Contracts used: +| Contract Name | +| --- | +| RuntimeTypeSystem | +| Loader | + +### SignatureTypeProvider +```csharp +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +public class SignatureTypeProvider : ISignatureTypeProvider +{ + private readonly Target _target; + private readonly DataContractReader.Contracts.ModuleHandle _moduleHandle; + + public SignatureTypeProvider(Target target, DataContractReader.Contracts.ModuleHandle moduleHandle) + { + _target = target; + _moduleHandle = moduleHandle; + } + public TypeHandle GetArrayType(TypeHandle elementType, ArrayShape shape) + => IterateTypeParams(elementType, CorElementType.Array, shape.Rank, default); + + public TypeHandle GetByReferenceType(TypeHandle elementType) + => IterateTypeParams(elementType, CorElementType.Byref, 0, default); + + private bool GenericInstantiationMatch(TypeHandle genericType, TypeHandle potentialMatch, ImmutableArray typeArguments) + { + IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + ReadOnlySpan instantiation = rtsContract.GetInstantiation(potentialMatch); + if (instantiation.Length != typeArguments.Length) + return false; + + if (rtsContract.GetTypeDefToken(genericType) != rtsContract.GetTypeDefToken(potentialMatch)) + return false; + + if (rtsContract.GetModule(genericType) != rtsContract.GetModule(potentialMatch)) + return false; + + for (int i = 0; i < instantiation.Length; i++) + { + if (!(instantiation[i].Address == typeArguments[i].Address)) + return false; + } + return true; + } + + private bool ArrayPtrMatch(TypeHandle elementType, CorElementType corElementType, int rank, TypeHandle potentialMatch) + { + IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + rtsContract.IsArray(potentialMatch, out uint typeHandleRank); + return rtsContract.GetSignatureCorElementType(potentialMatch) == corElementType && + rtsContract.GetTypeParam(potentialMatch).Address == elementType.Address && + (corElementType == CorElementType.SzArray || corElementType == CorElementType.Byref || + corElementType == CorElementType.Ptr || (rank == typeHandleRank)); + + } + + private TypeHandle IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) + { + ILoader loaderContract = _target.Contracts.Loader; + IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + TargetPointer loaderModule = rtsContract.GetLoaderModule(typeHandle); + DataContractReader.Contracts.ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); + foreach (TargetPointer ptr in loaderContract.GetAvailableTypeParams(moduleHandle)) + { + TypeHandle potentialMatch = rtsContract.GetTypeHandle(ptr); + if (corElementType == CorElementType.GenericInst) + { + if (GenericInstantiationMatch(typeHandle, potentialMatch, typeArguments)) + { + return potentialMatch; + } + } + else if (ArrayPtrMatch(typeHandle, corElementType, rank, potentialMatch)) + { + return potentialMatch; + } + } + return new TypeHandle(TargetPointer.Null); + } + public TypeHandle GetFunctionPointerType(MethodSignature signature) + => GetPrimitiveType(PrimitiveTypeCode.IntPtr); + + public TypeHandle GetGenericInstantiation(TypeHandle genericType, ImmutableArray typeArguments) + => IterateTypeParams(genericType, CorElementType.GenericInst, 0, typeArguments); + + public TypeHandle GetGenericMethodParameter(T context, int index) + { + if (typeof(T) == typeof(MethodDescHandle)) + { + MethodDescHandle methodContext = (MethodDescHandle)(object)context!; + return _target.Contracts.RuntimeTypeSystem.GetGenericMethodInstantiation(methodContext)[index]; + } + throw new NotSupportedException(); + } + public TypeHandle GetGenericTypeParameter(T context, int index) + { + TypeHandle typeContext; + if (typeof(T) == typeof(TypeHandle)) + { + typeContext = (TypeHandle)(object)context!; + return _target.Contracts.RuntimeTypeSystem.GetInstantiation(typeContext)[index]; + } + throw new NotImplementedException(); + } + public TypeHandle GetModifiedType(TypeHandle modifier, TypeHandle unmodifiedType, bool isRequired) + => unmodifiedType; + + public TypeHandle GetPinnedType(TypeHandle elementType) + => elementType; + + public TypeHandle GetPointerType(TypeHandle elementType) + => IterateTypeParams(elementType, CorElementType.Ptr, 0, default); + + public TypeHandle GetPrimitiveType(PrimitiveTypeCode typeCode) + { + TargetPointer coreLib = _target.ReadGlobalPointer("CoreLib"); + CoreLibBinder coreLibData = _target.ProcessedData.GetOrAdd(coreLib); + TargetPointer typeHandlePtr = _target.ReadPointer(coreLibData.Classes + (ulong)typeCode * (ulong)_target.PointerSize); + return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); + } + + private TypeHandle GetPrimitiveArrayType(CorElementType elementType) + { + TargetPointer arrayPtr = _target.ReadGlobalPointer("PredefinedArrayTypes"); + TargetPointer typeHandlePtr = _target.ReadPointer(arrayPtr + (ulong)elementType * (ulong)_target.PointerSize); + return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); + } + + public TypeHandle GetSZArrayType(TypeHandle elementType) + { + IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + CorElementType corElementType = rtsContract.GetSignatureCorElementType(elementType); + TypeHandle typeHandle = default; + if (corElementType <= CorElementType.R8) + { + typeHandle = GetPrimitiveArrayType(corElementType); + } + else if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer("ObjectMethodTable"))) + { + typeHandle = GetPrimitiveArrayType(CorElementType.Object); + } + else if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer("StringMethodTable"))) + { + typeHandle = GetPrimitiveArrayType(CorElementType.String); + } + if (typeHandle.Address == TargetPointer.Null) + { + return IterateTypeParams(elementType, CorElementType.SzArray, 1, default); + } + return typeHandle; + } + + public TypeHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) + { + Module module = _target.ProcessedData.GetOrAdd(_moduleHandle.Address); + int token = MetadataTokens.GetToken((EntityHandle)handle); + TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(module.TypeDefToMethodTableMap, (uint)token, out _); + return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); + } + + public TypeHandle GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) + { + Module module = _target.ProcessedData.GetOrAdd(_moduleHandle.Address); + int token = MetadataTokens.GetToken((EntityHandle)handle); + TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(module.TypeRefToMethodTableMap, (uint)token, out _); + return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); + } + + public TypeHandle GetTypeFromSpecification(MetadataReader reader, T context, TypeSpecificationHandle handle, byte rawTypeKind) + => throw new NotImplementedException(); +} + +``` + +### APIs +```csharp +TypeHandle ISignatureDecoder.DecodeFieldSignature(BlobHandle blobHandle, ModuleHandle moduleHandle, TypeHandle ctx) +{ + SignatureTypeProvider provider = new(_target, moduleHandle); + MetadataReader mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle)!; + BlobReader blobReader = mdReader.GetBlobReader(blobHandle); + SignatureDecoder decoder = new(provider, mdReader, ctx); + return decoder.DecodeFieldSignature(ref blobReader); +} +``` \ No newline at end of file diff --git a/src/coreclr/vm/binder.h b/src/coreclr/vm/binder.h index 8e9369cc85a1b0..f8515a26b1a7c6 100644 --- a/src/coreclr/vm/binder.h +++ b/src/coreclr/vm/binder.h @@ -28,7 +28,7 @@ struct HardCodedMetaSig #define DEFINE_METASIG_T(body) extern body #define METASIG_BODY(varname, types) HardCodedMetaSig gsig_ ## varname; #include "metasig.h" - +#include "cdacdata.h" // // Use the Binder objects to avoid doing unnecessary name lookup // (esp. in the prejit case) @@ -309,10 +309,17 @@ class CoreLibBinder }; static const OffsetAndSizeCheck OffsetsAndSizes[]; + friend struct ::cdac_data; #endif }; +template<> +struct cdac_data +{ + static constexpr size_t Classes = offsetof(CoreLibBinder, m_pClasses); +}; + // // Global bound modules: // diff --git a/src/coreclr/vm/datadescriptor/contracts.jsonc b/src/coreclr/vm/datadescriptor/contracts.jsonc index 63d61aeda40baf..3d8d8e17ea0543 100644 --- a/src/coreclr/vm/datadescriptor/contracts.jsonc +++ b/src/coreclr/vm/datadescriptor/contracts.jsonc @@ -24,5 +24,6 @@ "RuntimeTypeSystem": 1, "StackWalk": 1, "StressLog": 2, - "Thread": 1 + "Thread": 1, + "SignatureDecoder": 1 } \ No newline at end of file diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 672f1ba6dbc63d..1f3e8a787793de 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -320,6 +320,13 @@ CDAC_TYPE_INDETERMINATE(TypeDesc) CDAC_TYPE_FIELD(TypeDesc, /*uint32*/, TypeAndFlags, cdac_data::TypeAndFlags) CDAC_TYPE_END(TypeDesc) +CDAC_TYPE_BEGIN(FieldDesc) +CDAC_TYPE_SIZE(sizeof(FieldDesc)) +CDAC_TYPE_FIELD(FieldDesc, /*uint32*/, DWord1, cdac_data::DWord1) +CDAC_TYPE_FIELD(FieldDesc, /*uint32*/, DWord2, cdac_data::DWord2) +CDAC_TYPE_FIELD(FieldDesc, /*pointer*/, MTOfEnclosingClass, cdac_data::MTOfEnclosingClass) +CDAC_TYPE_END(FieldDesc) + CDAC_TYPE_BEGIN(ParamTypeDesc) CDAC_TYPE_INDETERMINATE(ParamTypeDesc) CDAC_TYPE_FIELD(ParamTypeDesc, /*pointer*/, TypeArg, cdac_data::TypeArg) @@ -898,6 +905,11 @@ CDAC_TYPE_FIELD(InstMethodHashTable, /*pointer*/, VolatileEntryValue, cdac_data< CDAC_TYPE_FIELD(InstMethodHashTable, /*pointer*/, VolatileEntryNextEntry, cdac_data::VolatileEntryNextEntry) CDAC_TYPE_END(InstMethodHashTable) +CDAC_TYPE_BEGIN(CoreLibBinder) +CDAC_TYPE_INDETERMINATE(CoreLibBinder) +CDAC_TYPE_FIELD(CoreLibBinder, /*pointer*/, Classes, cdac_data::Classes) +CDAC_TYPE_END(CoreLibBinder) + CDAC_TYPES_END() CDAC_GLOBALS_BEGIN() @@ -973,12 +985,14 @@ CDAC_GLOBAL(StaticsPointerMask, uintptr_t, DynamicStaticsInfo::STATICSPOINTERMAS CDAC_GLOBAL(PtrArrayOffsetToDataArray, uintptr_t, offsetof(PtrArray, m_Array)) CDAC_GLOBAL(NumberOfTlsOffsetsNotUsedInNoncollectibleArray, uint8, NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY) CDAC_GLOBAL(MaxClrNotificationArgs, uint32, MAX_CLR_NOTIFICATION_ARGS) +CDAC_GLOBAL(FieldOffsetBigRVA, uint32, FIELD_OFFSET_BIG_RVA) CDAC_GLOBAL_POINTER(ClrNotificationArguments, &::g_clrNotificationArguments) CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data::ArrayBoundsZero) CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass) CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable) CDAC_GLOBAL_POINTER(ObjectMethodTable, &::g_pObjectClass) CDAC_GLOBAL_POINTER(ObjectArrayMethodTable, &::g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT]) +CDAC_GLOBAL_POINTER(PredefinedArrayTypes, &::g_pPredefinedArrayTypes) CDAC_GLOBAL_POINTER(StringMethodTable, &::g_pStringClass) CDAC_GLOBAL_POINTER(SyncTableEntries, &::g_pSyncTable) CDAC_GLOBAL_POINTER(MiniMetaDataBuffAddress, &::g_MiniMetaDataBuffAddress) @@ -986,6 +1000,7 @@ CDAC_GLOBAL_POINTER(MiniMetaDataBuffMaxSize, &::g_MiniMetaDataBuffMaxSize) CDAC_GLOBAL_POINTER(DacNotificationFlags, &::g_dacNotificationFlags) CDAC_GLOBAL_POINTER(OffsetOfCurrentThreadInfo, &::g_offsetOfCurrentThreadInfo) CDAC_GLOBAL_POINTER(ThinlockThreadIdDispenser, &::g_pThinLockThreadIdDispenser) +CDAC_GLOBAL_POINTER(CoreLib, &::g_CoreLib) #ifdef TARGET_WINDOWS CDAC_GLOBAL_POINTER(TlsIndexBase, &::_tls_index) #endif // TARGET_WINDOWS diff --git a/src/coreclr/vm/field.h b/src/coreclr/vm/field.h index ddc5665190327c..f78928d042c3de 100644 --- a/src/coreclr/vm/field.h +++ b/src/coreclr/vm/field.h @@ -10,6 +10,7 @@ #define _FIELD_H_ #include "excep.h" +#include "cdacdata.h" // Temporary values stored in FieldDesc m_dwOffset during loading // The high 5 bits must be zero (because in field.h we steal them for other uses), so we must choose values > 0 @@ -36,6 +37,7 @@ class FieldDesc { friend class MethodTableBuilder; + friend struct ::cdac_data; protected: PTR_MethodTable m_pMTOfEnclosingClass; // This is used to hold the log2 of the field size temporarily during class loading. Yuck. @@ -744,5 +746,13 @@ class FieldDesc #endif }; +template<> +struct cdac_data +{ + static constexpr size_t DWord1 = offsetof(FieldDesc, m_pMTOfEnclosingClass) + sizeof(PTR_MethodTable); + static constexpr size_t DWord2 = DWord1 + 4; + static constexpr size_t MTOfEnclosingClass = offsetof(FieldDesc, m_pMTOfEnclosingClass); +}; + #endif // _FIELD_H_ diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs index 4dd941006db544..7cf561b5feaa99 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs @@ -74,4 +74,8 @@ public abstract class ContractRegistry /// Gets an instance of the GC contract for the target. /// public abstract IGC GC { get; } + /// + /// Gets an instance of the SignatureDecoder contract for the target. + /// + public abstract ISignatureDecoder SignatureDecoder { get; } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index d0f4476fbbca1a..44bea4eac85abf 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Reflection.Metadata; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -90,6 +91,8 @@ public interface IRuntimeTypeSystem : IContract TargetPointer GetMethodDescForSlot(TypeHandle methodTable, ushort slot) => throw new NotImplementedException(); + TypeHandle GetMethodTable(TypeHandle typeHandle) => throw new NotImplementedException(); + uint GetBaseSize(TypeHandle typeHandle) => throw new NotImplementedException(); // The component size is only available for strings and arrays. It is the size of the element type of the array, or the size of an ECMA 335 character (2 bytes) uint GetComponentSize(TypeHandle typeHandle) => throw new NotImplementedException(); @@ -134,6 +137,7 @@ public interface IRuntimeTypeSystem : IContract bool IsArray(TypeHandle typeHandle, out uint rank) => throw new NotImplementedException(); TypeHandle GetTypeParam(TypeHandle typeHandle) => throw new NotImplementedException(); bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) => throw new NotImplementedException(); + TargetPointer GetLoaderModule(TypeHandle typeHandle) => throw new NotImplementedException(); bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan retAndArgTypes, out byte callConv) => throw new NotImplementedException(); // Returns null if the TypeHandle is not a class/struct/generic variable #endregion TypeHandle inspection APIs @@ -184,6 +188,15 @@ public interface IRuntimeTypeSystem : IContract TargetPointer GetGCStressCodeCopy(MethodDescHandle methodDesc) => throw new NotImplementedException(); #endregion MethodDesc inspection APIs + #region FieldDesc inspection APIs + TargetPointer GetMTOfEnclosingClass(TargetPointer fieldDescPointer) => throw new NotImplementedException(); + uint GetFieldDescMemberDef(TargetPointer fieldDescPointer) => throw new NotImplementedException(); + bool IsFieldDescThreadStatic(TargetPointer fieldDescPointer) => throw new NotImplementedException(); + bool IsFieldDescStatic(TargetPointer fieldDescPointer) => throw new NotImplementedException(); + uint GetFieldDescType(TargetPointer fieldDescPointer) => throw new NotImplementedException(); + uint GetFieldDescOffset(TargetPointer fieldDescPointer, FieldDefinition fieldDef) => throw new NotImplementedException(); + TargetPointer GetFieldDescNextField(TargetPointer fieldDescPointer) => throw new NotImplementedException(); + #endregion FieldDesc inspection APIs } public struct RuntimeTypeSystem : IRuntimeTypeSystem diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ISignatureDecoder.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ISignatureDecoder.cs new file mode 100644 index 00000000000000..fbe1038929b679 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ISignatureDecoder.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Reflection.Metadata; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +public interface ISignatureDecoder : IContract +{ + static string IContract.Name { get; } = nameof(SignatureDecoder); + TypeHandle DecodeFieldSignature(BlobHandle blobHandle, ModuleHandle moduleHandle, TypeHandle ctx) => + throw new NotImplementedException(); +} + +public readonly struct SignatureDecoder : ISignatureDecoder +{ + // Everything throws NotImplementedException +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs index 834aad423c4169..dd05bc8c9ba579 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -48,6 +48,7 @@ public enum DataType MethodTable, DynamicStaticsInfo, EEClass, + CoreLibBinder, ArrayClass, MethodTableAuxiliaryData, GenericsDictInfo, @@ -55,6 +56,7 @@ public enum DataType ParamTypeDesc, TypeVarTypeDesc, FnPtrTypeDesc, + FieldDesc, DynamicMetadata, StressLog, StressLogModuleDesc, diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs index 5d184703853b41..cf25489eb918ac 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -25,6 +25,7 @@ public static class Globals public const string ObjectMethodTable = nameof(ObjectMethodTable); public const string ObjectArrayMethodTable = nameof(ObjectArrayMethodTable); public const string StringMethodTable = nameof(StringMethodTable); + public const string PredefinedArrayTypes = nameof(PredefinedArrayTypes); public const string MiniMetaDataBuffAddress = nameof(MiniMetaDataBuffAddress); public const string MiniMetaDataBuffMaxSize = nameof(MiniMetaDataBuffMaxSize); @@ -50,6 +51,7 @@ public static class Globals public const string SyncTableEntries = nameof(SyncTableEntries); public const string ArrayBoundsZero = nameof(ArrayBoundsZero); + public const string CoreLib = nameof(CoreLib); public const string MethodDescTokenRemainderBitCount = nameof(MethodDescTokenRemainderBitCount); public const string DirectorySeparator = nameof(DirectorySeparator); @@ -62,6 +64,7 @@ public static class Globals public const string NumberOfTlsOffsetsNotUsedInNoncollectibleArray = nameof(NumberOfTlsOffsetsNotUsedInNoncollectibleArray); public const string MaxClrNotificationArgs = nameof(MaxClrNotificationArgs); public const string ClrNotificationArguments = nameof(ClrNotificationArguments); + public const string FieldOffsetBigRVA = nameof(FieldOffsetBigRVA); public const string PlatformMetadata = nameof(PlatformMetadata); public const string ProfilerControlBlock = nameof(ProfilerControlBlock); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs index 2e00ce75b93f70..ac23ea521cecde 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs @@ -7,6 +7,7 @@ using System.Numerics; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -15,6 +16,13 @@ internal sealed class EcmaMetadata_1(Target target) : IEcmaMetadata { private Dictionary _metadata = new(); + private sealed class ModuleHandleBox + { + public ModuleHandle Value { get; } + public ModuleHandleBox(ModuleHandle value) => Value = value; + } + private static ConditionalWeakTable _moduleHandles = new(); + public TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle) { ILoader loader = target.Contracts.Loader; @@ -37,16 +45,28 @@ public TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle) public MetadataReader? GetMetadata(ModuleHandle handle) { + MetadataReader? reader; if (_metadata.TryGetValue(handle, out MetadataReaderProvider? result)) { - return result?.GetMetadataReader(); + reader = result?.GetMetadataReader(); } else { MetadataReaderProvider? provider = GetMetadataProvider(handle); _metadata.Add(handle, provider); - return provider?.GetMetadataReader(); + reader = provider?.GetMetadataReader(); + _moduleHandles.Add(reader!, new ModuleHandleBox(handle)); + } + return reader; + } + + public static ModuleHandle? GetModuleFromMetadataReader(MetadataReader reader) + { + if (_moduleHandles.TryGetValue(reader, out ModuleHandleBox? box)) + { + return box!.Value; } + return null; } private MetadataReaderProvider? GetMetadataProvider(ModuleHandle handle) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 9bb21f02365ce8..d30aab0901b579 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -7,6 +7,8 @@ using System.Reflection.Metadata.Ecma335; using Microsoft.Diagnostics.DataContractReader.RuntimeTypeSystemHelpers; using Microsoft.Diagnostics.DataContractReader.Data; +using System.Reflection.Metadata; +using Microsoft.Diagnostics.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -96,6 +98,19 @@ internal enum MethodTableAuxiliaryFlags : uint IsInitError = 0x0100, } + internal enum FieldDescFlags1 : uint + { + TokenMask = 0xffffff, + IsStatic = 0x1000000, + IsThreadStatic = 0x2000000, + } + + internal enum FieldDescFlags2 : uint + { + TypeMask = 0xf8000000, + OffsetMask = 0x07ffffff, + } + internal struct MethodDesc { private readonly Data.MethodDesc _desc; @@ -955,14 +970,14 @@ private bool HasMethodInstantiation(MethodDesc md) return md.Classification == MethodClassification.Instantiated && AsInstantiatedMethodDesc(md).HasMethodInstantiation; } - private TargetPointer GetLoaderModule(TypeHandle typeHandle) + TargetPointer IRuntimeTypeSystem.GetLoaderModule(TypeHandle typeHandle) { if (typeHandle.IsTypeDesc()) { // TypeDesc::GetLoaderModule if (HasTypeParam(typeHandle)) { - return GetLoaderModule(GetTypeParam(typeHandle)); + return ((IRuntimeTypeSystem)this).GetLoaderModule(GetTypeParam(typeHandle)); } else if (IsGenericVariable(typeHandle, out TargetPointer genericParamModule, out _)) { @@ -1002,7 +1017,7 @@ private TargetPointer GetLoaderModule(MethodDesc md) { TargetPointer mtAddr = GetMethodTable(new MethodDescHandle(md.Address)); TypeHandle mt = GetTypeHandle(mtAddr); - return GetLoaderModule(mt); + return ((IRuntimeTypeSystem)this).GetLoaderModule(mt); } } @@ -1118,6 +1133,30 @@ TargetPointer IRuntimeTypeSystem.GetMethodDescForSlot(TypeHandle typeHandle, ush return GetMethodDescForEntrypoint(pCode); } + TypeHandle IRuntimeTypeSystem.GetMethodTable(TypeHandle typeHandle) + { + if (typeHandle.IsTypeDesc()) + { + Data.TypeDesc typeDesc = _target.ProcessedData.GetOrAdd(typeHandle.TypeDescAddress()); + CorElementType elemType = (CorElementType)(typeDesc.TypeAndFlags & 0xFF); + switch (elemType) + { + case CorElementType.Ptr: + case CorElementType.FnPtr: + TargetPointer coreLib = _target.ReadGlobalPointer(Constants.Globals.CoreLib); + CoreLibBinder coreLibData = _target.ProcessedData.GetOrAdd(coreLib); + TargetPointer typeHandlePtr = _target.ReadPointer(coreLibData.Classes + (ulong)CorElementType.U * (ulong)_target.PointerSize); + return GetTypeHandle(typeHandlePtr); + case CorElementType.ValueType: + Data.ParamTypeDesc paramTypeDesc = _target.ProcessedData.GetOrAdd(typeHandle.TypeDescAddress()); + return GetTypeHandle(paramTypeDesc.TypeArg); + default: + return new TypeHandle(TargetPointer.Null); + } + } + return typeHandle; + } + private readonly TargetPointer GetMethodDescForEntrypoint(TargetCodePointer pCode) { // standard path, ask ExecutionManager for the MethodDesc @@ -1229,4 +1268,47 @@ private bool SlotIsVtableSlot(TargetPointer methodTablePointer, uint slot) return slot < GetNumVtableSlots(typeHandle); } + TargetPointer IRuntimeTypeSystem.GetMTOfEnclosingClass(TargetPointer fieldDescPointer) + { + Data.FieldDesc fieldDesc = _target.ProcessedData.GetOrAdd(fieldDescPointer); + return fieldDesc.MTOfEnclosingClass; + } + + uint IRuntimeTypeSystem.GetFieldDescMemberDef(TargetPointer fieldDescPointer) + { + Data.FieldDesc fieldDesc = _target.ProcessedData.GetOrAdd(fieldDescPointer); + return EcmaMetadataUtils.CreateFieldDef(fieldDesc.DWord1 & (uint)FieldDescFlags1.TokenMask); + } + + bool IRuntimeTypeSystem.IsFieldDescThreadStatic(TargetPointer fieldDescPointer) + { + Data.FieldDesc fieldDesc = _target.ProcessedData.GetOrAdd(fieldDescPointer); + return (fieldDesc.DWord1 & (uint)FieldDescFlags1.IsThreadStatic) != 0; + } + + bool IRuntimeTypeSystem.IsFieldDescStatic(TargetPointer fieldDescPointer) + { + Data.FieldDesc fieldDesc = _target.ProcessedData.GetOrAdd(fieldDescPointer); + return (fieldDesc.DWord1 & (uint)FieldDescFlags1.IsStatic) != 0; + } + + uint IRuntimeTypeSystem.GetFieldDescType(TargetPointer fieldDescPointer) + { + Data.FieldDesc fieldDesc = _target.ProcessedData.GetOrAdd(fieldDescPointer); + return (fieldDesc.DWord2 & (uint)FieldDescFlags2.TypeMask) >> 27; + } + + uint IRuntimeTypeSystem.GetFieldDescOffset(TargetPointer fieldDescPointer, FieldDefinition fieldDef) + { + Data.FieldDesc fieldDesc = _target.ProcessedData.GetOrAdd(fieldDescPointer); + if (fieldDesc.DWord2 == _target.ReadGlobal(Constants.Globals.FieldOffsetBigRVA)) + { + return (uint)fieldDef.GetRelativeVirtualAddress(); + } + return fieldDesc.DWord2 & (uint)FieldDescFlags2.OffsetMask; + } + + TargetPointer IRuntimeTypeSystem.GetFieldDescNextField(TargetPointer fieldDescPointer) + => fieldDescPointer + _target.GetTypeInfo(DataType.FieldDesc).Size!.Value; + } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs new file mode 100644 index 00000000000000..a44c5d9c831cb8 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs @@ -0,0 +1,177 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection.Metadata.Ecma335; +using System.Reflection.Metadata; +using Microsoft.Diagnostics.DataContractReader.Data; +using Microsoft.Diagnostics.DataContractReader.Contracts; +using System; +using System.Collections.Immutable; +using Microsoft.Diagnostics.DataContractReader; + +namespace Microsoft.Diagnostics.Contracts; + +public class SignatureTypeProvider : ISignatureTypeProvider +{ + // All interface methods throw NotImplementedException for now + private readonly Target _target; + private readonly DataContractReader.Contracts.ModuleHandle _moduleHandle; + + public SignatureTypeProvider(Target target, DataContractReader.Contracts.ModuleHandle moduleHandle) + { + _target = target; + _moduleHandle = moduleHandle; + } + public TypeHandle GetArrayType(TypeHandle elementType, ArrayShape shape) + => IterateTypeParams(elementType, CorElementType.Array, shape.Rank, default); + + public TypeHandle GetByReferenceType(TypeHandle elementType) + => IterateTypeParams(elementType, CorElementType.Byref, 0, default); + + private bool GenericInstantiationMatch(TypeHandle genericType, TypeHandle potentialMatch, ImmutableArray typeArguments) + { + IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + ReadOnlySpan instantiation = rtsContract.GetInstantiation(potentialMatch); + if (instantiation.Length != typeArguments.Length) + return false; + + if (rtsContract.GetTypeDefToken(genericType) != rtsContract.GetTypeDefToken(potentialMatch)) + return false; + + if (rtsContract.GetModule(genericType) != rtsContract.GetModule(potentialMatch)) + return false; + + for (int i = 0; i < instantiation.Length; i++) + { + if (!(instantiation[i].Address == typeArguments[i].Address)) + return false; + } + return true; + } + + private bool ArrayPtrMatch(TypeHandle elementType, CorElementType corElementType, int rank, TypeHandle potentialMatch) + { + IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + rtsContract.IsArray(potentialMatch, out uint typeHandleRank); + return rtsContract.GetSignatureCorElementType(potentialMatch) == corElementType && + rtsContract.GetTypeParam(potentialMatch).Address == elementType.Address && + (corElementType == CorElementType.SzArray || corElementType == CorElementType.Byref || + corElementType == CorElementType.Ptr || (rank == typeHandleRank)); + + } + + private TypeHandle IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) + { + ILoader loaderContract = _target.Contracts.Loader; + IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + TargetPointer loaderModule = rtsContract.GetLoaderModule(typeHandle); + DataContractReader.Contracts.ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); + foreach (TargetPointer ptr in loaderContract.GetAvailableTypeParams(moduleHandle)) + { + TypeHandle potentialMatch = rtsContract.GetTypeHandle(ptr); + if (corElementType == CorElementType.GenericInst) + { + if (GenericInstantiationMatch(typeHandle, potentialMatch, typeArguments)) + { + return potentialMatch; + } + } + else if (ArrayPtrMatch(typeHandle, corElementType, rank, potentialMatch)) + { + return potentialMatch; + } + } + return new TypeHandle(TargetPointer.Null); + } + public TypeHandle GetFunctionPointerType(MethodSignature signature) + => GetPrimitiveType(PrimitiveTypeCode.IntPtr); + + public TypeHandle GetGenericInstantiation(TypeHandle genericType, ImmutableArray typeArguments) + => IterateTypeParams(genericType, CorElementType.GenericInst, 0, typeArguments); + + public TypeHandle GetGenericMethodParameter(T context, int index) + { + if (typeof(T) == typeof(MethodDescHandle)) + { + MethodDescHandle methodContext = (MethodDescHandle)(object)context!; + return _target.Contracts.RuntimeTypeSystem.GetGenericMethodInstantiation(methodContext)[index]; + } + throw new NotSupportedException(); + } + public TypeHandle GetGenericTypeParameter(T context, int index) + { + TypeHandle typeContext; + if (typeof(T) == typeof(TypeHandle)) + { + typeContext = (TypeHandle)(object)context!; + return _target.Contracts.RuntimeTypeSystem.GetInstantiation(typeContext)[index]; + } + throw new NotImplementedException(); + } + public TypeHandle GetModifiedType(TypeHandle modifier, TypeHandle unmodifiedType, bool isRequired) + => unmodifiedType; + + public TypeHandle GetPinnedType(TypeHandle elementType) + => elementType; + + public TypeHandle GetPointerType(TypeHandle elementType) + => IterateTypeParams(elementType, CorElementType.Ptr, 0, default); + + public TypeHandle GetPrimitiveType(PrimitiveTypeCode typeCode) + { + TargetPointer coreLib = _target.ReadGlobalPointer(Constants.Globals.CoreLib); + CoreLibBinder coreLibData = _target.ProcessedData.GetOrAdd(coreLib); + TargetPointer typeHandlePtr = _target.ReadPointer(coreLibData.Classes + (ulong)typeCode * (ulong)_target.PointerSize); + return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); + } + + private TypeHandle GetPrimitiveArrayType(CorElementType elementType) + { + TargetPointer arrayPtr = _target.ReadGlobalPointer(Constants.Globals.PredefinedArrayTypes); + TargetPointer typeHandlePtr = _target.ReadPointer(arrayPtr + (ulong)elementType * (ulong)_target.PointerSize); + return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); + } + + public TypeHandle GetSZArrayType(TypeHandle elementType) + { + IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + CorElementType corElementType = rtsContract.GetSignatureCorElementType(elementType); + TypeHandle typeHandle = default; + if (corElementType <= CorElementType.R8) + { + typeHandle = GetPrimitiveArrayType(corElementType); + } + else if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable))) + { + typeHandle = GetPrimitiveArrayType(CorElementType.Object); + } + else if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.StringMethodTable))) + { + typeHandle = GetPrimitiveArrayType(CorElementType.String); + } + if (typeHandle.Address == TargetPointer.Null) + { + return IterateTypeParams(elementType, CorElementType.SzArray, 1, default); + } + return typeHandle; + } + + public TypeHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) + { + Module module = _target.ProcessedData.GetOrAdd(_moduleHandle.Address); + int token = MetadataTokens.GetToken((EntityHandle)handle); + TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(module.TypeDefToMethodTableMap, (uint)token, out _); + return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); + } + + public TypeHandle GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) + { + Module module = _target.ProcessedData.GetOrAdd(_moduleHandle.Address); + int token = MetadataTokens.GetToken((EntityHandle)handle); + TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(module.TypeRefToMethodTableMap, (uint)token, out _); + return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); + } + + public TypeHandle GetTypeFromSpecification(MetadataReader reader, T context, TypeSpecificationHandle handle, byte rawTypeKind) + => throw new NotImplementedException(); +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoderFactory.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoderFactory.cs new file mode 100644 index 00000000000000..9715fc7de8adb9 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoderFactory.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +public sealed class SignatureDecoderFactory : IContractFactory +{ + ISignatureDecoder IContractFactory.CreateContract(Target target, int version) + { + return version switch + { + 1 => new SignatureDecoder_1(target), + _ => default(SignatureDecoder), + }; + } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoder_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoder_1.cs new file mode 100644 index 00000000000000..f0a2d4d1a026d5 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoder_1.cs @@ -0,0 +1,67 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.InteropServices; +using Microsoft.Diagnostics.Contracts; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal sealed class SignatureDecoder_1 : ISignatureDecoder +{ + private readonly Target _target; + private Dictionary> _thProviders; + private Dictionary> _mdhProviders; + + internal SignatureDecoder_1(Target target) + { + _target = target; + _thProviders = new Dictionary>(); + _mdhProviders = new Dictionary>(); + } + + + private SignatureTypeProvider GetProvider(ModuleHandle moduleHandle) + { + if (typeof(T) == typeof(TypeHandle)) + { + if (_thProviders.TryGetValue(moduleHandle, out SignatureTypeProvider? thProvider)) + { + return (SignatureTypeProvider)(object)thProvider; + } + + SignatureTypeProvider newProvider = new(_target, moduleHandle); + _thProviders[moduleHandle] = newProvider; + return (SignatureTypeProvider)(object)newProvider; + } + else if (typeof(T) == typeof(MethodDescHandle)) + { + if (_mdhProviders.TryGetValue(moduleHandle, out SignatureTypeProvider? mdhProvider)) + { + return (SignatureTypeProvider)(object)mdhProvider; + } + + SignatureTypeProvider newProvider = new(_target, moduleHandle); + _mdhProviders[moduleHandle] = newProvider; + return (SignatureTypeProvider)(object)newProvider; + } + else + { + throw new NotSupportedException($"Type parameter {typeof(T)} is not supported."); + } + } + TypeHandle ISignatureDecoder.DecodeFieldSignature(BlobHandle blobHandle, ModuleHandle moduleHandle, TypeHandle ctx) + { + SignatureTypeProvider provider = GetProvider(moduleHandle); + MetadataReader mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle)!; + BlobReader blobReader = mdReader.GetBlobReader(blobHandle); + SignatureDecoder decoder = new(provider, mdReader, ctx); + // Implementation pending + return decoder.DecodeFieldSignature(ref blobReader); + } + +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs new file mode 100644 index 00000000000000..781e3aa5e29644 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class CoreLibBinder : IData +{ + static CoreLibBinder IData.Create(Target target, TargetPointer address) => new CoreLibBinder(target, address); + public CoreLibBinder(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.CoreLibBinder); + + Classes = target.ReadPointer(address + (ulong)type.Fields[nameof(Classes)].Offset); + } + public TargetPointer Classes { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/FieldDesc.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/FieldDesc.cs new file mode 100644 index 00000000000000..6ce2f4d2227219 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/FieldDesc.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class FieldDesc : IData +{ + static FieldDesc IData.Create(Target target, TargetPointer address) => new FieldDesc(target, address); + public FieldDesc(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.FieldDesc); + DWord1 = target.Read(address + (ulong)type.Fields[nameof(DWord1)].Offset); + DWord2 = target.Read(address + (ulong)type.Fields[nameof(DWord2)].Offset); + MTOfEnclosingClass = target.ReadPointer(address + (ulong)type.Fields[nameof(MTOfEnclosingClass)].Offset); + } + + public uint DWord1 { get; init; } + public uint DWord2 { get; init; } + public TargetPointer MTOfEnclosingClass { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/EcmaMetadataUtils.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/EcmaMetadataUtils.cs index f542da0e956ec0..83701bc8abe812 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/EcmaMetadataUtils.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/EcmaMetadataUtils.cs @@ -18,7 +18,8 @@ internal static class EcmaMetadataUtils // Metadata table index is the most significant byte of the 4-byte token public enum TokenType : uint { - mdtMethodDef = 0x06 << 24 + mdtMethodDef = 0x06 << 24, + mdtFieldDef = 0x04 << 24 } public static uint CreateMethodDef(uint tokenParts) @@ -26,4 +27,9 @@ public static uint CreateMethodDef(uint tokenParts) Debug.Assert((tokenParts & 0xff000000) == 0, $"Token type should not be set in {nameof(tokenParts)}"); return (uint)TokenType.mdtMethodDef | tokenParts; } + + public static uint CreateFieldDef(uint tokenParts) + { + return (uint)TokenType.mdtFieldDef | tokenParts; + } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs index 715aa19b202b72..f86da2a1a7e84f 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs @@ -42,6 +42,7 @@ public CachingContractRegistry(Target target, TryGetContractVersionDelegate tryG [typeof(IRuntimeInfo)] = new RuntimeInfoFactory(), [typeof(IDebugInfo)] = new DebugInfoFactory(), [typeof(IGC)] = new GCFactory(), + [typeof(ISignatureDecoder)] = new SignatureDecoderFactory(), }; configureFactories?.Invoke(_factories); } @@ -62,6 +63,7 @@ public CachingContractRegistry(Target target, TryGetContractVersionDelegate tryG public override IRuntimeInfo RuntimeInfo => GetContract(); public override IDebugInfo DebugInfo => GetContract(); public override IGC GC => GetContract(); + public override ISignatureDecoder SignatureDecoder => GetContract(); private TContract GetContract() where TContract : IContract { diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs index eabf1d516e7565..ecb39be84530fd 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs @@ -231,6 +231,22 @@ public enum Flags : uint public ClrDataAddress NativeCodeAddr; }; +internal struct DacpFieldDescData +{ + public uint Type; + public uint sigType; // ELEMENT_TYPE_XXX from signature. We need this to disply pretty name for String in minidump's case + public ClrDataAddress MTOfType; // NULL if Type is not loaded + public ClrDataAddress ModuleOfType; + public uint TokenOfType; + public uint mb; + public ClrDataAddress MTOfEnclosingClass; + public uint dwOffset; + public int bIsThreadLocal; + public int bIsContextLocal; + public int bIsStatic; + public ClrDataAddress NextField; +}; + internal struct DacpMethodDescData { public int bHasNativeCode; @@ -395,7 +411,7 @@ internal unsafe partial interface ISOSDacInterface // FieldDesc [PreserveSig] - int GetFieldDescData(ClrDataAddress fieldDesc, /*struct DacpFieldDescData*/ void* data); + int GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescData* data); // Frames [PreserveSig] diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index ea56a52440ee2e..1d90b33bcc6a0b 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -13,6 +13,8 @@ using Microsoft.Diagnostics.DataContractReader.Contracts; using Microsoft.Diagnostics.DataContractReader.Contracts.Extensions; using Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -671,8 +673,99 @@ int ISOSDacInterface.GetFailedAssemblyList(ClrDataAddress appDomain, int count, => _legacyImpl is not null ? _legacyImpl.GetFailedAssemblyList(appDomain, count, values, pNeeded) : HResults.E_NOTIMPL; int ISOSDacInterface.GetFailedAssemblyLocation(ClrDataAddress assesmbly, uint count, char* location, uint* pNeeded) => _legacyImpl is not null ? _legacyImpl.GetFailedAssemblyLocation(assesmbly, count, location, pNeeded) : HResults.E_NOTIMPL; - int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, void* data) - => _legacyImpl is not null ? _legacyImpl.GetFieldDescData(fieldDesc, data) : HResults.E_NOTIMPL; + int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescData* data) + { + int hr = HResults.S_OK; + try + { + if (fieldDesc == 0 || data == null) + throw new ArgumentException(); + + IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + TargetPointer fieldDescTargetPtr = fieldDesc.ToTargetPointer(_target); + uint fieldDescType = rtsContract.GetFieldDescType(fieldDescTargetPtr); + data->Type = fieldDescType; + data->sigType = fieldDescType; + + uint token = rtsContract.GetFieldDescMemberDef(fieldDescTargetPtr); + FieldDefinitionHandle fieldHandle = (FieldDefinitionHandle)MetadataTokens.Handle((int)token); + IEcmaMetadata ecmaMetadataContract = _target.Contracts.EcmaMetadata; + TargetPointer enclosingMT = rtsContract.GetMTOfEnclosingClass(fieldDescTargetPtr); + TypeHandle ctx = rtsContract.GetTypeHandle(enclosingMT); + TargetPointer modulePtr = rtsContract.GetModule(ctx); + Contracts.ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePtr); + MetadataReader mdReader = ecmaMetadataContract.GetMetadata(moduleHandle)!; + FieldDefinition fieldDef = mdReader.GetFieldDefinition(fieldHandle); + ISignatureDecoder signatureDecoder = _target.Contracts.SignatureDecoder; + try + { + // try to completely decode the signature + TypeHandle foundTypeHandle = signatureDecoder.DecodeFieldSignature(fieldDef.Signature, moduleHandle, ctx); + TypeHandle methodTableHandle = rtsContract.GetMethodTable(foundTypeHandle); + data->MTOfType = methodTableHandle.Address.ToClrDataAddress(_target); + } + catch (System.Exception) + { + // if we can't find the MT (e.g in a minidump) + data->MTOfType = 0; + } + + // partial decoding of signature + BlobReader blobReader = mdReader.GetBlobReader(fieldDef.Signature); + SignatureHeader header = blobReader.ReadSignatureHeader(); + if (header.Kind != SignatureKind.Field) + throw new BadImageFormatException(); + CorElementType typeCode = (CorElementType)blobReader.ReadCompressedInteger(); + if (typeCode == CorElementType.Class || typeCode == CorElementType.ValueType) + { + EntityHandle entityHandle = blobReader.ReadTypeHandle(); + data->TokenOfType = (uint)MetadataTokens.GetToken(entityHandle); + } + else + { + data->TokenOfType = (uint)CorTokenType.mdtTypeDef; + if (data->MTOfType == 0) + data->sigType = (uint)typeCode; + } + + data->ModuleOfType = modulePtr.ToClrDataAddress(_target); + data->mb = token; + data->MTOfEnclosingClass = ctx.Address.ToClrDataAddress(_target); + data->dwOffset = rtsContract.GetFieldDescOffset(fieldDescTargetPtr, fieldDef); + data->bIsThreadLocal = rtsContract.IsFieldDescThreadStatic(fieldDescTargetPtr) ? 1 : 0; + data->bIsContextLocal = 0; + data->bIsStatic = rtsContract.IsFieldDescStatic(fieldDescTargetPtr) ? 1 : 0; + data->NextField = rtsContract.GetFieldDescNextField(fieldDescTargetPtr).ToClrDataAddress(_target); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacyImpl is not null) + { + DacpFieldDescData dataLocal = default; + int hrLocal = _legacyImpl.GetFieldDescData(fieldDesc, &dataLocal); + Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}"); + if (hr == HResults.S_OK) + { + Debug.Assert(data->Type == dataLocal.Type, $"cDAC: {data->Type}, DAC: {dataLocal.Type}"); + Debug.Assert(data->sigType == dataLocal.sigType, $"cDAC: {data->sigType}, DAC: {dataLocal.sigType}"); + Debug.Assert(data->TokenOfType == dataLocal.TokenOfType, $"cDAC: {data->TokenOfType:x}, DAC: {dataLocal.TokenOfType:x}"); + Debug.Assert(data->MTOfType == dataLocal.MTOfType, $"cDAC: {data->MTOfType:x}, DAC: {dataLocal.MTOfType:x}"); + Debug.Assert(data->ModuleOfType == dataLocal.ModuleOfType, $"cDAC: {data->ModuleOfType:x}, DAC: {dataLocal.ModuleOfType:x}"); + Debug.Assert(data->mb == dataLocal.mb, $"cDAC: {data->mb:x}, DAC: {dataLocal.mb:x}"); + Debug.Assert(data->MTOfEnclosingClass == dataLocal.MTOfEnclosingClass, $"cDAC: {data->MTOfEnclosingClass:x}, DAC: {dataLocal.MTOfEnclosingClass:x}"); + Debug.Assert(data->dwOffset == dataLocal.dwOffset, $"cDAC: {data->dwOffset:x}, DAC: {dataLocal.dwOffset:x}"); + Debug.Assert(data->bIsThreadLocal == dataLocal.bIsThreadLocal, $"cDAC: {data->bIsThreadLocal}, DAC: {dataLocal.bIsThreadLocal}"); + Debug.Assert(data->bIsContextLocal == dataLocal.bIsContextLocal, $"cDAC: {data->bIsContextLocal}, DAC: {dataLocal.bIsContextLocal}"); + Debug.Assert(data->bIsStatic == dataLocal.bIsStatic, $"cDAC: {data->bIsStatic}, DAC: {dataLocal.bIsStatic}"); + Debug.Assert(data->NextField == dataLocal.NextField, $"cDAC: {data->NextField:x}, DAC: {dataLocal.NextField:x}"); + } + } +#endif + return hr; + } int ISOSDacInterface.GetFrameName(ClrDataAddress vtable, uint count, char* frameName, uint* pNeeded) { if (vtable == 0) From bbc99bc5bc3ca5e5f48e7e52457ab406da2f1e2d Mon Sep 17 00:00:00 2001 From: Rachel Date: Fri, 5 Sep 2025 15:41:47 -0700 Subject: [PATCH 02/17] Fix missing newline at end of contracts.jsonc --- src/coreclr/vm/datadescriptor/contracts.jsonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/datadescriptor/contracts.jsonc b/src/coreclr/vm/datadescriptor/contracts.jsonc index 3d8d8e17ea0543..363dabd1f9bd00 100644 --- a/src/coreclr/vm/datadescriptor/contracts.jsonc +++ b/src/coreclr/vm/datadescriptor/contracts.jsonc @@ -26,4 +26,4 @@ "StressLog": 2, "Thread": 1, "SignatureDecoder": 1 -} \ No newline at end of file +} From 14d46312c3a38a28149cfe31186e56dfc93fa4fb Mon Sep 17 00:00:00 2001 From: Rachel Date: Fri, 5 Sep 2025 15:44:35 -0700 Subject: [PATCH 03/17] Update src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs index 404147fd440853..8a2ab037359aed 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs @@ -234,7 +234,7 @@ public enum Flags : uint internal struct DacpFieldDescData { public uint Type; - public uint sigType; // ELEMENT_TYPE_XXX from signature. We need this to disply pretty name for String in minidump's case + public uint sigType; // ELEMENT_TYPE_XXX from signature. We need this to display pretty name for String in minidump's case public ClrDataAddress MTOfType; // NULL if Type is not loaded public ClrDataAddress ModuleOfType; public uint TokenOfType; From 387207c40dad95137a4fd50ee3f5496b1a4de4fe Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 5 Sep 2025 16:25:04 -0700 Subject: [PATCH 04/17] fix --- src/coreclr/vm/binder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/binder.h b/src/coreclr/vm/binder.h index f8515a26b1a7c6..ba3cc41aba0e9e 100644 --- a/src/coreclr/vm/binder.h +++ b/src/coreclr/vm/binder.h @@ -294,6 +294,7 @@ class CoreLibBinder USHORT m_cFields; static CrstStatic s_SigConvertCrst; + friend struct ::cdac_data; #ifdef _DEBUG @@ -309,7 +310,6 @@ class CoreLibBinder }; static const OffsetAndSizeCheck OffsetsAndSizes[]; - friend struct ::cdac_data; #endif }; From 7917e1bd39342f669494f15a9ec410128aeec52f Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 10 Sep 2025 15:51:41 -0700 Subject: [PATCH 05/17] code review --- .../design/datacontracts/RuntimeTypeSystem.md | 110 ++++++++++++------ docs/design/datacontracts/SignatureDecoder.md | 5 +- .../vm/datadescriptor/datadescriptor.inc | 2 +- src/coreclr/vm/field.h | 1 + .../Contracts/IRuntimeTypeSystem.cs | 4 +- .../Constants.cs | 3 +- .../Contracts/RuntimeTypeSystem_1.cs | 87 ++++++++++---- .../Signature/SignatureTypeProvider.cs | 101 +++------------- .../Contracts/SignatureDecoder_1.cs | 44 +++---- .../EcmaMetadataUtils.cs | 1 + .../Legacy/ISOSDacInterface.cs | 31 ++--- .../Legacy/SOSDacImpl.cs | 6 +- 12 files changed, 197 insertions(+), 198 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 10128650ab610c..d9cf39cd75e171 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -87,6 +87,8 @@ partial interface IRuntimeTypeSystem : IContract // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. public virtual bool IsArray(TypeHandle typeHandle, out uint rank); public virtual TypeHandle GetTypeParam(TypeHandle typeHandle); + public virtual TypeHandle IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments); + public TypeHandle GetPrimitiveType(CorElementType typeCode); public virtual bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token); public virtual bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan retAndArgTypes, out byte callConv); @@ -183,6 +185,17 @@ partial interface IRuntimeTypeSystem : IContract } ``` +### FieldDesc +```csharp +TargetPointer GetMTOfEnclosingClass(TargetPointer fieldDescPointer); +uint GetFieldDescMemberDef(TargetPointer fieldDescPointer); +bool IsFieldDescThreadStatic(TargetPointer fieldDescPointer); +bool IsFieldDescStatic(TargetPointer fieldDescPointer); +uint GetFieldDescType(TargetPointer fieldDescPointer); +uint GetFieldDescOffset(TargetPointer fieldDescPointer, FieldDefinition fieldDef); +TargetPointer GetFieldDescNextField(TargetPointer fieldDescPointer); +``` + ## Version 1 ### TypeHandle @@ -289,17 +302,6 @@ internal partial struct RuntimeTypeSystem_1 } ``` -### FieldDesc -```csharp -TargetPointer GetMTOfEnclosingClass(TargetPointer fieldDescPointer); -uint GetFieldDescMemberDef(TargetPointer fieldDescPointer); -bool IsFieldDescThreadStatic(TargetPointer fieldDescPointer); -bool IsFieldDescStatic(TargetPointer fieldDescPointer); -uint GetFieldDescType(TargetPointer fieldDescPointer); -uint GetFieldDescOffset(TargetPointer fieldDescPointer, FieldDefinition fieldDef); -TargetPointer GetFieldDescNextField(TargetPointer fieldDescPointer); -``` - Internally the contract has a `MethodTable_1` struct that depends on the `MethodTable` data descriptor ```csharp @@ -713,6 +715,69 @@ Contracts used: throw new ArgumentException(nameof(typeHandle)); } + // helper functions + + private bool GenericInstantiationMatch(TypeHandle genericType, TypeHandle potentialMatch, ImmutableArray typeArguments) + { + ReadOnlySpan instantiation = GetInstantiation(potentialMatch); + if (instantiation.Length != typeArguments.Length) + return false; + + if (GetTypeDefToken(genericType) != GetTypeDefToken(potentialMatch)) + return false; + + if (GetModule(genericType) != GetModule(potentialMatch)) + return false; + + for (int i = 0; i < instantiation.Length; i++) + { + if (!(instantiation[i].Address == typeArguments[i].Address)) + return false; + } + return true; + } + + private bool ArrayPtrMatch(TypeHandle elementType, CorElementType corElementType, int rank, TypeHandle potentialMatch) + { + IsArray(potentialMatch, out uint typeHandleRank); + return GetSignatureCorElementType(potentialMatch) == corElementType && + GetTypeParam(potentialMatch).Address == elementType.Address && + (corElementType == CorElementType.SzArray || corElementType == CorElementType.Byref || + corElementType == CorElementType.Ptr || (rank == typeHandleRank)); + + } + + public TypeHandle IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) + { + ILoader loaderContract = _target.Contracts.Loader; + TargetPointer loaderModule = ((IRuntimeTypeSystem)this).GetLoaderModule(typeHandle); + ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); + foreach (TargetPointer ptr in loaderContract.GetAvailableTypeParams(moduleHandle)) + { + TypeHandle potentialMatch = GetTypeHandle(ptr); + if (corElementType == CorElementType.GenericInst) + { + if (GenericInstantiationMatch(typeHandle, potentialMatch, typeArguments)) + { + return potentialMatch; + } + } + else if (ArrayPtrMatch(typeHandle, corElementType, rank, potentialMatch)) + { + return potentialMatch; + } + } + return new TypeHandle(TargetPointer.Null); + } + + public TypeHandle GetPrimitiveType(CorElementType typeCode) + { + TargetPointer coreLib = _target.ReadGlobalPointer("CoreLib"); + TargetPointer classes = _target.ReadPointer(coreLib + /* CoreLibBinder::Classes offset */); + TargetPointer typeHandlePtr = _target.ReadPointer(classes + (ulong)typeCode * (ulong)_target.PointerSize); + return GetTypeHandle(typeHandlePtr); + } + public bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) { module = TargetPointer.Null; @@ -1480,29 +1545,6 @@ Getting a MethodDesc for a certain slot in a MethodTable return GetMethodDescForEntrypoint(pCode); } - - TypeHandle IRuntimeTypeSystem.GetMethodTable(TypeHandle typeHandle) - { - if (typeHandle.IsTypeDesc()) - { - Data.TypeDesc typeDesc = target.ProcessedData.GetOrAdd(typeHandle.TypeDescAddress()); - CorElementType elemType = (CorElementType)(typeDesc.TypeAndFlags & 0xFF); - switch (elemType) - { - case CorElementType.Ptr: - case CorElementType.FnPtr: - TargetPointer coreLib = target.ReadGlobalPointer(Constants.Globals.CoreLib); - TargetPointer classes = target.ReadPointer(coreLib + /* CoreLibData::Classes offset */); - TargetPointer typeHandlePtr = target.ReadPointer(classes + (ulong)CorElementType.U * (ulong)target.PointerSize); - return GetTypeHandle(typeHandlePtr); - case CorElementType.ValueType: - return GetTypeHandle(target.ReadPointer(typeHandle.TypeDescAddress() + /* ParamTypeDesc::TypeArg offset */)); - default: - return new TypeHandle(TargetPointer.Null); - } - } - return typeHandle; - } ``` ### FieldDesc diff --git a/docs/design/datacontracts/SignatureDecoder.md b/docs/design/datacontracts/SignatureDecoder.md index 7a08124b0a1e64..20a5797cc68c83 100644 --- a/docs/design/datacontracts/SignatureDecoder.md +++ b/docs/design/datacontracts/SignatureDecoder.md @@ -16,14 +16,13 @@ Data descriptors used: | Data Descriptor Name | Field | Meaning | | --- | --- | --- | | CoreLibBinder | Classes | MTs for primitive types | -| ILCodeVersionNode | TypeDefToMethodTableMap | Mapping table | -| ILCodeVersionNode | TypeRefToMethodTableMap | Mapping table | +| Module | TypeDefToMethodTableMap | Mapping table | +| Module | TypeRefToMethodTableMap | Mapping table | Global variables used: | Global Name | Type | Purpose | | --- | --- | --- | | CoreLib | TargetPointer | pointer to the `CoreLibBinder` | -| PredefinedArrayTypes | TargetPointer | pointer to the cache of primitive-type array MTs | | ObjectMethodTable | TargetPointer | pointer to the MT of `object` | | StringMethodTable | TargetPointer | pointer to the MT of `string` | diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index dda52c9c178921..edbdcbc0bbb32e 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -992,7 +992,7 @@ CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass) CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable) CDAC_GLOBAL_POINTER(ObjectMethodTable, &::g_pObjectClass) CDAC_GLOBAL_POINTER(ObjectArrayMethodTable, &::g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT]) -CDAC_GLOBAL_POINTER(PredefinedArrayTypes, &::g_pPredefinedArrayTypes) +CDAC_GLOBAL_POINTER(StringArrayMethodTable, &::g_pPredefinedArrayTypes[ELEMENT_TYPE_STRING]) CDAC_GLOBAL_POINTER(StringMethodTable, &::g_pStringClass) CDAC_GLOBAL_POINTER(SyncTableEntries, &::g_pSyncTable) CDAC_GLOBAL_POINTER(MiniMetaDataBuffAddress, &::g_MiniMetaDataBuffAddress) diff --git a/src/coreclr/vm/field.h b/src/coreclr/vm/field.h index f78928d042c3de..a97d25fa5c1ef2 100644 --- a/src/coreclr/vm/field.h +++ b/src/coreclr/vm/field.h @@ -43,6 +43,7 @@ class FieldDesc PTR_MethodTable m_pMTOfEnclosingClass; // This is used to hold the log2 of the field size temporarily during class loading. Yuck. // See also: FieldDesc::InitializeFrom method + // if this structure is changed please update cdac_data #if defined(DACCESS_COMPILE) union { //create a union so I can get the correct offset for ClrDump. diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index a1a9c6c1d7e41c..da7262288894d0 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -4,6 +4,7 @@ using System; using System.Reflection.Metadata; using System.Collections.Generic; +using System.Collections.Immutable; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -94,7 +95,6 @@ public interface IRuntimeTypeSystem : IContract IEnumerable GetIntroducedMethodDescs(TypeHandle methodTable) => throw new NotImplementedException(); TargetCodePointer GetSlot(TypeHandle typeHandle, uint slot) => throw new NotImplementedException(); - TypeHandle GetMethodTable(TypeHandle typeHandle) => throw new NotImplementedException(); uint GetBaseSize(TypeHandle typeHandle) => throw new NotImplementedException(); // The component size is only available for strings and arrays. It is the size of the element type of the array, or the size of an ECMA 335 character (2 bytes) @@ -140,6 +140,8 @@ public interface IRuntimeTypeSystem : IContract // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. bool IsArray(TypeHandle typeHandle, out uint rank) => throw new NotImplementedException(); TypeHandle GetTypeParam(TypeHandle typeHandle) => throw new NotImplementedException(); + TypeHandle IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) => throw new NotImplementedException(); + TypeHandle GetPrimitiveType(CorElementType typeCode) => throw new NotImplementedException(); bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) => throw new NotImplementedException(); TargetPointer GetLoaderModule(TypeHandle typeHandle) => throw new NotImplementedException(); bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan retAndArgTypes, out byte callConv) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs index 5f86805aec3ca2..3a602379043b12 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -24,9 +24,8 @@ public static class Globals public const string FreeObjectMethodTable = nameof(FreeObjectMethodTable); public const string ObjectMethodTable = nameof(ObjectMethodTable); public const string ObjectArrayMethodTable = nameof(ObjectArrayMethodTable); + public const string StringArrayMethodTable = nameof(StringArrayMethodTable); public const string StringMethodTable = nameof(StringMethodTable); - public const string PredefinedArrayTypes = nameof(PredefinedArrayTypes); - public const string MiniMetaDataBuffAddress = nameof(MiniMetaDataBuffAddress); public const string MiniMetaDataBuffMaxSize = nameof(MiniMetaDataBuffMaxSize); public const string DacNotificationFlags = nameof(DacNotificationFlags); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 4d947585e9dc97..500992a474aa96 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -8,7 +8,7 @@ using Microsoft.Diagnostics.DataContractReader.RuntimeTypeSystemHelpers; using Microsoft.Diagnostics.DataContractReader.Data; using System.Reflection.Metadata; -using Microsoft.Diagnostics.Contracts; +using System.Collections.Immutable; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -660,6 +660,67 @@ public TypeHandle GetTypeParam(TypeHandle typeHandle) throw new ArgumentException(nameof(typeHandle)); } + private bool GenericInstantiationMatch(TypeHandle genericType, TypeHandle potentialMatch, ImmutableArray typeArguments) + { + ReadOnlySpan instantiation = GetInstantiation(potentialMatch); + if (instantiation.Length != typeArguments.Length) + return false; + + if (GetTypeDefToken(genericType) != GetTypeDefToken(potentialMatch)) + return false; + + if (GetModule(genericType) != GetModule(potentialMatch)) + return false; + + for (int i = 0; i < instantiation.Length; i++) + { + if (!(instantiation[i].Address == typeArguments[i].Address)) + return false; + } + return true; + } + + private bool ArrayPtrMatch(TypeHandle elementType, CorElementType corElementType, int rank, TypeHandle potentialMatch) + { + IsArray(potentialMatch, out uint typeHandleRank); + return GetSignatureCorElementType(potentialMatch) == corElementType && + GetTypeParam(potentialMatch).Address == elementType.Address && + (corElementType == CorElementType.SzArray || corElementType == CorElementType.Byref || + corElementType == CorElementType.Ptr || (rank == typeHandleRank)); + + } + + TypeHandle IRuntimeTypeSystem.IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) + { + ILoader loaderContract = _target.Contracts.Loader; + TargetPointer loaderModule = ((IRuntimeTypeSystem)this).GetLoaderModule(typeHandle); + ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); + foreach (TargetPointer ptr in loaderContract.GetAvailableTypeParams(moduleHandle)) + { + TypeHandle potentialMatch = GetTypeHandle(ptr); + if (corElementType == CorElementType.GenericInst) + { + if (GenericInstantiationMatch(typeHandle, potentialMatch, typeArguments)) + { + return potentialMatch; + } + } + else if (ArrayPtrMatch(typeHandle, corElementType, rank, potentialMatch)) + { + return potentialMatch; + } + } + return new TypeHandle(TargetPointer.Null); + } + + TypeHandle IRuntimeTypeSystem.GetPrimitiveType(CorElementType typeCode) + { + TargetPointer coreLib = _target.ReadGlobalPointer(Constants.Globals.CoreLib); + CoreLibBinder coreLibData = _target.ProcessedData.GetOrAdd(coreLib); + TargetPointer typeHandlePtr = _target.ReadPointer(coreLibData.Classes + (ulong)typeCode * (ulong)_target.PointerSize); + return GetTypeHandle(typeHandlePtr); + } + public bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) { module = TargetPointer.Null; @@ -1179,30 +1240,6 @@ private TargetPointer GetMethodDescForVtableSlot(TypeHandle typeHandle, ushort s return GetMethodDescForEntrypoint(pCode); } - TypeHandle IRuntimeTypeSystem.GetMethodTable(TypeHandle typeHandle) - { - if (typeHandle.IsTypeDesc()) - { - Data.TypeDesc typeDesc = _target.ProcessedData.GetOrAdd(typeHandle.TypeDescAddress()); - CorElementType elemType = (CorElementType)(typeDesc.TypeAndFlags & 0xFF); - switch (elemType) - { - case CorElementType.Ptr: - case CorElementType.FnPtr: - TargetPointer coreLib = _target.ReadGlobalPointer(Constants.Globals.CoreLib); - CoreLibBinder coreLibData = _target.ProcessedData.GetOrAdd(coreLib); - TargetPointer typeHandlePtr = _target.ReadPointer(coreLibData.Classes + (ulong)CorElementType.U * (ulong)_target.PointerSize); - return GetTypeHandle(typeHandlePtr); - case CorElementType.ValueType: - Data.ParamTypeDesc paramTypeDesc = _target.ProcessedData.GetOrAdd(typeHandle.TypeDescAddress()); - return GetTypeHandle(paramTypeDesc.TypeArg); - default: - return new TypeHandle(TargetPointer.Null); - } - } - return typeHandle; - } - private readonly TargetPointer GetMethodDescForEntrypoint(TargetCodePointer pCode) { // standard path, ask ExecutionManager for the MethodDesc diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs index a44c5d9c831cb8..4da33d7c8216e6 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs @@ -4,90 +4,33 @@ using System.Reflection.Metadata.Ecma335; using System.Reflection.Metadata; using Microsoft.Diagnostics.DataContractReader.Data; -using Microsoft.Diagnostics.DataContractReader.Contracts; using System; using System.Collections.Immutable; -using Microsoft.Diagnostics.DataContractReader; -namespace Microsoft.Diagnostics.Contracts; +namespace Microsoft.Diagnostics.DataContractReader.Contracts; public class SignatureTypeProvider : ISignatureTypeProvider { // All interface methods throw NotImplementedException for now private readonly Target _target; - private readonly DataContractReader.Contracts.ModuleHandle _moduleHandle; + private readonly ModuleHandle _moduleHandle; - public SignatureTypeProvider(Target target, DataContractReader.Contracts.ModuleHandle moduleHandle) + public SignatureTypeProvider(Target target, ModuleHandle moduleHandle) { _target = target; _moduleHandle = moduleHandle; } public TypeHandle GetArrayType(TypeHandle elementType, ArrayShape shape) - => IterateTypeParams(elementType, CorElementType.Array, shape.Rank, default); + => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.Array, shape.Rank, default); public TypeHandle GetByReferenceType(TypeHandle elementType) - => IterateTypeParams(elementType, CorElementType.Byref, 0, default); + => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.Byref, 0, default); - private bool GenericInstantiationMatch(TypeHandle genericType, TypeHandle potentialMatch, ImmutableArray typeArguments) - { - IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; - ReadOnlySpan instantiation = rtsContract.GetInstantiation(potentialMatch); - if (instantiation.Length != typeArguments.Length) - return false; - - if (rtsContract.GetTypeDefToken(genericType) != rtsContract.GetTypeDefToken(potentialMatch)) - return false; - - if (rtsContract.GetModule(genericType) != rtsContract.GetModule(potentialMatch)) - return false; - - for (int i = 0; i < instantiation.Length; i++) - { - if (!(instantiation[i].Address == typeArguments[i].Address)) - return false; - } - return true; - } - - private bool ArrayPtrMatch(TypeHandle elementType, CorElementType corElementType, int rank, TypeHandle potentialMatch) - { - IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; - rtsContract.IsArray(potentialMatch, out uint typeHandleRank); - return rtsContract.GetSignatureCorElementType(potentialMatch) == corElementType && - rtsContract.GetTypeParam(potentialMatch).Address == elementType.Address && - (corElementType == CorElementType.SzArray || corElementType == CorElementType.Byref || - corElementType == CorElementType.Ptr || (rank == typeHandleRank)); - - } - - private TypeHandle IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) - { - ILoader loaderContract = _target.Contracts.Loader; - IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; - TargetPointer loaderModule = rtsContract.GetLoaderModule(typeHandle); - DataContractReader.Contracts.ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); - foreach (TargetPointer ptr in loaderContract.GetAvailableTypeParams(moduleHandle)) - { - TypeHandle potentialMatch = rtsContract.GetTypeHandle(ptr); - if (corElementType == CorElementType.GenericInst) - { - if (GenericInstantiationMatch(typeHandle, potentialMatch, typeArguments)) - { - return potentialMatch; - } - } - else if (ArrayPtrMatch(typeHandle, corElementType, rank, potentialMatch)) - { - return potentialMatch; - } - } - return new TypeHandle(TargetPointer.Null); - } public TypeHandle GetFunctionPointerType(MethodSignature signature) => GetPrimitiveType(PrimitiveTypeCode.IntPtr); public TypeHandle GetGenericInstantiation(TypeHandle genericType, ImmutableArray typeArguments) - => IterateTypeParams(genericType, CorElementType.GenericInst, 0, typeArguments); + => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(genericType, CorElementType.GenericInst, 0, typeArguments); public TypeHandle GetGenericMethodParameter(T context, int index) { @@ -115,43 +58,27 @@ public TypeHandle GetPinnedType(TypeHandle elementType) => elementType; public TypeHandle GetPointerType(TypeHandle elementType) - => IterateTypeParams(elementType, CorElementType.Ptr, 0, default); + => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.Ptr, 0, default); public TypeHandle GetPrimitiveType(PrimitiveTypeCode typeCode) - { - TargetPointer coreLib = _target.ReadGlobalPointer(Constants.Globals.CoreLib); - CoreLibBinder coreLibData = _target.ProcessedData.GetOrAdd(coreLib); - TargetPointer typeHandlePtr = _target.ReadPointer(coreLibData.Classes + (ulong)typeCode * (ulong)_target.PointerSize); - return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); - } - - private TypeHandle GetPrimitiveArrayType(CorElementType elementType) - { - TargetPointer arrayPtr = _target.ReadGlobalPointer(Constants.Globals.PredefinedArrayTypes); - TargetPointer typeHandlePtr = _target.ReadPointer(arrayPtr + (ulong)elementType * (ulong)_target.PointerSize); - return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); - } + => _target.Contracts.RuntimeTypeSystem.GetPrimitiveType(typeCode); public TypeHandle GetSZArrayType(TypeHandle elementType) { - IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; - CorElementType corElementType = rtsContract.GetSignatureCorElementType(elementType); TypeHandle typeHandle = default; - if (corElementType <= CorElementType.R8) - { - typeHandle = GetPrimitiveArrayType(corElementType); - } - else if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable))) + if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable))) { - typeHandle = GetPrimitiveArrayType(CorElementType.Object); + TargetPointer arrayPtr = _target.ReadGlobalPointer(Constants.Globals.ObjectArrayMethodTable); + typeHandle = _target.Contracts.RuntimeTypeSystem.GetTypeHandle(arrayPtr); } else if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.StringMethodTable))) { - typeHandle = GetPrimitiveArrayType(CorElementType.String); + TargetPointer arrayPtr = _target.ReadGlobalPointer(Constants.Globals.StringArrayMethodTable); + typeHandle = _target.Contracts.RuntimeTypeSystem.GetTypeHandle(arrayPtr); } if (typeHandle.Address == TargetPointer.Null) { - return IterateTypeParams(elementType, CorElementType.SzArray, 1, default); + return _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.SzArray, 1, default); } return typeHandle; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoder_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoder_1.cs index f0a2d4d1a026d5..e0ff6f1f1b1a63 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoder_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoder_1.cs @@ -3,11 +3,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; -using System.Runtime.InteropServices; -using Microsoft.Diagnostics.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -24,39 +21,32 @@ internal SignatureDecoder_1(Target target) _mdhProviders = new Dictionary>(); } - - private SignatureTypeProvider GetProvider(ModuleHandle moduleHandle) + private SignatureTypeProvider GetTypeHandleProvider(ModuleHandle moduleHandle) { - if (typeof(T) == typeof(TypeHandle)) + if (_thProviders.TryGetValue(moduleHandle, out SignatureTypeProvider? thProvider)) { - if (_thProviders.TryGetValue(moduleHandle, out SignatureTypeProvider? thProvider)) - { - return (SignatureTypeProvider)(object)thProvider; - } - - SignatureTypeProvider newProvider = new(_target, moduleHandle); - _thProviders[moduleHandle] = newProvider; - return (SignatureTypeProvider)(object)newProvider; + return (SignatureTypeProvider)(object)thProvider; } - else if (typeof(T) == typeof(MethodDescHandle)) - { - if (_mdhProviders.TryGetValue(moduleHandle, out SignatureTypeProvider? mdhProvider)) - { - return (SignatureTypeProvider)(object)mdhProvider; - } - SignatureTypeProvider newProvider = new(_target, moduleHandle); - _mdhProviders[moduleHandle] = newProvider; - return (SignatureTypeProvider)(object)newProvider; - } - else + SignatureTypeProvider newProvider = new(_target, moduleHandle); + _thProviders[moduleHandle] = newProvider; + return newProvider; + } + + private SignatureTypeProvider GetMethodDescHandleProvider(ModuleHandle moduleHandle) + { + if (_mdhProviders.TryGetValue(moduleHandle, out SignatureTypeProvider? mdhProvider)) { - throw new NotSupportedException($"Type parameter {typeof(T)} is not supported."); + return (SignatureTypeProvider)(object)mdhProvider; } + SignatureTypeProvider newProvider = new(_target, moduleHandle); + _mdhProviders[moduleHandle] = newProvider; + return newProvider; } + TypeHandle ISignatureDecoder.DecodeFieldSignature(BlobHandle blobHandle, ModuleHandle moduleHandle, TypeHandle ctx) { - SignatureTypeProvider provider = GetProvider(moduleHandle); + SignatureTypeProvider provider = GetTypeHandleProvider(moduleHandle); MetadataReader mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle)!; BlobReader blobReader = mdReader.GetBlobReader(blobHandle); SignatureDecoder decoder = new(provider, mdReader, ctx); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/EcmaMetadataUtils.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/EcmaMetadataUtils.cs index 83701bc8abe812..e49be30507f531 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/EcmaMetadataUtils.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/EcmaMetadataUtils.cs @@ -30,6 +30,7 @@ public static uint CreateMethodDef(uint tokenParts) public static uint CreateFieldDef(uint tokenParts) { + Debug.Assert((tokenParts & 0xff000000) == 0, $"Token type should not be set in {nameof(tokenParts)}"); return (uint)TokenType.mdtFieldDef | tokenParts; } } diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs index 8a2ab037359aed..2dc89a08e97fed 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs @@ -231,21 +231,6 @@ public enum Flags : uint public ClrDataAddress NativeCodeAddr; }; -internal struct DacpFieldDescData -{ - public uint Type; - public uint sigType; // ELEMENT_TYPE_XXX from signature. We need this to display pretty name for String in minidump's case - public ClrDataAddress MTOfType; // NULL if Type is not loaded - public ClrDataAddress ModuleOfType; - public uint TokenOfType; - public uint mb; - public ClrDataAddress MTOfEnclosingClass; - public uint dwOffset; - public int bIsThreadLocal; - public int bIsContextLocal; - public int bIsStatic; - public ClrDataAddress NextField; -}; internal struct DacpMethodDescData { @@ -365,6 +350,22 @@ internal unsafe partial interface ISOSEnum int GetCount(uint* pCount); } +internal struct DacpFieldDescData +{ + public uint Type; + public uint sigType; // ELEMENT_TYPE_XXX from signature. We need this to display pretty name for String in minidump's case + public ClrDataAddress MTOfType; // NULL if Type is not loaded + public ClrDataAddress ModuleOfType; + public uint TokenOfType; + public uint mb; + public ClrDataAddress MTOfEnclosingClass; + public uint dwOffset; + public int bIsThreadLocal; + public int bIsContextLocal; + public int bIsStatic; + public ClrDataAddress NextField; +}; + [GeneratedComInterface] [Guid("436f00f2-b42a-4b9f-870c-e73db66ae930")] internal unsafe partial interface ISOSDacInterface diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index 06698c21ccda18..aa341a9321aa52 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -673,6 +673,7 @@ int ISOSDacInterface.GetFailedAssemblyList(ClrDataAddress appDomain, int count, => _legacyImpl is not null ? _legacyImpl.GetFailedAssemblyList(appDomain, count, values, pNeeded) : HResults.E_NOTIMPL; int ISOSDacInterface.GetFailedAssemblyLocation(ClrDataAddress assesmbly, uint count, char* location, uint* pNeeded) => _legacyImpl is not null ? _legacyImpl.GetFailedAssemblyLocation(assesmbly, count, location, pNeeded) : HResults.E_NOTIMPL; + int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescData* data) { int hr = HResults.S_OK; @@ -701,10 +702,9 @@ int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescDat { // try to completely decode the signature TypeHandle foundTypeHandle = signatureDecoder.DecodeFieldSignature(fieldDef.Signature, moduleHandle, ctx); - TypeHandle methodTableHandle = rtsContract.GetMethodTable(foundTypeHandle); - data->MTOfType = methodTableHandle.Address.ToClrDataAddress(_target); + data->MTOfType = foundTypeHandle.Address.ToClrDataAddress(_target); } - catch (System.Exception) + catch (VirtualReadException) { // if we can't find the MT (e.g in a minidump) data->MTOfType = 0; From 00c25b51abb387c1fbb3901c926754d189ef2a84 Mon Sep 17 00:00:00 2001 From: Rachel Date: Thu, 11 Sep 2025 22:34:59 -0700 Subject: [PATCH 06/17] Update SignatureDecoder.md --- docs/design/datacontracts/SignatureDecoder.md | 105 +++--------------- 1 file changed, 16 insertions(+), 89 deletions(-) diff --git a/docs/design/datacontracts/SignatureDecoder.md b/docs/design/datacontracts/SignatureDecoder.md index 20a5797cc68c83..dc92c73949bea2 100644 --- a/docs/design/datacontracts/SignatureDecoder.md +++ b/docs/design/datacontracts/SignatureDecoder.md @@ -15,16 +15,16 @@ In version 1 of the SignatureDecoder contract we take advantage of the System.Re Data descriptors used: | Data Descriptor Name | Field | Meaning | | --- | --- | --- | -| CoreLibBinder | Classes | MTs for primitive types | | Module | TypeDefToMethodTableMap | Mapping table | | Module | TypeRefToMethodTableMap | Mapping table | Global variables used: | Global Name | Type | Purpose | | --- | --- | --- | -| CoreLib | TargetPointer | pointer to the `CoreLibBinder` | | ObjectMethodTable | TargetPointer | pointer to the MT of `object` | | StringMethodTable | TargetPointer | pointer to the MT of `string` | +| ObjectArrayMethodTable | TargetPointer | pointer to the MT of `object[]` | +| StringArrayMethodTable | TargetPointer | pointer to the MT of `string[]` | Contracts used: | Contract Name | @@ -48,71 +48,16 @@ public class SignatureTypeProvider : ISignatureTypeProvider _moduleHandle = moduleHandle; } public TypeHandle GetArrayType(TypeHandle elementType, ArrayShape shape) - => IterateTypeParams(elementType, CorElementType.Array, shape.Rank, default); + => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.Array, shape.Rank, default); public TypeHandle GetByReferenceType(TypeHandle elementType) - => IterateTypeParams(elementType, CorElementType.Byref, 0, default); + => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.Byref, 0, default); - private bool GenericInstantiationMatch(TypeHandle genericType, TypeHandle potentialMatch, ImmutableArray typeArguments) - { - IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; - ReadOnlySpan instantiation = rtsContract.GetInstantiation(potentialMatch); - if (instantiation.Length != typeArguments.Length) - return false; - - if (rtsContract.GetTypeDefToken(genericType) != rtsContract.GetTypeDefToken(potentialMatch)) - return false; - - if (rtsContract.GetModule(genericType) != rtsContract.GetModule(potentialMatch)) - return false; - - for (int i = 0; i < instantiation.Length; i++) - { - if (!(instantiation[i].Address == typeArguments[i].Address)) - return false; - } - return true; - } - - private bool ArrayPtrMatch(TypeHandle elementType, CorElementType corElementType, int rank, TypeHandle potentialMatch) - { - IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; - rtsContract.IsArray(potentialMatch, out uint typeHandleRank); - return rtsContract.GetSignatureCorElementType(potentialMatch) == corElementType && - rtsContract.GetTypeParam(potentialMatch).Address == elementType.Address && - (corElementType == CorElementType.SzArray || corElementType == CorElementType.Byref || - corElementType == CorElementType.Ptr || (rank == typeHandleRank)); - - } - - private TypeHandle IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) - { - ILoader loaderContract = _target.Contracts.Loader; - IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; - TargetPointer loaderModule = rtsContract.GetLoaderModule(typeHandle); - DataContractReader.Contracts.ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); - foreach (TargetPointer ptr in loaderContract.GetAvailableTypeParams(moduleHandle)) - { - TypeHandle potentialMatch = rtsContract.GetTypeHandle(ptr); - if (corElementType == CorElementType.GenericInst) - { - if (GenericInstantiationMatch(typeHandle, potentialMatch, typeArguments)) - { - return potentialMatch; - } - } - else if (ArrayPtrMatch(typeHandle, corElementType, rank, potentialMatch)) - { - return potentialMatch; - } - } - return new TypeHandle(TargetPointer.Null); - } public TypeHandle GetFunctionPointerType(MethodSignature signature) => GetPrimitiveType(PrimitiveTypeCode.IntPtr); public TypeHandle GetGenericInstantiation(TypeHandle genericType, ImmutableArray typeArguments) - => IterateTypeParams(genericType, CorElementType.GenericInst, 0, typeArguments); + => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(genericType, CorElementType.GenericInst, 0, typeArguments); public TypeHandle GetGenericMethodParameter(T context, int index) { @@ -140,60 +85,42 @@ public class SignatureTypeProvider : ISignatureTypeProvider => elementType; public TypeHandle GetPointerType(TypeHandle elementType) - => IterateTypeParams(elementType, CorElementType.Ptr, 0, default); + => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.Ptr, 0, default); public TypeHandle GetPrimitiveType(PrimitiveTypeCode typeCode) - { - TargetPointer coreLib = _target.ReadGlobalPointer("CoreLib"); - CoreLibBinder coreLibData = _target.ProcessedData.GetOrAdd(coreLib); - TargetPointer typeHandlePtr = _target.ReadPointer(coreLibData.Classes + (ulong)typeCode * (ulong)_target.PointerSize); - return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); - } - - private TypeHandle GetPrimitiveArrayType(CorElementType elementType) - { - TargetPointer arrayPtr = _target.ReadGlobalPointer("PredefinedArrayTypes"); - TargetPointer typeHandlePtr = _target.ReadPointer(arrayPtr + (ulong)elementType * (ulong)_target.PointerSize); - return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); - } + => _target.Contracts.RuntimeTypeSystem.GetPrimitiveType(typeCode); public TypeHandle GetSZArrayType(TypeHandle elementType) { - IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; - CorElementType corElementType = rtsContract.GetSignatureCorElementType(elementType); TypeHandle typeHandle = default; - if (corElementType <= CorElementType.R8) + if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer("ObjectMethodTable"))) { - typeHandle = GetPrimitiveArrayType(corElementType); - } - else if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer("ObjectMethodTable"))) - { - typeHandle = GetPrimitiveArrayType(CorElementType.Object); + TargetPointer arrayPtr = _target.ReadGlobalPointer("ObjectArrayMethodTable"); + typeHandle = _target.Contracts.RuntimeTypeSystem.GetTypeHandle(arrayPtr); } else if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer("StringMethodTable"))) { - typeHandle = GetPrimitiveArrayType(CorElementType.String); + TargetPointer arrayPtr = _target.ReadGlobalPointer("StringArrayMethodTable"); + typeHandle = _target.Contracts.RuntimeTypeSystem.GetTypeHandle(arrayPtr); } if (typeHandle.Address == TargetPointer.Null) { - return IterateTypeParams(elementType, CorElementType.SzArray, 1, default); + return _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.SzArray, 1, default); } return typeHandle; } public TypeHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) { - Module module = _target.ProcessedData.GetOrAdd(_moduleHandle.Address); int token = MetadataTokens.GetToken((EntityHandle)handle); - TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(module.TypeDefToMethodTableMap, (uint)token, out _); + TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(_target.ReadPointer(moduleHandle.Address + /* Module::TypeDefToMethodTableMap offset */, (uint)token, out _); return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); } public TypeHandle GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) { - Module module = _target.ProcessedData.GetOrAdd(_moduleHandle.Address); int token = MetadataTokens.GetToken((EntityHandle)handle); - TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(module.TypeRefToMethodTableMap, (uint)token, out _); + TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(_target.ReadPointer(moduleHandle.Address + /* Module::TypeRefToMethodTableMap offset */, (uint)token, out _); return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); } @@ -213,4 +140,4 @@ TypeHandle ISignatureDecoder.DecodeFieldSignature(BlobHandle blobHandle, ModuleH SignatureDecoder decoder = new(provider, mdReader, ctx); return decoder.DecodeFieldSignature(ref blobReader); } -``` \ No newline at end of file +``` From b1f541ec5aa26a8b648601b558e70655f70a470a Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 12 Sep 2025 10:25:03 -0700 Subject: [PATCH 07/17] code review --- .../design/datacontracts/RuntimeTypeSystem.md | 13 ++++- docs/design/datacontracts/SignatureDecoder.md | 21 +------- .../vm/datadescriptor/datadescriptor.inc | 1 - src/coreclr/vm/field.h | 13 +---- .../Contracts/IRuntimeTypeSystem.cs | 1 + .../Constants.cs | 1 - .../Contracts/RuntimeTypeSystem_1.cs | 10 ++++ .../SignatureDecoderFactory.cs | 0 .../{ => Signature}/SignatureDecoder_1.cs | 1 + .../Signature/SignatureTypeProvider.cs | 52 +++++++------------ .../Legacy/SOSDacImpl.cs | 25 ++++++++- 11 files changed, 71 insertions(+), 67 deletions(-) rename src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/{ => Signature}/SignatureDecoderFactory.cs (100%) rename src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/{ => Signature}/SignatureDecoder_1.cs (97%) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index d9cf39cd75e171..3c377fe70d78b7 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -91,6 +91,7 @@ partial interface IRuntimeTypeSystem : IContract public TypeHandle GetPrimitiveType(CorElementType typeCode); public virtual bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token); public virtual bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan retAndArgTypes, out byte callConv); + public virtual bool IsPointer(TypeHandle typeHandle); #endregion TypeHandle inspection APIs } @@ -809,7 +810,7 @@ Contracts used: return false; int TypeAndFlags = // Read TypeAndFlags field from TypeDesc contract using address typeHandle.TypeDescAddress() - CorElementType elemType = (CorElementType)(typeDesc.TypeAndFlags & 0xFF); + CorElementType elemType = (CorElementType)(TypeAndFlags & 0xFF); if (elemType != CorElementType.FnPtr) return false; @@ -825,6 +826,16 @@ Contracts used: callConv = (byte) // Read CallConv field from FnPtrTypeDesc contract using address typeHandle.TypeDescAddress(), and then ignore all but the low 8 bits. return true; } + + public bool IsPointer(TypeHandle typeHandle) + { + if (!typeHandle.IsTypeDesc()) + return false; + + int TypeAndFlags = // Read TypeAndFlags field from TypeDesc contract using address typeHandle.TypeDescAddress() + CorElementType elemType = (CorElementType)(TypeAndFlags & 0xFF); + return elemType == CorElementType.Ptr; + } ``` ### MethodDesc diff --git a/docs/design/datacontracts/SignatureDecoder.md b/docs/design/datacontracts/SignatureDecoder.md index dc92c73949bea2..0063f14af1de9f 100644 --- a/docs/design/datacontracts/SignatureDecoder.md +++ b/docs/design/datacontracts/SignatureDecoder.md @@ -23,8 +23,6 @@ Global variables used: | --- | --- | --- | | ObjectMethodTable | TargetPointer | pointer to the MT of `object` | | StringMethodTable | TargetPointer | pointer to the MT of `string` | -| ObjectArrayMethodTable | TargetPointer | pointer to the MT of `object[]` | -| StringArrayMethodTable | TargetPointer | pointer to the MT of `string[]` | Contracts used: | Contract Name | @@ -91,24 +89,7 @@ public class SignatureTypeProvider : ISignatureTypeProvider => _target.Contracts.RuntimeTypeSystem.GetPrimitiveType(typeCode); public TypeHandle GetSZArrayType(TypeHandle elementType) - { - TypeHandle typeHandle = default; - if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer("ObjectMethodTable"))) - { - TargetPointer arrayPtr = _target.ReadGlobalPointer("ObjectArrayMethodTable"); - typeHandle = _target.Contracts.RuntimeTypeSystem.GetTypeHandle(arrayPtr); - } - else if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer("StringMethodTable"))) - { - TargetPointer arrayPtr = _target.ReadGlobalPointer("StringArrayMethodTable"); - typeHandle = _target.Contracts.RuntimeTypeSystem.GetTypeHandle(arrayPtr); - } - if (typeHandle.Address == TargetPointer.Null) - { - return _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.SzArray, 1, default); - } - return typeHandle; - } + => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.SzArray, 1, default); public TypeHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) { diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index edbdcbc0bbb32e..ff32c0d9763010 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -992,7 +992,6 @@ CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass) CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable) CDAC_GLOBAL_POINTER(ObjectMethodTable, &::g_pObjectClass) CDAC_GLOBAL_POINTER(ObjectArrayMethodTable, &::g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT]) -CDAC_GLOBAL_POINTER(StringArrayMethodTable, &::g_pPredefinedArrayTypes[ELEMENT_TYPE_STRING]) CDAC_GLOBAL_POINTER(StringMethodTable, &::g_pStringClass) CDAC_GLOBAL_POINTER(SyncTableEntries, &::g_pSyncTable) CDAC_GLOBAL_POINTER(MiniMetaDataBuffAddress, &::g_MiniMetaDataBuffAddress) diff --git a/src/coreclr/vm/field.h b/src/coreclr/vm/field.h index a97d25fa5c1ef2..38bb0b44f39ff1 100644 --- a/src/coreclr/vm/field.h +++ b/src/coreclr/vm/field.h @@ -45,11 +45,9 @@ class FieldDesc // See also: FieldDesc::InitializeFrom method // if this structure is changed please update cdac_data -#if defined(DACCESS_COMPILE) union { //create a union so I can get the correct offset for ClrDump. unsigned m_dword1; struct { -#endif unsigned m_mb : 24; // 8 bits... @@ -57,24 +55,17 @@ class FieldDesc unsigned m_isThreadLocal : 1; unsigned m_isRVA : 1; unsigned m_prot : 3; -#if defined(DACCESS_COMPILE) }; }; -#endif - -#if defined(DACCESS_COMPILE) union { //create a union so I can get the correct offset for ClrDump unsigned m_dword2; struct { -#endif // Note: this has been as low as 22 bits in the past & seemed to be OK. // we can steal some more bits here if we need them. unsigned m_dwOffset : 27; unsigned m_type : 5; -#if defined(DACCESS_COMPILE) }; }; -#endif #ifdef _DEBUG LPUTF8 m_debugName; @@ -750,8 +741,8 @@ class FieldDesc template<> struct cdac_data { - static constexpr size_t DWord1 = offsetof(FieldDesc, m_pMTOfEnclosingClass) + sizeof(PTR_MethodTable); - static constexpr size_t DWord2 = DWord1 + 4; + static constexpr size_t DWord1 = offsetof(FieldDesc, m_dword1); + static constexpr size_t DWord2 = offsetof(FieldDesc, m_dword2); static constexpr size_t MTOfEnclosingClass = offsetof(FieldDesc, m_pMTOfEnclosingClass); }; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index da7262288894d0..e6c5ecb80fe001 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -145,6 +145,7 @@ public interface IRuntimeTypeSystem : IContract bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) => throw new NotImplementedException(); TargetPointer GetLoaderModule(TypeHandle typeHandle) => throw new NotImplementedException(); bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan retAndArgTypes, out byte callConv) => throw new NotImplementedException(); + bool IsPointer(TypeHandle typeHandle) => throw new NotImplementedException(); // Returns null if the TypeHandle is not a class/struct/generic variable #endregion TypeHandle inspection APIs diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs index 3a602379043b12..fbd7ccfb66ce62 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -24,7 +24,6 @@ public static class Globals public const string FreeObjectMethodTable = nameof(FreeObjectMethodTable); public const string ObjectMethodTable = nameof(ObjectMethodTable); public const string ObjectArrayMethodTable = nameof(ObjectArrayMethodTable); - public const string StringArrayMethodTable = nameof(StringArrayMethodTable); public const string StringMethodTable = nameof(StringMethodTable); public const string MiniMetaDataBuffAddress = nameof(MiniMetaDataBuffAddress); public const string MiniMetaDataBuffMaxSize = nameof(MiniMetaDataBuffMaxSize); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 500992a474aa96..7bb3e769333031 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -762,6 +762,16 @@ public bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan(typeHandle.TypeDescAddress()); + CorElementType elemType = (CorElementType)(typeDesc.TypeAndFlags & 0xFF); + return elemType == CorElementType.Ptr; + } + private sealed class FunctionPointerRetAndArgs : IData { public static FunctionPointerRetAndArgs Create(Target target, TargetPointer address) => new FunctionPointerRetAndArgs(target, address); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoderFactory.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoderFactory.cs similarity index 100% rename from src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoderFactory.cs rename to src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoderFactory.cs diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoder_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs similarity index 97% rename from src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoder_1.cs rename to src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs index e0ff6f1f1b1a63..95434abcb768f6 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SignatureDecoder_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using Microsoft.Diagnostics.DataContractReader.SignatureHelpers; namespace Microsoft.Diagnostics.DataContractReader.Contracts; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs index 4da33d7c8216e6..f2f4616b811100 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs @@ -6,38 +6,43 @@ using Microsoft.Diagnostics.DataContractReader.Data; using System; using System.Collections.Immutable; +using Microsoft.Diagnostics.DataContractReader.Contracts; -namespace Microsoft.Diagnostics.DataContractReader.Contracts; +namespace Microsoft.Diagnostics.DataContractReader.SignatureHelpers; public class SignatureTypeProvider : ISignatureTypeProvider { // All interface methods throw NotImplementedException for now private readonly Target _target; - private readonly ModuleHandle _moduleHandle; + private readonly Contracts.ModuleHandle _moduleHandle; + private readonly Contracts.ILoader _loader; + private readonly Contracts.IRuntimeTypeSystem _runtimeTypeSystem; - public SignatureTypeProvider(Target target, ModuleHandle moduleHandle) + public SignatureTypeProvider(Target target, Contracts.ModuleHandle moduleHandle) { _target = target; _moduleHandle = moduleHandle; + _loader = target.Contracts.Loader; + _runtimeTypeSystem = target.Contracts.RuntimeTypeSystem; } public TypeHandle GetArrayType(TypeHandle elementType, ArrayShape shape) - => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.Array, shape.Rank, default); + => _runtimeTypeSystem.IterateTypeParams(elementType, CorElementType.Array, shape.Rank, default); public TypeHandle GetByReferenceType(TypeHandle elementType) - => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.Byref, 0, default); + => _runtimeTypeSystem.IterateTypeParams(elementType, CorElementType.Byref, 0, default); public TypeHandle GetFunctionPointerType(MethodSignature signature) => GetPrimitiveType(PrimitiveTypeCode.IntPtr); public TypeHandle GetGenericInstantiation(TypeHandle genericType, ImmutableArray typeArguments) - => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(genericType, CorElementType.GenericInst, 0, typeArguments); + => _runtimeTypeSystem.IterateTypeParams(genericType, CorElementType.GenericInst, 0, typeArguments); public TypeHandle GetGenericMethodParameter(T context, int index) { if (typeof(T) == typeof(MethodDescHandle)) { MethodDescHandle methodContext = (MethodDescHandle)(object)context!; - return _target.Contracts.RuntimeTypeSystem.GetGenericMethodInstantiation(methodContext)[index]; + return _runtimeTypeSystem.GetGenericMethodInstantiation(methodContext)[index]; } throw new NotSupportedException(); } @@ -47,7 +52,7 @@ public TypeHandle GetGenericTypeParameter(T context, int index) if (typeof(T) == typeof(TypeHandle)) { typeContext = (TypeHandle)(object)context!; - return _target.Contracts.RuntimeTypeSystem.GetInstantiation(typeContext)[index]; + return _runtimeTypeSystem.GetInstantiation(typeContext)[index]; } throw new NotImplementedException(); } @@ -58,45 +63,28 @@ public TypeHandle GetPinnedType(TypeHandle elementType) => elementType; public TypeHandle GetPointerType(TypeHandle elementType) - => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.Ptr, 0, default); + => _runtimeTypeSystem.IterateTypeParams(elementType, CorElementType.Ptr, 0, default); public TypeHandle GetPrimitiveType(PrimitiveTypeCode typeCode) - => _target.Contracts.RuntimeTypeSystem.GetPrimitiveType(typeCode); + => _runtimeTypeSystem.GetPrimitiveType((CorElementType)typeCode); public TypeHandle GetSZArrayType(TypeHandle elementType) - { - TypeHandle typeHandle = default; - if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable))) - { - TargetPointer arrayPtr = _target.ReadGlobalPointer(Constants.Globals.ObjectArrayMethodTable); - typeHandle = _target.Contracts.RuntimeTypeSystem.GetTypeHandle(arrayPtr); - } - else if (elementType.Address == _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.StringMethodTable))) - { - TargetPointer arrayPtr = _target.ReadGlobalPointer(Constants.Globals.StringArrayMethodTable); - typeHandle = _target.Contracts.RuntimeTypeSystem.GetTypeHandle(arrayPtr); - } - if (typeHandle.Address == TargetPointer.Null) - { - return _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.SzArray, 1, default); - } - return typeHandle; - } + => _runtimeTypeSystem.IterateTypeParams(elementType, CorElementType.SzArray, 1, default); public TypeHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) { Module module = _target.ProcessedData.GetOrAdd(_moduleHandle.Address); int token = MetadataTokens.GetToken((EntityHandle)handle); - TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(module.TypeDefToMethodTableMap, (uint)token, out _); - return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); + TargetPointer typeHandlePtr = _loader.GetModuleLookupMapElement(module.TypeDefToMethodTableMap, (uint)token, out _); + return _runtimeTypeSystem.GetTypeHandle(typeHandlePtr); } public TypeHandle GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) { Module module = _target.ProcessedData.GetOrAdd(_moduleHandle.Address); int token = MetadataTokens.GetToken((EntityHandle)handle); - TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(module.TypeRefToMethodTableMap, (uint)token, out _); - return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); + TargetPointer typeHandlePtr = _loader.GetModuleLookupMapElement(module.TypeRefToMethodTableMap, (uint)token, out _); + return _runtimeTypeSystem.GetTypeHandle(typeHandlePtr); } public TypeHandle GetTypeFromSpecification(MetadataReader reader, T context, TypeSpecificationHandle handle, byte rawTypeKind) diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index aa341a9321aa52..38d9e00a89d4c1 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -702,7 +702,30 @@ int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescDat { // try to completely decode the signature TypeHandle foundTypeHandle = signatureDecoder.DecodeFieldSignature(fieldDef.Signature, moduleHandle, ctx); - data->MTOfType = foundTypeHandle.Address.ToClrDataAddress(_target); + + // get the MT of the type + // This is an implementation detail of the DAC that we replicate here to get method tables for non-MT types + // that we can return to SOS for pretty-printing. + // In the future we may want to return a TypeHandle instead of a MethodTable, and modify SOS to do more complete pretty-printing. + if (rtsContract.IsFunctionPointer(foundTypeHandle, out _, out _) || rtsContract.IsPointer(foundTypeHandle)) + data->MTOfType = rtsContract.GetPrimitiveType(CorElementType.U).Address.ToClrDataAddress(_target); + // array MTs + else if (rtsContract.IsArray(foundTypeHandle, out _)) + data->MTOfType = foundTypeHandle.Address.ToClrDataAddress(_target); + else + { + try + { + // value typedescs + TypeHandle paramTypeHandle = rtsContract.GetTypeParam(foundTypeHandle); + data->MTOfType = paramTypeHandle.Address.ToClrDataAddress(_target); + } + catch (ArgumentException) + { + // non-array MTs + data->MTOfType = foundTypeHandle.Address.ToClrDataAddress(_target); + } + } } catch (VirtualReadException) { From 6b1dc39b350216c80cfb3737a1db33c00a2a2f51 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 12 Sep 2025 11:15:24 -0700 Subject: [PATCH 08/17] fix bad merge --- .../design/datacontracts/RuntimeTypeSystem.md | 2 +- .../Contracts/IRuntimeTypeSystem.cs | 1 - .../Contracts/RuntimeTypeSystem_1.cs | 30 ++----------------- 3 files changed, 3 insertions(+), 30 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index c621e603e03de7..2ddc7034cec36c 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -762,7 +762,7 @@ Contracts used: public TypeHandle IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) { ILoader loaderContract = _target.Contracts.Loader; - TargetPointer loaderModule = ((IRuntimeTypeSystem)this).GetLoaderModule(typeHandle); + TargetPointer loaderModule = GetLoaderModule(typeHandle); ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); foreach (TargetPointer ptr in loaderContract.GetAvailableTypeParams(moduleHandle)) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index ce8bea8143c0d0..555877ae5c6df2 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -85,7 +85,6 @@ public interface IRuntimeTypeSystem : IContract #region TypeHandle inspection APIs TypeHandle GetTypeHandle(TargetPointer address) => throw new NotImplementedException(); TargetPointer GetModule(TypeHandle typeHandle) => throw new NotImplementedException(); - TargetPointer GetLoaderModule(TypeHandle typeHandle) => throw new NotImplementedException(); // A canonical method table is either the MethodTable itself, or in the case of a generic instantiation, it is the // MethodTable of the prototypical instance. diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 83bd0e25257d76..0aa8862ae26d8b 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -693,7 +693,7 @@ private bool ArrayPtrMatch(TypeHandle elementType, CorElementType corElementType TypeHandle IRuntimeTypeSystem.IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) { ILoader loaderContract = _target.Contracts.Loader; - TargetPointer loaderModule = ((IRuntimeTypeSystem)this).GetLoaderModule(typeHandle); + TargetPointer loaderModule = GetLoaderModule(typeHandle); ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); foreach (TargetPointer ptr in loaderContract.GetAvailableTypeParams(moduleHandle)) { @@ -1066,32 +1066,6 @@ private bool HasMethodInstantiation(MethodDesc md) return md.Classification == MethodClassification.Instantiated && AsInstantiatedMethodDesc(md).HasMethodInstantiation; } - TargetPointer IRuntimeTypeSystem.GetLoaderModule(TypeHandle typeHandle) - { - if (typeHandle.IsTypeDesc()) - { - // TypeDesc::GetLoaderModule - if (HasTypeParam(typeHandle)) - { - return ((IRuntimeTypeSystem)this).GetLoaderModule(GetTypeParam(typeHandle)); - } - else if (IsGenericVariable(typeHandle, out TargetPointer genericParamModule, out _)) - { - return genericParamModule; - } - else - { - System.Diagnostics.Debug.Assert(IsFunctionPointer(typeHandle, out _, out _)); - FnPtrTypeDesc fnPtrTypeDesc = _target.ProcessedData.GetOrAdd(typeHandle.TypeDescAddress()); - return fnPtrTypeDesc.LoaderModule; - } - } - - MethodTable mt = _methodTables[typeHandle.Address]; - Data.MethodTableAuxiliaryData mtAuxData = _target.ProcessedData.GetOrAdd(mt.AuxiliaryData); - return mtAuxData.LoaderModule; - } - private bool IsGenericMethodDefinition(MethodDesc md) { return md.Classification == MethodClassification.Instantiated && AsInstantiatedMethodDesc(md).IsGenericMethodDefinition; @@ -1113,7 +1087,7 @@ private TargetPointer GetLoaderModule(MethodDesc md) { TargetPointer mtAddr = GetMethodTable(new MethodDescHandle(md.Address)); TypeHandle mt = GetTypeHandle(mtAddr); - return ((IRuntimeTypeSystem)this).GetLoaderModule(mt); + return GetLoaderModule(mt); } } From f38a02a693a5fbc6df935e39d0bc9aea1817b88f Mon Sep 17 00:00:00 2001 From: rcj1 Date: Sat, 13 Sep 2025 11:09:32 -0700 Subject: [PATCH 09/17] fixing custom modifiers and not-founds --- docs/design/datacontracts/RuntimeTypeSystem.md | 2 ++ docs/design/datacontracts/SignatureDecoder.md | 4 ++-- .../Contracts/RuntimeTypeSystem_1.cs | 2 ++ .../Contracts/Signature/SignatureTypeProvider.cs | 4 ++-- .../mscordaccore_universal/Legacy/SOSDacImpl.cs | 13 ++++++++++--- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 2ddc7034cec36c..8314f4f44b198d 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -761,6 +761,8 @@ Contracts used: public TypeHandle IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) { + if (typeHandle.Address == TargetPointer.Null) + return new TypeHandle(TargetPointer.Null); ILoader loaderContract = _target.Contracts.Loader; TargetPointer loaderModule = GetLoaderModule(typeHandle); ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); diff --git a/docs/design/datacontracts/SignatureDecoder.md b/docs/design/datacontracts/SignatureDecoder.md index 0063f14af1de9f..6f2d4435d39e3c 100644 --- a/docs/design/datacontracts/SignatureDecoder.md +++ b/docs/design/datacontracts/SignatureDecoder.md @@ -95,14 +95,14 @@ public class SignatureTypeProvider : ISignatureTypeProvider { int token = MetadataTokens.GetToken((EntityHandle)handle); TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(_target.ReadPointer(moduleHandle.Address + /* Module::TypeDefToMethodTableMap offset */, (uint)token, out _); - return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); + return typeHandlePtr == TargetPointer.Null ? new TypeHandle(TargetPointer.Null) : _runtimeTypeSystem.GetTypeHandle(typeHandlePtr); } public TypeHandle GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) { int token = MetadataTokens.GetToken((EntityHandle)handle); TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(_target.ReadPointer(moduleHandle.Address + /* Module::TypeRefToMethodTableMap offset */, (uint)token, out _); - return _target.Contracts.RuntimeTypeSystem.GetTypeHandle(typeHandlePtr); + return typeHandlePtr == TargetPointer.Null ? new TypeHandle(TargetPointer.Null) : _runtimeTypeSystem.GetTypeHandle(typeHandlePtr); } public TypeHandle GetTypeFromSpecification(MetadataReader reader, T context, TypeSpecificationHandle handle, byte rawTypeKind) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 0aa8862ae26d8b..dc40bead1031e4 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -692,6 +692,8 @@ private bool ArrayPtrMatch(TypeHandle elementType, CorElementType corElementType TypeHandle IRuntimeTypeSystem.IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) { + if (typeHandle.Address == TargetPointer.Null) + return new TypeHandle(TargetPointer.Null); ILoader loaderContract = _target.Contracts.Loader; TargetPointer loaderModule = GetLoaderModule(typeHandle); ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs index f2f4616b811100..ff6f4e362dbcd2 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs @@ -76,7 +76,7 @@ public TypeHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHan Module module = _target.ProcessedData.GetOrAdd(_moduleHandle.Address); int token = MetadataTokens.GetToken((EntityHandle)handle); TargetPointer typeHandlePtr = _loader.GetModuleLookupMapElement(module.TypeDefToMethodTableMap, (uint)token, out _); - return _runtimeTypeSystem.GetTypeHandle(typeHandlePtr); + return typeHandlePtr == TargetPointer.Null ? new TypeHandle(TargetPointer.Null) : _runtimeTypeSystem.GetTypeHandle(typeHandlePtr); } public TypeHandle GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) @@ -84,7 +84,7 @@ public TypeHandle GetTypeFromReference(MetadataReader reader, TypeReferenceHandl Module module = _target.ProcessedData.GetOrAdd(_moduleHandle.Address); int token = MetadataTokens.GetToken((EntityHandle)handle); TargetPointer typeHandlePtr = _loader.GetModuleLookupMapElement(module.TypeRefToMethodTableMap, (uint)token, out _); - return _runtimeTypeSystem.GetTypeHandle(typeHandlePtr); + return typeHandlePtr == TargetPointer.Null ? new TypeHandle(TargetPointer.Null) : _runtimeTypeSystem.GetTypeHandle(typeHandlePtr); } public TypeHandle GetTypeFromSpecification(MetadataReader reader, T context, TypeSpecificationHandle handle, byte rawTypeKind) diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index f21416a0fb773b..4a636c783e8d50 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -819,10 +819,17 @@ int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescDat SignatureHeader header = blobReader.ReadSignatureHeader(); if (header.Kind != SignatureKind.Field) throw new BadImageFormatException(); - CorElementType typeCode = (CorElementType)blobReader.ReadCompressedInteger(); - if (typeCode == CorElementType.Class || typeCode == CorElementType.ValueType) + // read the top-level type + CorElementType typeCode; + EntityHandle entityHandle; + do + { + typeCode = (CorElementType)blobReader.ReadByte(); + entityHandle = blobReader.ReadTypeHandle(); // consume the type + } while (typeCode is CorElementType.CModReqd or CorElementType.CModOpt); // eat custom modifiers + + if (typeCode is CorElementType.Class or CorElementType.ValueType) { - EntityHandle entityHandle = blobReader.ReadTypeHandle(); data->TokenOfType = (uint)MetadataTokens.GetToken(entityHandle); } else From b6a8e71f64e2cbfc3d703a7c7c929ae90152a526 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Sat, 13 Sep 2025 13:01:45 -0700 Subject: [PATCH 10/17] cache and renaming --- .../design/datacontracts/RuntimeTypeSystem.md | 4 +- docs/design/datacontracts/SignatureDecoder.md | 10 ++-- .../Contracts/IRuntimeTypeSystem.cs | 2 +- .../Contracts/RuntimeTypeSystem_1.cs | 46 ++++++++++++++++++- .../Signature/SignatureTypeProvider.cs | 10 ++-- 5 files changed, 58 insertions(+), 14 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 8314f4f44b198d..f24427f825a1d7 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -88,7 +88,7 @@ partial interface IRuntimeTypeSystem : IContract // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. public virtual bool IsArray(TypeHandle typeHandle, out uint rank); public virtual TypeHandle GetTypeParam(TypeHandle typeHandle); - public virtual TypeHandle IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments); + public virtual TypeHandle GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments); public TypeHandle GetPrimitiveType(CorElementType typeCode); public virtual bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token); public virtual bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan retAndArgTypes, out byte callConv); @@ -759,7 +759,7 @@ Contracts used: } - public TypeHandle IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) + public TypeHandle GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) { if (typeHandle.Address == TargetPointer.Null) return new TypeHandle(TargetPointer.Null); diff --git a/docs/design/datacontracts/SignatureDecoder.md b/docs/design/datacontracts/SignatureDecoder.md index 6f2d4435d39e3c..d14edd14b672d0 100644 --- a/docs/design/datacontracts/SignatureDecoder.md +++ b/docs/design/datacontracts/SignatureDecoder.md @@ -46,16 +46,16 @@ public class SignatureTypeProvider : ISignatureTypeProvider _moduleHandle = moduleHandle; } public TypeHandle GetArrayType(TypeHandle elementType, ArrayShape shape) - => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.Array, shape.Rank, default); + => _target.Contracts.RuntimeTypeSystem.GetConstructedType(elementType, CorElementType.Array, shape.Rank, ImmutableArray.Empty); public TypeHandle GetByReferenceType(TypeHandle elementType) - => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.Byref, 0, default); + => _target.Contracts.RuntimeTypeSystem.GetConstructedType(elementType, CorElementType.Byref, 0, ImmutableArray.Empty); public TypeHandle GetFunctionPointerType(MethodSignature signature) => GetPrimitiveType(PrimitiveTypeCode.IntPtr); public TypeHandle GetGenericInstantiation(TypeHandle genericType, ImmutableArray typeArguments) - => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(genericType, CorElementType.GenericInst, 0, typeArguments); + => _target.Contracts.RuntimeTypeSystem.GetConstructedType(genericType, CorElementType.GenericInst, 0, typeArguments); public TypeHandle GetGenericMethodParameter(T context, int index) { @@ -83,13 +83,13 @@ public class SignatureTypeProvider : ISignatureTypeProvider => elementType; public TypeHandle GetPointerType(TypeHandle elementType) - => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.Ptr, 0, default); + => _target.Contracts.RuntimeTypeSystem.GetConstructedType(elementType, CorElementType.Ptr, 0, ImmutableArray.Empty); public TypeHandle GetPrimitiveType(PrimitiveTypeCode typeCode) => _target.Contracts.RuntimeTypeSystem.GetPrimitiveType(typeCode); public TypeHandle GetSZArrayType(TypeHandle elementType) - => _target.Contracts.RuntimeTypeSystem.IterateTypeParams(elementType, CorElementType.SzArray, 1, default); + => _target.Contracts.RuntimeTypeSystem.GetConstructedType(elementType, CorElementType.SzArray, 1, ImmutableArray.Empty); public TypeHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index 555877ae5c6df2..30089bd5edd5d0 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -141,7 +141,7 @@ public interface IRuntimeTypeSystem : IContract // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. bool IsArray(TypeHandle typeHandle, out uint rank) => throw new NotImplementedException(); TypeHandle GetTypeParam(TypeHandle typeHandle) => throw new NotImplementedException(); - TypeHandle IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) => throw new NotImplementedException(); + TypeHandle GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) => throw new NotImplementedException(); TypeHandle GetPrimitiveType(CorElementType typeCode) => throw new NotImplementedException(); bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) => throw new NotImplementedException(); TargetPointer GetLoaderModule(TypeHandle typeHandle) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index dc40bead1031e4..77af41d8e700b0 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -24,6 +24,7 @@ internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem // If we need to invalidate our view of memory, we should clear this dictionary. private readonly Dictionary _methodTables = new(); private readonly Dictionary _methodDescs = new(); + private readonly Dictionary _typeHandles = new(); internal struct MethodTable { @@ -56,6 +57,45 @@ internal MethodTable(Data.MethodTable data) internal bool IsCanonMT => MethodTableFlags_1.GetEEClassOrCanonMTBits(EEClassOrCanonMT) == MethodTableFlags_1.EEClassOrCanonMTBits.EEClass; } + internal readonly struct TypeKey : IEquatable + { + public TypeKey(TypeHandle typeHandle, CorElementType elementType, int rank, ImmutableArray typeArgs) + { + TypeHandle = typeHandle; + ElementType = elementType; + Rank = rank; + TypeArgs = typeArgs; + } + public TypeHandle TypeHandle { get; } + public CorElementType ElementType { get; } + public int Rank { get; } + public ImmutableArray TypeArgs { get; } + + public bool Equals(TypeKey other) + { + if (ElementType != other.ElementType || Rank != other.Rank || TypeArgs.Length != other.TypeArgs.Length) + return false; + for (int i = 0; i < TypeArgs.Length; i++) + { + if (!TypeArgs[i].Equals(other.TypeArgs[i])) + return false; + } + return true; + } + + public override bool Equals(object? obj) => obj is TypeKey other && Equals(other); + + public override int GetHashCode() + { + int hash = HashCode.Combine(TypeHandle.GetHashCode(), (int)ElementType, Rank); + foreach (TypeHandle th in TypeArgs) + { + hash = HashCode.Combine(hash, th.GetHashCode()); + } + return hash; + } + } + // Low order bits of TypeHandle address. // If the low bits contain a 2, then it is a TypeDesc [Flags] @@ -690,10 +730,12 @@ private bool ArrayPtrMatch(TypeHandle elementType, CorElementType corElementType } - TypeHandle IRuntimeTypeSystem.IterateTypeParams(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) + TypeHandle IRuntimeTypeSystem.GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) { if (typeHandle.Address == TargetPointer.Null) return new TypeHandle(TargetPointer.Null); + if (_typeHandles.TryGetValue(new TypeKey(typeHandle, corElementType, rank, typeArguments), out TypeHandle existing)) + return existing; ILoader loaderContract = _target.Contracts.Loader; TargetPointer loaderModule = GetLoaderModule(typeHandle); ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); @@ -704,11 +746,13 @@ TypeHandle IRuntimeTypeSystem.IterateTypeParams(TypeHandle typeHandle, CorElemen { if (GenericInstantiationMatch(typeHandle, potentialMatch, typeArguments)) { + _ = _typeHandles.TryAdd(new TypeKey(typeHandle, corElementType, rank, typeArguments), potentialMatch); return potentialMatch; } } else if (ArrayPtrMatch(typeHandle, corElementType, rank, potentialMatch)) { + _ = _typeHandles.TryAdd(new TypeKey(typeHandle, corElementType, rank, typeArguments), potentialMatch); return potentialMatch; } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs index ff6f4e362dbcd2..4145d69df83ea8 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs @@ -26,16 +26,16 @@ public SignatureTypeProvider(Target target, Contracts.ModuleHandle moduleHandle) _runtimeTypeSystem = target.Contracts.RuntimeTypeSystem; } public TypeHandle GetArrayType(TypeHandle elementType, ArrayShape shape) - => _runtimeTypeSystem.IterateTypeParams(elementType, CorElementType.Array, shape.Rank, default); + => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Array, shape.Rank, ImmutableArray.Empty); public TypeHandle GetByReferenceType(TypeHandle elementType) - => _runtimeTypeSystem.IterateTypeParams(elementType, CorElementType.Byref, 0, default); + => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Byref, 0, ImmutableArray.Empty); public TypeHandle GetFunctionPointerType(MethodSignature signature) => GetPrimitiveType(PrimitiveTypeCode.IntPtr); public TypeHandle GetGenericInstantiation(TypeHandle genericType, ImmutableArray typeArguments) - => _runtimeTypeSystem.IterateTypeParams(genericType, CorElementType.GenericInst, 0, typeArguments); + => _runtimeTypeSystem.GetConstructedType(genericType, CorElementType.GenericInst, 0, typeArguments); public TypeHandle GetGenericMethodParameter(T context, int index) { @@ -63,13 +63,13 @@ public TypeHandle GetPinnedType(TypeHandle elementType) => elementType; public TypeHandle GetPointerType(TypeHandle elementType) - => _runtimeTypeSystem.IterateTypeParams(elementType, CorElementType.Ptr, 0, default); + => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Ptr, 0, ImmutableArray.Empty); public TypeHandle GetPrimitiveType(PrimitiveTypeCode typeCode) => _runtimeTypeSystem.GetPrimitiveType((CorElementType)typeCode); public TypeHandle GetSZArrayType(TypeHandle elementType) - => _runtimeTypeSystem.IterateTypeParams(elementType, CorElementType.SzArray, 1, default); + => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.SzArray, 1, ImmutableArray.Empty); public TypeHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) { From 538ba6f2e9a6b391614eb363eb644ab3c39bed66 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Sun, 14 Sep 2025 09:07:25 -0700 Subject: [PATCH 11/17] loadlevel --- .../design/datacontracts/RuntimeTypeSystem.md | 38 ++++++++++++++---- .../Contracts/RuntimeTypeSystem_1.cs | 39 ++++++++++++++----- 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index f24427f825a1d7..e2ee361abe880d 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -759,27 +759,43 @@ Contracts used: } - public TypeHandle GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) + private bool IsLoaded(TypeHandle typeHandle) + { + if (typeHandle.Address == TargetPointer.Null) + return false; + if (typeHandle.IsTypeDesc()) + { + uint typeAndFlags = _target.Read(typeHandle.TypeDescAddress() + /* TypeDesc::TypeAndFlags offset */); + return (typeAndFlags & (uint)TypeDescFlags.IsNotFullyLoaded) == 0; + } + + MethodTable methodTable = _methodTables[typeHandle.Address]; + uint flags = _target.Read(methodTable.AuxiliaryData + /* AuxiliaryData::Flags offset */); + return (flags & (uint)MethodTableAuxiliaryFlags.IsNotFullyLoaded) == 0; + } + + TypeHandle GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) { if (typeHandle.Address == TargetPointer.Null) return new TypeHandle(TargetPointer.Null); ILoader loaderContract = _target.Contracts.Loader; TargetPointer loaderModule = GetLoaderModule(typeHandle); ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); + TypeHandle potentialMatch = new TypeHandle(TargetPointer.Null); foreach (TargetPointer ptr in loaderContract.GetAvailableTypeParams(moduleHandle)) { - TypeHandle potentialMatch = GetTypeHandle(ptr); + potentialMatch = GetTypeHandle(ptr); if (corElementType == CorElementType.GenericInst) { if (GenericInstantiationMatch(typeHandle, potentialMatch, typeArguments)) - { - return potentialMatch; - } + break; } else if (ArrayPtrMatch(typeHandle, corElementType, rank, potentialMatch)) - { - return potentialMatch; - } + break; + } + if (IsLoaded(potentialMatch)) + { + return potentialMatch; } return new TypeHandle(TargetPointer.Null); } @@ -992,6 +1008,12 @@ And the following enumeration definitions { Initialized = 0x0001, IsInitError = 0x0100, + IsNotFullyLoaded = 0x0040, + } + + internal enum TypeDescFlags : uint + { + IsNotFullyLoaded = 0x00001000, } ``` diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 77af41d8e700b0..3c9df94092ea4b 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -136,6 +136,12 @@ internal enum MethodTableAuxiliaryFlags : uint { Initialized = 0x0001, IsInitError = 0x0100, + IsNotFullyLoaded = 0x0040, + } + + internal enum TypeDescFlags : uint + { + IsNotFullyLoaded = 0x00001000, } internal enum FieldDescFlags1 : uint @@ -730,6 +736,21 @@ private bool ArrayPtrMatch(TypeHandle elementType, CorElementType corElementType } + private bool IsLoaded(TypeHandle typeHandle) + { + if (typeHandle.Address == TargetPointer.Null) + return false; + if (typeHandle.IsTypeDesc()) + { + Data.TypeDesc typeDesc = _target.ProcessedData.GetOrAdd(typeHandle.TypeDescAddress()); + return (typeDesc.TypeAndFlags & (uint)TypeDescFlags.IsNotFullyLoaded) == 0; // IsUnloaded + } + + MethodTable methodTable = _methodTables[typeHandle.Address]; + Data.MethodTableAuxiliaryData auxData = _target.ProcessedData.GetOrAdd(methodTable.AuxiliaryData); + return (auxData.Flags & (uint)MethodTableAuxiliaryFlags.IsNotFullyLoaded) == 0; // IsUnloaded + } + TypeHandle IRuntimeTypeSystem.GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) { if (typeHandle.Address == TargetPointer.Null) @@ -739,22 +760,22 @@ TypeHandle IRuntimeTypeSystem.GetConstructedType(TypeHandle typeHandle, CorEleme ILoader loaderContract = _target.Contracts.Loader; TargetPointer loaderModule = GetLoaderModule(typeHandle); ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); + TypeHandle potentialMatch = new TypeHandle(TargetPointer.Null); foreach (TargetPointer ptr in loaderContract.GetAvailableTypeParams(moduleHandle)) { - TypeHandle potentialMatch = GetTypeHandle(ptr); + potentialMatch = GetTypeHandle(ptr); if (corElementType == CorElementType.GenericInst) { if (GenericInstantiationMatch(typeHandle, potentialMatch, typeArguments)) - { - _ = _typeHandles.TryAdd(new TypeKey(typeHandle, corElementType, rank, typeArguments), potentialMatch); - return potentialMatch; - } + break; } else if (ArrayPtrMatch(typeHandle, corElementType, rank, potentialMatch)) - { - _ = _typeHandles.TryAdd(new TypeKey(typeHandle, corElementType, rank, typeArguments), potentialMatch); - return potentialMatch; - } + break; + } + if (IsLoaded(potentialMatch)) + { + _ = _typeHandles.TryAdd(new TypeKey(typeHandle, corElementType, rank, typeArguments), potentialMatch); + return potentialMatch; } return new TypeHandle(TargetPointer.Null); } From c51cfbf383d758c76a6c5d0561458c75559e5a83 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Sun, 14 Sep 2025 16:15:08 -0700 Subject: [PATCH 12/17] e --- .../design/datacontracts/RuntimeTypeSystem.md | 18 +++++++++------- .../Contracts/RuntimeTypeSystem_1.cs | 21 ++++++++++--------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index e2ee361abe880d..2fb9fe31f8c425 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -787,15 +787,17 @@ Contracts used: potentialMatch = GetTypeHandle(ptr); if (corElementType == CorElementType.GenericInst) { - if (GenericInstantiationMatch(typeHandle, potentialMatch, typeArguments)) - break; + if (GenericInstantiationMatch(typeHandle, potentialMatch, typeArguments) && IsLoaded(potentialMatch)) + { + _ = _typeHandles.TryAdd(new TypeKey(typeHandle, corElementType, rank, typeArguments), potentialMatch); + return potentialMatch; + } + } + else if (ArrayPtrMatch(typeHandle, corElementType, rank, potentialMatch) && IsLoaded(potentialMatch)) + { + _ = _typeHandles.TryAdd(new TypeKey(typeHandle, corElementType, rank, typeArguments), potentialMatch); + return potentialMatch; } - else if (ArrayPtrMatch(typeHandle, corElementType, rank, potentialMatch)) - break; - } - if (IsLoaded(potentialMatch)) - { - return potentialMatch; } return new TypeHandle(TargetPointer.Null); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 3c9df94092ea4b..df62af8d396bbd 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -760,22 +760,23 @@ TypeHandle IRuntimeTypeSystem.GetConstructedType(TypeHandle typeHandle, CorEleme ILoader loaderContract = _target.Contracts.Loader; TargetPointer loaderModule = GetLoaderModule(typeHandle); ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(loaderModule); - TypeHandle potentialMatch = new TypeHandle(TargetPointer.Null); + TypeHandle potentialMatch; foreach (TargetPointer ptr in loaderContract.GetAvailableTypeParams(moduleHandle)) { potentialMatch = GetTypeHandle(ptr); if (corElementType == CorElementType.GenericInst) { - if (GenericInstantiationMatch(typeHandle, potentialMatch, typeArguments)) - break; + if (GenericInstantiationMatch(typeHandle, potentialMatch, typeArguments) && IsLoaded(potentialMatch)) + { + _ = _typeHandles.TryAdd(new TypeKey(typeHandle, corElementType, rank, typeArguments), potentialMatch); + return potentialMatch; + } + } + else if (ArrayPtrMatch(typeHandle, corElementType, rank, potentialMatch) && IsLoaded(potentialMatch)) + { + _ = _typeHandles.TryAdd(new TypeKey(typeHandle, corElementType, rank, typeArguments), potentialMatch); + return potentialMatch; } - else if (ArrayPtrMatch(typeHandle, corElementType, rank, potentialMatch)) - break; - } - if (IsLoaded(potentialMatch)) - { - _ = _typeHandles.TryAdd(new TypeKey(typeHandle, corElementType, rank, typeArguments), potentialMatch); - return potentialMatch; } return new TypeHandle(TargetPointer.Null); } From 17c4634f3e5bc155468a11c32bbcb4f8aa022043 Mon Sep 17 00:00:00 2001 From: Rachel Date: Tue, 16 Sep 2025 13:09:01 -0700 Subject: [PATCH 13/17] Apply suggestions from code review Co-authored-by: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> --- docs/design/datacontracts/RuntimeTypeSystem.md | 16 ++++++++-------- .../Contracts/IRuntimeTypeSystem.cs | 1 - .../Contracts/RuntimeTypeSystem_1.cs | 2 +- .../Contracts/Signature/SignatureDecoder_1.cs | 5 ++--- .../Contracts/Signature/SignatureTypeProvider.cs | 4 ++-- .../Data/CoreLibBinder.cs | 1 + .../Legacy/ISOSDacInterface.cs | 1 - 7 files changed, 14 insertions(+), 16 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index b2a2421645a8fc..62a54c1a7a802c 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -86,14 +86,14 @@ partial interface IRuntimeTypeSystem : IContract public virtual CorElementType GetSignatureCorElementType(TypeHandle typeHandle); // return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is. - public virtual bool IsArray(TypeHandle typeHandle, out uint rank); - public virtual TypeHandle GetTypeParam(TypeHandle typeHandle); - public virtual TypeHandle GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments); - public TypeHandle GetPrimitiveType(CorElementType typeCode); - public virtual bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token); - public virtual bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan retAndArgTypes, out byte callConv); - public virtual bool IsPointer(TypeHandle typeHandle); - public virtual TargetPointer GetLoaderModule(TypeHandle typeHandle); + bool IsArray(TypeHandle typeHandle, out uint rank); + TypeHandle GetTypeParam(TypeHandle typeHandle); + TypeHandle GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments); + TypeHandle GetPrimitiveType(CorElementType typeCode); + bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token); + bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan retAndArgTypes, out byte callConv); + bool IsPointer(TypeHandle typeHandle); + TargetPointer GetLoaderModule(TypeHandle typeHandle); #endregion TypeHandle inspection APIs } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index 30089bd5edd5d0..c4f94d344b48d6 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -95,7 +95,6 @@ public interface IRuntimeTypeSystem : IContract IEnumerable GetIntroducedMethodDescs(TypeHandle methodTable) => throw new NotImplementedException(); TargetCodePointer GetSlot(TypeHandle typeHandle, uint slot) => throw new NotImplementedException(); - uint GetBaseSize(TypeHandle typeHandle) => throw new NotImplementedException(); // The component size is only available for strings and arrays. It is the size of the element type of the array, or the size of an ECMA 335 character (2 bytes) uint GetComponentSize(TypeHandle typeHandle) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 1fe94baa5a21d8..43f75b7b25f485 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -57,7 +57,7 @@ internal MethodTable(Data.MethodTable data) internal bool IsCanonMT => MethodTableFlags_1.GetEEClassOrCanonMTBits(EEClassOrCanonMT) == MethodTableFlags_1.EEClassOrCanonMTBits.EEClass; } - internal readonly struct TypeKey : IEquatable + private readonly struct TypeKey : IEquatable { public TypeKey(TypeHandle typeHandle, CorElementType elementType, int rank, ImmutableArray typeArgs) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs index 95434abcb768f6..c2cbf38c2c8214 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs @@ -26,7 +26,7 @@ private SignatureTypeProvider GetTypeHandleProvider(ModuleHandle mod { if (_thProviders.TryGetValue(moduleHandle, out SignatureTypeProvider? thProvider)) { - return (SignatureTypeProvider)(object)thProvider; + return thProvider; } SignatureTypeProvider newProvider = new(_target, moduleHandle); @@ -38,7 +38,7 @@ private SignatureTypeProvider GetMethodDescHandleProvider(Modu { if (_mdhProviders.TryGetValue(moduleHandle, out SignatureTypeProvider? mdhProvider)) { - return (SignatureTypeProvider)(object)mdhProvider; + return mdhProvider; } SignatureTypeProvider newProvider = new(_target, moduleHandle); _mdhProviders[moduleHandle] = newProvider; @@ -54,5 +54,4 @@ TypeHandle ISignatureDecoder.DecodeFieldSignature(BlobHandle blobHandle, ModuleH // Implementation pending return decoder.DecodeFieldSignature(ref blobReader); } - } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs index 4145d69df83ea8..16647eb8ae3ab5 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs @@ -12,7 +12,6 @@ namespace Microsoft.Diagnostics.DataContractReader.SignatureHelpers; public class SignatureTypeProvider : ISignatureTypeProvider { - // All interface methods throw NotImplementedException for now private readonly Target _target; private readonly Contracts.ModuleHandle _moduleHandle; private readonly Contracts.ILoader _loader; @@ -25,6 +24,7 @@ public SignatureTypeProvider(Target target, Contracts.ModuleHandle moduleHandle) _loader = target.Contracts.Loader; _runtimeTypeSystem = target.Contracts.RuntimeTypeSystem; } + public TypeHandle GetArrayType(TypeHandle elementType, ArrayShape shape) => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Array, shape.Rank, ImmutableArray.Empty); @@ -69,7 +69,7 @@ public TypeHandle GetPrimitiveType(PrimitiveTypeCode typeCode) => _runtimeTypeSystem.GetPrimitiveType((CorElementType)typeCode); public TypeHandle GetSZArrayType(TypeHandle elementType) - => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.SzArray, 1, ImmutableArray.Empty); + => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.SzArray, 1, ImmutableArray.Empty); public TypeHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs index 781e3aa5e29644..49e6155d680cfa 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CoreLibBinder.cs @@ -14,5 +14,6 @@ public CoreLibBinder(Target target, TargetPointer address) Classes = target.ReadPointer(address + (ulong)type.Fields[nameof(Classes)].Offset); } + public TargetPointer Classes { get; init; } } diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs index 233df7076d05a3..9b31da61446f27 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs @@ -231,7 +231,6 @@ public enum Flags : uint public ClrDataAddress NativeCodeAddr; }; - internal struct DacpMethodDescData { public int bHasNativeCode; From 434bfade886938947e921d9010137840d52aa254 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Tue, 16 Sep 2025 14:33:14 -0700 Subject: [PATCH 14/17] code review --- .../design/datacontracts/RuntimeTypeSystem.md | 4 --- .../Contracts/IEcmaMetadata.cs | 2 +- .../Contracts/IRuntimeTypeSystem.cs | 5 ++- .../Contracts/EcmaMetadata_1.cs | 33 ++++--------------- .../Contracts/Loader_1.cs | 2 +- .../Contracts/RuntimeTypeSystem_1.cs | 8 ++--- .../Contracts/Signature/SignatureDecoder_1.cs | 17 ++++++---- .../Signature/SignatureTypeProvider.cs | 8 ++--- .../Legacy/ISOSDacInterface.cs | 5 +-- .../Legacy/SOSDacImpl.cs | 19 +++++++---- .../Legacy/SigFormat.cs | 6 ++-- .../Legacy/TypeNameBuilder.cs | 8 ++--- 12 files changed, 52 insertions(+), 65 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 62a54c1a7a802c..46e30b9e49341c 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -197,7 +197,6 @@ bool IsFieldDescThreadStatic(TargetPointer fieldDescPointer); bool IsFieldDescStatic(TargetPointer fieldDescPointer); uint GetFieldDescType(TargetPointer fieldDescPointer); uint GetFieldDescOffset(TargetPointer fieldDescPointer, FieldDefinition fieldDef); -TargetPointer GetFieldDescNextField(TargetPointer fieldDescPointer); ``` ## Version 1 @@ -1679,7 +1678,4 @@ uint GetFieldDescOffset(TargetPointer fieldDescPointer) } return DWord2 & (uint)FieldDescFlags2.OffsetMask; } - -TargetPointer GetFieldDescNextField(TargetPointer fieldDescPointer) - => fieldDescPointer + _target.GetTypeInfo(DataType.FieldDesc).Size!.Value; ``` \ No newline at end of file diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IEcmaMetadata.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IEcmaMetadata.cs index b69fd414f933ff..9ef128a4073fde 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IEcmaMetadata.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IEcmaMetadata.cs @@ -10,7 +10,7 @@ public interface IEcmaMetadata : IContract { static string IContract.Name { get; } = nameof(EcmaMetadata); TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle) => throw new NotImplementedException(); - MetadataReader? GetMetadata(ModuleHandle module) => throw new NotImplementedException(); + MetadataReader GetMetadata(ModuleHandle module) => throw new NotImplementedException(); } public readonly struct EcmaMetadata : IEcmaMetadata diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index c4f94d344b48d6..d48cd08ebec279 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -85,6 +85,7 @@ public interface IRuntimeTypeSystem : IContract #region TypeHandle inspection APIs TypeHandle GetTypeHandle(TargetPointer address) => throw new NotImplementedException(); TargetPointer GetModule(TypeHandle typeHandle) => throw new NotImplementedException(); + TargetPointer GetLoaderModule(TypeHandle typeHandle) => throw new NotImplementedException(); // A canonical method table is either the MethodTable itself, or in the case of a generic instantiation, it is the // MethodTable of the prototypical instance. @@ -143,7 +144,6 @@ public interface IRuntimeTypeSystem : IContract TypeHandle GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray typeArguments) => throw new NotImplementedException(); TypeHandle GetPrimitiveType(CorElementType typeCode) => throw new NotImplementedException(); bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) => throw new NotImplementedException(); - TargetPointer GetLoaderModule(TypeHandle typeHandle) => throw new NotImplementedException(); bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan retAndArgTypes, out byte callConv) => throw new NotImplementedException(); bool IsPointer(TypeHandle typeHandle) => throw new NotImplementedException(); // Returns null if the TypeHandle is not a class/struct/generic variable @@ -201,9 +201,8 @@ public interface IRuntimeTypeSystem : IContract uint GetFieldDescMemberDef(TargetPointer fieldDescPointer) => throw new NotImplementedException(); bool IsFieldDescThreadStatic(TargetPointer fieldDescPointer) => throw new NotImplementedException(); bool IsFieldDescStatic(TargetPointer fieldDescPointer) => throw new NotImplementedException(); - uint GetFieldDescType(TargetPointer fieldDescPointer) => throw new NotImplementedException(); + CorElementType GetFieldDescType(TargetPointer fieldDescPointer) => throw new NotImplementedException(); uint GetFieldDescOffset(TargetPointer fieldDescPointer, FieldDefinition fieldDef) => throw new NotImplementedException(); - TargetPointer GetFieldDescNextField(TargetPointer fieldDescPointer) => throw new NotImplementedException(); #endregion FieldDesc inspection APIs } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs index ac23ea521cecde..6a26a0ebae9293 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs @@ -14,14 +14,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal sealed class EcmaMetadata_1(Target target) : IEcmaMetadata { - private Dictionary _metadata = new(); - - private sealed class ModuleHandleBox - { - public ModuleHandle Value { get; } - public ModuleHandleBox(ModuleHandle value) => Value = value; - } - private static ConditionalWeakTable _moduleHandles = new(); + private Dictionary _metadata = new(); public TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle) { @@ -43,40 +36,28 @@ public TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle) return new TargetSpan(baseAddress + (ulong)metadataStartOffset, (ulong)metadataSize); } - public MetadataReader? GetMetadata(ModuleHandle handle) + public MetadataReader GetMetadata(ModuleHandle handle) { - MetadataReader? reader; + MetadataReader reader; if (_metadata.TryGetValue(handle, out MetadataReaderProvider? result)) { - reader = result?.GetMetadataReader(); + reader = result.GetMetadataReader(); } else { - MetadataReaderProvider? provider = GetMetadataProvider(handle); + MetadataReaderProvider provider = GetMetadataProvider(handle); _metadata.Add(handle, provider); - reader = provider?.GetMetadataReader(); - _moduleHandles.Add(reader!, new ModuleHandleBox(handle)); + reader = provider.GetMetadataReader(); } return reader; } - public static ModuleHandle? GetModuleFromMetadataReader(MetadataReader reader) - { - if (_moduleHandles.TryGetValue(reader, out ModuleHandleBox? box)) - { - return box!.Value; - } - return null; - } - - private MetadataReaderProvider? GetMetadataProvider(ModuleHandle handle) + private MetadataReaderProvider GetMetadataProvider(ModuleHandle handle) { AvailableMetadataType type = GetAvailableMetadataType(handle); switch (type) { - case AvailableMetadataType.None: - return null; case AvailableMetadataType.ReadOnly: { TargetSpan address = GetReadOnlyMetadataAddress(handle); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs index 592ee98f8b79a6..027d96a6cf7ee8 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs @@ -531,7 +531,7 @@ TargetPointer ILoader.GetObjectHandle(TargetPointer loaderAllocatorPointer) private int GetRVAFromMetadata(ModuleHandle handle, int token) { IEcmaMetadata ecmaMetadataContract = _target.Contracts.EcmaMetadata; - MetadataReader mdReader = ecmaMetadataContract.GetMetadata(handle)!; + MetadataReader mdReader = ecmaMetadataContract.GetMetadata(handle); MethodDefinition methodDef = mdReader.GetMethodDefinition(MetadataTokens.MethodDefinitionHandle(token)); return methodDef.RelativeVirtualAddress; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 43f75b7b25f485..e6e7cac933be68 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -1470,10 +1470,11 @@ bool IRuntimeTypeSystem.IsFieldDescStatic(TargetPointer fieldDescPointer) return (fieldDesc.DWord1 & (uint)FieldDescFlags1.IsStatic) != 0; } - uint IRuntimeTypeSystem.GetFieldDescType(TargetPointer fieldDescPointer) + CorElementType IRuntimeTypeSystem.GetFieldDescType(TargetPointer fieldDescPointer) { Data.FieldDesc fieldDesc = _target.ProcessedData.GetOrAdd(fieldDescPointer); - return (fieldDesc.DWord2 & (uint)FieldDescFlags2.TypeMask) >> 27; + // 27 is the number of bits that the type is shifted left. if you change the enum, please change this too. + return (CorElementType)((fieldDesc.DWord2 & (uint)FieldDescFlags2.TypeMask) >> 27); } uint IRuntimeTypeSystem.GetFieldDescOffset(TargetPointer fieldDescPointer, FieldDefinition fieldDef) @@ -1485,7 +1486,4 @@ uint IRuntimeTypeSystem.GetFieldDescOffset(TargetPointer fieldDescPointer, Field } return fieldDesc.DWord2 & (uint)FieldDescFlags2.OffsetMask; } - - TargetPointer IRuntimeTypeSystem.GetFieldDescNextField(TargetPointer fieldDescPointer) - => fieldDescPointer + _target.GetTypeInfo(DataType.FieldDesc).Size!.Value; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs index c2cbf38c2c8214..f193acf5893cf3 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs @@ -9,17 +9,23 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; +/* NOTE: some elements of SignatureTypeProvider remain unimplemented or minimally implemented + * as they are not needed for the current usage of ISignatureDecoder. + * GetModifiedType and GetPinnedType ignore pinning and custom modifiers. + * GetTypeFromReference does not look up the type in another module. + * GetTypeFromSpecification is unimplemented. + * These can be completed as needed. + */ + internal sealed class SignatureDecoder_1 : ISignatureDecoder { private readonly Target _target; - private Dictionary> _thProviders; - private Dictionary> _mdhProviders; + private readonly Dictionary> _thProviders = []; + private readonly Dictionary> _mdhProviders = []; internal SignatureDecoder_1(Target target) { _target = target; - _thProviders = new Dictionary>(); - _mdhProviders = new Dictionary>(); } private SignatureTypeProvider GetTypeHandleProvider(ModuleHandle moduleHandle) @@ -48,10 +54,9 @@ private SignatureTypeProvider GetMethodDescHandleProvider(Modu TypeHandle ISignatureDecoder.DecodeFieldSignature(BlobHandle blobHandle, ModuleHandle moduleHandle, TypeHandle ctx) { SignatureTypeProvider provider = GetTypeHandleProvider(moduleHandle); - MetadataReader mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle)!; + MetadataReader mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle); BlobReader blobReader = mdReader.GetBlobReader(blobHandle); SignatureDecoder decoder = new(provider, mdReader, ctx); - // Implementation pending return decoder.DecodeFieldSignature(ref blobReader); } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs index 16647eb8ae3ab5..5d51311f41a005 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs @@ -26,10 +26,10 @@ public SignatureTypeProvider(Target target, Contracts.ModuleHandle moduleHandle) } public TypeHandle GetArrayType(TypeHandle elementType, ArrayShape shape) - => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Array, shape.Rank, ImmutableArray.Empty); + => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Array, shape.Rank, []); public TypeHandle GetByReferenceType(TypeHandle elementType) - => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Byref, 0, ImmutableArray.Empty); + => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Byref, 0, []); public TypeHandle GetFunctionPointerType(MethodSignature signature) => GetPrimitiveType(PrimitiveTypeCode.IntPtr); @@ -63,13 +63,13 @@ public TypeHandle GetPinnedType(TypeHandle elementType) => elementType; public TypeHandle GetPointerType(TypeHandle elementType) - => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Ptr, 0, ImmutableArray.Empty); + => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Ptr, 0, []); public TypeHandle GetPrimitiveType(PrimitiveTypeCode typeCode) => _runtimeTypeSystem.GetPrimitiveType((CorElementType)typeCode); public TypeHandle GetSZArrayType(TypeHandle elementType) - => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.SzArray, 1, ImmutableArray.Empty); + => _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.SzArray, 1, []); public TypeHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) { diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs index 9b31da61446f27..1ea822b4cacf8a 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; +using CorElementType = Microsoft.Diagnostics.DataContractReader.Contracts.CorElementType; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -351,8 +352,8 @@ internal unsafe partial interface ISOSEnum internal struct DacpFieldDescData { - public uint Type; - public uint sigType; // ELEMENT_TYPE_XXX from signature. We need this to display pretty name for String in minidump's case + public CorElementType Type; + public CorElementType sigType; // ELEMENT_TYPE_XXX from signature. We need this to display pretty name for String in minidump's case public ClrDataAddress MTOfType; // NULL if Type is not loaded public ClrDataAddress ModuleOfType; public uint TokenOfType; diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index 57462bc44db6a7..341180c4fade64 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -764,21 +764,23 @@ int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescDat throw new ArgumentException(); IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + IEcmaMetadata ecmaMetadataContract = _target.Contracts.EcmaMetadata; + ISignatureDecoder signatureDecoder = _target.Contracts.SignatureDecoder; + TargetPointer fieldDescTargetPtr = fieldDesc.ToTargetPointer(_target); - uint fieldDescType = rtsContract.GetFieldDescType(fieldDescTargetPtr); + CorElementType fieldDescType = rtsContract.GetFieldDescType(fieldDescTargetPtr); data->Type = fieldDescType; data->sigType = fieldDescType; uint token = rtsContract.GetFieldDescMemberDef(fieldDescTargetPtr); FieldDefinitionHandle fieldHandle = (FieldDefinitionHandle)MetadataTokens.Handle((int)token); - IEcmaMetadata ecmaMetadataContract = _target.Contracts.EcmaMetadata; + TargetPointer enclosingMT = rtsContract.GetMTOfEnclosingClass(fieldDescTargetPtr); TypeHandle ctx = rtsContract.GetTypeHandle(enclosingMT); TargetPointer modulePtr = rtsContract.GetModule(ctx); Contracts.ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePtr); - MetadataReader mdReader = ecmaMetadataContract.GetMetadata(moduleHandle)!; + MetadataReader mdReader = ecmaMetadataContract.GetMetadata(moduleHandle); FieldDefinition fieldDef = mdReader.GetFieldDefinition(fieldHandle); - ISignatureDecoder signatureDecoder = _target.Contracts.SignatureDecoder; try { // try to completely decode the signature @@ -788,6 +790,7 @@ int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescDat // This is an implementation detail of the DAC that we replicate here to get method tables for non-MT types // that we can return to SOS for pretty-printing. // In the future we may want to return a TypeHandle instead of a MethodTable, and modify SOS to do more complete pretty-printing. + // DAC equivalent: src/coreclr/vm/typehandle.inl TypeHandle::GetMethodTable if (rtsContract.IsFunctionPointer(foundTypeHandle, out _, out _) || rtsContract.IsPointer(foundTypeHandle)) data->MTOfType = rtsContract.GetPrimitiveType(CorElementType.U).Address.ToClrDataAddress(_target); // array MTs @@ -817,11 +820,13 @@ int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescDat // partial decoding of signature BlobReader blobReader = mdReader.GetBlobReader(fieldDef.Signature); SignatureHeader header = blobReader.ReadSignatureHeader(); + // read the header byte and check for correctness if (header.Kind != SignatureKind.Field) throw new BadImageFormatException(); // read the top-level type CorElementType typeCode; EntityHandle entityHandle; + // in a loop, read custom modifiers until we get to the underlying type do { typeCode = (CorElementType)blobReader.ReadByte(); @@ -830,13 +835,15 @@ int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescDat if (typeCode is CorElementType.Class or CorElementType.ValueType) { + // if the typecode is class or value, we have been able to read the token that follows in the sig data->TokenOfType = (uint)MetadataTokens.GetToken(entityHandle); } else { + // otherwise we have not found the token here, but we can encode the underlying type in sigType data->TokenOfType = (uint)CorTokenType.mdtTypeDef; if (data->MTOfType == 0) - data->sigType = (uint)typeCode; + data->sigType = typeCode; } data->ModuleOfType = modulePtr.ToClrDataAddress(_target); @@ -846,7 +853,7 @@ int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescDat data->bIsThreadLocal = rtsContract.IsFieldDescThreadStatic(fieldDescTargetPtr) ? 1 : 0; data->bIsContextLocal = 0; data->bIsStatic = rtsContract.IsFieldDescStatic(fieldDescTargetPtr) ? 1 : 0; - data->NextField = rtsContract.GetFieldDescNextField(fieldDescTargetPtr).ToClrDataAddress(_target); + data->NextField = fieldDescTargetPtr + _target.GetTypeInfo(DataType.FieldDesc).Size!.Value; } catch (System.Exception ex) { diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SigFormat.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SigFormat.cs index 98ac68d98d0dde..dea6cef3581f71 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SigFormat.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SigFormat.cs @@ -180,7 +180,7 @@ private static unsafe void AddTypeString(Target target, uint typeDefToken = runtimeTypeSystem.GetTypeDefToken(th); TargetPointer modulePointer = target.Contracts.RuntimeTypeSystem.GetModule(th); Contracts.ModuleHandle module = target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePointer); - MetadataReader internalTypeMetadata = target.Contracts.EcmaMetadata.GetMetadata(module)!; + MetadataReader internalTypeMetadata = target.Contracts.EcmaMetadata.GetMetadata(module); TypeDefinition internalTypeDef = internalTypeMetadata.GetTypeDefinition((TypeDefinitionHandle)MetadataTokens.Handle((int)typeDefToken)); _namespace = internalTypeMetadata.GetString(internalTypeDef.Namespace); @@ -346,7 +346,7 @@ private static void AddType(Target target, StringBuilder stringBuilder, TypeHand uint typeDefToken = runtimeTypeSystem.GetTypeDefToken(typeHandle); TargetPointer modulePointer = target.Contracts.RuntimeTypeSystem.GetModule(typeHandle); Contracts.ModuleHandle module = target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePointer); - MetadataReader metadata = target.Contracts.EcmaMetadata.GetMetadata(module)!; + MetadataReader metadata = target.Contracts.EcmaMetadata.GetMetadata(module); TypeDefinition typeDef = metadata.GetTypeDefinition((TypeDefinitionHandle)MetadataTokens.Handle((int)typeDefToken)); string _namespace = metadata.GetString(typeDef.Namespace); string name = metadata.GetString(typeDef.Name); @@ -391,7 +391,7 @@ private static void AddType(Target target, StringBuilder stringBuilder, TypeHand case CorElementType.Var: runtimeTypeSystem.IsGenericVariable(typeHandle, out TargetPointer genericVariableModulePointer, out uint typeVarToken); Contracts.ModuleHandle genericVariableModule = target.Contracts.Loader.GetModuleHandleFromModulePtr(genericVariableModulePointer); - MetadataReader generatedVariableMetadata = target.Contracts.EcmaMetadata.GetMetadata(genericVariableModule)!; + MetadataReader generatedVariableMetadata = target.Contracts.EcmaMetadata.GetMetadata(genericVariableModule); GenericParameter genericVariable = generatedVariableMetadata.GetGenericParameter((GenericParameterHandle)MetadataTokens.Handle((int)typeVarToken)); stringBuilder.Append(generatedVariableMetadata.GetString(genericVariable.Name)); return; diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/TypeNameBuilder.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/TypeNameBuilder.cs index d05f14803d5baa..3e9847d9a72568 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/TypeNameBuilder.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/TypeNameBuilder.cs @@ -120,7 +120,7 @@ public static void AppendMethodImpl(Target target, StringBuilder stringBuilder, else { module = loader.GetModuleHandleFromModulePtr(runtimeTypeSystem.GetModule(th)); - MetadataReader reader = target.Contracts.EcmaMetadata.GetMetadata(module)!; + MetadataReader reader = target.Contracts.EcmaMetadata.GetMetadata(module); MethodDefinition methodDef = reader.GetMethodDefinition(MetadataTokens.MethodDefinitionHandle((int)runtimeTypeSystem.GetMethodToken(method))); stringBuilder.Append(reader.GetString(methodDef.Name)); } @@ -227,7 +227,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle else if (typeSystemContract.IsGenericVariable(typeHandle, out TargetPointer modulePointer, out uint genericParamToken)) { Contracts.ModuleHandle module = tnb.Target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePointer); - MetadataReader reader = tnb.Target.Contracts.EcmaMetadata.GetMetadata(module)!; + MetadataReader reader = tnb.Target.Contracts.EcmaMetadata.GetMetadata(module); var handle = (GenericParameterHandle)MetadataTokens.Handle((int)genericParamToken); GenericParameter genericParam = reader.GetGenericParameter(handle); if (format.HasFlag(TypeNameFormat.FormatGenericParam)) @@ -287,7 +287,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle } else { - MetadataReader reader = tnb.Target.Contracts.EcmaMetadata.GetMetadata(moduleHandle)!; + MetadataReader reader = tnb.Target.Contracts.EcmaMetadata.GetMetadata(moduleHandle); AppendNestedTypeDef(ref tnb, reader, (TypeDefinitionHandle)MetadataTokens.EntityHandle((int)typeDefToken), format); } @@ -314,7 +314,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle Contracts.ModuleHandle module = tnb.Target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePtr); // NOTE: The DAC variant of assembly name generation is different than the runtime version. The DAC variant is simpler, and only uses SimpleName - MetadataReader mr = tnb.Target.Contracts.EcmaMetadata.GetMetadata(module)!; + MetadataReader mr = tnb.Target.Contracts.EcmaMetadata.GetMetadata(module); string assemblySimpleName = mr.GetString(mr.GetAssemblyDefinition().Name); tnb.AddAssemblySpec(assemblySimpleName); From cfd962ca9362ba11992ba2e3ac20d40d3bebce48 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 17 Sep 2025 16:13:25 -0700 Subject: [PATCH 15/17] codereview --- .../design/datacontracts/RuntimeTypeSystem.md | 5 + docs/design/datacontracts/SignatureDecoder.md | 107 +++++------------- src/coreclr/vm/datadescriptor/contracts.jsonc | 4 +- src/coreclr/vm/field.h | 1 - .../Contracts/IEcmaMetadata.cs | 2 +- .../Contracts/ISignatureDecoder.cs | 3 +- .../Constants.cs | 1 + .../Contracts/EcmaMetadata_1.cs | 17 ++- .../Contracts/Loader_1.cs | 2 +- .../Contracts/RuntimeTypeSystem_1.cs | 3 +- .../Contracts/Signature/SignatureDecoder_1.cs | 2 +- .../Signature/SignatureTypeProvider.cs | 8 +- .../Legacy/SOSDacImpl.cs | 2 +- .../Legacy/SigFormat.cs | 6 +- .../Legacy/TypeNameBuilder.cs | 10 +- 15 files changed, 61 insertions(+), 112 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 46e30b9e49341c..23eb7eb8296c16 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -413,6 +413,11 @@ Contracts used: | --- | | `Thread` | +### Contract Constants: +| Name | Type | Purpose | Value | +| --- | --- | --- | --- | +| `TYPE_MASK_OFFSET` | int | The number of bits the type is shifted left in the field desc flags2 | `27` | + ```csharp private readonly Dictionary _methodTables; diff --git a/docs/design/datacontracts/SignatureDecoder.md b/docs/design/datacontracts/SignatureDecoder.md index d14edd14b672d0..3dc3d69a169bb6 100644 --- a/docs/design/datacontracts/SignatureDecoder.md +++ b/docs/design/datacontracts/SignatureDecoder.md @@ -15,14 +15,12 @@ In version 1 of the SignatureDecoder contract we take advantage of the System.Re Data descriptors used: | Data Descriptor Name | Field | Meaning | | --- | --- | --- | -| Module | TypeDefToMethodTableMap | Mapping table | -| Module | TypeRefToMethodTableMap | Mapping table | + Global variables used: | Global Name | Type | Purpose | | --- | --- | --- | -| ObjectMethodTable | TargetPointer | pointer to the MT of `object` | -| StringMethodTable | TargetPointer | pointer to the MT of `string` | + Contracts used: | Contract Name | @@ -31,85 +29,32 @@ Contracts used: | Loader | ### SignatureTypeProvider -```csharp -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; +The cDAC implements the ISignatureTypeProvider with TType=TypeHandle. TGenericContext can either be a MethodDescHandle or TypeHandle; MethodDescHandle context is used to look up generic method parameters, and TypeHandle context is used to look up generic type parameters. -public class SignatureTypeProvider : ISignatureTypeProvider -{ - private readonly Target _target; - private readonly DataContractReader.Contracts.ModuleHandle _moduleHandle; - - public SignatureTypeProvider(Target target, DataContractReader.Contracts.ModuleHandle moduleHandle) - { - _target = target; - _moduleHandle = moduleHandle; - } - public TypeHandle GetArrayType(TypeHandle elementType, ArrayShape shape) - => _target.Contracts.RuntimeTypeSystem.GetConstructedType(elementType, CorElementType.Array, shape.Rank, ImmutableArray.Empty); - - public TypeHandle GetByReferenceType(TypeHandle elementType) - => _target.Contracts.RuntimeTypeSystem.GetConstructedType(elementType, CorElementType.Byref, 0, ImmutableArray.Empty); - - public TypeHandle GetFunctionPointerType(MethodSignature signature) - => GetPrimitiveType(PrimitiveTypeCode.IntPtr); - - public TypeHandle GetGenericInstantiation(TypeHandle genericType, ImmutableArray typeArguments) - => _target.Contracts.RuntimeTypeSystem.GetConstructedType(genericType, CorElementType.GenericInst, 0, typeArguments); - - public TypeHandle GetGenericMethodParameter(T context, int index) - { - if (typeof(T) == typeof(MethodDescHandle)) - { - MethodDescHandle methodContext = (MethodDescHandle)(object)context!; - return _target.Contracts.RuntimeTypeSystem.GetGenericMethodInstantiation(methodContext)[index]; - } - throw new NotSupportedException(); - } - public TypeHandle GetGenericTypeParameter(T context, int index) - { - TypeHandle typeContext; - if (typeof(T) == typeof(TypeHandle)) - { - typeContext = (TypeHandle)(object)context!; - return _target.Contracts.RuntimeTypeSystem.GetInstantiation(typeContext)[index]; - } - throw new NotImplementedException(); - } - public TypeHandle GetModifiedType(TypeHandle modifier, TypeHandle unmodifiedType, bool isRequired) - => unmodifiedType; - - public TypeHandle GetPinnedType(TypeHandle elementType) - => elementType; - - public TypeHandle GetPointerType(TypeHandle elementType) - => _target.Contracts.RuntimeTypeSystem.GetConstructedType(elementType, CorElementType.Ptr, 0, ImmutableArray.Empty); - - public TypeHandle GetPrimitiveType(PrimitiveTypeCode typeCode) - => _target.Contracts.RuntimeTypeSystem.GetPrimitiveType(typeCode); - - public TypeHandle GetSZArrayType(TypeHandle elementType) - => _target.Contracts.RuntimeTypeSystem.GetConstructedType(elementType, CorElementType.SzArray, 1, ImmutableArray.Empty); - - public TypeHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) - { - int token = MetadataTokens.GetToken((EntityHandle)handle); - TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(_target.ReadPointer(moduleHandle.Address + /* Module::TypeDefToMethodTableMap offset */, (uint)token, out _); - return typeHandlePtr == TargetPointer.Null ? new TypeHandle(TargetPointer.Null) : _runtimeTypeSystem.GetTypeHandle(typeHandlePtr); - } - - public TypeHandle GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) - { - int token = MetadataTokens.GetToken((EntityHandle)handle); - TargetPointer typeHandlePtr = _target.Contracts.Loader.GetModuleLookupMapElement(_target.ReadPointer(moduleHandle.Address + /* Module::TypeRefToMethodTableMap offset */, (uint)token, out _); - return typeHandlePtr == TargetPointer.Null ? new TypeHandle(TargetPointer.Null) : _runtimeTypeSystem.GetTypeHandle(typeHandlePtr); - } - - public TypeHandle GetTypeFromSpecification(MetadataReader reader, T context, TypeSpecificationHandle handle, byte rawTypeKind) - => throw new NotImplementedException(); -} +A cDAC SignatureTypeProvider is instantiated over a Module which is used to lookup types. + +The following ISignatureTypeProvider APIs are trivially implemented using RuntimeTypeSystem.GetPrimitiveType and RuntimeTypeSystem.GetConstructedType: + +* GetArrayType - GetConstructedType +* GetByReferenceType - GetConstructedType +* GetFunctionPointerType - Implemented as primitive IntPtr type +* GetGenericInstantiation - GetConstructedType +* GetModifiedType - Returns unmodified type +* GetPinnedType - Returns unpinned type +* GetPointerType - GetConstructedType +* GetPrimitiveType - GetConstructedType +* GetSZArrayType - GetConstructedType + +GetGenericMethodParameter is only supported when TGenericContext=MethodDescHandle and looks up the method parameters from the context using RuntimeTypeSystem.GetGenericMethodInstantiation. + +GetGenericTypeParameter is only supported when TGenericContext=TypeHandle and looks up the type parameters from the context using RuntimeTypeSystem.GetInstantiation. + +GetTypeFromDefinition uses the SignatureTypeProvider's ModuleHandle to lookup the given Token in the Module's TypeDefToMethodTableMap. If a value is not found return null. + +GetTypeFromReference uses the SignatureTypeProvider's ModuleHandle to lookup the given Token in the Module's TypeRefToMethodTableMap. If a value is not found return null.The implementation when the type exists in a different module is incomplete. + +GetTypeFromSpecification is not currently implemented. -``` ### APIs ```csharp diff --git a/src/coreclr/vm/datadescriptor/contracts.jsonc b/src/coreclr/vm/datadescriptor/contracts.jsonc index ff0f9fec5fc291..d5a01ba25663e9 100644 --- a/src/coreclr/vm/datadescriptor/contracts.jsonc +++ b/src/coreclr/vm/datadescriptor/contracts.jsonc @@ -22,9 +22,9 @@ "ReJIT": 1, "RuntimeInfo": 1, "RuntimeTypeSystem": 1, - "Thread": 1, "SHash": 1, "SignatureDecoder": 1, "StackWalk": 1, - "StressLog": 2 + "StressLog": 2, + "Thread": 1 } diff --git a/src/coreclr/vm/field.h b/src/coreclr/vm/field.h index 38bb0b44f39ff1..2a8894480610f2 100644 --- a/src/coreclr/vm/field.h +++ b/src/coreclr/vm/field.h @@ -43,7 +43,6 @@ class FieldDesc PTR_MethodTable m_pMTOfEnclosingClass; // This is used to hold the log2 of the field size temporarily during class loading. Yuck. // See also: FieldDesc::InitializeFrom method - // if this structure is changed please update cdac_data union { //create a union so I can get the correct offset for ClrDump. unsigned m_dword1; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IEcmaMetadata.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IEcmaMetadata.cs index 9ef128a4073fde..b69fd414f933ff 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IEcmaMetadata.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IEcmaMetadata.cs @@ -10,7 +10,7 @@ public interface IEcmaMetadata : IContract { static string IContract.Name { get; } = nameof(EcmaMetadata); TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle) => throw new NotImplementedException(); - MetadataReader GetMetadata(ModuleHandle module) => throw new NotImplementedException(); + MetadataReader? GetMetadata(ModuleHandle module) => throw new NotImplementedException(); } public readonly struct EcmaMetadata : IEcmaMetadata diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ISignatureDecoder.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ISignatureDecoder.cs index fbe1038929b679..5977d736b74d43 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ISignatureDecoder.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ISignatureDecoder.cs @@ -9,8 +9,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; public interface ISignatureDecoder : IContract { static string IContract.Name { get; } = nameof(SignatureDecoder); - TypeHandle DecodeFieldSignature(BlobHandle blobHandle, ModuleHandle moduleHandle, TypeHandle ctx) => - throw new NotImplementedException(); + TypeHandle DecodeFieldSignature(BlobHandle blobHandle, ModuleHandle moduleHandle, TypeHandle ctx) => throw new NotImplementedException(); } public readonly struct SignatureDecoder : ISignatureDecoder diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs index aa1a376c5d794f..3d6834e30809e6 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -25,6 +25,7 @@ public static class Globals public const string ObjectMethodTable = nameof(ObjectMethodTable); public const string ObjectArrayMethodTable = nameof(ObjectArrayMethodTable); public const string StringMethodTable = nameof(StringMethodTable); + public const string MiniMetaDataBuffAddress = nameof(MiniMetaDataBuffAddress); public const string MiniMetaDataBuffMaxSize = nameof(MiniMetaDataBuffMaxSize); public const string DacNotificationFlags = nameof(DacNotificationFlags); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs index 6a26a0ebae9293..2e00ce75b93f70 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs @@ -7,14 +7,13 @@ using System.Numerics; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal sealed class EcmaMetadata_1(Target target) : IEcmaMetadata { - private Dictionary _metadata = new(); + private Dictionary _metadata = new(); public TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle) { @@ -36,28 +35,28 @@ public TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle) return new TargetSpan(baseAddress + (ulong)metadataStartOffset, (ulong)metadataSize); } - public MetadataReader GetMetadata(ModuleHandle handle) + public MetadataReader? GetMetadata(ModuleHandle handle) { - MetadataReader reader; if (_metadata.TryGetValue(handle, out MetadataReaderProvider? result)) { - reader = result.GetMetadataReader(); + return result?.GetMetadataReader(); } else { - MetadataReaderProvider provider = GetMetadataProvider(handle); + MetadataReaderProvider? provider = GetMetadataProvider(handle); _metadata.Add(handle, provider); - reader = provider.GetMetadataReader(); + return provider?.GetMetadataReader(); } - return reader; } - private MetadataReaderProvider GetMetadataProvider(ModuleHandle handle) + private MetadataReaderProvider? GetMetadataProvider(ModuleHandle handle) { AvailableMetadataType type = GetAvailableMetadataType(handle); switch (type) { + case AvailableMetadataType.None: + return null; case AvailableMetadataType.ReadOnly: { TargetSpan address = GetReadOnlyMetadataAddress(handle); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs index 027d96a6cf7ee8..592ee98f8b79a6 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs @@ -531,7 +531,7 @@ TargetPointer ILoader.GetObjectHandle(TargetPointer loaderAllocatorPointer) private int GetRVAFromMetadata(ModuleHandle handle, int token) { IEcmaMetadata ecmaMetadataContract = _target.Contracts.EcmaMetadata; - MetadataReader mdReader = ecmaMetadataContract.GetMetadata(handle); + MetadataReader mdReader = ecmaMetadataContract.GetMetadata(handle)!; MethodDefinition methodDef = mdReader.GetMethodDefinition(MetadataTokens.MethodDefinitionHandle(token)); return methodDef.RelativeVirtualAddress; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index e6e7cac933be68..8ea9ef5b47c061 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -14,6 +14,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem { + private const int TYPE_MASK_OFFSET = 27; // offset of type in field desc flags2 private readonly Target _target; private readonly TargetPointer _freeObjectMethodTablePointer; private readonly ulong _methodDescAlignment; @@ -1474,7 +1475,7 @@ CorElementType IRuntimeTypeSystem.GetFieldDescType(TargetPointer fieldDescPointe { Data.FieldDesc fieldDesc = _target.ProcessedData.GetOrAdd(fieldDescPointer); // 27 is the number of bits that the type is shifted left. if you change the enum, please change this too. - return (CorElementType)((fieldDesc.DWord2 & (uint)FieldDescFlags2.TypeMask) >> 27); + return (CorElementType)((fieldDesc.DWord2 & (uint)FieldDescFlags2.TypeMask) >> TYPE_MASK_OFFSET); } uint IRuntimeTypeSystem.GetFieldDescOffset(TargetPointer fieldDescPointer, FieldDefinition fieldDef) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs index f193acf5893cf3..4ca665fab31915 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs @@ -54,7 +54,7 @@ private SignatureTypeProvider GetMethodDescHandleProvider(Modu TypeHandle ISignatureDecoder.DecodeFieldSignature(BlobHandle blobHandle, ModuleHandle moduleHandle, TypeHandle ctx) { SignatureTypeProvider provider = GetTypeHandleProvider(moduleHandle); - MetadataReader mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle); + MetadataReader mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle)!; BlobReader blobReader = mdReader.GetBlobReader(blobHandle); SignatureDecoder decoder = new(provider, mdReader, ctx); return decoder.DecodeFieldSignature(ref blobReader); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs index 5d51311f41a005..82672504975f49 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs @@ -73,17 +73,17 @@ public TypeHandle GetSZArrayType(TypeHandle elementType) public TypeHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) { - Module module = _target.ProcessedData.GetOrAdd(_moduleHandle.Address); int token = MetadataTokens.GetToken((EntityHandle)handle); - TargetPointer typeHandlePtr = _loader.GetModuleLookupMapElement(module.TypeDefToMethodTableMap, (uint)token, out _); + TargetPointer typeDefToMethodTable = _loader.GetLookupTables(_moduleHandle).TypeDefToMethodTable; + TargetPointer typeHandlePtr = _loader.GetModuleLookupMapElement(typeDefToMethodTable, (uint)token, out _); return typeHandlePtr == TargetPointer.Null ? new TypeHandle(TargetPointer.Null) : _runtimeTypeSystem.GetTypeHandle(typeHandlePtr); } public TypeHandle GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) { - Module module = _target.ProcessedData.GetOrAdd(_moduleHandle.Address); int token = MetadataTokens.GetToken((EntityHandle)handle); - TargetPointer typeHandlePtr = _loader.GetModuleLookupMapElement(module.TypeRefToMethodTableMap, (uint)token, out _); + TargetPointer typeRefToMethodTable = _loader.GetLookupTables(_moduleHandle).TypeRefToMethodTable; + TargetPointer typeHandlePtr = _loader.GetModuleLookupMapElement(typeRefToMethodTable, (uint)token, out _); return typeHandlePtr == TargetPointer.Null ? new TypeHandle(TargetPointer.Null) : _runtimeTypeSystem.GetTypeHandle(typeHandlePtr); } diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index 341180c4fade64..8f7b6a261c73d9 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -779,7 +779,7 @@ int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescDat TypeHandle ctx = rtsContract.GetTypeHandle(enclosingMT); TargetPointer modulePtr = rtsContract.GetModule(ctx); Contracts.ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePtr); - MetadataReader mdReader = ecmaMetadataContract.GetMetadata(moduleHandle); + MetadataReader mdReader = ecmaMetadataContract.GetMetadata(moduleHandle)!; FieldDefinition fieldDef = mdReader.GetFieldDefinition(fieldHandle); try { diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SigFormat.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SigFormat.cs index dea6cef3581f71..98ac68d98d0dde 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SigFormat.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SigFormat.cs @@ -180,7 +180,7 @@ private static unsafe void AddTypeString(Target target, uint typeDefToken = runtimeTypeSystem.GetTypeDefToken(th); TargetPointer modulePointer = target.Contracts.RuntimeTypeSystem.GetModule(th); Contracts.ModuleHandle module = target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePointer); - MetadataReader internalTypeMetadata = target.Contracts.EcmaMetadata.GetMetadata(module); + MetadataReader internalTypeMetadata = target.Contracts.EcmaMetadata.GetMetadata(module)!; TypeDefinition internalTypeDef = internalTypeMetadata.GetTypeDefinition((TypeDefinitionHandle)MetadataTokens.Handle((int)typeDefToken)); _namespace = internalTypeMetadata.GetString(internalTypeDef.Namespace); @@ -346,7 +346,7 @@ private static void AddType(Target target, StringBuilder stringBuilder, TypeHand uint typeDefToken = runtimeTypeSystem.GetTypeDefToken(typeHandle); TargetPointer modulePointer = target.Contracts.RuntimeTypeSystem.GetModule(typeHandle); Contracts.ModuleHandle module = target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePointer); - MetadataReader metadata = target.Contracts.EcmaMetadata.GetMetadata(module); + MetadataReader metadata = target.Contracts.EcmaMetadata.GetMetadata(module)!; TypeDefinition typeDef = metadata.GetTypeDefinition((TypeDefinitionHandle)MetadataTokens.Handle((int)typeDefToken)); string _namespace = metadata.GetString(typeDef.Namespace); string name = metadata.GetString(typeDef.Name); @@ -391,7 +391,7 @@ private static void AddType(Target target, StringBuilder stringBuilder, TypeHand case CorElementType.Var: runtimeTypeSystem.IsGenericVariable(typeHandle, out TargetPointer genericVariableModulePointer, out uint typeVarToken); Contracts.ModuleHandle genericVariableModule = target.Contracts.Loader.GetModuleHandleFromModulePtr(genericVariableModulePointer); - MetadataReader generatedVariableMetadata = target.Contracts.EcmaMetadata.GetMetadata(genericVariableModule); + MetadataReader generatedVariableMetadata = target.Contracts.EcmaMetadata.GetMetadata(genericVariableModule)!; GenericParameter genericVariable = generatedVariableMetadata.GetGenericParameter((GenericParameterHandle)MetadataTokens.Handle((int)typeVarToken)); stringBuilder.Append(generatedVariableMetadata.GetString(genericVariable.Name)); return; diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/TypeNameBuilder.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/TypeNameBuilder.cs index 3e9847d9a72568..2946352dd163e0 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/TypeNameBuilder.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/TypeNameBuilder.cs @@ -120,7 +120,7 @@ public static void AppendMethodImpl(Target target, StringBuilder stringBuilder, else { module = loader.GetModuleHandleFromModulePtr(runtimeTypeSystem.GetModule(th)); - MetadataReader reader = target.Contracts.EcmaMetadata.GetMetadata(module); + MetadataReader reader = target.Contracts.EcmaMetadata.GetMetadata(module)!; MethodDefinition methodDef = reader.GetMethodDefinition(MetadataTokens.MethodDefinitionHandle((int)runtimeTypeSystem.GetMethodToken(method))); stringBuilder.Append(reader.GetString(methodDef.Name)); } @@ -137,7 +137,7 @@ public static void AppendMethodImpl(Target target, StringBuilder stringBuilder, MetadataReader? reader = default; if (!runtimeTypeSystem.IsStoredSigMethodDesc(method, out signature)) { - reader = target.Contracts.EcmaMetadata.GetMetadata(module); + reader = target.Contracts.EcmaMetadata.GetMetadata(module)!; if (reader is not null) { MethodDefinition methodDef = reader.GetMethodDefinition(MetadataTokens.MethodDefinitionHandle((int)runtimeTypeSystem.GetMethodToken(method))); @@ -227,7 +227,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle else if (typeSystemContract.IsGenericVariable(typeHandle, out TargetPointer modulePointer, out uint genericParamToken)) { Contracts.ModuleHandle module = tnb.Target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePointer); - MetadataReader reader = tnb.Target.Contracts.EcmaMetadata.GetMetadata(module); + MetadataReader reader = tnb.Target.Contracts.EcmaMetadata.GetMetadata(module)!; var handle = (GenericParameterHandle)MetadataTokens.Handle((int)genericParamToken); GenericParameter genericParam = reader.GetGenericParameter(handle); if (format.HasFlag(TypeNameFormat.FormatGenericParam)) @@ -287,7 +287,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle } else { - MetadataReader reader = tnb.Target.Contracts.EcmaMetadata.GetMetadata(moduleHandle); + MetadataReader reader = tnb.Target.Contracts.EcmaMetadata.GetMetadata(moduleHandle)!; AppendNestedTypeDef(ref tnb, reader, (TypeDefinitionHandle)MetadataTokens.EntityHandle((int)typeDefToken), format); } @@ -314,7 +314,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle Contracts.ModuleHandle module = tnb.Target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePtr); // NOTE: The DAC variant of assembly name generation is different than the runtime version. The DAC variant is simpler, and only uses SimpleName - MetadataReader mr = tnb.Target.Contracts.EcmaMetadata.GetMetadata(module); + MetadataReader mr = tnb.Target.Contracts.EcmaMetadata.GetMetadata(module)!; string assemblySimpleName = mr.GetString(mr.GetAssemblyDefinition().Name); tnb.AddAssemblySpec(assemblySimpleName); From 13e30e153e73c8e9cdf1dca81033c9b7340804e1 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Mon, 22 Sep 2025 13:22:14 -0700 Subject: [PATCH 16/17] small edits --- docs/design/datacontracts/SignatureDecoder.md | 1 + src/coreclr/vm/datadescriptor/datadescriptor.inc | 1 + .../cdac/mscordaccore_universal/Legacy/TypeNameBuilder.cs | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/design/datacontracts/SignatureDecoder.md b/docs/design/datacontracts/SignatureDecoder.md index 3dc3d69a169bb6..08f41f49917dd3 100644 --- a/docs/design/datacontracts/SignatureDecoder.md +++ b/docs/design/datacontracts/SignatureDecoder.md @@ -27,6 +27,7 @@ Contracts used: | --- | | RuntimeTypeSystem | | Loader | +| EcmaMetadata | ### SignatureTypeProvider The cDAC implements the ISignatureTypeProvider with TType=TypeHandle. TGenericContext can either be a MethodDescHandle or TypeHandle; MethodDescHandle context is used to look up generic method parameters, and TypeHandle context is used to look up generic type parameters. diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 851f8275745d73..841f004eb5e6b4 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -923,6 +923,7 @@ CDAC_TYPE_BEGIN(CoreLibBinder) CDAC_TYPE_INDETERMINATE(CoreLibBinder) CDAC_TYPE_FIELD(CoreLibBinder, /*pointer*/, Classes, cdac_data::Classes) CDAC_TYPE_END(CoreLibBinder) + // this is an SHash type CDAC_TYPE_BEGIN(DynamicILBlobTable) CDAC_TYPE_SIZE(cdac_data::EntrySize) diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/TypeNameBuilder.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/TypeNameBuilder.cs index 2946352dd163e0..d05f14803d5baa 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/TypeNameBuilder.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/TypeNameBuilder.cs @@ -137,7 +137,7 @@ public static void AppendMethodImpl(Target target, StringBuilder stringBuilder, MetadataReader? reader = default; if (!runtimeTypeSystem.IsStoredSigMethodDesc(method, out signature)) { - reader = target.Contracts.EcmaMetadata.GetMetadata(module)!; + reader = target.Contracts.EcmaMetadata.GetMetadata(module); if (reader is not null) { MethodDefinition methodDef = reader.GetMethodDefinition(MetadataTokens.MethodDefinitionHandle((int)runtimeTypeSystem.GetMethodToken(method))); From 2cfa600c8ab7427faeceee45a5c7f622ca736da4 Mon Sep 17 00:00:00 2001 From: Rachel Date: Mon, 22 Sep 2025 15:05:59 -0700 Subject: [PATCH 17/17] Update src/coreclr/vm/datadescriptor/datadescriptor.inc --- src/coreclr/vm/datadescriptor/datadescriptor.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 841f004eb5e6b4..9f057af35b7199 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1067,7 +1067,7 @@ CDAC_GLOBAL_CONTRACT(ReJIT, 1) CDAC_GLOBAL_CONTRACT(RuntimeInfo, 1) CDAC_GLOBAL_CONTRACT(RuntimeTypeSystem, 1) CDAC_GLOBAL_CONTRACT(SHash, 1) -CDAC_GLOBAL_CONTRACT(Signature, 1) +CDAC_GLOBAL_CONTRACT(SignatureDecoder, 1) CDAC_GLOBAL_CONTRACT(StackWalk, 1) CDAC_GLOBAL_CONTRACT(StressLog, 2) CDAC_GLOBAL_CONTRACT(Thread, 1)