Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 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
181 changes: 180 additions & 1 deletion docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,11 @@ 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 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);

#endregion TypeHandle inspection APIs
Expand Down Expand Up @@ -186,6 +189,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
Expand Down Expand Up @@ -714,6 +728,89 @@ Contracts used:
throw new ArgumentException(nameof(typeHandle));
}

// helper functions

private bool GenericInstantiationMatch(TypeHandle genericType, TypeHandle potentialMatch, ImmutableArray<TypeHandle> typeArguments)
{
ReadOnlySpan<TypeHandle> 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));

}

private bool IsLoaded(TypeHandle typeHandle)
{
if (typeHandle.Address == TargetPointer.Null)
return false;
if (typeHandle.IsTypeDesc())
{
uint typeAndFlags = _target.Read<uint>(typeHandle.TypeDescAddress() + /* TypeDesc::TypeAndFlags offset */);
return (typeAndFlags & (uint)TypeDescFlags.IsNotFullyLoaded) == 0;
}

MethodTable methodTable = _methodTables[typeHandle.Address];
uint flags = _target.Read<uint>(methodTable.AuxiliaryData + /* AuxiliaryData::Flags offset */);
return (flags & (uint)MethodTableAuxiliaryFlags.IsNotFullyLoaded) == 0;
}

TypeHandle GetConstructedType(TypeHandle typeHandle, CorElementType corElementType, int rank, ImmutableArray<TypeHandle> 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))
{
potentialMatch = GetTypeHandle(ptr);
if (corElementType == CorElementType.GenericInst)
{
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;
}
}
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;
Expand Down Expand Up @@ -745,7 +842,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;
Expand All @@ -762,6 +859,16 @@ Contracts used:
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;
}

public TargetPointer GetLoaderModule(TypeHandle typeHandle)
{
if (typeHandle.IsTypeDesc())
Expand Down Expand Up @@ -904,6 +1011,12 @@ And the following enumeration definitions
{
Initialized = 0x0001,
IsInitError = 0x0100,
IsNotFullyLoaded = 0x0040,
}

internal enum TypeDescFlags : uint
{
IsNotFullyLoaded = 0x00001000,
}

```
Expand Down Expand Up @@ -1504,3 +1617,69 @@ Getting a MethodDesc for a certain slot in a MethodTable
return GetMethodDescForEntrypoint(pCode);
}
```

### 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<uint>(fieldDescPointer + /* FieldDesc::DWord1 offset */);
return EcmaMetadataUtils.CreateFieldDef(DWord1 & (uint)FieldDescFlags1.TokenMask);
}

bool IsFieldDescThreadStatic(TargetPointer fieldDescPointer)
{
uint DWord1 = target.Read<uint>(fieldDescPointer + /* FieldDesc::DWord1 offset */);
return (DWord1 & (uint)FieldDescFlags1.IsThreadStatic) != 0;
}

bool IsFieldDescStatic(TargetPointer fieldDescPointer)
{
uint DWord1 = target.Read<uint>(fieldDescPointer + /* FieldDesc::DWord1 offset */);
return (DWord1 & (uint)FieldDescFlags1.IsStatic) != 0;
}

uint GetFieldDescType(TargetPointer fieldDescPointer)
{
uint DWord2 = target.Read<uint>(fieldDescPointer + /* FieldDesc::DWord2 offset */);
return (DWord2 & (uint)FieldDescFlags2.TypeMask) >> 27;
}

uint GetFieldDescOffset(TargetPointer fieldDescPointer)
{
uint DWord2 = target.Read<uint>(fieldDescPointer + /* FieldDesc::DWord2 offset */);
if (DWord2 == _target.ReadGlobal<uint>("FieldOffsetBigRVA"))
{
return (uint)fieldDef.GetRelativeVirtualAddress();
}
return DWord2 & (uint)FieldDescFlags2.OffsetMask;
}

TargetPointer GetFieldDescNextField(TargetPointer fieldDescPointer)
=> fieldDescPointer + _target.GetTypeInfo(DataType.FieldDesc).Size!.Value;
```
124 changes: 124 additions & 0 deletions docs/design/datacontracts/SignatureDecoder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# 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 |
| --- | --- | --- |
| 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 |
| --- |
| RuntimeTypeSystem |
| Loader |

### SignatureTypeProvider
```csharp
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;

public class SignatureTypeProvider<T> : ISignatureTypeProvider<TypeHandle, T>
{
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<TypeHandle>.Empty);

public TypeHandle GetByReferenceType(TypeHandle elementType)
=> _target.Contracts.RuntimeTypeSystem.GetConstructedType(elementType, CorElementType.Byref, 0, ImmutableArray<TypeHandle>.Empty);

public TypeHandle GetFunctionPointerType(MethodSignature<TypeHandle> signature)
=> GetPrimitiveType(PrimitiveTypeCode.IntPtr);

public TypeHandle GetGenericInstantiation(TypeHandle genericType, ImmutableArray<TypeHandle> 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<TypeHandle>.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<TypeHandle>.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();
}

```

### APIs
```csharp
TypeHandle ISignatureDecoder.DecodeFieldSignature(BlobHandle blobHandle, ModuleHandle moduleHandle, TypeHandle ctx)
{
SignatureTypeProvider<TypeHandle> provider = new(_target, moduleHandle);
MetadataReader mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle)!;
BlobReader blobReader = mdReader.GetBlobReader(blobHandle);
SignatureDecoder<TypeHandle, TypeHandle> decoder = new(provider, mdReader, ctx);
return decoder.DecodeFieldSignature(ref blobReader);
}
```
9 changes: 8 additions & 1 deletion src/coreclr/vm/binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -294,6 +294,7 @@ class CoreLibBinder
USHORT m_cFields;

static CrstStatic s_SigConvertCrst;
friend struct ::cdac_data<CoreLibBinder>;

#ifdef _DEBUG

Expand All @@ -313,6 +314,12 @@ class CoreLibBinder
#endif
};

template<>
struct cdac_data<CoreLibBinder>
{
static constexpr size_t Classes = offsetof(CoreLibBinder, m_pClasses);
};

//
// Global bound modules:
//
Expand Down
5 changes: 3 additions & 2 deletions src/coreclr/vm/datadescriptor/contracts.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@
"ReJIT": 1,
"RuntimeInfo": 1,
"RuntimeTypeSystem": 1,
"Thread": 1,
"SHash": 1,
"SignatureDecoder": 1,
"StackWalk": 1,
"StressLog": 2,
"Thread": 1
"StressLog": 2
}
Loading
Loading