Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 8 additions & 12 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<TypeHandle> 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<TypeHandle> 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<TypeHandle> typeArguments);
TypeHandle GetPrimitiveType(CorElementType typeCode);
bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token);
bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan<TypeHandle> retAndArgTypes, out byte callConv);
bool IsPointer(TypeHandle typeHandle);
TargetPointer GetLoaderModule(TypeHandle typeHandle);

#endregion TypeHandle inspection APIs
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1679,7 +1678,4 @@ uint GetFieldDescOffset(TargetPointer fieldDescPointer)
}
return DWord2 & (uint)FieldDescFlags2.OffsetMask;
}

TargetPointer GetFieldDescNextField(TargetPointer fieldDescPointer)
=> fieldDescPointer + _target.GetTypeInfo(DataType.FieldDesc).Size!.Value;
```
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -95,7 +96,6 @@ public interface IRuntimeTypeSystem : IContract
IEnumerable<TargetPointer> 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();
Expand Down Expand Up @@ -144,7 +144,6 @@ public interface IRuntimeTypeSystem : IContract
TypeHandle GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray<TypeHandle> 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<TypeHandle> 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
Expand Down Expand Up @@ -202,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
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts;

internal sealed class EcmaMetadata_1(Target target) : IEcmaMetadata
{
private Dictionary<ModuleHandle, MetadataReaderProvider?> _metadata = new();

private sealed class ModuleHandleBox
{
public ModuleHandle Value { get; }
public ModuleHandleBox(ModuleHandle value) => Value = value;
}
private static ConditionalWeakTable<MetadataReader, ModuleHandleBox> _moduleHandles = new();
private Dictionary<ModuleHandle, MetadataReaderProvider> _metadata = new();

public TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle)
{
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<TypeKey>
private readonly struct TypeKey : IEquatable<TypeKey>
{
public TypeKey(TypeHandle typeHandle, CorElementType elementType, int rank, ImmutableArray<TypeHandle> typeArgs)
{
Expand Down Expand Up @@ -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<Data.FieldDesc>(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)
Expand All @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,30 @@

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<ModuleHandle, SignatureTypeProvider<TypeHandle>> _thProviders;
private Dictionary<ModuleHandle, SignatureTypeProvider<MethodDescHandle>> _mdhProviders;
private readonly Dictionary<ModuleHandle, SignatureTypeProvider<TypeHandle>> _thProviders = [];
private readonly Dictionary<ModuleHandle, SignatureTypeProvider<MethodDescHandle>> _mdhProviders = [];

internal SignatureDecoder_1(Target target)
{
_target = target;
_thProviders = new Dictionary<ModuleHandle, SignatureTypeProvider<TypeHandle>>();
_mdhProviders = new Dictionary<ModuleHandle, SignatureTypeProvider<MethodDescHandle>>();
}

private SignatureTypeProvider<TypeHandle> GetTypeHandleProvider(ModuleHandle moduleHandle)
{
if (_thProviders.TryGetValue(moduleHandle, out SignatureTypeProvider<TypeHandle>? thProvider))
{
return (SignatureTypeProvider<TypeHandle>)(object)thProvider;
return thProvider;
}

SignatureTypeProvider<TypeHandle> newProvider = new(_target, moduleHandle);
Expand All @@ -38,7 +44,7 @@ private SignatureTypeProvider<MethodDescHandle> GetMethodDescHandleProvider(Modu
{
if (_mdhProviders.TryGetValue(moduleHandle, out SignatureTypeProvider<MethodDescHandle>? mdhProvider))
{
return (SignatureTypeProvider<MethodDescHandle>)(object)mdhProvider;
return mdhProvider;
}
SignatureTypeProvider<MethodDescHandle> newProvider = new(_target, moduleHandle);
_mdhProviders[moduleHandle] = newProvider;
Expand All @@ -48,11 +54,9 @@ private SignatureTypeProvider<MethodDescHandle> GetMethodDescHandleProvider(Modu
TypeHandle ISignatureDecoder.DecodeFieldSignature(BlobHandle blobHandle, ModuleHandle moduleHandle, TypeHandle ctx)
{
SignatureTypeProvider<TypeHandle> provider = GetTypeHandleProvider(moduleHandle);
MetadataReader mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle)!;
MetadataReader mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle);
BlobReader blobReader = mdReader.GetBlobReader(blobHandle);
SignatureDecoder<TypeHandle, TypeHandle> decoder = new(provider, mdReader, ctx);
// Implementation pending
return decoder.DecodeFieldSignature(ref blobReader);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ namespace Microsoft.Diagnostics.DataContractReader.SignatureHelpers;

public class SignatureTypeProvider<T> : ISignatureTypeProvider<TypeHandle, T>
{
// All interface methods throw NotImplementedException for now
private readonly Target _target;
private readonly Contracts.ModuleHandle _moduleHandle;
private readonly Contracts.ILoader _loader;
Expand All @@ -25,11 +24,12 @@ 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<TypeHandle>.Empty);
=> _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Array, shape.Rank, []);

public TypeHandle GetByReferenceType(TypeHandle elementType)
=> _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Byref, 0, ImmutableArray<TypeHandle>.Empty);
=> _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Byref, 0, []);

public TypeHandle GetFunctionPointerType(MethodSignature<TypeHandle> signature)
=> GetPrimitiveType(PrimitiveTypeCode.IntPtr);
Expand Down Expand Up @@ -63,13 +63,13 @@ public TypeHandle GetPinnedType(TypeHandle elementType)
=> elementType;

public TypeHandle GetPointerType(TypeHandle elementType)
=> _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.Ptr, 0, ImmutableArray<TypeHandle>.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<TypeHandle>.Empty);
=> _runtimeTypeSystem.GetConstructedType(elementType, CorElementType.SzArray, 1, []);

public TypeHandle GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -231,7 +232,6 @@ public enum Flags : uint
public ClrDataAddress NativeCodeAddr;
};


internal struct DacpMethodDescData
{
public int bHasNativeCode;
Expand Down Expand Up @@ -352,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;
Expand Down
Loading
Loading