Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
4ed3a59
Move ArgIterator and TransitionBlock to tools/Common/CallingConvention
May 21, 2026
9d63284
Introduce ITypeHandle interface and extract TypeHandle to own file
May 21, 2026
8500cfd
Move TypeHandle to crossgen2 project directory
May 21, 2026
63ba9a4
Move shared CallingConvention to Internal.Runtime.CallingConvention n…
May 21, 2026
6c8d22e
Eliminate TypeSystem deps, add CallingConvention contract with CdacTy…
May 21, 2026
c5793ba
Add CallingConvention contract with GCDesc-based value type GC ref en…
May 22, 2026
05b74e8
Refactor ICallingConvention to be GC-agnostic and wire into GcScanner
May 24, 2026
3f8a754
WIP: dump test for CallingConvention vs GCRefMap + NotImplementedExce…
May 29, 2026
4871a47
[cdac stress] Phase 1: ArgIterator sub-check + restructure DOTNET_Cda…
Jun 22, 2026
162066a
[cdac stress] Phase 2: wire ComputeCallRefMap as the runtime oracle
Jun 22, 2026
a790180
[cdac stress] Phase 3-5: ArgIterator encoder, pretty-print FAILs, ByR…
Jun 22, 2026
91f60ad
[cdac stress] Phase 5: encode by-value structs containing GC pointers
Jun 23, 2026
4629836
[cdac stress] Phase 6: resolve both VAR and MVAR via combined generic…
Jun 23, 2026
4626b20
[cdac stress] Phase 7: enable x86 in the GCRefMap encoder
Jun 23, 2026
f38f8e8
[cdac stress] Phase 7.1: x86 ARG_FAIL pretty-print + GetCbStackPop ha…
Jun 23, 2026
32aeb1e
[cdac stress] Phase 7.2: propagate OutermostKind into CdacTypeHandle …
Jun 23, 2026
6a0d298
[cdac stress] Phase 8: implement IsTrivialPointerSizedStruct for x86 …
Jun 23, 2026
520b73a
cDAC RuntimeTypeSystem: add IsByRefLike and GetFieldDescApproxTypeHandle
Jun 23, 2026
c16f04c
cDAC CallingConvention: support ByRefLike struct args and nested valu…
Jun 23, 2026
f395308
cDAC stress: nested-struct scenario + CallSignatures debuggee
Jun 23, 2026
edd8f1c
cDAC CallingConvention: normalize value-type args via GetInternalCorE…
Jun 23, 2026
af5df05
cDAC CallingConvention: emit VASigCookie token for vararg methods
Jun 23, 2026
17c19ec
cDAC stress: add ARGITER theory + machine-readable [GC_STATS] marker
Jun 23, 2026
0f28c3a
cDAC stress CI: add windows_x86 to the stress test matrix
Jun 23, 2026
b87168a
cDAC stress: tolerate ARG_SKIP and route unsupported archs there
Jun 24, 2026
68a29a4
cDAC stress: catch NotImplementedException across the whole encoder
Jun 24, 2026
9165ab2
cDAC stress: new CrossModule debuggee covering cross-module type refs
Jun 24, 2026
31fabbe
Address PR review feedback from copilot-pull-request-reviewer
Jun 24, 2026
03f3db5
cDAC stress: scope ARGITER theories to windows-x86/x64, split out Var…
Jun 24, 2026
df2b289
cDAC stress: consolidate VarArgs into WindowsOnlyDebuggees, rename GC…
Jun 24, 2026
6b8f881
Address PR review feedback: narrow surface, redesign wire format, fol…
Jun 24, 2026
f28f3c3
Address PR review feedback round 3
Jun 24, 2026
821fcea
Stress tests: add CrossModule to xunit list; exclude VarArgs from GCREFS
Jun 25, 2026
2a79af0
ArgIterator: require objectTypeHandle/intPtrTypeHandle/isWindows
Jun 25, 2026
be6aaf3
ArgIterator: make generic over TTypeHandle to avoid boxing
Jun 25, 2026
7a20278
CallingConvention_1: fold GetCbStackPop into GetArgumentLayout
Jun 25, 2026
1f100d7
Address PR review feedback round 4 (Copilot follow-up)
Jun 25, 2026
af7c18f
Final polish: misleading comment, README rename, Helix chmod
Jun 26, 2026
807b833
CdacTypeHandle: promote _arch field to public Arch property
Jun 26, 2026
e497ec8
cdacstress: fix gcc -Werror=address and -Werror=format-truncation
Jun 27, 2026
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
41 changes: 41 additions & 0 deletions docs/design/datacontracts/CallingConvention.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Contract CallingConvention

This contract walks a method's argument signature using the runtime's
calling-convention rules so consumers can locate each argument on the
caller's transition frame and reason about which slots hold GC references.

The actual ABI (which registers hold which arguments, what alignment and
padding rules apply, how structs are promoted to registers vs spilled, how
varargs are passed, etc.) is documented in the CLR ABI specs and is not
re-described here:

- [Common CLR ABI conventions](../coreclr/botr/clr-abi.md)

This contract's responsibility is to surface the *result* of that walk in
a form the cDAC can use, byte-for-byte compatible with what the runtime
itself produces.

## APIs of contract

``` csharp
// Encode the argument GCRefMap blob for `methodDesc` byte-for-byte
// compatible with the runtime's ComputeCallRefMap (frames.cpp).
// Returns false when this contract declines to encode the method
// (e.g. an unported ABI path); callers should map false to E_NOTIMPL.
// When false, the value of `blob` is unspecified.
bool TryComputeArgGCRefMapBlob(MethodDescHandle methodDesc, out byte[] blob);
```

## Version 1

The single API is implemented by walking the shared `ArgIterator`
(`src/coreclr/tools/Common/CallingConvention/ArgIterator.cs`) and feeding
the per-argument result into a GCRefMap encoder that mirrors
`GCRefMapBuilder` (`src/coreclr/inc/gcrefmap.h`).

`TryComputeArgGCRefMapBlob` returns `false` for any method whose
signature, ABI path, or generic context the encoder hasn't been taught
yet. The cdacstress harness (`src/coreclr/vm/cdacstress.cpp`,
`ARGITER` sub-check) uses byte-for-byte comparison of the returned blob
against the runtime's `ComputeCallRefMap` output as its correctness
oracle.
32 changes: 32 additions & 0 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ partial interface IRuntimeTypeSystem : IContract
public virtual bool IsObjRef(TypeHandle typeHandle);
// True if the MethodTable represents a type that contains managed references
public virtual bool ContainsGCPointers(TypeHandle typeHandle);
// True if the MethodTable represents a byref-like value type (Span<T>, ReadOnlySpan<T>, any ref struct).
public virtual bool IsByRefLike(TypeHandle typeHandle);
// 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
Expand Down Expand Up @@ -290,6 +292,10 @@ partial interface IRuntimeTypeSystem : IContract
// Return true if the method is a wrapper stub (unboxing or instantiating).
public virtual bool IsWrapperStub(MethodDescHandle methodDesc);

// Return true if the method is an unboxing stub (a wrapper around a
// value-type instance method that unboxes `this` before forwarding).
public virtual bool IsUnboxingStub(MethodDescHandle methodDesc);

}
```

Expand All @@ -302,6 +308,7 @@ bool IsFieldDescStatic(TargetPointer fieldDescPointer);
bool IsFieldDescRVA(TargetPointer fieldDescPointer);
uint GetFieldDescType(TargetPointer fieldDescPointer);
uint GetFieldDescOffset(TargetPointer fieldDescPointer, FieldDefinition? fieldDef);
TypeHandle GetFieldDescApproxTypeHandle(TargetPointer fieldDescPointer);
TargetPointer GetFieldDescStaticAddress(TargetPointer fieldDescPointer, bool unboxValueTypes = true);
TargetPointer GetFieldDescThreadStaticAddress(TargetPointer fieldDescPointer, TargetPointer thread, bool unboxValueTypes = true);
```
Expand Down Expand Up @@ -330,6 +337,8 @@ internal partial struct RuntimeTypeSystem_1
GenericsMask_SharedInst = 0x00000020, // shared instantiation, e.g. List<__Canon> or List<MyValueType<__Canon>>
GenericsMask_TypicalInstantiation = 0x00000030, // the type instantiated at its formal parameters, e.g. List<T>

IsByRefLike = 0x00001000, // value type that may contain managed pointers (e.g. Span<T>, ReadOnlySpan<T>)

StringArrayValues = GenericsMask_NonGeneric,
}

Expand Down Expand Up @@ -404,6 +413,7 @@ internal partial struct RuntimeTypeSystem_1
public bool IsTrackedReferenceWithFinalizer => GetFlag(WFLAGS_HIGH.IsTrackedReferenceWithFinalizer) != 0;
public bool IsGenericTypeDefinition => TestFlagWithMask(WFLAGS_LOW.GenericsMask, WFLAGS_LOW.GenericsMask_TypicalInstantiation);
public bool IsSharedByGenericInstantiations => TestFlagWithMask(WFLAGS_LOW.GenericsMask, WFLAGS_LOW.GenericsMask_SharedInst);
public bool IsByRefLike => TestFlagWithMask(WFLAGS_LOW.IsByRefLike, WFLAGS_LOW.IsByRefLike);
}

[Flags]
Expand Down Expand Up @@ -663,6 +673,8 @@ Contracts used:

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

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

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

public bool IsCanonicalMethodTable(TypeHandle typeHandle)
Expand Down Expand Up @@ -1867,6 +1879,17 @@ Determining if a method is a wrapper stub (unboxing or instantiating):
}
```

Determining if a method is an unboxing stub. An unboxing stub is a wrapper
around a value-type instance method whose `this` is a boxed object: the
stub unboxes `this` and forwards to the real instance method. The bit is
stored in `MethodDescFlags3` and surfaces as the `IsUnboxingStub` flag on
`MethodDesc`:

```csharp
public bool IsUnboxingStub(MethodDescHandle methodDescHandle)
=> _methodDescs[methodDescHandle.Address].IsUnboxingStub;
```

Extracting a pointer to the `MethodDescVersioningState` data for a given method

```csharp
Expand Down Expand Up @@ -2227,6 +2250,15 @@ TargetPointer GetFieldDescThreadStaticAddress(TargetPointer fieldDescPointer, Ta
// Uses GetGCThreadStaticsBasePointer / GetNonGCThreadStaticsBasePointer.
// The unboxValueTypes parameter behaves the same as in GetFieldDescStaticAddress.
}

TypeHandle GetFieldDescApproxTypeHandle(TargetPointer fieldDescPointer)
{
// Resolve enclosing MT -> Module -> MetadataReader, decode the field's
// signature using the SignatureDecoder contract with a SignatureTypeProvider
// bound to the enclosing class as generic context, and return the resulting
// TypeHandle. Returns TypeHandle.Null if any link in the chain is unavailable
// (e.g. uncached constructed instantiation).
}
```

### Other APIs
Expand Down
1 change: 1 addition & 0 deletions eng/pipelines/runtime-diagnostics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ parameters:
type: object
default:
- windows_x64
- windows_x86
- linux_x64
- windows_arm64
- linux_arm64
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ CONFIG_STRING_INFO(INTERNAL_PrestubHalt, W("PrestubHalt"), "")
RETAIL_CONFIG_STRING_INFO(EXTERNAL_RestrictedGCStressExe, W("RestrictedGCStressExe"), "")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_CdacStressFailFast, W("CdacStressFailFast"), 0, "If nonzero, assert on cDAC/runtime GC ref mismatch during cDAC stress verification.")
RETAIL_CONFIG_STRING_INFO(INTERNAL_CdacStressLogFile, W("CdacStressLogFile"), "Log file path for cDAC stress verification results.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_CdacStress, W("CdacStress"), 0, "Enable cDAC stress verification. Bit flags: 0x1=alloc points, 0x200=verbose per-ref diagnostics.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_CdacStress, W("CdacStress"), 0, "Enable cDAC stress verification.")
CONFIG_DWORD_INFO(INTERNAL_ReturnSourceTypeForTesting, W("ReturnSourceTypeForTesting"), 0, "Allows returning the (internal only) source type of an IL to Native mapping for debugging purposes")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_RSStressLog, W("RSStressLog"), 0, "Allows turning on logging for RS startup")
CONFIG_DWORD_INFO(INTERNAL_SBDumpOnNewIndex, W("SBDumpOnNewIndex"), 0, "Used for Syncblock debugging. It's been a while since any of those have been used.")
Expand Down
23 changes: 22 additions & 1 deletion src/coreclr/inc/dacprivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,33 @@ enum
DACSTACKPRIV_REQUEST_FRAME_DATA = 0xf0000000
};

#ifdef CDAC_STRESS
// Private requests for the cDAC stress harness.
enum
{
DACSTRESSPRIV_REQUEST_FLUSH_TARGET_STATE = 0xf2000000
DACSTRESSPRIV_REQUEST_FLUSH_TARGET_STATE = 0xf2000000,
DACSTRESSPRIV_REQUEST_COMPUTE_ARG_GCREFMAP = 0xf2000001
};

// In/out request descriptor for DACSTRESSPRIV_REQUEST_COMPUTE_ARG_GCREFMAP.
// outBuffer is unused; the caller-allocated blob destination + size are
// carried by this struct, and the handler writes cbFilled and cbNeeded in
// place.
// S_OK blob fit; cbFilled bytes written to *BlobBuffer; cbNeeded == cbFilled.
// HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) cbFilled = 0, cbNeeded = required size; *BlobBuffer untouched.
// E_NOTIMPL encoder declined this MD (bucketed as ARG_SKIP).
// E_FAIL encoder threw (bucketed as ARG_ERROR).
// E_INVALIDARG bad inBuffer.
struct DacStressArgGCRefMapRequest
{
CLRDATA_ADDRESS MethodDesc; // [in]
CLRDATA_ADDRESS BlobBuffer; // [in] caller-allocated destination (in-proc pointer)
ULONG32 BlobBufferLen; // [in] capacity at BlobBuffer
ULONG32 cbFilled; // [out] bytes actually written to *BlobBuffer
ULONG32 cbNeeded; // [out] total bytes the blob requires
};
Comment thread
max-charlamb marked this conversation as resolved.
#endif // CDAC_STRESS

enum DacpObjectType { OBJ_STRING=0,OBJ_FREE,OBJ_OBJECT,OBJ_ARRAY,OBJ_OTHER };
struct MSLAYOUT DacpObjectData
{
Expand Down
Loading
Loading