Closed
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
28 changes: 8 additions & 20 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,11 +39,6 @@ partial interface IRuntimeTypeSystem : IContract
// 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.
public virtual TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle);
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
public virtual TargetPointer GetClassPointer(TypeHandle typeHandle);
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
public virtual bool IsCanonicalMethodTable(TypeHandle typeHandle);
public virtual TargetPointer GetParentMethodTable(TypeHandle typeHandle);

public virtual TargetPointer GetMethodDescForSlot(TypeHandle typeHandle, ushort slot);
Expand All@@ -66,7 +61,7 @@ partial interface IRuntimeTypeSystem : IContract
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
public virtual bool RequiresAlign8(TypeHandle typeHandle);
// True if the MethodTable represents a continuation type used by the async continuation feature
public virtual bool IsContinuationWithoutMetadata(TypeHandle typeHandle);
public virtual bool IsContinuation(TypeHandle typeHandle);
// Returns the GC pointer runs for the method table as (offset, size) pairs. Each
// run starts Offset bytes from the object pointer (`this`), where offset 0
// is the method table pointer, and includes Size bytes of contiguous pointers
Expand DownExpand Up@@ -456,7 +451,6 @@ The contract depends on the following globals
| Global name | Meaning |
| --- | --- |
| `ContinuationMethodTable` | A pointer to the address of the base `Continuation` `MethodTable`, or null if no continuations have been created
| `ContinuationSingletonEEClass` | A pointer to the address of the singleton `EEClass` shared by continuation subtypes that have no metadata of their own
| `FreeObjectMethodTable` | A pointer to the address of a `MethodTable` used by the GC to indicate reclaimed memory
| `ObjectMethodTable` | A pointer to the address of the `System.Object` `MethodTable` (`g_pObjectClass`)
| `StaticsPointerMask` | For masking out a bit of DynamicStaticsInfo pointer fields
Expand DownExpand Up@@ -533,7 +527,6 @@ Contracts used:
internal TargetPointer FreeObjectMethodTablePointer {get; }
internal TargetPointer ObjectMethodTablePointer {get; }
internal TargetPointer ContinuationMethodTablePointer {get; }
private TargetPointer _continuationSingletonEEClassPointer;

public TypeHandle GetTypeHandle(TargetPointer typeHandlePointer)
{
Expand DownExpand Up@@ -577,12 +570,12 @@ Contracts used:

public uint GetComponentSize(TypeHandle TypeHandle) =>!typeHandle.IsMethodTable() ? (uint)0 : GetComponentSize(_methodTables[TypeHandle.Address]);

public TargetPointer GetClassPointer(TypeHandle TypeHandle)
private TargetPointer GetClassPointer(TypeHandle TypeHandle)
{
// Returns TargetPointer.Null if not a MethodTable.
// If EEClassOrCanonMT points directly to an EEClass, returns that pointer.
// If EEClassOrCanonMT is a tagged pointer to a canonical MethodTable, follows
// the canonical MT and returns its EEClass pointer.
... // if the MethodTable stores a pointer to the EEClass, return it
// otherwise the MethodTable stores a pointer to the canonical MethodTable
// in that case, return the canonical MethodTable's EEClass.
// Canonical MethodTables always store an EEClass pointer.
}

private Data.EEClass GetClassData(TypeHandle TypeHandle)
Expand All@@ -603,14 +596,9 @@ Contracts used:

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

public bool IsCanonicalMethodTable(TypeHandle typeHandle)
=> typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;

public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& ContinuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> GetGCDescSeries(TypeHandle typeHandle, uint numComponents = 0)
{
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line numberDiff line numberDiff line change
Expand Up@@ -1541,7 +1541,6 @@ CDAC_GLOBAL(FieldOffsetDynamicRVA, T_UINT32, FIELD_OFFSET_DYNAMIC_RVA)
CDAC_GLOBAL_POINTER(ClrNotificationArguments, &::g_clrNotificationArguments)
CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data<ArrayBase>::ArrayBoundsZero)
CDAC_GLOBAL_POINTER(ContinuationMethodTable, &::g_pContinuationClassIfSubTypeCreated)
CDAC_GLOBAL_POINTER(ContinuationSingletonEEClass, &::g_singletonContinuationEEClass)
CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass)
CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable)
CDAC_GLOBAL_POINTER(ObjectMethodTable, &::g_pObjectClass)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,11 +109,6 @@ public interface IRuntimeTypeSystem : IContract
// 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.
TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
TargetPointer GetClassPointer(TypeHandle typeHandle) => throw new NotImplementedException();
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
bool IsCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
TargetPointer GetParentMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();

TargetPointer GetMethodDescForSlot(TypeHandle methodTable, ushort slot) => throw new NotImplementedException();
Expand All@@ -134,8 +129,8 @@ public interface IRuntimeTypeSystem : IContract
bool ContainsGCPointers(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
bool RequiresAlign8(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation subtype that has no metadata of its own
bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation type used by the async continuation feature
bool IsContinuation(TypeHandle typeHandle) => throw new NotImplementedException();
/// <summary>
/// Enumerates GC pointer runs from the CGCDesc stored before the method table.
/// Returns (offset, size) pairs normalized to actual byte lengths.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,7 +32,6 @@ public static class Globals
public const string RecommendedReaderVersion = nameof(RecommendedReaderVersion);

public const string ContinuationMethodTable = nameof(ContinuationMethodTable);
public const string ContinuationSingletonEEClass = nameof(ContinuationSingletonEEClass);
public const string ExceptionMethodTable = nameof(ExceptionMethodTable);
public const string FreeObjectMethodTable = nameof(FreeObjectMethodTable);
public const string ObjectMethodTable = nameof(ObjectMethodTable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,6 @@ internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem
private readonly TargetPointer _freeObjectMethodTablePointer;
private readonly TargetPointer _objectMethodTablePointer;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;
private readonly ulong _methodDescAlignment;
private readonly TypeValidation _typeValidation;
private readonly MethodValidation _methodValidation;
Expand DownExpand Up@@ -439,10 +438,8 @@ internal RuntimeTypeSystem_1(Target target)
target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable));
_continuationMethodTablePointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationMethodTable));
_continuationSingletonEEClassPointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationSingletonEEClass));
_methodDescAlignment = target.ReadGlobal<ulong>(Constants.Globals.MethodDescAlignment);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer, _continuationSingletonEEClassPointer);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer);
_methodValidation = new MethodValidation(target, _methodDescAlignment);
_methodValidation.SetMethodTableQueries(new NonValidatedMethodTableQueries(this));
}
Expand DownExpand Up@@ -534,17 +531,14 @@ public TargetPointer GetModule(TypeHandle typeHandle)
}
}
public TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : GetClassData(typeHandle).MethodTable;
public bool IsCanonicalMethodTable(TypeHandle typeHandle) => typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;
public TargetPointer GetParentMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : _methodTables[typeHandle.Address].ParentMethodTable;

public uint GetBaseSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.BaseSize;

public uint GetComponentSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.ComponentSize;

public TargetPointer GetClassPointer(TypeHandle typeHandle)
private TargetPointer GetClassPointer(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return TargetPointer.Null;
MethodTable methodTable = _methodTables[typeHandle.Address];
switch (MethodTableFlags_1.GetEEClassOrCanonMTBits(methodTable.EEClassOrCanonMT))
{
Expand DownExpand Up@@ -581,11 +575,9 @@ public bool IsObjRef(TypeHandle typeHandle)
}
public bool ContainsGCPointers(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.ContainsGCPointers;
public bool RequiresAlign8(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8;
public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& _continuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> IRuntimeTypeSystem.GetGCDescSeries(TypeHandle typeHandle, uint numComponents)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,13 +10,11 @@ internal sealed class TypeValidation
{
private readonly Target _target;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;

internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer, TargetPointer continuationSingletonEEClassPointer)
internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer)
{
_target = target;
_continuationMethodTablePointer = continuationMethodTablePointer;
_continuationSingletonEEClassPointer = continuationSingletonEEClassPointer;
}

// This doesn't need as many properties as MethodTable because we don't want to be operating on
Expand DownExpand Up@@ -169,7 +167,7 @@ private bool ValidateThrowing(NonValidatedMethodTable methodTable)
{
return true;
}
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuationWithoutMetadata(methodTable))
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuation(methodTable))
{
NonValidatedMethodTable methodTableFromClass = GetMethodTableData(_target, methodTablePtrFromClass);
if (!methodTableFromClass.ValidateReadable())
Expand DownExpand Up@@ -229,16 +227,14 @@ private TargetPointer GetClassThrowing(NonValidatedMethodTable methodTable)
}
}

// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuationWithoutMetadata.
// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuation.
// TypeValidation runs before the MethodTable is added to the RuntimeTypeSystem's cache, so we
// cannot call into RuntimeTypeSystem_1 — the type handle does not exist yet. Instead we
// duplicate the check using the raw ParentMethodTable read from target memory.
private bool IsContinuationWithoutMetadata(NonValidatedMethodTable methodTable)
private bool IsContinuation(NonValidatedMethodTable methodTable)
{
return _continuationMethodTablePointer != TargetPointer.Null
&& methodTable.ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassThrowing(methodTable) == _continuationSingletonEEClassPointer;
&& methodTable.ParentMethodTable == _continuationMethodTablePointer;
}

internal bool TryValidateMethodTablePointer(TargetPointer methodTablePointer)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2397,54 +2397,7 @@ private static IEnumerable<GCHeapData> EnumerateHeaps(IGC gc, bool isWorkstation
};

public int IsValidObject(ulong obj, Interop.BOOL* pResult)
{
int hr = HResults.S_OK;
Interop.BOOL isValid = Interop.BOOL.FALSE;

if (obj != 0 && obj != ulong.MaxValue)
{
try
{
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
TargetPointer mt = _target.Contracts.Object.GetMethodTableAddress(new TargetPointer(obj));
TypeHandle th = rts.GetTypeHandle(mt);
TargetPointer canonMT = rts.GetCanonicalMethodTable(th);

if (mt == canonMT)
{
isValid = Interop.BOOL.TRUE;
}
else if (!rts.IsCanonicalMethodTable(th) || rts.IsContinuationWithoutMetadata(th))
{
TargetPointer cls = rts.GetClassPointer(th);
TypeHandle canonTh = rts.GetTypeHandle(canonMT);
TargetPointer canonCls = rts.GetClassPointer(canonTh);
if (canonCls == cls)
isValid = Interop.BOOL.TRUE;
}
}
catch (System.Exception)
{
isValid = Interop.BOOL.FALSE;
}
}
*pResult = isValid;

#if DEBUG
if (_legacy is not null)
{
Interop.BOOL resultLocal;
int hrLocal = _legacy.IsValidObject(obj, &resultLocal);
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
{
Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}");
}
}
#endif

return hr;
}
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsValidObject(obj, pResult) : HResults.E_NOTIMPL;

Comment thread
barosiak marked this conversation as resolved.
public int CreateRefWalk(nuint* pHandle, Interop.BOOL walkStacks, Interop.BOOL walkFQ, uint handleWalkMask)
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.CreateRefWalk(pHandle, walkStacks, walkFQ, handleWalkMask) : HResults.E_NOTIMPL;
Expand DownExpand Up@@ -3252,7 +3205,7 @@ private static CorElementType GetElementType(IRuntimeTypeSystem rts, TypeHandle
// parent (continuation base) type handle instead.
private static TypeHandle UpCastTypeIfNeeded(IRuntimeTypeSystem rts, TypeHandle typeHandle)
{
if (rts.IsContinuationWithoutMetadata(typeHandle))
if (rts.IsContinuation(typeHandle))
{
TargetPointer parentMT = rts.GetParentMethodTable(typeHandle);
if (parentMT != TargetPointer.Null)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -284,7 +284,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle
Contracts.ModuleHandle moduleHandle = tnb.Target.Contracts.Loader.GetModuleHandleFromModulePtr(typeSystemContract.GetModule(typeHandle));
if (MetadataTokens.EntityHandle((int)typeDefToken).IsNil)
{
if (typeSystemContract.IsContinuationWithoutMetadata(typeHandle))
if (typeSystemContract.IsContinuation(typeHandle))
{
AppendContinuationName(ref tnb, typeSystemContract, typeHandle);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,15 +38,14 @@ public void ContinuationBaseClass_IsNotContinuation(TestConfiguration config)
IRuntimeTypeSystem rts = Target.Contracts.RuntimeTypeSystem;

// The ContinuationMethodTable global points to the Continuation base class itself.
// IsContinuationWithoutMetadata checks if a type's parent is the Continuation base class
// and its EEClass matches the singleton continuation EEClass,
// IsContinuation checks if a type's parent is the Continuation base class,
// so the base class itself is NOT considered a continuation (its parent is Object).
TargetPointer continuationMTGlobal = Target.ReadGlobalPointer("ContinuationMethodTable");
TargetPointer continuationMT = Target.ReadPointer(continuationMTGlobal);
Assert.NotEqual(TargetPointer.Null, continuationMT);

TypeHandle handle = rts.GetTypeHandle(continuationMT);
Assert.False(rts.IsContinuationWithoutMetadata(handle));
Assert.False(rts.IsContinuation(handle));
}

[ConditionalTheory]
Expand All@@ -60,7 +59,7 @@ public void ObjectMethodTable_IsNotContinuation(TestConfiguration config)
TargetPointer objectMTGlobal = Target.ReadGlobalPointer("ObjectMethodTable");
TargetPointer objectMT = Target.ReadPointer(objectMTGlobal);
TypeHandle objectHandle = rts.GetTypeHandle(objectMT);
Assert.False(rts.IsContinuationWithoutMetadata(objectHandle));
Assert.False(rts.IsContinuation(objectHandle));
}

[ConditionalTheory]
Expand DownExpand Up@@ -159,6 +158,6 @@ public void ThreadLocalContinuation_IsContinuation(TestConfiguration config)
TargetPointer objMT = Target.Contracts.Object.GetMethodTableAddress(
new TargetPointer(continuationAddress));
TypeHandle handle = rts.GetTypeHandle(objMT);
Assert.True(rts.IsContinuationWithoutMetadata(handle));
Assert.True(rts.IsContinuation(handle));
}
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Closed
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
28 changes: 8 additions & 20 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,11 +39,6 @@ partial interface IRuntimeTypeSystem : IContract
// 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.
public virtual TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle);
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
public virtual TargetPointer GetClassPointer(TypeHandle typeHandle);
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
public virtual bool IsCanonicalMethodTable(TypeHandle typeHandle);
public virtual TargetPointer GetParentMethodTable(TypeHandle typeHandle);

public virtual TargetPointer GetMethodDescForSlot(TypeHandle typeHandle, ushort slot);
Expand All@@ -66,7 +61,7 @@ partial interface IRuntimeTypeSystem : IContract
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
public virtual bool RequiresAlign8(TypeHandle typeHandle);
// True if the MethodTable represents a continuation type used by the async continuation feature
public virtual bool IsContinuationWithoutMetadata(TypeHandle typeHandle);
public virtual bool IsContinuation(TypeHandle typeHandle);
// Returns the GC pointer runs for the method table as (offset, size) pairs. Each
// run starts Offset bytes from the object pointer (`this`), where offset 0
// is the method table pointer, and includes Size bytes of contiguous pointers
Expand DownExpand Up@@ -456,7 +451,6 @@ The contract depends on the following globals
| Global name | Meaning |
| --- | --- |
| `ContinuationMethodTable` | A pointer to the address of the base `Continuation` `MethodTable`, or null if no continuations have been created
| `ContinuationSingletonEEClass` | A pointer to the address of the singleton `EEClass` shared by continuation subtypes that have no metadata of their own
| `FreeObjectMethodTable` | A pointer to the address of a `MethodTable` used by the GC to indicate reclaimed memory
| `ObjectMethodTable` | A pointer to the address of the `System.Object` `MethodTable` (`g_pObjectClass`)
| `StaticsPointerMask` | For masking out a bit of DynamicStaticsInfo pointer fields
Expand DownExpand Up@@ -533,7 +527,6 @@ Contracts used:
internal TargetPointer FreeObjectMethodTablePointer {get; }
internal TargetPointer ObjectMethodTablePointer {get; }
internal TargetPointer ContinuationMethodTablePointer {get; }
private TargetPointer _continuationSingletonEEClassPointer;

public TypeHandle GetTypeHandle(TargetPointer typeHandlePointer)
{
Expand DownExpand Up@@ -577,12 +570,12 @@ Contracts used:

public uint GetComponentSize(TypeHandle TypeHandle) =>!typeHandle.IsMethodTable() ? (uint)0 : GetComponentSize(_methodTables[TypeHandle.Address]);

public TargetPointer GetClassPointer(TypeHandle TypeHandle)
private TargetPointer GetClassPointer(TypeHandle TypeHandle)
{
// Returns TargetPointer.Null if not a MethodTable.
// If EEClassOrCanonMT points directly to an EEClass, returns that pointer.
// If EEClassOrCanonMT is a tagged pointer to a canonical MethodTable, follows
// the canonical MT and returns its EEClass pointer.
... // if the MethodTable stores a pointer to the EEClass, return it
// otherwise the MethodTable stores a pointer to the canonical MethodTable
// in that case, return the canonical MethodTable's EEClass.
// Canonical MethodTables always store an EEClass pointer.
}

private Data.EEClass GetClassData(TypeHandle TypeHandle)
Expand All@@ -603,14 +596,9 @@ Contracts used:

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

public bool IsCanonicalMethodTable(TypeHandle typeHandle)
=> typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;

public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& ContinuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> GetGCDescSeries(TypeHandle typeHandle, uint numComponents = 0)
{
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line numberDiff line numberDiff line change
Expand Up@@ -1541,7 +1541,6 @@ CDAC_GLOBAL(FieldOffsetDynamicRVA, T_UINT32, FIELD_OFFSET_DYNAMIC_RVA)
CDAC_GLOBAL_POINTER(ClrNotificationArguments, &::g_clrNotificationArguments)
CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data<ArrayBase>::ArrayBoundsZero)
CDAC_GLOBAL_POINTER(ContinuationMethodTable, &::g_pContinuationClassIfSubTypeCreated)
CDAC_GLOBAL_POINTER(ContinuationSingletonEEClass, &::g_singletonContinuationEEClass)
CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass)
CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable)
CDAC_GLOBAL_POINTER(ObjectMethodTable, &::g_pObjectClass)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,11 +109,6 @@ public interface IRuntimeTypeSystem : IContract
// 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.
TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
TargetPointer GetClassPointer(TypeHandle typeHandle) => throw new NotImplementedException();
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
bool IsCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
TargetPointer GetParentMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();

TargetPointer GetMethodDescForSlot(TypeHandle methodTable, ushort slot) => throw new NotImplementedException();
Expand All@@ -134,8 +129,8 @@ public interface IRuntimeTypeSystem : IContract
bool ContainsGCPointers(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
bool RequiresAlign8(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation subtype that has no metadata of its own
bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation type used by the async continuation feature
bool IsContinuation(TypeHandle typeHandle) => throw new NotImplementedException();
/// <summary>
/// Enumerates GC pointer runs from the CGCDesc stored before the method table.
/// Returns (offset, size) pairs normalized to actual byte lengths.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,7 +32,6 @@ public static class Globals
public const string RecommendedReaderVersion = nameof(RecommendedReaderVersion);

public const string ContinuationMethodTable = nameof(ContinuationMethodTable);
public const string ContinuationSingletonEEClass = nameof(ContinuationSingletonEEClass);
public const string ExceptionMethodTable = nameof(ExceptionMethodTable);
public const string FreeObjectMethodTable = nameof(FreeObjectMethodTable);
public const string ObjectMethodTable = nameof(ObjectMethodTable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,6 @@ internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem
private readonly TargetPointer _freeObjectMethodTablePointer;
private readonly TargetPointer _objectMethodTablePointer;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;
private readonly ulong _methodDescAlignment;
private readonly TypeValidation _typeValidation;
private readonly MethodValidation _methodValidation;
Expand DownExpand Up@@ -439,10 +438,8 @@ internal RuntimeTypeSystem_1(Target target)
target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable));
_continuationMethodTablePointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationMethodTable));
_continuationSingletonEEClassPointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationSingletonEEClass));
_methodDescAlignment = target.ReadGlobal<ulong>(Constants.Globals.MethodDescAlignment);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer, _continuationSingletonEEClassPointer);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer);
_methodValidation = new MethodValidation(target, _methodDescAlignment);
_methodValidation.SetMethodTableQueries(new NonValidatedMethodTableQueries(this));
}
Expand DownExpand Up@@ -534,17 +531,14 @@ public TargetPointer GetModule(TypeHandle typeHandle)
}
}
public TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : GetClassData(typeHandle).MethodTable;
public bool IsCanonicalMethodTable(TypeHandle typeHandle) => typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;
public TargetPointer GetParentMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : _methodTables[typeHandle.Address].ParentMethodTable;

public uint GetBaseSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.BaseSize;

public uint GetComponentSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.ComponentSize;

public TargetPointer GetClassPointer(TypeHandle typeHandle)
private TargetPointer GetClassPointer(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return TargetPointer.Null;
MethodTable methodTable = _methodTables[typeHandle.Address];
switch (MethodTableFlags_1.GetEEClassOrCanonMTBits(methodTable.EEClassOrCanonMT))
{
Expand DownExpand Up@@ -581,11 +575,9 @@ public bool IsObjRef(TypeHandle typeHandle)
}
public bool ContainsGCPointers(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.ContainsGCPointers;
public bool RequiresAlign8(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8;
public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& _continuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> IRuntimeTypeSystem.GetGCDescSeries(TypeHandle typeHandle, uint numComponents)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,13 +10,11 @@ internal sealed class TypeValidation
{
private readonly Target _target;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;

internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer, TargetPointer continuationSingletonEEClassPointer)
internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer)
{
_target = target;
_continuationMethodTablePointer = continuationMethodTablePointer;
_continuationSingletonEEClassPointer = continuationSingletonEEClassPointer;
}

// This doesn't need as many properties as MethodTable because we don't want to be operating on
Expand DownExpand Up@@ -169,7 +167,7 @@ private bool ValidateThrowing(NonValidatedMethodTable methodTable)
{
return true;
}
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuationWithoutMetadata(methodTable))
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuation(methodTable))
{
NonValidatedMethodTable methodTableFromClass = GetMethodTableData(_target, methodTablePtrFromClass);
if (!methodTableFromClass.ValidateReadable())
Expand DownExpand Up@@ -229,16 +227,14 @@ private TargetPointer GetClassThrowing(NonValidatedMethodTable methodTable)
}
}

// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuationWithoutMetadata.
// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuation.
// TypeValidation runs before the MethodTable is added to the RuntimeTypeSystem's cache, so we
// cannot call into RuntimeTypeSystem_1 — the type handle does not exist yet. Instead we
// duplicate the check using the raw ParentMethodTable read from target memory.
private bool IsContinuationWithoutMetadata(NonValidatedMethodTable methodTable)
private bool IsContinuation(NonValidatedMethodTable methodTable)
{
return _continuationMethodTablePointer != TargetPointer.Null
&& methodTable.ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassThrowing(methodTable) == _continuationSingletonEEClassPointer;
&& methodTable.ParentMethodTable == _continuationMethodTablePointer;
}

internal bool TryValidateMethodTablePointer(TargetPointer methodTablePointer)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2397,54 +2397,7 @@ private static IEnumerable<GCHeapData> EnumerateHeaps(IGC gc, bool isWorkstation
};

public int IsValidObject(ulong obj, Interop.BOOL* pResult)
{
int hr = HResults.S_OK;
Interop.BOOL isValid = Interop.BOOL.FALSE;

if (obj != 0 && obj != ulong.MaxValue)
{
try
{
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
TargetPointer mt = _target.Contracts.Object.GetMethodTableAddress(new TargetPointer(obj));
TypeHandle th = rts.GetTypeHandle(mt);
TargetPointer canonMT = rts.GetCanonicalMethodTable(th);

if (mt == canonMT)
{
isValid = Interop.BOOL.TRUE;
}
else if (!rts.IsCanonicalMethodTable(th) || rts.IsContinuationWithoutMetadata(th))
{
TargetPointer cls = rts.GetClassPointer(th);
TypeHandle canonTh = rts.GetTypeHandle(canonMT);
TargetPointer canonCls = rts.GetClassPointer(canonTh);
if (canonCls == cls)
isValid = Interop.BOOL.TRUE;
}
}
catch (System.Exception)
{
isValid = Interop.BOOL.FALSE;
}
}
*pResult = isValid;

#if DEBUG
if (_legacy is not null)
{
Interop.BOOL resultLocal;
int hrLocal = _legacy.IsValidObject(obj, &resultLocal);
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
{
Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}");
}
}
#endif

return hr;
}
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsValidObject(obj, pResult) : HResults.E_NOTIMPL;

Comment thread
barosiak marked this conversation as resolved.
public int CreateRefWalk(nuint* pHandle, Interop.BOOL walkStacks, Interop.BOOL walkFQ, uint handleWalkMask)
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.CreateRefWalk(pHandle, walkStacks, walkFQ, handleWalkMask) : HResults.E_NOTIMPL;
Expand DownExpand Up@@ -3252,7 +3205,7 @@ private static CorElementType GetElementType(IRuntimeTypeSystem rts, TypeHandle
// parent (continuation base) type handle instead.
private static TypeHandle UpCastTypeIfNeeded(IRuntimeTypeSystem rts, TypeHandle typeHandle)
{
if (rts.IsContinuationWithoutMetadata(typeHandle))
if (rts.IsContinuation(typeHandle))
{
TargetPointer parentMT = rts.GetParentMethodTable(typeHandle);
if (parentMT != TargetPointer.Null)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -284,7 +284,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle
Contracts.ModuleHandle moduleHandle = tnb.Target.Contracts.Loader.GetModuleHandleFromModulePtr(typeSystemContract.GetModule(typeHandle));
if (MetadataTokens.EntityHandle((int)typeDefToken).IsNil)
{
if (typeSystemContract.IsContinuationWithoutMetadata(typeHandle))
if (typeSystemContract.IsContinuation(typeHandle))
{
AppendContinuationName(ref tnb, typeSystemContract, typeHandle);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,15 +38,14 @@ public void ContinuationBaseClass_IsNotContinuation(TestConfiguration config)
IRuntimeTypeSystem rts = Target.Contracts.RuntimeTypeSystem;

// The ContinuationMethodTable global points to the Continuation base class itself.
// IsContinuationWithoutMetadata checks if a type's parent is the Continuation base class
// and its EEClass matches the singleton continuation EEClass,
// IsContinuation checks if a type's parent is the Continuation base class,
// so the base class itself is NOT considered a continuation (its parent is Object).
TargetPointer continuationMTGlobal = Target.ReadGlobalPointer("ContinuationMethodTable");
TargetPointer continuationMT = Target.ReadPointer(continuationMTGlobal);
Assert.NotEqual(TargetPointer.Null, continuationMT);

TypeHandle handle = rts.GetTypeHandle(continuationMT);
Assert.False(rts.IsContinuationWithoutMetadata(handle));
Assert.False(rts.IsContinuation(handle));
}

[ConditionalTheory]
Expand All@@ -60,7 +59,7 @@ public void ObjectMethodTable_IsNotContinuation(TestConfiguration config)
TargetPointer objectMTGlobal = Target.ReadGlobalPointer("ObjectMethodTable");
TargetPointer objectMT = Target.ReadPointer(objectMTGlobal);
TypeHandle objectHandle = rts.GetTypeHandle(objectMT);
Assert.False(rts.IsContinuationWithoutMetadata(objectHandle));
Assert.False(rts.IsContinuation(objectHandle));
}

[ConditionalTheory]
Expand DownExpand Up@@ -159,6 +158,6 @@ public void ThreadLocalContinuation_IsContinuation(TestConfiguration config)
TargetPointer objMT = Target.Contracts.Object.GetMethodTableAddress(
new TargetPointer(continuationAddress));
TypeHandle handle = rts.GetTypeHandle(objMT);
Assert.True(rts.IsContinuationWithoutMetadata(handle));
Assert.True(rts.IsContinuation(handle));
}
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
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
28 changes: 8 additions & 20 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,11 +39,6 @@ partial interface IRuntimeTypeSystem : IContract
// 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.
public virtual TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle);
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
public virtual TargetPointer GetClassPointer(TypeHandle typeHandle);
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
public virtual bool IsCanonicalMethodTable(TypeHandle typeHandle);
public virtual TargetPointer GetParentMethodTable(TypeHandle typeHandle);

public virtual TargetPointer GetMethodDescForSlot(TypeHandle typeHandle, ushort slot);
Expand All@@ -66,7 +61,7 @@ partial interface IRuntimeTypeSystem : IContract
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
public virtual bool RequiresAlign8(TypeHandle typeHandle);
// True if the MethodTable represents a continuation type used by the async continuation feature
public virtual bool IsContinuationWithoutMetadata(TypeHandle typeHandle);
public virtual bool IsContinuation(TypeHandle typeHandle);
// Returns the GC pointer runs for the method table as (offset, size) pairs. Each
// run starts Offset bytes from the object pointer (`this`), where offset 0
// is the method table pointer, and includes Size bytes of contiguous pointers
Expand DownExpand Up@@ -456,7 +451,6 @@ The contract depends on the following globals
| Global name | Meaning |
| --- | --- |
| `ContinuationMethodTable` | A pointer to the address of the base `Continuation` `MethodTable`, or null if no continuations have been created
| `ContinuationSingletonEEClass` | A pointer to the address of the singleton `EEClass` shared by continuation subtypes that have no metadata of their own
| `FreeObjectMethodTable` | A pointer to the address of a `MethodTable` used by the GC to indicate reclaimed memory
| `ObjectMethodTable` | A pointer to the address of the `System.Object` `MethodTable` (`g_pObjectClass`)
| `StaticsPointerMask` | For masking out a bit of DynamicStaticsInfo pointer fields
Expand DownExpand Up@@ -533,7 +527,6 @@ Contracts used:
internal TargetPointer FreeObjectMethodTablePointer {get; }
internal TargetPointer ObjectMethodTablePointer {get; }
internal TargetPointer ContinuationMethodTablePointer {get; }
private TargetPointer _continuationSingletonEEClassPointer;

public TypeHandle GetTypeHandle(TargetPointer typeHandlePointer)
{
Expand DownExpand Up@@ -577,12 +570,12 @@ Contracts used:

public uint GetComponentSize(TypeHandle TypeHandle) =>!typeHandle.IsMethodTable() ? (uint)0 : GetComponentSize(_methodTables[TypeHandle.Address]);

public TargetPointer GetClassPointer(TypeHandle TypeHandle)
private TargetPointer GetClassPointer(TypeHandle TypeHandle)
{
// Returns TargetPointer.Null if not a MethodTable.
// If EEClassOrCanonMT points directly to an EEClass, returns that pointer.
// If EEClassOrCanonMT is a tagged pointer to a canonical MethodTable, follows
// the canonical MT and returns its EEClass pointer.
... // if the MethodTable stores a pointer to the EEClass, return it
// otherwise the MethodTable stores a pointer to the canonical MethodTable
// in that case, return the canonical MethodTable's EEClass.
// Canonical MethodTables always store an EEClass pointer.
}

private Data.EEClass GetClassData(TypeHandle TypeHandle)
Expand All@@ -603,14 +596,9 @@ Contracts used:

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

public bool IsCanonicalMethodTable(TypeHandle typeHandle)
=> typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;

public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& ContinuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> GetGCDescSeries(TypeHandle typeHandle, uint numComponents = 0)
{
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line numberDiff line numberDiff line change
Expand Up@@ -1541,7 +1541,6 @@ CDAC_GLOBAL(FieldOffsetDynamicRVA, T_UINT32, FIELD_OFFSET_DYNAMIC_RVA)
CDAC_GLOBAL_POINTER(ClrNotificationArguments, &::g_clrNotificationArguments)
CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data<ArrayBase>::ArrayBoundsZero)
CDAC_GLOBAL_POINTER(ContinuationMethodTable, &::g_pContinuationClassIfSubTypeCreated)
CDAC_GLOBAL_POINTER(ContinuationSingletonEEClass, &::g_singletonContinuationEEClass)
CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass)
CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable)
CDAC_GLOBAL_POINTER(ObjectMethodTable, &::g_pObjectClass)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,11 +109,6 @@ public interface IRuntimeTypeSystem : IContract
// 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.
TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
TargetPointer GetClassPointer(TypeHandle typeHandle) => throw new NotImplementedException();
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
bool IsCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
TargetPointer GetParentMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();

TargetPointer GetMethodDescForSlot(TypeHandle methodTable, ushort slot) => throw new NotImplementedException();
Expand All@@ -134,8 +129,8 @@ public interface IRuntimeTypeSystem : IContract
bool ContainsGCPointers(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
bool RequiresAlign8(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation subtype that has no metadata of its own
bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation type used by the async continuation feature
bool IsContinuation(TypeHandle typeHandle) => throw new NotImplementedException();
/// <summary>
/// Enumerates GC pointer runs from the CGCDesc stored before the method table.
/// Returns (offset, size) pairs normalized to actual byte lengths.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,7 +32,6 @@ public static class Globals
public const string RecommendedReaderVersion = nameof(RecommendedReaderVersion);

public const string ContinuationMethodTable = nameof(ContinuationMethodTable);
public const string ContinuationSingletonEEClass = nameof(ContinuationSingletonEEClass);
public const string ExceptionMethodTable = nameof(ExceptionMethodTable);
public const string FreeObjectMethodTable = nameof(FreeObjectMethodTable);
public const string ObjectMethodTable = nameof(ObjectMethodTable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,6 @@ internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem
private readonly TargetPointer _freeObjectMethodTablePointer;
private readonly TargetPointer _objectMethodTablePointer;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;
private readonly ulong _methodDescAlignment;
private readonly TypeValidation _typeValidation;
private readonly MethodValidation _methodValidation;
Expand DownExpand Up@@ -439,10 +438,8 @@ internal RuntimeTypeSystem_1(Target target)
target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable));
_continuationMethodTablePointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationMethodTable));
_continuationSingletonEEClassPointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationSingletonEEClass));
_methodDescAlignment = target.ReadGlobal<ulong>(Constants.Globals.MethodDescAlignment);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer, _continuationSingletonEEClassPointer);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer);
_methodValidation = new MethodValidation(target, _methodDescAlignment);
_methodValidation.SetMethodTableQueries(new NonValidatedMethodTableQueries(this));
}
Expand DownExpand Up@@ -534,17 +531,14 @@ public TargetPointer GetModule(TypeHandle typeHandle)
}
}
public TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : GetClassData(typeHandle).MethodTable;
public bool IsCanonicalMethodTable(TypeHandle typeHandle) => typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;
public TargetPointer GetParentMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : _methodTables[typeHandle.Address].ParentMethodTable;

public uint GetBaseSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.BaseSize;

public uint GetComponentSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.ComponentSize;

public TargetPointer GetClassPointer(TypeHandle typeHandle)
private TargetPointer GetClassPointer(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return TargetPointer.Null;
MethodTable methodTable = _methodTables[typeHandle.Address];
switch (MethodTableFlags_1.GetEEClassOrCanonMTBits(methodTable.EEClassOrCanonMT))
{
Expand DownExpand Up@@ -581,11 +575,9 @@ public bool IsObjRef(TypeHandle typeHandle)
}
public bool ContainsGCPointers(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.ContainsGCPointers;
public bool RequiresAlign8(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8;
public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& _continuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> IRuntimeTypeSystem.GetGCDescSeries(TypeHandle typeHandle, uint numComponents)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,13 +10,11 @@ internal sealed class TypeValidation
{
private readonly Target _target;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;

internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer, TargetPointer continuationSingletonEEClassPointer)
internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer)
{
_target = target;
_continuationMethodTablePointer = continuationMethodTablePointer;
_continuationSingletonEEClassPointer = continuationSingletonEEClassPointer;
}

// This doesn't need as many properties as MethodTable because we don't want to be operating on
Expand DownExpand Up@@ -169,7 +167,7 @@ private bool ValidateThrowing(NonValidatedMethodTable methodTable)
{
return true;
}
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuationWithoutMetadata(methodTable))
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuation(methodTable))
{
NonValidatedMethodTable methodTableFromClass = GetMethodTableData(_target, methodTablePtrFromClass);
if (!methodTableFromClass.ValidateReadable())
Expand DownExpand Up@@ -229,16 +227,14 @@ private TargetPointer GetClassThrowing(NonValidatedMethodTable methodTable)
}
}

// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuationWithoutMetadata.
// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuation.
// TypeValidation runs before the MethodTable is added to the RuntimeTypeSystem's cache, so we
// cannot call into RuntimeTypeSystem_1 — the type handle does not exist yet. Instead we
// duplicate the check using the raw ParentMethodTable read from target memory.
private bool IsContinuationWithoutMetadata(NonValidatedMethodTable methodTable)
private bool IsContinuation(NonValidatedMethodTable methodTable)
{
return _continuationMethodTablePointer != TargetPointer.Null
&& methodTable.ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassThrowing(methodTable) == _continuationSingletonEEClassPointer;
&& methodTable.ParentMethodTable == _continuationMethodTablePointer;
}

internal bool TryValidateMethodTablePointer(TargetPointer methodTablePointer)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2397,54 +2397,7 @@ private static IEnumerable<GCHeapData> EnumerateHeaps(IGC gc, bool isWorkstation
};

public int IsValidObject(ulong obj, Interop.BOOL* pResult)
{
int hr = HResults.S_OK;
Interop.BOOL isValid = Interop.BOOL.FALSE;

if (obj != 0 && obj != ulong.MaxValue)
{
try
{
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
TargetPointer mt = _target.Contracts.Object.GetMethodTableAddress(new TargetPointer(obj));
TypeHandle th = rts.GetTypeHandle(mt);
TargetPointer canonMT = rts.GetCanonicalMethodTable(th);

if (mt == canonMT)
{
isValid = Interop.BOOL.TRUE;
}
else if (!rts.IsCanonicalMethodTable(th) || rts.IsContinuationWithoutMetadata(th))
{
TargetPointer cls = rts.GetClassPointer(th);
TypeHandle canonTh = rts.GetTypeHandle(canonMT);
TargetPointer canonCls = rts.GetClassPointer(canonTh);
if (canonCls == cls)
isValid = Interop.BOOL.TRUE;
}
}
catch (System.Exception)
{
isValid = Interop.BOOL.FALSE;
}
}
*pResult = isValid;

#if DEBUG
if (_legacy is not null)
{
Interop.BOOL resultLocal;
int hrLocal = _legacy.IsValidObject(obj, &resultLocal);
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
{
Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}");
}
}
#endif

return hr;
}
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsValidObject(obj, pResult) : HResults.E_NOTIMPL;

Comment thread
barosiak marked this conversation as resolved.
public int CreateRefWalk(nuint* pHandle, Interop.BOOL walkStacks, Interop.BOOL walkFQ, uint handleWalkMask)
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.CreateRefWalk(pHandle, walkStacks, walkFQ, handleWalkMask) : HResults.E_NOTIMPL;
Expand DownExpand Up@@ -3252,7 +3205,7 @@ private static CorElementType GetElementType(IRuntimeTypeSystem rts, TypeHandle
// parent (continuation base) type handle instead.
private static TypeHandle UpCastTypeIfNeeded(IRuntimeTypeSystem rts, TypeHandle typeHandle)
{
if (rts.IsContinuationWithoutMetadata(typeHandle))
if (rts.IsContinuation(typeHandle))
{
TargetPointer parentMT = rts.GetParentMethodTable(typeHandle);
if (parentMT != TargetPointer.Null)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -284,7 +284,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle
Contracts.ModuleHandle moduleHandle = tnb.Target.Contracts.Loader.GetModuleHandleFromModulePtr(typeSystemContract.GetModule(typeHandle));
if (MetadataTokens.EntityHandle((int)typeDefToken).IsNil)
{
if (typeSystemContract.IsContinuationWithoutMetadata(typeHandle))
if (typeSystemContract.IsContinuation(typeHandle))
{
AppendContinuationName(ref tnb, typeSystemContract, typeHandle);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,15 +38,14 @@ public void ContinuationBaseClass_IsNotContinuation(TestConfiguration config)
IRuntimeTypeSystem rts = Target.Contracts.RuntimeTypeSystem;

// The ContinuationMethodTable global points to the Continuation base class itself.
// IsContinuationWithoutMetadata checks if a type's parent is the Continuation base class
// and its EEClass matches the singleton continuation EEClass,
// IsContinuation checks if a type's parent is the Continuation base class,
// so the base class itself is NOT considered a continuation (its parent is Object).
TargetPointer continuationMTGlobal = Target.ReadGlobalPointer("ContinuationMethodTable");
TargetPointer continuationMT = Target.ReadPointer(continuationMTGlobal);
Assert.NotEqual(TargetPointer.Null, continuationMT);

TypeHandle handle = rts.GetTypeHandle(continuationMT);
Assert.False(rts.IsContinuationWithoutMetadata(handle));
Assert.False(rts.IsContinuation(handle));
}

[ConditionalTheory]
Expand All@@ -60,7 +59,7 @@ public void ObjectMethodTable_IsNotContinuation(TestConfiguration config)
TargetPointer objectMTGlobal = Target.ReadGlobalPointer("ObjectMethodTable");
TargetPointer objectMT = Target.ReadPointer(objectMTGlobal);
TypeHandle objectHandle = rts.GetTypeHandle(objectMT);
Assert.False(rts.IsContinuationWithoutMetadata(objectHandle));
Assert.False(rts.IsContinuation(objectHandle));
}

[ConditionalTheory]
Expand DownExpand Up@@ -159,6 +158,6 @@ public void ThreadLocalContinuation_IsContinuation(TestConfiguration config)
TargetPointer objMT = Target.Contracts.Object.GetMethodTableAddress(
new TargetPointer(continuationAddress));
TypeHandle handle = rts.GetTypeHandle(objMT);
Assert.True(rts.IsContinuationWithoutMetadata(handle));
Assert.True(rts.IsContinuation(handle));
}
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
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
28 changes: 8 additions & 20 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,11 +39,6 @@ partial interface IRuntimeTypeSystem : IContract
// 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.
public virtual TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle);
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
public virtual TargetPointer GetClassPointer(TypeHandle typeHandle);
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
public virtual bool IsCanonicalMethodTable(TypeHandle typeHandle);
public virtual TargetPointer GetParentMethodTable(TypeHandle typeHandle);

public virtual TargetPointer GetMethodDescForSlot(TypeHandle typeHandle, ushort slot);
Expand All@@ -66,7 +61,7 @@ partial interface IRuntimeTypeSystem : IContract
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
public virtual bool RequiresAlign8(TypeHandle typeHandle);
// True if the MethodTable represents a continuation type used by the async continuation feature
public virtual bool IsContinuationWithoutMetadata(TypeHandle typeHandle);
public virtual bool IsContinuation(TypeHandle typeHandle);
// Returns the GC pointer runs for the method table as (offset, size) pairs. Each
// run starts Offset bytes from the object pointer (`this`), where offset 0
// is the method table pointer, and includes Size bytes of contiguous pointers
Expand DownExpand Up@@ -456,7 +451,6 @@ The contract depends on the following globals
| Global name | Meaning |
| --- | --- |
| `ContinuationMethodTable` | A pointer to the address of the base `Continuation` `MethodTable`, or null if no continuations have been created
| `ContinuationSingletonEEClass` | A pointer to the address of the singleton `EEClass` shared by continuation subtypes that have no metadata of their own
| `FreeObjectMethodTable` | A pointer to the address of a `MethodTable` used by the GC to indicate reclaimed memory
| `ObjectMethodTable` | A pointer to the address of the `System.Object` `MethodTable` (`g_pObjectClass`)
| `StaticsPointerMask` | For masking out a bit of DynamicStaticsInfo pointer fields
Expand DownExpand Up@@ -533,7 +527,6 @@ Contracts used:
internal TargetPointer FreeObjectMethodTablePointer {get; }
internal TargetPointer ObjectMethodTablePointer {get; }
internal TargetPointer ContinuationMethodTablePointer {get; }
private TargetPointer _continuationSingletonEEClassPointer;

public TypeHandle GetTypeHandle(TargetPointer typeHandlePointer)
{
Expand DownExpand Up@@ -577,12 +570,12 @@ Contracts used:

public uint GetComponentSize(TypeHandle TypeHandle) =>!typeHandle.IsMethodTable() ? (uint)0 : GetComponentSize(_methodTables[TypeHandle.Address]);

public TargetPointer GetClassPointer(TypeHandle TypeHandle)
private TargetPointer GetClassPointer(TypeHandle TypeHandle)
{
// Returns TargetPointer.Null if not a MethodTable.
// If EEClassOrCanonMT points directly to an EEClass, returns that pointer.
// If EEClassOrCanonMT is a tagged pointer to a canonical MethodTable, follows
// the canonical MT and returns its EEClass pointer.
... // if the MethodTable stores a pointer to the EEClass, return it
// otherwise the MethodTable stores a pointer to the canonical MethodTable
// in that case, return the canonical MethodTable's EEClass.
// Canonical MethodTables always store an EEClass pointer.
}

private Data.EEClass GetClassData(TypeHandle TypeHandle)
Expand All@@ -603,14 +596,9 @@ Contracts used:

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

public bool IsCanonicalMethodTable(TypeHandle typeHandle)
=> typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;

public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& ContinuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> GetGCDescSeries(TypeHandle typeHandle, uint numComponents = 0)
{
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line numberDiff line numberDiff line change
Expand Up@@ -1541,7 +1541,6 @@ CDAC_GLOBAL(FieldOffsetDynamicRVA, T_UINT32, FIELD_OFFSET_DYNAMIC_RVA)
CDAC_GLOBAL_POINTER(ClrNotificationArguments, &::g_clrNotificationArguments)
CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data<ArrayBase>::ArrayBoundsZero)
CDAC_GLOBAL_POINTER(ContinuationMethodTable, &::g_pContinuationClassIfSubTypeCreated)
CDAC_GLOBAL_POINTER(ContinuationSingletonEEClass, &::g_singletonContinuationEEClass)
CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass)
CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable)
CDAC_GLOBAL_POINTER(ObjectMethodTable, &::g_pObjectClass)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,11 +109,6 @@ public interface IRuntimeTypeSystem : IContract
// 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.
TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
TargetPointer GetClassPointer(TypeHandle typeHandle) => throw new NotImplementedException();
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
bool IsCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
TargetPointer GetParentMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();

TargetPointer GetMethodDescForSlot(TypeHandle methodTable, ushort slot) => throw new NotImplementedException();
Expand All@@ -134,8 +129,8 @@ public interface IRuntimeTypeSystem : IContract
bool ContainsGCPointers(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
bool RequiresAlign8(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation subtype that has no metadata of its own
bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation type used by the async continuation feature
bool IsContinuation(TypeHandle typeHandle) => throw new NotImplementedException();
/// <summary>
/// Enumerates GC pointer runs from the CGCDesc stored before the method table.
/// Returns (offset, size) pairs normalized to actual byte lengths.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,7 +32,6 @@ public static class Globals
public const string RecommendedReaderVersion = nameof(RecommendedReaderVersion);

public const string ContinuationMethodTable = nameof(ContinuationMethodTable);
public const string ContinuationSingletonEEClass = nameof(ContinuationSingletonEEClass);
public const string ExceptionMethodTable = nameof(ExceptionMethodTable);
public const string FreeObjectMethodTable = nameof(FreeObjectMethodTable);
public const string ObjectMethodTable = nameof(ObjectMethodTable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,6 @@ internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem
private readonly TargetPointer _freeObjectMethodTablePointer;
private readonly TargetPointer _objectMethodTablePointer;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;
private readonly ulong _methodDescAlignment;
private readonly TypeValidation _typeValidation;
private readonly MethodValidation _methodValidation;
Expand DownExpand Up@@ -439,10 +438,8 @@ internal RuntimeTypeSystem_1(Target target)
target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable));
_continuationMethodTablePointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationMethodTable));
_continuationSingletonEEClassPointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationSingletonEEClass));
_methodDescAlignment = target.ReadGlobal<ulong>(Constants.Globals.MethodDescAlignment);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer, _continuationSingletonEEClassPointer);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer);
_methodValidation = new MethodValidation(target, _methodDescAlignment);
_methodValidation.SetMethodTableQueries(new NonValidatedMethodTableQueries(this));
}
Expand DownExpand Up@@ -534,17 +531,14 @@ public TargetPointer GetModule(TypeHandle typeHandle)
}
}
public TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : GetClassData(typeHandle).MethodTable;
public bool IsCanonicalMethodTable(TypeHandle typeHandle) => typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;
public TargetPointer GetParentMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : _methodTables[typeHandle.Address].ParentMethodTable;

public uint GetBaseSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.BaseSize;

public uint GetComponentSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.ComponentSize;

public TargetPointer GetClassPointer(TypeHandle typeHandle)
private TargetPointer GetClassPointer(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return TargetPointer.Null;
MethodTable methodTable = _methodTables[typeHandle.Address];
switch (MethodTableFlags_1.GetEEClassOrCanonMTBits(methodTable.EEClassOrCanonMT))
{
Expand DownExpand Up@@ -581,11 +575,9 @@ public bool IsObjRef(TypeHandle typeHandle)
}
public bool ContainsGCPointers(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.ContainsGCPointers;
public bool RequiresAlign8(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8;
public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& _continuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> IRuntimeTypeSystem.GetGCDescSeries(TypeHandle typeHandle, uint numComponents)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,13 +10,11 @@ internal sealed class TypeValidation
{
private readonly Target _target;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;

internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer, TargetPointer continuationSingletonEEClassPointer)
internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer)
{
_target = target;
_continuationMethodTablePointer = continuationMethodTablePointer;
_continuationSingletonEEClassPointer = continuationSingletonEEClassPointer;
}

// This doesn't need as many properties as MethodTable because we don't want to be operating on
Expand DownExpand Up@@ -169,7 +167,7 @@ private bool ValidateThrowing(NonValidatedMethodTable methodTable)
{
return true;
}
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuationWithoutMetadata(methodTable))
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuation(methodTable))
{
NonValidatedMethodTable methodTableFromClass = GetMethodTableData(_target, methodTablePtrFromClass);
if (!methodTableFromClass.ValidateReadable())
Expand DownExpand Up@@ -229,16 +227,14 @@ private TargetPointer GetClassThrowing(NonValidatedMethodTable methodTable)
}
}

// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuationWithoutMetadata.
// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuation.
// TypeValidation runs before the MethodTable is added to the RuntimeTypeSystem's cache, so we
// cannot call into RuntimeTypeSystem_1 — the type handle does not exist yet. Instead we
// duplicate the check using the raw ParentMethodTable read from target memory.
private bool IsContinuationWithoutMetadata(NonValidatedMethodTable methodTable)
private bool IsContinuation(NonValidatedMethodTable methodTable)
{
return _continuationMethodTablePointer != TargetPointer.Null
&& methodTable.ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassThrowing(methodTable) == _continuationSingletonEEClassPointer;
&& methodTable.ParentMethodTable == _continuationMethodTablePointer;
}

internal bool TryValidateMethodTablePointer(TargetPointer methodTablePointer)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2397,54 +2397,7 @@ private static IEnumerable<GCHeapData> EnumerateHeaps(IGC gc, bool isWorkstation
};

public int IsValidObject(ulong obj, Interop.BOOL* pResult)
{
int hr = HResults.S_OK;
Interop.BOOL isValid = Interop.BOOL.FALSE;

if (obj != 0 && obj != ulong.MaxValue)
{
try
{
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
TargetPointer mt = _target.Contracts.Object.GetMethodTableAddress(new TargetPointer(obj));
TypeHandle th = rts.GetTypeHandle(mt);
TargetPointer canonMT = rts.GetCanonicalMethodTable(th);

if (mt == canonMT)
{
isValid = Interop.BOOL.TRUE;
}
else if (!rts.IsCanonicalMethodTable(th) || rts.IsContinuationWithoutMetadata(th))
{
TargetPointer cls = rts.GetClassPointer(th);
TypeHandle canonTh = rts.GetTypeHandle(canonMT);
TargetPointer canonCls = rts.GetClassPointer(canonTh);
if (canonCls == cls)
isValid = Interop.BOOL.TRUE;
}
}
catch (System.Exception)
{
isValid = Interop.BOOL.FALSE;
}
}
*pResult = isValid;

#if DEBUG
if (_legacy is not null)
{
Interop.BOOL resultLocal;
int hrLocal = _legacy.IsValidObject(obj, &resultLocal);
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
{
Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}");
}
}
#endif

return hr;
}
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsValidObject(obj, pResult) : HResults.E_NOTIMPL;

Comment thread
barosiak marked this conversation as resolved.
public int CreateRefWalk(nuint* pHandle, Interop.BOOL walkStacks, Interop.BOOL walkFQ, uint handleWalkMask)
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.CreateRefWalk(pHandle, walkStacks, walkFQ, handleWalkMask) : HResults.E_NOTIMPL;
Expand DownExpand Up@@ -3252,7 +3205,7 @@ private static CorElementType GetElementType(IRuntimeTypeSystem rts, TypeHandle
// parent (continuation base) type handle instead.
private static TypeHandle UpCastTypeIfNeeded(IRuntimeTypeSystem rts, TypeHandle typeHandle)
{
if (rts.IsContinuationWithoutMetadata(typeHandle))
if (rts.IsContinuation(typeHandle))
{
TargetPointer parentMT = rts.GetParentMethodTable(typeHandle);
if (parentMT != TargetPointer.Null)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -284,7 +284,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle
Contracts.ModuleHandle moduleHandle = tnb.Target.Contracts.Loader.GetModuleHandleFromModulePtr(typeSystemContract.GetModule(typeHandle));
if (MetadataTokens.EntityHandle((int)typeDefToken).IsNil)
{
if (typeSystemContract.IsContinuationWithoutMetadata(typeHandle))
if (typeSystemContract.IsContinuation(typeHandle))
{
AppendContinuationName(ref tnb, typeSystemContract, typeHandle);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,15 +38,14 @@ public void ContinuationBaseClass_IsNotContinuation(TestConfiguration config)
IRuntimeTypeSystem rts = Target.Contracts.RuntimeTypeSystem;

// The ContinuationMethodTable global points to the Continuation base class itself.
// IsContinuationWithoutMetadata checks if a type's parent is the Continuation base class
// and its EEClass matches the singleton continuation EEClass,
// IsContinuation checks if a type's parent is the Continuation base class,
// so the base class itself is NOT considered a continuation (its parent is Object).
TargetPointer continuationMTGlobal = Target.ReadGlobalPointer("ContinuationMethodTable");
TargetPointer continuationMT = Target.ReadPointer(continuationMTGlobal);
Assert.NotEqual(TargetPointer.Null, continuationMT);

TypeHandle handle = rts.GetTypeHandle(continuationMT);
Assert.False(rts.IsContinuationWithoutMetadata(handle));
Assert.False(rts.IsContinuation(handle));
}

[ConditionalTheory]
Expand All@@ -60,7 +59,7 @@ public void ObjectMethodTable_IsNotContinuation(TestConfiguration config)
TargetPointer objectMTGlobal = Target.ReadGlobalPointer("ObjectMethodTable");
TargetPointer objectMT = Target.ReadPointer(objectMTGlobal);
TypeHandle objectHandle = rts.GetTypeHandle(objectMT);
Assert.False(rts.IsContinuationWithoutMetadata(objectHandle));
Assert.False(rts.IsContinuation(objectHandle));
}

[ConditionalTheory]
Expand DownExpand Up@@ -159,6 +158,6 @@ public void ThreadLocalContinuation_IsContinuation(TestConfiguration config)
TargetPointer objMT = Target.Contracts.Object.GetMethodTableAddress(
new TargetPointer(continuationAddress));
TypeHandle handle = rts.GetTypeHandle(objMT);
Assert.True(rts.IsContinuationWithoutMetadata(handle));
Assert.True(rts.IsContinuation(handle));
}
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Closed
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
28 changes: 8 additions & 20 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,11 +39,6 @@ partial interface IRuntimeTypeSystem : IContract
// 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.
public virtual TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle);
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
public virtual TargetPointer GetClassPointer(TypeHandle typeHandle);
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
public virtual bool IsCanonicalMethodTable(TypeHandle typeHandle);
public virtual TargetPointer GetParentMethodTable(TypeHandle typeHandle);

public virtual TargetPointer GetMethodDescForSlot(TypeHandle typeHandle, ushort slot);
Expand All@@ -66,7 +61,7 @@ partial interface IRuntimeTypeSystem : IContract
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
public virtual bool RequiresAlign8(TypeHandle typeHandle);
// True if the MethodTable represents a continuation type used by the async continuation feature
public virtual bool IsContinuationWithoutMetadata(TypeHandle typeHandle);
public virtual bool IsContinuation(TypeHandle typeHandle);
// Returns the GC pointer runs for the method table as (offset, size) pairs. Each
// run starts Offset bytes from the object pointer (`this`), where offset 0
// is the method table pointer, and includes Size bytes of contiguous pointers
Expand DownExpand Up@@ -456,7 +451,6 @@ The contract depends on the following globals
| Global name | Meaning |
| --- | --- |
| `ContinuationMethodTable` | A pointer to the address of the base `Continuation` `MethodTable`, or null if no continuations have been created
| `ContinuationSingletonEEClass` | A pointer to the address of the singleton `EEClass` shared by continuation subtypes that have no metadata of their own
| `FreeObjectMethodTable` | A pointer to the address of a `MethodTable` used by the GC to indicate reclaimed memory
| `ObjectMethodTable` | A pointer to the address of the `System.Object` `MethodTable` (`g_pObjectClass`)
| `StaticsPointerMask` | For masking out a bit of DynamicStaticsInfo pointer fields
Expand DownExpand Up@@ -533,7 +527,6 @@ Contracts used:
internal TargetPointer FreeObjectMethodTablePointer {get; }
internal TargetPointer ObjectMethodTablePointer {get; }
internal TargetPointer ContinuationMethodTablePointer {get; }
private TargetPointer _continuationSingletonEEClassPointer;

public TypeHandle GetTypeHandle(TargetPointer typeHandlePointer)
{
Expand DownExpand Up@@ -577,12 +570,12 @@ Contracts used:

public uint GetComponentSize(TypeHandle TypeHandle) =>!typeHandle.IsMethodTable() ? (uint)0 : GetComponentSize(_methodTables[TypeHandle.Address]);

public TargetPointer GetClassPointer(TypeHandle TypeHandle)
private TargetPointer GetClassPointer(TypeHandle TypeHandle)
{
// Returns TargetPointer.Null if not a MethodTable.
// If EEClassOrCanonMT points directly to an EEClass, returns that pointer.
// If EEClassOrCanonMT is a tagged pointer to a canonical MethodTable, follows
// the canonical MT and returns its EEClass pointer.
... // if the MethodTable stores a pointer to the EEClass, return it
// otherwise the MethodTable stores a pointer to the canonical MethodTable
// in that case, return the canonical MethodTable's EEClass.
// Canonical MethodTables always store an EEClass pointer.
}

private Data.EEClass GetClassData(TypeHandle TypeHandle)
Expand All@@ -603,14 +596,9 @@ Contracts used:

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

public bool IsCanonicalMethodTable(TypeHandle typeHandle)
=> typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;

public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& ContinuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> GetGCDescSeries(TypeHandle typeHandle, uint numComponents = 0)
{
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line numberDiff line numberDiff line change
Expand Up@@ -1541,7 +1541,6 @@ CDAC_GLOBAL(FieldOffsetDynamicRVA, T_UINT32, FIELD_OFFSET_DYNAMIC_RVA)
CDAC_GLOBAL_POINTER(ClrNotificationArguments, &::g_clrNotificationArguments)
CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data<ArrayBase>::ArrayBoundsZero)
CDAC_GLOBAL_POINTER(ContinuationMethodTable, &::g_pContinuationClassIfSubTypeCreated)
CDAC_GLOBAL_POINTER(ContinuationSingletonEEClass, &::g_singletonContinuationEEClass)
CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass)
CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable)
CDAC_GLOBAL_POINTER(ObjectMethodTable, &::g_pObjectClass)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,11 +109,6 @@ public interface IRuntimeTypeSystem : IContract
// 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.
TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
TargetPointer GetClassPointer(TypeHandle typeHandle) => throw new NotImplementedException();
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
bool IsCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
TargetPointer GetParentMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();

TargetPointer GetMethodDescForSlot(TypeHandle methodTable, ushort slot) => throw new NotImplementedException();
Expand All@@ -134,8 +129,8 @@ public interface IRuntimeTypeSystem : IContract
bool ContainsGCPointers(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
bool RequiresAlign8(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation subtype that has no metadata of its own
bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation type used by the async continuation feature
bool IsContinuation(TypeHandle typeHandle) => throw new NotImplementedException();
/// <summary>
/// Enumerates GC pointer runs from the CGCDesc stored before the method table.
/// Returns (offset, size) pairs normalized to actual byte lengths.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,7 +32,6 @@ public static class Globals
public const string RecommendedReaderVersion = nameof(RecommendedReaderVersion);

public const string ContinuationMethodTable = nameof(ContinuationMethodTable);
public const string ContinuationSingletonEEClass = nameof(ContinuationSingletonEEClass);
public const string ExceptionMethodTable = nameof(ExceptionMethodTable);
public const string FreeObjectMethodTable = nameof(FreeObjectMethodTable);
public const string ObjectMethodTable = nameof(ObjectMethodTable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,6 @@ internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem
private readonly TargetPointer _freeObjectMethodTablePointer;
private readonly TargetPointer _objectMethodTablePointer;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;
private readonly ulong _methodDescAlignment;
private readonly TypeValidation _typeValidation;
private readonly MethodValidation _methodValidation;
Expand DownExpand Up@@ -439,10 +438,8 @@ internal RuntimeTypeSystem_1(Target target)
target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable));
_continuationMethodTablePointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationMethodTable));
_continuationSingletonEEClassPointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationSingletonEEClass));
_methodDescAlignment = target.ReadGlobal<ulong>(Constants.Globals.MethodDescAlignment);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer, _continuationSingletonEEClassPointer);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer);
_methodValidation = new MethodValidation(target, _methodDescAlignment);
_methodValidation.SetMethodTableQueries(new NonValidatedMethodTableQueries(this));
}
Expand DownExpand Up@@ -534,17 +531,14 @@ public TargetPointer GetModule(TypeHandle typeHandle)
}
}
public TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : GetClassData(typeHandle).MethodTable;
public bool IsCanonicalMethodTable(TypeHandle typeHandle) => typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;
public TargetPointer GetParentMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : _methodTables[typeHandle.Address].ParentMethodTable;

public uint GetBaseSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.BaseSize;

public uint GetComponentSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.ComponentSize;

public TargetPointer GetClassPointer(TypeHandle typeHandle)
private TargetPointer GetClassPointer(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return TargetPointer.Null;
MethodTable methodTable = _methodTables[typeHandle.Address];
switch (MethodTableFlags_1.GetEEClassOrCanonMTBits(methodTable.EEClassOrCanonMT))
{
Expand DownExpand Up@@ -581,11 +575,9 @@ public bool IsObjRef(TypeHandle typeHandle)
}
public bool ContainsGCPointers(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.ContainsGCPointers;
public bool RequiresAlign8(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8;
public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& _continuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> IRuntimeTypeSystem.GetGCDescSeries(TypeHandle typeHandle, uint numComponents)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,13 +10,11 @@ internal sealed class TypeValidation
{
private readonly Target _target;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;

internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer, TargetPointer continuationSingletonEEClassPointer)
internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer)
{
_target = target;
_continuationMethodTablePointer = continuationMethodTablePointer;
_continuationSingletonEEClassPointer = continuationSingletonEEClassPointer;
}

// This doesn't need as many properties as MethodTable because we don't want to be operating on
Expand DownExpand Up@@ -169,7 +167,7 @@ private bool ValidateThrowing(NonValidatedMethodTable methodTable)
{
return true;
}
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuationWithoutMetadata(methodTable))
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuation(methodTable))
{
NonValidatedMethodTable methodTableFromClass = GetMethodTableData(_target, methodTablePtrFromClass);
if (!methodTableFromClass.ValidateReadable())
Expand DownExpand Up@@ -229,16 +227,14 @@ private TargetPointer GetClassThrowing(NonValidatedMethodTable methodTable)
}
}

// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuationWithoutMetadata.
// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuation.
// TypeValidation runs before the MethodTable is added to the RuntimeTypeSystem's cache, so we
// cannot call into RuntimeTypeSystem_1 — the type handle does not exist yet. Instead we
// duplicate the check using the raw ParentMethodTable read from target memory.
private bool IsContinuationWithoutMetadata(NonValidatedMethodTable methodTable)
private bool IsContinuation(NonValidatedMethodTable methodTable)
{
return _continuationMethodTablePointer != TargetPointer.Null
&& methodTable.ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassThrowing(methodTable) == _continuationSingletonEEClassPointer;
&& methodTable.ParentMethodTable == _continuationMethodTablePointer;
}

internal bool TryValidateMethodTablePointer(TargetPointer methodTablePointer)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2397,54 +2397,7 @@ private static IEnumerable<GCHeapData> EnumerateHeaps(IGC gc, bool isWorkstation
};

public int IsValidObject(ulong obj, Interop.BOOL* pResult)
{
int hr = HResults.S_OK;
Interop.BOOL isValid = Interop.BOOL.FALSE;

if (obj != 0 && obj != ulong.MaxValue)
{
try
{
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
TargetPointer mt = _target.Contracts.Object.GetMethodTableAddress(new TargetPointer(obj));
TypeHandle th = rts.GetTypeHandle(mt);
TargetPointer canonMT = rts.GetCanonicalMethodTable(th);

if (mt == canonMT)
{
isValid = Interop.BOOL.TRUE;
}
else if (!rts.IsCanonicalMethodTable(th) || rts.IsContinuationWithoutMetadata(th))
{
TargetPointer cls = rts.GetClassPointer(th);
TypeHandle canonTh = rts.GetTypeHandle(canonMT);
TargetPointer canonCls = rts.GetClassPointer(canonTh);
if (canonCls == cls)
isValid = Interop.BOOL.TRUE;
}
}
catch (System.Exception)
{
isValid = Interop.BOOL.FALSE;
}
}
*pResult = isValid;

#if DEBUG
if (_legacy is not null)
{
Interop.BOOL resultLocal;
int hrLocal = _legacy.IsValidObject(obj, &resultLocal);
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
{
Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}");
}
}
#endif

return hr;
}
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsValidObject(obj, pResult) : HResults.E_NOTIMPL;

Comment thread
barosiak marked this conversation as resolved.
public int CreateRefWalk(nuint* pHandle, Interop.BOOL walkStacks, Interop.BOOL walkFQ, uint handleWalkMask)
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.CreateRefWalk(pHandle, walkStacks, walkFQ, handleWalkMask) : HResults.E_NOTIMPL;
Expand DownExpand Up@@ -3252,7 +3205,7 @@ private static CorElementType GetElementType(IRuntimeTypeSystem rts, TypeHandle
// parent (continuation base) type handle instead.
private static TypeHandle UpCastTypeIfNeeded(IRuntimeTypeSystem rts, TypeHandle typeHandle)
{
if (rts.IsContinuationWithoutMetadata(typeHandle))
if (rts.IsContinuation(typeHandle))
{
TargetPointer parentMT = rts.GetParentMethodTable(typeHandle);
if (parentMT != TargetPointer.Null)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -284,7 +284,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle
Contracts.ModuleHandle moduleHandle = tnb.Target.Contracts.Loader.GetModuleHandleFromModulePtr(typeSystemContract.GetModule(typeHandle));
if (MetadataTokens.EntityHandle((int)typeDefToken).IsNil)
{
if (typeSystemContract.IsContinuationWithoutMetadata(typeHandle))
if (typeSystemContract.IsContinuation(typeHandle))
{
AppendContinuationName(ref tnb, typeSystemContract, typeHandle);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,15 +38,14 @@ public void ContinuationBaseClass_IsNotContinuation(TestConfiguration config)
IRuntimeTypeSystem rts = Target.Contracts.RuntimeTypeSystem;

// The ContinuationMethodTable global points to the Continuation base class itself.
// IsContinuationWithoutMetadata checks if a type's parent is the Continuation base class
// and its EEClass matches the singleton continuation EEClass,
// IsContinuation checks if a type's parent is the Continuation base class,
// so the base class itself is NOT considered a continuation (its parent is Object).
TargetPointer continuationMTGlobal = Target.ReadGlobalPointer("ContinuationMethodTable");
TargetPointer continuationMT = Target.ReadPointer(continuationMTGlobal);
Assert.NotEqual(TargetPointer.Null, continuationMT);

TypeHandle handle = rts.GetTypeHandle(continuationMT);
Assert.False(rts.IsContinuationWithoutMetadata(handle));
Assert.False(rts.IsContinuation(handle));
}

[ConditionalTheory]
Expand All@@ -60,7 +59,7 @@ public void ObjectMethodTable_IsNotContinuation(TestConfiguration config)
TargetPointer objectMTGlobal = Target.ReadGlobalPointer("ObjectMethodTable");
TargetPointer objectMT = Target.ReadPointer(objectMTGlobal);
TypeHandle objectHandle = rts.GetTypeHandle(objectMT);
Assert.False(rts.IsContinuationWithoutMetadata(objectHandle));
Assert.False(rts.IsContinuation(objectHandle));
}

[ConditionalTheory]
Expand DownExpand Up@@ -159,6 +158,6 @@ public void ThreadLocalContinuation_IsContinuation(TestConfiguration config)
TargetPointer objMT = Target.Contracts.Object.GetMethodTableAddress(
new TargetPointer(continuationAddress));
TypeHandle handle = rts.GetTypeHandle(objMT);
Assert.True(rts.IsContinuationWithoutMetadata(handle));
Assert.True(rts.IsContinuation(handle));
}
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
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
28 changes: 8 additions & 20 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,11 +39,6 @@ partial interface IRuntimeTypeSystem : IContract
// 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.
public virtual TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle);
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
public virtual TargetPointer GetClassPointer(TypeHandle typeHandle);
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
public virtual bool IsCanonicalMethodTable(TypeHandle typeHandle);
public virtual TargetPointer GetParentMethodTable(TypeHandle typeHandle);

public virtual TargetPointer GetMethodDescForSlot(TypeHandle typeHandle, ushort slot);
Expand All@@ -66,7 +61,7 @@ partial interface IRuntimeTypeSystem : IContract
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
public virtual bool RequiresAlign8(TypeHandle typeHandle);
// True if the MethodTable represents a continuation type used by the async continuation feature
public virtual bool IsContinuationWithoutMetadata(TypeHandle typeHandle);
public virtual bool IsContinuation(TypeHandle typeHandle);
// Returns the GC pointer runs for the method table as (offset, size) pairs. Each
// run starts Offset bytes from the object pointer (`this`), where offset 0
// is the method table pointer, and includes Size bytes of contiguous pointers
Expand DownExpand Up@@ -456,7 +451,6 @@ The contract depends on the following globals
| Global name | Meaning |
| --- | --- |
| `ContinuationMethodTable` | A pointer to the address of the base `Continuation` `MethodTable`, or null if no continuations have been created
| `ContinuationSingletonEEClass` | A pointer to the address of the singleton `EEClass` shared by continuation subtypes that have no metadata of their own
| `FreeObjectMethodTable` | A pointer to the address of a `MethodTable` used by the GC to indicate reclaimed memory
| `ObjectMethodTable` | A pointer to the address of the `System.Object` `MethodTable` (`g_pObjectClass`)
| `StaticsPointerMask` | For masking out a bit of DynamicStaticsInfo pointer fields
Expand DownExpand Up@@ -533,7 +527,6 @@ Contracts used:
internal TargetPointer FreeObjectMethodTablePointer {get; }
internal TargetPointer ObjectMethodTablePointer {get; }
internal TargetPointer ContinuationMethodTablePointer {get; }
private TargetPointer _continuationSingletonEEClassPointer;

public TypeHandle GetTypeHandle(TargetPointer typeHandlePointer)
{
Expand DownExpand Up@@ -577,12 +570,12 @@ Contracts used:

public uint GetComponentSize(TypeHandle TypeHandle) =>!typeHandle.IsMethodTable() ? (uint)0 : GetComponentSize(_methodTables[TypeHandle.Address]);

public TargetPointer GetClassPointer(TypeHandle TypeHandle)
private TargetPointer GetClassPointer(TypeHandle TypeHandle)
{
// Returns TargetPointer.Null if not a MethodTable.
// If EEClassOrCanonMT points directly to an EEClass, returns that pointer.
// If EEClassOrCanonMT is a tagged pointer to a canonical MethodTable, follows
// the canonical MT and returns its EEClass pointer.
... // if the MethodTable stores a pointer to the EEClass, return it
// otherwise the MethodTable stores a pointer to the canonical MethodTable
// in that case, return the canonical MethodTable's EEClass.
// Canonical MethodTables always store an EEClass pointer.
}

private Data.EEClass GetClassData(TypeHandle TypeHandle)
Expand All@@ -603,14 +596,9 @@ Contracts used:

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

public bool IsCanonicalMethodTable(TypeHandle typeHandle)
=> typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;

public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& ContinuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> GetGCDescSeries(TypeHandle typeHandle, uint numComponents = 0)
{
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line numberDiff line numberDiff line change
Expand Up@@ -1541,7 +1541,6 @@ CDAC_GLOBAL(FieldOffsetDynamicRVA, T_UINT32, FIELD_OFFSET_DYNAMIC_RVA)
CDAC_GLOBAL_POINTER(ClrNotificationArguments, &::g_clrNotificationArguments)
CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data<ArrayBase>::ArrayBoundsZero)
CDAC_GLOBAL_POINTER(ContinuationMethodTable, &::g_pContinuationClassIfSubTypeCreated)
CDAC_GLOBAL_POINTER(ContinuationSingletonEEClass, &::g_singletonContinuationEEClass)
CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass)
CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable)
CDAC_GLOBAL_POINTER(ObjectMethodTable, &::g_pObjectClass)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,11 +109,6 @@ public interface IRuntimeTypeSystem : IContract
// 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.
TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
TargetPointer GetClassPointer(TypeHandle typeHandle) => throw new NotImplementedException();
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
bool IsCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
TargetPointer GetParentMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();

TargetPointer GetMethodDescForSlot(TypeHandle methodTable, ushort slot) => throw new NotImplementedException();
Expand All@@ -134,8 +129,8 @@ public interface IRuntimeTypeSystem : IContract
bool ContainsGCPointers(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
bool RequiresAlign8(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation subtype that has no metadata of its own
bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation type used by the async continuation feature
bool IsContinuation(TypeHandle typeHandle) => throw new NotImplementedException();
/// <summary>
/// Enumerates GC pointer runs from the CGCDesc stored before the method table.
/// Returns (offset, size) pairs normalized to actual byte lengths.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,7 +32,6 @@ public static class Globals
public const string RecommendedReaderVersion = nameof(RecommendedReaderVersion);

public const string ContinuationMethodTable = nameof(ContinuationMethodTable);
public const string ContinuationSingletonEEClass = nameof(ContinuationSingletonEEClass);
public const string ExceptionMethodTable = nameof(ExceptionMethodTable);
public const string FreeObjectMethodTable = nameof(FreeObjectMethodTable);
public const string ObjectMethodTable = nameof(ObjectMethodTable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,6 @@ internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem
private readonly TargetPointer _freeObjectMethodTablePointer;
private readonly TargetPointer _objectMethodTablePointer;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;
private readonly ulong _methodDescAlignment;
private readonly TypeValidation _typeValidation;
private readonly MethodValidation _methodValidation;
Expand DownExpand Up@@ -439,10 +438,8 @@ internal RuntimeTypeSystem_1(Target target)
target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable));
_continuationMethodTablePointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationMethodTable));
_continuationSingletonEEClassPointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationSingletonEEClass));
_methodDescAlignment = target.ReadGlobal<ulong>(Constants.Globals.MethodDescAlignment);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer, _continuationSingletonEEClassPointer);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer);
_methodValidation = new MethodValidation(target, _methodDescAlignment);
_methodValidation.SetMethodTableQueries(new NonValidatedMethodTableQueries(this));
}
Expand DownExpand Up@@ -534,17 +531,14 @@ public TargetPointer GetModule(TypeHandle typeHandle)
}
}
public TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : GetClassData(typeHandle).MethodTable;
public bool IsCanonicalMethodTable(TypeHandle typeHandle) => typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;
public TargetPointer GetParentMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : _methodTables[typeHandle.Address].ParentMethodTable;

public uint GetBaseSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.BaseSize;

public uint GetComponentSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.ComponentSize;

public TargetPointer GetClassPointer(TypeHandle typeHandle)
private TargetPointer GetClassPointer(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return TargetPointer.Null;
MethodTable methodTable = _methodTables[typeHandle.Address];
switch (MethodTableFlags_1.GetEEClassOrCanonMTBits(methodTable.EEClassOrCanonMT))
{
Expand DownExpand Up@@ -581,11 +575,9 @@ public bool IsObjRef(TypeHandle typeHandle)
}
public bool ContainsGCPointers(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.ContainsGCPointers;
public bool RequiresAlign8(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8;
public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& _continuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> IRuntimeTypeSystem.GetGCDescSeries(TypeHandle typeHandle, uint numComponents)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,13 +10,11 @@ internal sealed class TypeValidation
{
private readonly Target _target;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;

internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer, TargetPointer continuationSingletonEEClassPointer)
internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer)
{
_target = target;
_continuationMethodTablePointer = continuationMethodTablePointer;
_continuationSingletonEEClassPointer = continuationSingletonEEClassPointer;
}

// This doesn't need as many properties as MethodTable because we don't want to be operating on
Expand DownExpand Up@@ -169,7 +167,7 @@ private bool ValidateThrowing(NonValidatedMethodTable methodTable)
{
return true;
}
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuationWithoutMetadata(methodTable))
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuation(methodTable))
{
NonValidatedMethodTable methodTableFromClass = GetMethodTableData(_target, methodTablePtrFromClass);
if (!methodTableFromClass.ValidateReadable())
Expand DownExpand Up@@ -229,16 +227,14 @@ private TargetPointer GetClassThrowing(NonValidatedMethodTable methodTable)
}
}

// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuationWithoutMetadata.
// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuation.
// TypeValidation runs before the MethodTable is added to the RuntimeTypeSystem's cache, so we
// cannot call into RuntimeTypeSystem_1 — the type handle does not exist yet. Instead we
// duplicate the check using the raw ParentMethodTable read from target memory.
private bool IsContinuationWithoutMetadata(NonValidatedMethodTable methodTable)
private bool IsContinuation(NonValidatedMethodTable methodTable)
{
return _continuationMethodTablePointer != TargetPointer.Null
&& methodTable.ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassThrowing(methodTable) == _continuationSingletonEEClassPointer;
&& methodTable.ParentMethodTable == _continuationMethodTablePointer;
}

internal bool TryValidateMethodTablePointer(TargetPointer methodTablePointer)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2397,54 +2397,7 @@ private static IEnumerable<GCHeapData> EnumerateHeaps(IGC gc, bool isWorkstation
};

public int IsValidObject(ulong obj, Interop.BOOL* pResult)
{
int hr = HResults.S_OK;
Interop.BOOL isValid = Interop.BOOL.FALSE;

if (obj != 0 && obj != ulong.MaxValue)
{
try
{
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
TargetPointer mt = _target.Contracts.Object.GetMethodTableAddress(new TargetPointer(obj));
TypeHandle th = rts.GetTypeHandle(mt);
TargetPointer canonMT = rts.GetCanonicalMethodTable(th);

if (mt == canonMT)
{
isValid = Interop.BOOL.TRUE;
}
else if (!rts.IsCanonicalMethodTable(th) || rts.IsContinuationWithoutMetadata(th))
{
TargetPointer cls = rts.GetClassPointer(th);
TypeHandle canonTh = rts.GetTypeHandle(canonMT);
TargetPointer canonCls = rts.GetClassPointer(canonTh);
if (canonCls == cls)
isValid = Interop.BOOL.TRUE;
}
}
catch (System.Exception)
{
isValid = Interop.BOOL.FALSE;
}
}
*pResult = isValid;

#if DEBUG
if (_legacy is not null)
{
Interop.BOOL resultLocal;
int hrLocal = _legacy.IsValidObject(obj, &resultLocal);
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
{
Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}");
}
}
#endif

return hr;
}
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsValidObject(obj, pResult) : HResults.E_NOTIMPL;

Comment thread
barosiak marked this conversation as resolved.
public int CreateRefWalk(nuint* pHandle, Interop.BOOL walkStacks, Interop.BOOL walkFQ, uint handleWalkMask)
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.CreateRefWalk(pHandle, walkStacks, walkFQ, handleWalkMask) : HResults.E_NOTIMPL;
Expand DownExpand Up@@ -3252,7 +3205,7 @@ private static CorElementType GetElementType(IRuntimeTypeSystem rts, TypeHandle
// parent (continuation base) type handle instead.
private static TypeHandle UpCastTypeIfNeeded(IRuntimeTypeSystem rts, TypeHandle typeHandle)
{
if (rts.IsContinuationWithoutMetadata(typeHandle))
if (rts.IsContinuation(typeHandle))
{
TargetPointer parentMT = rts.GetParentMethodTable(typeHandle);
if (parentMT != TargetPointer.Null)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -284,7 +284,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle
Contracts.ModuleHandle moduleHandle = tnb.Target.Contracts.Loader.GetModuleHandleFromModulePtr(typeSystemContract.GetModule(typeHandle));
if (MetadataTokens.EntityHandle((int)typeDefToken).IsNil)
{
if (typeSystemContract.IsContinuationWithoutMetadata(typeHandle))
if (typeSystemContract.IsContinuation(typeHandle))
{
AppendContinuationName(ref tnb, typeSystemContract, typeHandle);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,15 +38,14 @@ public void ContinuationBaseClass_IsNotContinuation(TestConfiguration config)
IRuntimeTypeSystem rts = Target.Contracts.RuntimeTypeSystem;

// The ContinuationMethodTable global points to the Continuation base class itself.
// IsContinuationWithoutMetadata checks if a type's parent is the Continuation base class
// and its EEClass matches the singleton continuation EEClass,
// IsContinuation checks if a type's parent is the Continuation base class,
// so the base class itself is NOT considered a continuation (its parent is Object).
TargetPointer continuationMTGlobal = Target.ReadGlobalPointer("ContinuationMethodTable");
TargetPointer continuationMT = Target.ReadPointer(continuationMTGlobal);
Assert.NotEqual(TargetPointer.Null, continuationMT);

TypeHandle handle = rts.GetTypeHandle(continuationMT);
Assert.False(rts.IsContinuationWithoutMetadata(handle));
Assert.False(rts.IsContinuation(handle));
}

[ConditionalTheory]
Expand All@@ -60,7 +59,7 @@ public void ObjectMethodTable_IsNotContinuation(TestConfiguration config)
TargetPointer objectMTGlobal = Target.ReadGlobalPointer("ObjectMethodTable");
TargetPointer objectMT = Target.ReadPointer(objectMTGlobal);
TypeHandle objectHandle = rts.GetTypeHandle(objectMT);
Assert.False(rts.IsContinuationWithoutMetadata(objectHandle));
Assert.False(rts.IsContinuation(objectHandle));
}

[ConditionalTheory]
Expand DownExpand Up@@ -159,6 +158,6 @@ public void ThreadLocalContinuation_IsContinuation(TestConfiguration config)
TargetPointer objMT = Target.Contracts.Object.GetMethodTableAddress(
new TargetPointer(continuationAddress));
TypeHandle handle = rts.GetTypeHandle(objMT);
Assert.True(rts.IsContinuationWithoutMetadata(handle));
Assert.True(rts.IsContinuation(handle));
}
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
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
28 changes: 8 additions & 20 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,11 +39,6 @@ partial interface IRuntimeTypeSystem : IContract
// 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.
public virtual TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle);
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
public virtual TargetPointer GetClassPointer(TypeHandle typeHandle);
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
public virtual bool IsCanonicalMethodTable(TypeHandle typeHandle);
public virtual TargetPointer GetParentMethodTable(TypeHandle typeHandle);

public virtual TargetPointer GetMethodDescForSlot(TypeHandle typeHandle, ushort slot);
Expand All@@ -66,7 +61,7 @@ partial interface IRuntimeTypeSystem : IContract
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
public virtual bool RequiresAlign8(TypeHandle typeHandle);
// True if the MethodTable represents a continuation type used by the async continuation feature
public virtual bool IsContinuationWithoutMetadata(TypeHandle typeHandle);
public virtual bool IsContinuation(TypeHandle typeHandle);
// Returns the GC pointer runs for the method table as (offset, size) pairs. Each
// run starts Offset bytes from the object pointer (`this`), where offset 0
// is the method table pointer, and includes Size bytes of contiguous pointers
Expand DownExpand Up@@ -456,7 +451,6 @@ The contract depends on the following globals
| Global name | Meaning |
| --- | --- |
| `ContinuationMethodTable` | A pointer to the address of the base `Continuation` `MethodTable`, or null if no continuations have been created
| `ContinuationSingletonEEClass` | A pointer to the address of the singleton `EEClass` shared by continuation subtypes that have no metadata of their own
| `FreeObjectMethodTable` | A pointer to the address of a `MethodTable` used by the GC to indicate reclaimed memory
| `ObjectMethodTable` | A pointer to the address of the `System.Object` `MethodTable` (`g_pObjectClass`)
| `StaticsPointerMask` | For masking out a bit of DynamicStaticsInfo pointer fields
Expand DownExpand Up@@ -533,7 +527,6 @@ Contracts used:
internal TargetPointer FreeObjectMethodTablePointer {get; }
internal TargetPointer ObjectMethodTablePointer {get; }
internal TargetPointer ContinuationMethodTablePointer {get; }
private TargetPointer _continuationSingletonEEClassPointer;

public TypeHandle GetTypeHandle(TargetPointer typeHandlePointer)
{
Expand DownExpand Up@@ -577,12 +570,12 @@ Contracts used:

public uint GetComponentSize(TypeHandle TypeHandle) =>!typeHandle.IsMethodTable() ? (uint)0 : GetComponentSize(_methodTables[TypeHandle.Address]);

public TargetPointer GetClassPointer(TypeHandle TypeHandle)
private TargetPointer GetClassPointer(TypeHandle TypeHandle)
{
// Returns TargetPointer.Null if not a MethodTable.
// If EEClassOrCanonMT points directly to an EEClass, returns that pointer.
// If EEClassOrCanonMT is a tagged pointer to a canonical MethodTable, follows
// the canonical MT and returns its EEClass pointer.
... // if the MethodTable stores a pointer to the EEClass, return it
// otherwise the MethodTable stores a pointer to the canonical MethodTable
// in that case, return the canonical MethodTable's EEClass.
// Canonical MethodTables always store an EEClass pointer.
}

private Data.EEClass GetClassData(TypeHandle TypeHandle)
Expand All@@ -603,14 +596,9 @@ Contracts used:

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

public bool IsCanonicalMethodTable(TypeHandle typeHandle)
=> typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;

public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& ContinuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> GetGCDescSeries(TypeHandle typeHandle, uint numComponents = 0)
{
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line numberDiff line numberDiff line change
Expand Up@@ -1541,7 +1541,6 @@ CDAC_GLOBAL(FieldOffsetDynamicRVA, T_UINT32, FIELD_OFFSET_DYNAMIC_RVA)
CDAC_GLOBAL_POINTER(ClrNotificationArguments, &::g_clrNotificationArguments)
CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data<ArrayBase>::ArrayBoundsZero)
CDAC_GLOBAL_POINTER(ContinuationMethodTable, &::g_pContinuationClassIfSubTypeCreated)
CDAC_GLOBAL_POINTER(ContinuationSingletonEEClass, &::g_singletonContinuationEEClass)
CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass)
CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable)
CDAC_GLOBAL_POINTER(ObjectMethodTable, &::g_pObjectClass)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,11 +109,6 @@ public interface IRuntimeTypeSystem : IContract
// 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.
TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
TargetPointer GetClassPointer(TypeHandle typeHandle) => throw new NotImplementedException();
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
bool IsCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
TargetPointer GetParentMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();

TargetPointer GetMethodDescForSlot(TypeHandle methodTable, ushort slot) => throw new NotImplementedException();
Expand All@@ -134,8 +129,8 @@ public interface IRuntimeTypeSystem : IContract
bool ContainsGCPointers(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
bool RequiresAlign8(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation subtype that has no metadata of its own
bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation type used by the async continuation feature
bool IsContinuation(TypeHandle typeHandle) => throw new NotImplementedException();
/// <summary>
/// Enumerates GC pointer runs from the CGCDesc stored before the method table.
/// Returns (offset, size) pairs normalized to actual byte lengths.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,7 +32,6 @@ public static class Globals
public const string RecommendedReaderVersion = nameof(RecommendedReaderVersion);

public const string ContinuationMethodTable = nameof(ContinuationMethodTable);
public const string ContinuationSingletonEEClass = nameof(ContinuationSingletonEEClass);
public const string ExceptionMethodTable = nameof(ExceptionMethodTable);
public const string FreeObjectMethodTable = nameof(FreeObjectMethodTable);
public const string ObjectMethodTable = nameof(ObjectMethodTable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,6 @@ internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem
private readonly TargetPointer _freeObjectMethodTablePointer;
private readonly TargetPointer _objectMethodTablePointer;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;
private readonly ulong _methodDescAlignment;
private readonly TypeValidation _typeValidation;
private readonly MethodValidation _methodValidation;
Expand DownExpand Up@@ -439,10 +438,8 @@ internal RuntimeTypeSystem_1(Target target)
target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable));
_continuationMethodTablePointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationMethodTable));
_continuationSingletonEEClassPointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationSingletonEEClass));
_methodDescAlignment = target.ReadGlobal<ulong>(Constants.Globals.MethodDescAlignment);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer, _continuationSingletonEEClassPointer);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer);
_methodValidation = new MethodValidation(target, _methodDescAlignment);
_methodValidation.SetMethodTableQueries(new NonValidatedMethodTableQueries(this));
}
Expand DownExpand Up@@ -534,17 +531,14 @@ public TargetPointer GetModule(TypeHandle typeHandle)
}
}
public TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : GetClassData(typeHandle).MethodTable;
public bool IsCanonicalMethodTable(TypeHandle typeHandle) => typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;
public TargetPointer GetParentMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : _methodTables[typeHandle.Address].ParentMethodTable;

public uint GetBaseSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.BaseSize;

public uint GetComponentSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.ComponentSize;

public TargetPointer GetClassPointer(TypeHandle typeHandle)
private TargetPointer GetClassPointer(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return TargetPointer.Null;
MethodTable methodTable = _methodTables[typeHandle.Address];
switch (MethodTableFlags_1.GetEEClassOrCanonMTBits(methodTable.EEClassOrCanonMT))
{
Expand DownExpand Up@@ -581,11 +575,9 @@ public bool IsObjRef(TypeHandle typeHandle)
}
public bool ContainsGCPointers(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.ContainsGCPointers;
public bool RequiresAlign8(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8;
public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& _continuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> IRuntimeTypeSystem.GetGCDescSeries(TypeHandle typeHandle, uint numComponents)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,13 +10,11 @@ internal sealed class TypeValidation
{
private readonly Target _target;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;

internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer, TargetPointer continuationSingletonEEClassPointer)
internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer)
{
_target = target;
_continuationMethodTablePointer = continuationMethodTablePointer;
_continuationSingletonEEClassPointer = continuationSingletonEEClassPointer;
}

// This doesn't need as many properties as MethodTable because we don't want to be operating on
Expand DownExpand Up@@ -169,7 +167,7 @@ private bool ValidateThrowing(NonValidatedMethodTable methodTable)
{
return true;
}
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuationWithoutMetadata(methodTable))
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuation(methodTable))
{
NonValidatedMethodTable methodTableFromClass = GetMethodTableData(_target, methodTablePtrFromClass);
if (!methodTableFromClass.ValidateReadable())
Expand DownExpand Up@@ -229,16 +227,14 @@ private TargetPointer GetClassThrowing(NonValidatedMethodTable methodTable)
}
}

// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuationWithoutMetadata.
// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuation.
// TypeValidation runs before the MethodTable is added to the RuntimeTypeSystem's cache, so we
// cannot call into RuntimeTypeSystem_1 — the type handle does not exist yet. Instead we
// duplicate the check using the raw ParentMethodTable read from target memory.
private bool IsContinuationWithoutMetadata(NonValidatedMethodTable methodTable)
private bool IsContinuation(NonValidatedMethodTable methodTable)
{
return _continuationMethodTablePointer != TargetPointer.Null
&& methodTable.ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassThrowing(methodTable) == _continuationSingletonEEClassPointer;
&& methodTable.ParentMethodTable == _continuationMethodTablePointer;
}

internal bool TryValidateMethodTablePointer(TargetPointer methodTablePointer)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2397,54 +2397,7 @@ private static IEnumerable<GCHeapData> EnumerateHeaps(IGC gc, bool isWorkstation
};

public int IsValidObject(ulong obj, Interop.BOOL* pResult)
{
int hr = HResults.S_OK;
Interop.BOOL isValid = Interop.BOOL.FALSE;

if (obj != 0 && obj != ulong.MaxValue)
{
try
{
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
TargetPointer mt = _target.Contracts.Object.GetMethodTableAddress(new TargetPointer(obj));
TypeHandle th = rts.GetTypeHandle(mt);
TargetPointer canonMT = rts.GetCanonicalMethodTable(th);

if (mt == canonMT)
{
isValid = Interop.BOOL.TRUE;
}
else if (!rts.IsCanonicalMethodTable(th) || rts.IsContinuationWithoutMetadata(th))
{
TargetPointer cls = rts.GetClassPointer(th);
TypeHandle canonTh = rts.GetTypeHandle(canonMT);
TargetPointer canonCls = rts.GetClassPointer(canonTh);
if (canonCls == cls)
isValid = Interop.BOOL.TRUE;
}
}
catch (System.Exception)
{
isValid = Interop.BOOL.FALSE;
}
}
*pResult = isValid;

#if DEBUG
if (_legacy is not null)
{
Interop.BOOL resultLocal;
int hrLocal = _legacy.IsValidObject(obj, &resultLocal);
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
{
Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}");
}
}
#endif

return hr;
}
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsValidObject(obj, pResult) : HResults.E_NOTIMPL;

Comment thread
barosiak marked this conversation as resolved.
public int CreateRefWalk(nuint* pHandle, Interop.BOOL walkStacks, Interop.BOOL walkFQ, uint handleWalkMask)
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.CreateRefWalk(pHandle, walkStacks, walkFQ, handleWalkMask) : HResults.E_NOTIMPL;
Expand DownExpand Up@@ -3252,7 +3205,7 @@ private static CorElementType GetElementType(IRuntimeTypeSystem rts, TypeHandle
// parent (continuation base) type handle instead.
private static TypeHandle UpCastTypeIfNeeded(IRuntimeTypeSystem rts, TypeHandle typeHandle)
{
if (rts.IsContinuationWithoutMetadata(typeHandle))
if (rts.IsContinuation(typeHandle))
{
TargetPointer parentMT = rts.GetParentMethodTable(typeHandle);
if (parentMT != TargetPointer.Null)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -284,7 +284,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle
Contracts.ModuleHandle moduleHandle = tnb.Target.Contracts.Loader.GetModuleHandleFromModulePtr(typeSystemContract.GetModule(typeHandle));
if (MetadataTokens.EntityHandle((int)typeDefToken).IsNil)
{
if (typeSystemContract.IsContinuationWithoutMetadata(typeHandle))
if (typeSystemContract.IsContinuation(typeHandle))
{
AppendContinuationName(ref tnb, typeSystemContract, typeHandle);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,15 +38,14 @@ public void ContinuationBaseClass_IsNotContinuation(TestConfiguration config)
IRuntimeTypeSystem rts = Target.Contracts.RuntimeTypeSystem;

// The ContinuationMethodTable global points to the Continuation base class itself.
// IsContinuationWithoutMetadata checks if a type's parent is the Continuation base class
// and its EEClass matches the singleton continuation EEClass,
// IsContinuation checks if a type's parent is the Continuation base class,
// so the base class itself is NOT considered a continuation (its parent is Object).
TargetPointer continuationMTGlobal = Target.ReadGlobalPointer("ContinuationMethodTable");
TargetPointer continuationMT = Target.ReadPointer(continuationMTGlobal);
Assert.NotEqual(TargetPointer.Null, continuationMT);

TypeHandle handle = rts.GetTypeHandle(continuationMT);
Assert.False(rts.IsContinuationWithoutMetadata(handle));
Assert.False(rts.IsContinuation(handle));
}

[ConditionalTheory]
Expand All@@ -60,7 +59,7 @@ public void ObjectMethodTable_IsNotContinuation(TestConfiguration config)
TargetPointer objectMTGlobal = Target.ReadGlobalPointer("ObjectMethodTable");
TargetPointer objectMT = Target.ReadPointer(objectMTGlobal);
TypeHandle objectHandle = rts.GetTypeHandle(objectMT);
Assert.False(rts.IsContinuationWithoutMetadata(objectHandle));
Assert.False(rts.IsContinuation(objectHandle));
}

[ConditionalTheory]
Expand DownExpand Up@@ -159,6 +158,6 @@ public void ThreadLocalContinuation_IsContinuation(TestConfiguration config)
TargetPointer objMT = Target.Contracts.Object.GetMethodTableAddress(
new TargetPointer(continuationAddress));
TypeHandle handle = rts.GetTypeHandle(objMT);
Assert.True(rts.IsContinuationWithoutMetadata(handle));
Assert.True(rts.IsContinuation(handle));
}
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Closed
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
28 changes: 8 additions & 20 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,11 +39,6 @@ partial interface IRuntimeTypeSystem : IContract
// 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.
public virtual TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle);
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
public virtual TargetPointer GetClassPointer(TypeHandle typeHandle);
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
public virtual bool IsCanonicalMethodTable(TypeHandle typeHandle);
public virtual TargetPointer GetParentMethodTable(TypeHandle typeHandle);

public virtual TargetPointer GetMethodDescForSlot(TypeHandle typeHandle, ushort slot);
Expand All@@ -66,7 +61,7 @@ partial interface IRuntimeTypeSystem : IContract
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
public virtual bool RequiresAlign8(TypeHandle typeHandle);
// True if the MethodTable represents a continuation type used by the async continuation feature
public virtual bool IsContinuationWithoutMetadata(TypeHandle typeHandle);
public virtual bool IsContinuation(TypeHandle typeHandle);
// Returns the GC pointer runs for the method table as (offset, size) pairs. Each
// run starts Offset bytes from the object pointer (`this`), where offset 0
// is the method table pointer, and includes Size bytes of contiguous pointers
Expand DownExpand Up@@ -456,7 +451,6 @@ The contract depends on the following globals
| Global name | Meaning |
| --- | --- |
| `ContinuationMethodTable` | A pointer to the address of the base `Continuation` `MethodTable`, or null if no continuations have been created
| `ContinuationSingletonEEClass` | A pointer to the address of the singleton `EEClass` shared by continuation subtypes that have no metadata of their own
| `FreeObjectMethodTable` | A pointer to the address of a `MethodTable` used by the GC to indicate reclaimed memory
| `ObjectMethodTable` | A pointer to the address of the `System.Object` `MethodTable` (`g_pObjectClass`)
| `StaticsPointerMask` | For masking out a bit of DynamicStaticsInfo pointer fields
Expand DownExpand Up@@ -533,7 +527,6 @@ Contracts used:
internal TargetPointer FreeObjectMethodTablePointer {get; }
internal TargetPointer ObjectMethodTablePointer {get; }
internal TargetPointer ContinuationMethodTablePointer {get; }
private TargetPointer _continuationSingletonEEClassPointer;

public TypeHandle GetTypeHandle(TargetPointer typeHandlePointer)
{
Expand DownExpand Up@@ -577,12 +570,12 @@ Contracts used:

public uint GetComponentSize(TypeHandle TypeHandle) =>!typeHandle.IsMethodTable() ? (uint)0 : GetComponentSize(_methodTables[TypeHandle.Address]);

public TargetPointer GetClassPointer(TypeHandle TypeHandle)
private TargetPointer GetClassPointer(TypeHandle TypeHandle)
{
// Returns TargetPointer.Null if not a MethodTable.
// If EEClassOrCanonMT points directly to an EEClass, returns that pointer.
// If EEClassOrCanonMT is a tagged pointer to a canonical MethodTable, follows
// the canonical MT and returns its EEClass pointer.
... // if the MethodTable stores a pointer to the EEClass, return it
// otherwise the MethodTable stores a pointer to the canonical MethodTable
// in that case, return the canonical MethodTable's EEClass.
// Canonical MethodTables always store an EEClass pointer.
}

private Data.EEClass GetClassData(TypeHandle TypeHandle)
Expand All@@ -603,14 +596,9 @@ Contracts used:

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

public bool IsCanonicalMethodTable(TypeHandle typeHandle)
=> typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;

public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& ContinuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> GetGCDescSeries(TypeHandle typeHandle, uint numComponents = 0)
{
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line numberDiff line numberDiff line change
Expand Up@@ -1541,7 +1541,6 @@ CDAC_GLOBAL(FieldOffsetDynamicRVA, T_UINT32, FIELD_OFFSET_DYNAMIC_RVA)
CDAC_GLOBAL_POINTER(ClrNotificationArguments, &::g_clrNotificationArguments)
CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data<ArrayBase>::ArrayBoundsZero)
CDAC_GLOBAL_POINTER(ContinuationMethodTable, &::g_pContinuationClassIfSubTypeCreated)
CDAC_GLOBAL_POINTER(ContinuationSingletonEEClass, &::g_singletonContinuationEEClass)
CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass)
CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable)
CDAC_GLOBAL_POINTER(ObjectMethodTable, &::g_pObjectClass)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,11 +109,6 @@ public interface IRuntimeTypeSystem : IContract
// 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.
TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
// Returns the EEClass pointer for this MethodTable. For non-canonical MTs, follows the tagged pointer
// to the canonical MT and returns its EEClass.
TargetPointer GetClassPointer(TypeHandle typeHandle) => throw new NotImplementedException();
// True if this MethodTable is the canonical MethodTable (i.e., EEClassOrCanonMT points directly to the EEClass)
bool IsCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
TargetPointer GetParentMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();

TargetPointer GetMethodDescForSlot(TypeHandle methodTable, ushort slot) => throw new NotImplementedException();
Expand All@@ -134,8 +129,8 @@ public interface IRuntimeTypeSystem : IContract
bool ContainsGCPointers(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
bool RequiresAlign8(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation subtype that has no metadata of its own
bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation type used by the async continuation feature
bool IsContinuation(TypeHandle typeHandle) => throw new NotImplementedException();
/// <summary>
/// Enumerates GC pointer runs from the CGCDesc stored before the method table.
/// Returns (offset, size) pairs normalized to actual byte lengths.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,7 +32,6 @@ public static class Globals
public const string RecommendedReaderVersion = nameof(RecommendedReaderVersion);

public const string ContinuationMethodTable = nameof(ContinuationMethodTable);
public const string ContinuationSingletonEEClass = nameof(ContinuationSingletonEEClass);
public const string ExceptionMethodTable = nameof(ExceptionMethodTable);
public const string FreeObjectMethodTable = nameof(FreeObjectMethodTable);
public const string ObjectMethodTable = nameof(ObjectMethodTable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,6 @@ internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem
private readonly TargetPointer _freeObjectMethodTablePointer;
private readonly TargetPointer _objectMethodTablePointer;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;
private readonly ulong _methodDescAlignment;
private readonly TypeValidation _typeValidation;
private readonly MethodValidation _methodValidation;
Expand DownExpand Up@@ -439,10 +438,8 @@ internal RuntimeTypeSystem_1(Target target)
target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable));
_continuationMethodTablePointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationMethodTable));
_continuationSingletonEEClassPointer = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.ContinuationSingletonEEClass));
_methodDescAlignment = target.ReadGlobal<ulong>(Constants.Globals.MethodDescAlignment);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer, _continuationSingletonEEClassPointer);
_typeValidation = new TypeValidation(target, _continuationMethodTablePointer);
_methodValidation = new MethodValidation(target, _methodDescAlignment);
_methodValidation.SetMethodTableQueries(new NonValidatedMethodTableQueries(this));
}
Expand DownExpand Up@@ -534,17 +531,14 @@ public TargetPointer GetModule(TypeHandle typeHandle)
}
}
public TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : GetClassData(typeHandle).MethodTable;
public bool IsCanonicalMethodTable(TypeHandle typeHandle) => typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT;
public TargetPointer GetParentMethodTable(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : _methodTables[typeHandle.Address].ParentMethodTable;

public uint GetBaseSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.BaseSize;

public uint GetComponentSize(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.ComponentSize;

public TargetPointer GetClassPointer(TypeHandle typeHandle)
private TargetPointer GetClassPointer(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return TargetPointer.Null;
MethodTable methodTable = _methodTables[typeHandle.Address];
switch (MethodTableFlags_1.GetEEClassOrCanonMTBits(methodTable.EEClassOrCanonMT))
{
Expand DownExpand Up@@ -581,11 +575,9 @@ public bool IsObjRef(TypeHandle typeHandle)
}
public bool ContainsGCPointers(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.ContainsGCPointers;
public bool RequiresAlign8(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8;
public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& _continuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassPointer(typeHandle) == _continuationSingletonEEClassPointer;
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer;

IEnumerable<(uint Offset, uint Size)> IRuntimeTypeSystem.GetGCDescSeries(TypeHandle typeHandle, uint numComponents)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,13 +10,11 @@ internal sealed class TypeValidation
{
private readonly Target _target;
private readonly TargetPointer _continuationMethodTablePointer;
private readonly TargetPointer _continuationSingletonEEClassPointer;

internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer, TargetPointer continuationSingletonEEClassPointer)
internal TypeValidation(Target target, TargetPointer continuationMethodTablePointer)
{
_target = target;
_continuationMethodTablePointer = continuationMethodTablePointer;
_continuationSingletonEEClassPointer = continuationSingletonEEClassPointer;
}

// This doesn't need as many properties as MethodTable because we don't want to be operating on
Expand DownExpand Up@@ -169,7 +167,7 @@ private bool ValidateThrowing(NonValidatedMethodTable methodTable)
{
return true;
}
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuationWithoutMetadata(methodTable))
if (methodTable.Flags.HasInstantiation || methodTable.Flags.IsArray || IsContinuation(methodTable))
{
NonValidatedMethodTable methodTableFromClass = GetMethodTableData(_target, methodTablePtrFromClass);
if (!methodTableFromClass.ValidateReadable())
Expand DownExpand Up@@ -229,16 +227,14 @@ private TargetPointer GetClassThrowing(NonValidatedMethodTable methodTable)
}
}

// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuationWithoutMetadata.
// NOTE: The continuation check is duplicated here and in RuntimeTypeSystem_1.IsContinuation.
// TypeValidation runs before the MethodTable is added to the RuntimeTypeSystem's cache, so we
// cannot call into RuntimeTypeSystem_1 — the type handle does not exist yet. Instead we
// duplicate the check using the raw ParentMethodTable read from target memory.
private bool IsContinuationWithoutMetadata(NonValidatedMethodTable methodTable)
private bool IsContinuation(NonValidatedMethodTable methodTable)
{
return _continuationMethodTablePointer != TargetPointer.Null
&& methodTable.ParentMethodTable == _continuationMethodTablePointer
&& _continuationSingletonEEClassPointer != TargetPointer.Null
&& GetClassThrowing(methodTable) == _continuationSingletonEEClassPointer;
&& methodTable.ParentMethodTable == _continuationMethodTablePointer;
}

internal bool TryValidateMethodTablePointer(TargetPointer methodTablePointer)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2397,54 +2397,7 @@ private static IEnumerable<GCHeapData> EnumerateHeaps(IGC gc, bool isWorkstation
};

public int IsValidObject(ulong obj, Interop.BOOL* pResult)
{
int hr = HResults.S_OK;
Interop.BOOL isValid = Interop.BOOL.FALSE;

if (obj != 0 && obj != ulong.MaxValue)
{
try
{
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
TargetPointer mt = _target.Contracts.Object.GetMethodTableAddress(new TargetPointer(obj));
TypeHandle th = rts.GetTypeHandle(mt);
TargetPointer canonMT = rts.GetCanonicalMethodTable(th);

if (mt == canonMT)
{
isValid = Interop.BOOL.TRUE;
}
else if (!rts.IsCanonicalMethodTable(th) || rts.IsContinuationWithoutMetadata(th))
{
TargetPointer cls = rts.GetClassPointer(th);
TypeHandle canonTh = rts.GetTypeHandle(canonMT);
TargetPointer canonCls = rts.GetClassPointer(canonTh);
if (canonCls == cls)
isValid = Interop.BOOL.TRUE;
}
}
catch (System.Exception)
{
isValid = Interop.BOOL.FALSE;
}
}
*pResult = isValid;

#if DEBUG
if (_legacy is not null)
{
Interop.BOOL resultLocal;
int hrLocal = _legacy.IsValidObject(obj, &resultLocal);
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
{
Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}");
}
}
#endif

return hr;
}
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsValidObject(obj, pResult) : HResults.E_NOTIMPL;

Comment thread
barosiak marked this conversation as resolved.
public int CreateRefWalk(nuint* pHandle, Interop.BOOL walkStacks, Interop.BOOL walkFQ, uint handleWalkMask)
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.CreateRefWalk(pHandle, walkStacks, walkFQ, handleWalkMask) : HResults.E_NOTIMPL;
Expand DownExpand Up@@ -3252,7 +3205,7 @@ private static CorElementType GetElementType(IRuntimeTypeSystem rts, TypeHandle
// parent (continuation base) type handle instead.
private static TypeHandle UpCastTypeIfNeeded(IRuntimeTypeSystem rts, TypeHandle typeHandle)
{
if (rts.IsContinuationWithoutMetadata(typeHandle))
if (rts.IsContinuation(typeHandle))
{
TargetPointer parentMT = rts.GetParentMethodTable(typeHandle);
if (parentMT != TargetPointer.Null)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -284,7 +284,7 @@ private static void AppendTypeCore(ref TypeNameBuilder tnb, Contracts.TypeHandle
Contracts.ModuleHandle moduleHandle = tnb.Target.Contracts.Loader.GetModuleHandleFromModulePtr(typeSystemContract.GetModule(typeHandle));
if (MetadataTokens.EntityHandle((int)typeDefToken).IsNil)
{
if (typeSystemContract.IsContinuationWithoutMetadata(typeHandle))
if (typeSystemContract.IsContinuation(typeHandle))
{
AppendContinuationName(ref tnb, typeSystemContract, typeHandle);
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,15 +38,14 @@ public void ContinuationBaseClass_IsNotContinuation(TestConfiguration config)
IRuntimeTypeSystem rts = Target.Contracts.RuntimeTypeSystem;

// The ContinuationMethodTable global points to the Continuation base class itself.
// IsContinuationWithoutMetadata checks if a type's parent is the Continuation base class
// and its EEClass matches the singleton continuation EEClass,
// IsContinuation checks if a type's parent is the Continuation base class,
// so the base class itself is NOT considered a continuation (its parent is Object).
TargetPointer continuationMTGlobal = Target.ReadGlobalPointer("ContinuationMethodTable");
TargetPointer continuationMT = Target.ReadPointer(continuationMTGlobal);
Assert.NotEqual(TargetPointer.Null, continuationMT);

TypeHandle handle = rts.GetTypeHandle(continuationMT);
Assert.False(rts.IsContinuationWithoutMetadata(handle));
Assert.False(rts.IsContinuation(handle));
}

[ConditionalTheory]
Expand All@@ -60,7 +59,7 @@ public void ObjectMethodTable_IsNotContinuation(TestConfiguration config)
TargetPointer objectMTGlobal = Target.ReadGlobalPointer("ObjectMethodTable");
TargetPointer objectMT = Target.ReadPointer(objectMTGlobal);
TypeHandle objectHandle = rts.GetTypeHandle(objectMT);
Assert.False(rts.IsContinuationWithoutMetadata(objectHandle));
Assert.False(rts.IsContinuation(objectHandle));
}

[ConditionalTheory]
Expand DownExpand Up@@ -159,6 +158,6 @@ public void ThreadLocalContinuation_IsContinuation(TestConfiguration config)
TargetPointer objMT = Target.Contracts.Object.GetMethodTableAddress(
new TargetPointer(continuationAddress));
TypeHandle handle = rts.GetTypeHandle(objMT);
Assert.True(rts.IsContinuationWithoutMetadata(handle));
Assert.True(rts.IsContinuation(handle));
}
}
Loading
Loading