Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
29 changes: 29 additions & 0 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ partial interface IRuntimeTypeSystem : IContract
public TargetPointer GetGCStaticsBasePointer(TypeHandle typeHandle);
public TargetPointer GetNonGCStaticsBasePointer(TypeHandle typeHandle);
public virtual ReadOnlySpan<TypeHandle> GetInstantiation(TypeHandle typeHandle);
public bool IsClassInited(TypeHandle typeHandle);
public bool IsInitError(TypeHandle typeHandle);
public virtual bool IsGenericTypeDefinition(TypeHandle typeHandle);

public virtual bool HasTypeParam(TypeHandle typeHandle);
Expand Down Expand Up @@ -354,6 +356,7 @@ The contract additionally depends on these data descriptors
| `MethodTable` | `NumInterfaces` | Number of interfaces of `MethodTable` |
| `MethodTable` | `NumVirtuals` | Number of virtual methods in `MethodTable` |
| `MethodTable` | `PerInstInfo` | Either the array element type, or pointer to generic information for `MethodTable` |
| `MethodTableAuxiliaryData` | `Flags` | Flags of `MethodTableAuxiliaryData` |
| `MethodTable` | `AuxiliaryData` | Pointer to the AuxiliaryData of a method table |
| `DynamicStaticsInfo` | `NonGCStatics` | Pointer to non-GC statics |
| `DynamicStaticsInfo` | `GCStatics` | Pointer to the GC statics |
Expand Down Expand Up @@ -556,6 +559,26 @@ Contracts used:
return instantiation;
}

public bool IsClassInited(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return false;
TargetPointer auxiliaryDataPtr = target.ReadPointer(typeHandle.Address + /* MethodTable.AuxiliaryData offset */);
TargetPointer flagsPtr = target.ReadPointer(auxiliaryDataPtr + /* MethodTableAuxiliaryData::Flags offset */);
uint flags = target.Read<uint>(flagsPtr);
return (flags & (uint)MethodTableAuxiliaryFlags.Initialized) != 0;
}

public bool IsInitError(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return false;
TargetPointer auxiliaryDataPtr = target.ReadPointer(typeHandle.Address + /* MethodTable.AuxiliaryData offset */);
TargetPointer flagsPtr = target.ReadPointer(auxiliaryDataPtr + /* MethodTableAuxiliaryData::Flags offset */);
uint flags = target.Read<uint>(flagsPtr);
return (flags & (uint)MethodTableAuxiliaryFlags.IsInitError) != 0;
}

public bool IsDynamicStatics(TypeHandle TypeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[TypeHandle.Address].Flags.IsDynamicStatics;

public bool HasTypeParam(TypeHandle typeHandle)
Expand Down Expand Up @@ -827,6 +850,12 @@ And the following enumeration definitions
TemporaryEntryPointAssigned = 0x04,
}

internal enum MethodTableAuxiliaryFlags : uint
{
Initialized = 0x0001,
IsInitError = 0x0100,
}

```

Internal to the contract in order to answer queries about method descriptors,
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ CDAC_TYPE_BEGIN(MethodTableAuxiliaryData)
CDAC_TYPE_INDETERMINATE(MethodTableAuxiliaryData)
CDAC_TYPE_FIELD(MethodTableAuxiliaryData, /*pointer*/, LoaderModule, offsetof(MethodTableAuxiliaryData, m_pLoaderModule))
CDAC_TYPE_FIELD(MethodTableAuxiliaryData, /*int16*/, OffsetToNonVirtualSlots, offsetof(MethodTableAuxiliaryData, m_offsetToNonVirtualSlots))
CDAC_TYPE_FIELD(MethodTableAuxiliaryData, /*uint32*/, Flags, offsetof(MethodTableAuxiliaryData, m_dwFlags))
CDAC_TYPE_END(MethodTableAuxiliaryData)

CDAC_TYPE_BEGIN(EEClass)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ public interface IRuntimeTypeSystem : IContract


ReadOnlySpan<TypeHandle> GetInstantiation(TypeHandle typeHandle) => throw new NotImplementedException();
public bool IsClassInited(TypeHandle typeHandle) => throw new NotImplementedException();
public bool IsInitError(TypeHandle typeHandle) => throw new NotImplementedException();
bool IsGenericTypeDefinition(TypeHandle typeHandle) => throw new NotImplementedException();

bool HasTypeParam(TypeHandle typeHandle) => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ internal enum MethodDescChunkFlags : ushort
LoaderModuleAttachedToChunk = 0x8000,
}

internal enum MethodTableAuxiliaryFlags : uint
{
Initialized = 0x0001,
IsInitError = 0x0100,
}

internal struct MethodDesc
{
private readonly Data.MethodDesc _desc;
Expand Down Expand Up @@ -480,6 +486,24 @@ public ReadOnlySpan<TypeHandle> GetInstantiation(TypeHandle typeHandle)
return _target.ProcessedData.GetOrAdd<TypeInstantiation>(typeHandle.Address).TypeHandles;
}

public bool IsClassInited(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return false;
MethodTable methodTable = _methodTables[typeHandle.Address];
MethodTableAuxiliaryData auxiliaryData = _target.ProcessedData.GetOrAdd<MethodTableAuxiliaryData>(methodTable.AuxiliaryData);
return (auxiliaryData.Flags & (uint)MethodTableAuxiliaryFlags.Initialized) != 0;
}

public bool IsInitError(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return false;
MethodTable methodTable = _methodTables[typeHandle.Address];
MethodTableAuxiliaryData auxiliaryData = _target.ProcessedData.GetOrAdd<MethodTableAuxiliaryData>(methodTable.AuxiliaryData);
return (auxiliaryData.Flags & (uint)MethodTableAuxiliaryFlags.IsInitError) != 0;
}

private sealed class TypeInstantiation : IData<TypeInstantiation>
{
public static TypeInstantiation Create(Target target, TargetPointer address) => new TypeInstantiation(target, address);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ private MethodTableAuxiliaryData(Target target, TargetPointer address)

LoaderModule = target.ReadPointer(address + (ulong)type.Fields[nameof(LoaderModule)].Offset);
OffsetToNonVirtualSlots = target.Read<short>(address + (ulong)type.Fields[nameof(OffsetToNonVirtualSlots)].Offset);
Flags = target.Read<uint>(address + (ulong)type.Fields[nameof(Flags)].Offset);

}

public TargetPointer LoaderModule { get; init; }
public short OffsetToNonVirtualSlots { get; init; }
public uint Flags { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ internal struct DacpMethodTableFieldData
public ushort wContextStaticsSize;
};

internal enum MethodTableInitializationFlags
{
MethodTableInitialized = 1,
MethodTableInitializationFailed = 2
};

internal struct DacpReJitData
{
// FIXME[cdac]: the C++ definition enum doesn't have an explicit underlying type or constant values for the flags
Expand Down Expand Up @@ -647,7 +653,7 @@ internal unsafe partial interface ISOSDacInterface14
[PreserveSig]
int GetThreadStaticBaseAddress(ClrDataAddress methodTable, ClrDataAddress thread, ClrDataAddress* nonGCStaticsAddress, ClrDataAddress* GCStaticsAddress);
[PreserveSig]
int GetMethodTableInitializationFlags(ClrDataAddress methodTable, /*MethodTableInitializationFlags*/ int* initializationStatus);
int GetMethodTableInitializationFlags(ClrDataAddress methodTable, MethodTableInitializationFlags* initializationStatus);
}

[GeneratedComInterface]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2503,8 +2503,47 @@ int ISOSDacInterface14.GetThreadStaticBaseAddress(ClrDataAddress methodTable, Cl
#endif
return hr;
}
int ISOSDacInterface14.GetMethodTableInitializationFlags(ClrDataAddress methodTable, /*MethodTableInitializationFlags*/ int* initializationStatus)
=> _legacyImpl14 is not null ? _legacyImpl14.GetMethodTableInitializationFlags(methodTable, initializationStatus) : HResults.E_NOTIMPL;

int ISOSDacInterface14.GetMethodTableInitializationFlags(ClrDataAddress methodTable, MethodTableInitializationFlags* initializationStatus)
{
int hr = HResults.S_OK;
if (methodTable == 0)
hr = HResults.E_INVALIDARG;
else if (initializationStatus == null)
hr = HResults.E_POINTER;

else
{
try
{
Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem;
Contracts.TypeHandle methodTableHandle = rtsContract.GetTypeHandle(methodTable.ToTargetPointer(_target));
*initializationStatus = (MethodTableInitializationFlags)0;
if (rtsContract.IsClassInited(methodTableHandle))
*initializationStatus = MethodTableInitializationFlags.MethodTableInitialized;
if (rtsContract.IsInitError(methodTableHandle))
*initializationStatus |= MethodTableInitializationFlags.MethodTableInitializationFailed;
}
catch (System.Exception ex)
{
hr = ex.HResult;
}
}
#if DEBUG
if (_legacyImpl14 is not null)
{
MethodTableInitializationFlags initializationStatusLocal;
int hrLocal = _legacyImpl14.GetMethodTableInitializationFlags(methodTable, &initializationStatusLocal);
Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}");
if (hr == HResults.S_OK)
{
Debug.Assert(*initializationStatus == initializationStatusLocal);
}
}
#endif
return hr;
}

#endregion ISOSDacInterface14

#region ISOSDacInterface15
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ internal record TypeFields
[
new(nameof(Data.MethodTableAuxiliaryData.LoaderModule), DataType.pointer),
new(nameof(Data.MethodTableAuxiliaryData.OffsetToNonVirtualSlots), DataType.int16),
new(nameof(Data.MethodTableAuxiliaryData.Flags), DataType.uint32),
]
};

Expand Down
Loading