[NativeAOT] Add cDAC data descriptor infrastructure - #126972

Merged
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors
May 1, 2026
Merged

[NativeAOT] Add cDAC data descriptor infrastructure#126972
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors

Conversation

@max-charlamb

@max-charlambmax-charlamb commented Apr 15, 2026

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame, thread link
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • StressLog/ThreadStressLog: Stress log infrastructure (guarded by STRESS_LOG)
  • Globals: ThreadStore static pointer, free object MethodTable, GC bounds, thread state flags, object unmask, stress log
  • Contracts: Thread (n1), Exception (c1), RuntimeTypeSystem (n1), StressLog (c2)
  • Sub-descriptors: GC (workstation + server) and managed type descriptors

ILC managed type descriptor (ManagedDataDescriptorNode)

  • Computes managed type field offsets at compile time in ILC
  • Emits a ContractDescriptor (DotNetManagedContractDescriptor) with JSON-encoded type layouts using Utf8JsonWriter
  • Types and fields discovered via [DataContract] attribute on types in MetadataManager.GetTypesWithEETypes()
  • Type name mangling: System.Threading.Thread -> System_Threading_Thread
  • Referenced by the native descriptor as a sub-descriptor via CDAC_GLOBAL_SUB_DESCRIPTOR
  • Currently registers System.Threading.Thread fields (ManagedThreadId, Name)

GC sub-descriptor

  • Enabled GC sub-descriptor for NativeAOT by setting GC_INTERFACE_*_VERSION before GC_Initialize
  • Added GC_DESCRIPTOR compile definition (guarded on non-WASM)
  • Linked both WKS and SVR GC descriptor objects into Runtime.ServerGC (ServerGC compiles both paths)
  • Added #ifdef HEAP_ANALYZE guards in shared GC datadescriptor files (NativeAOT disables HEAP_ANALYZE)

Attribute-based type discovery

  • [DataContract] attribute in System.Diagnostics namespace (internal, targets Class/Struct/Field)
  • Applied to System.Threading.Thread fields in Thread.NativeAot.cs
  • ILC scans for annotated types in GetTypesWithEETypes() ensuring only types with MethodTables are included

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • nativeaot_runtime_includes interface library captures all Runtime include paths for cross-target compilation
  • Separate GC descriptor targets for workstation and server GC
  • cdac-build-tool enabled for NativeAOT via ClrNativeAotSubset in runtime.proj
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets (WASM excluded)
  • Local copy of cdacdata.h template in Runtime/inc/ (matching GC pattern for self-contained builds)

Key design decisions

  • Contract versions: n1 for NativeAOT-specific contracts, c1/c2 for contracts shared with CoreCLR (same version)
  • ThreadStore: Uses SPTR_DECL/SPTR_IMPL for s_pThreadStore static member, matching CoreCLR pattern
  • Singleton node: ManagedDataDescriptorNode does not override CompareToImpl — follows the ILC singleton pattern (base class throws on duplicates)
  • SList: Unified slist.h shared between CoreCLR VM and NativeAOT Runtime

Validation

  • Build: build.cmd clr.aot+libs -rc release — 0 errors, 0 warnings
  • Symbol verified in Runtime.WorkstationGC.lib via dumpbin
  • cDAC reader tests: 1586/1586 passed
  • tools.cdac tests: All passed
  • Dump inspection: All 3 sub-descriptors verified (main: 4 contracts/11 types/20 globals, managed: System_Threading_Thread with fields, GC: 1 contract/10 types/41 globals)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds cDAC contract descriptor generation to the NativeAOT runtime, plus an ILC-emitted managed sub-descriptor so diagnostic tools can inspect NativeAOT runtime/managed state via the shared contract mechanism.

Changes:

  • Integrates NativeAOT cDAC contract descriptor (and GC sub-descriptors) into the NativeAOT CMake build and runtime libraries.
  • Introduces a managed type layout sub-descriptor emitted by ILC (DotNetManagedContractDescriptor) and wires it into the NativeAOT descriptor as a sub-descriptor.
  • Exposes select private NativeAOT runtime offsets/constants to the descriptor via the cdac_data<T> friend pattern and exports the main contract descriptor symbol for diagnostics.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/coreclr/tools/aot/ILCompiler/Program.csAdds the managed descriptor root provider to ILC compilation roots.
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csprojIncludes new managed descriptor provider/node sources in the build.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ManagedDataDescriptorProvider.csRegisters managed types to be described and roots the descriptor + JSON blob.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ManagedDataDescriptorNode.csEmits a ContractDescriptor-shaped symbol containing JSON type layout data.
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore private offsets for descriptor generation via cdac_data<>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable offsets and flag constants for descriptor consumption via cdac_data<>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incDefines the NativeAOT data descriptor types/globals/contracts and sub-descriptors.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hProvides includes and declares the managed sub-descriptor symbol address for inclusion.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds descriptor generation targets for NativeAOT runtime + GC (wks/svr).
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance private offsets via cdac_data<>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor libraries into WorkstationGC/ServerGC runtime libs.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the datadescriptor subdirectory to the NativeAOT runtime build (non-WASM).
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor symbol for diagnostics on all OSes.
Comments suppressed due to low confidence (1)

src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt:73

  • target_compile_definitions entries should be raw preprocessor symbols (e.g., SERVER_GC), not compiler flags. Passing -DSERVER_GC here will typically result in an invalid definition being forwarded to the compiler. Use SERVER_GC (or SERVER_GC=1) instead.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets Outdated
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlambforce-pushed the dev/max-charlamb/managed-type-descriptors branch from 9462d5c to f226bc3CompareApril 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:53
@max-charlamb
max-charlamb restored the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:54

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 7 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
@github-actions

This comment has been minimized.

CopilotAI review requested due to automatic review settings April 17, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.h
Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.cpp Outdated
CopilotAI review requested due to automatic review settings April 17, 2026 19:44
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 28, 2026 18:35

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MichalStrehovsky Could you please signoff as well?

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

@github-actions

This comment has been minimized.

…ed descriptor
- Remove MethodTable flag constant globals from datadescriptor.inc
and cdac_data<MethodTable> in MethodTable.h — these are already
defined as part of the contract in MethodTableFlags_1.cs
- Add baseline and contracts properties to managed sub-descriptor
JSON for self-describing format consistency
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Copilot Code Review — PR #126972

Note

This review was generated by GitHub Copilot.

Holistic Assessment

Motivation: This PR adds cDAC (data access component) data descriptor infrastructure to NativeAOT, enabling diagnostic tools (debuggers, crash dump analyzers) to inspect NativeAOT runtime state without symbols. This is well-motivated — it's a prerequisite for cDAC support in NativeAOT, analogous to what already exists for CoreCLR.

Approach: The approach is sound — it reuses the existing generate_data_descriptors() CMake infrastructure and shared datadescriptor.cpp machinery. Moving ThreadStore from RuntimeInstance::m_pThreadStore to a static ThreadStore::s_pThreadStore matches the CoreCLR pattern. The managed type descriptor emitted by ILC as a sub-descriptor integrates cleanly with the existing ContractDescriptorParser. The HEAP_ANALYZE guards fix real compilation errors for NativeAOT GC builds.

Summary: ⚠️ Needs Human Review. The implementation is largely correct and well-structured, but there are design questions around contract versioning (n1 vs c1) and its interaction with the cDAC reader that a domain expert should verify. A human reviewer should confirm whether n1 contracts are intentionally non-functional placeholders or need corresponding reader support.


Detailed Findings

⚠️ Contract Versions — n1 not registered in cDAC reader (advisory, not merge-blocking)

The NativeAOT descriptor declares:

CDAC_GLOBAL_CONTRACT(Thread, n1)
CDAC_GLOBAL_CONTRACT(RuntimeTypeSystem, n1)

However, the managed cDAC reader (CoreCLRContracts.cs:38) only registers c1 versions:

registry.Register<IThread>("c1",static t =>newThread_1(t));

There is no n1 handler anywhere in src/native/managed/cdac/. This means these contracts will not be resolved when diagnosing a NativeAOT process. If this is intentional (placeholder for future NativeAOT-specific contract implementations), consider adding a comment. If it's expected to work now, corresponding contract factories are needed.

Files:src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc (lines ~155-158)

✅ HEAP_ANALYZE guards — Correct fix

HEAP_ANALYZE is only defined when FEATURE_NATIVEAOT is NOT set (gcpriv.h:200-203). Without these guards, the GC data descriptor would fail to compile for NativeAOT. The guards are correctly placed in both datadescriptor.h and datadescriptor.inc, with proper #endif comments.

✅ ThreadStore refactoring — Correct and well-versioned

Moving m_pThreadStore from RuntimeInstance to ThreadStore::s_pThreadStore is consistent with CoreCLR's cDAC pattern. The DebugHeader major version is correctly bumped from 5→6 with appropriate documentation. The SPTR_DECL/SPTR_IMPL pattern matches existing DAC infrastructure. The initialization order in RuntimeInstance::Initialize() correctly assigns the static after g_pTheRuntimeInstance is set.

✅ ManagedDataDescriptorNode — JSON format matches reader expectations

The emitted JSON uses:

  • "!" sigil for value type sizes (matches TypeDescriptorSizeSigil in ContractDescriptorParser)
  • Plain numbers for field offsets (matches FieldDescriptorConverter compact format)
  • "version": 0, "baseline": "empty" top-level properties (match ContractDescriptor schema)

The ContractDescriptor C struct layout (magic, flags, descriptor_size, descriptor ptr, pointer_data_count, pad, pointer_data ptr) matches the shared contract-descriptor.h definition.

✅ WASM exclusion — Consistent

WASM is excluded via if(NOT CLR_CMAKE_TARGET_ARCH_WASM) for both the GC_DESCRIPTOR define and the datadescriptor subdirectory in CMake, and via '$(_targetOS)' != 'browser' for the export in MSBuild targets. This matches the broader WASM exclusion pattern in the NativeAOT Runtime CMakeLists.txt.

✅ GC version initialization — Correct

Adding g_gc_dac_vars.major_version_number and minor_version_number before GC_Initialize matches the CoreCLR pattern and ensures the GC sub-descriptor has version information.

✅ Build system integration — Well structured

The new datadescriptor/CMakeLists.txt correctly uses include(${CLR_DIR}/clrdatadescriptors.cmake), creates separate interface libraries for WKS/SVR GC descriptors, uses EXPORT_VISIBLE only for the main contract descriptor, and properly propagates include directories via nativeaot_runtime_includes.

💡 ManagedDataDescriptorProvider unconditionally added for WASM

ManagedDataDescriptorProvider is always added in Program.cs (lines 266, 278), even for WASM targets where the native datadescriptor isn't built. The ILC-emitted DotNetManagedContractDescriptor symbol is unused dead data on WASM. Non-blocking, but could be gated on !TargetsBrowser for binary size if desired. (Follow-up improvement, not in-scope for this PR.)

💡 DataContractAttribute naming overlap

System.Diagnostics.DataContractAttribute shares its short name with System.Runtime.Serialization.DataContractAttribute. No actual conflict exists (different namespaces, the new one is internal), but it could cause momentary confusion. The naming aligns with cDAC "data contract" terminology so it's appropriate — just noting for awareness.

Generated by Code Review for issue #126972 ·

@MichalStrehovskyMichalStrehovsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Comment threadsrc/coreclr/tools/aot/ILCompiler/Program.cs Outdated
@max-charlamb

Copy link
Copy Markdown
MemberAuthor

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Some of these values are read by the existing cDAC contracts, some will be read by new contracts (in a different repo). We don't have tests automated yet, but it is one of the next items I am working on.

- Simplify GetSection to always use ReadOnlyDataSection
- Add Debug.Assert for header size before emitting JSON
- Remove Phase override (default unordered is fine)
- Gate ManagedDataDescriptorProvider on EnableDebugInfo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 30, 2026 18:33

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/DebugHeader.cpp
Revert GetSection to use DataSection on non-Windows platforms.
Nodes with pointer relocations require writable sections on ELF.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@max-charlamb
max-charlamb merged commit e883467 into mainMay 1, 2026
110 checks passed
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch May 1, 2026 05:02
steveisok added a commit that referenced this pull request May 6, 2026
)
> [!NOTE]
> This PR was authored with assistance from GitHub Copilot.
## Problem
The OBJECT libraries created by `generate_data_descriptors()` in
`src/coreclr/clrdatadescriptors.cmake` compile `contract-descriptor.c`
and `contractpointerdata.cpp` with MSVC defaults, which routes debug
info into the compiler-default `vc140.pdb`. That PDB does not travel
with the `.obj` files when they are archived into a static library such
as `Runtime.ServerGC.lib`.
Downstream linkers — in particular the NativeAOT publish of
`ILCompiler`, `crossgen2`, and `ilasm` on Windows — then emit `LNK4099`
("PDB 'vc140.pdb' was not found") for each affected object, which is
fatal under `/WX`.
## Symptom
The `dotnet/runtime` → `dotnet/dotnet` codeflow PR
[dotnet/dotnet#6423](dotnet/dotnet#6423) is
blocked: the **VMR Vertical Build Windows_x64** and **VMR Vertical Build
Windows_x86** legs both fail with 22 `LNK4099` errors apiece, e.g.:
```
Runtime.ServerGC.lib(contract-descriptor.c.obj) : error LNK4099:
PDB 'vc140.pdb' was not found with 'Runtime.ServerGC.lib(contract-descriptor.c.obj)'
or at '...\artifacts\bin\ILCompiler_publish\x64\Release\native\vc140.pdb';
linking object as if no debug info
[src\coreclr\tools\aot\ILCompiler\ILCompiler_publish.csproj]
Runtime.ServerGC.lib(contractpointerdata.cpp.obj) : error LNK4099: ...
```
repeated for `crossgen2_publish.csproj` and `ilasm.csproj`.
Linux/macOS/WASM/iOS/Android verticals all pass — `LNK4099` is
MSVC-specific.
The regression was introduced by #126972 ("[NativeAOT] Add cDAC data
descriptor infrastructure"), which wired the new descriptor `OBJECT`
libraries into the NativeAOT runtime so they end up archived inside
`Runtime.ServerGC.lib`.
## Fix
Set `COMPILE_PDB_NAME` and `COMPILE_PDB_OUTPUT_DIRECTORY` on
`${LIBRARY}` so each descriptor library produces its own deterministic
PDB that the consuming linker can locate. This matches the convention
already used by `install_static_library` in
`eng/native/functions.cmake`.
## Validation
- CMake reconfigures cleanly.
- Ninja built `nativeaot_gc_svr_descriptor`,
`nativeaot_gc_wks_descriptor`, `nativeaot_cdac_contract_descriptor`, and
`cdac_contract_descriptor` without errors on linux-x64.
- The actual `LNK4099` resolution can only be verified on a Windows
NativeAOT publish leg in CI; please pay particular attention to the
Windows legs and to the next forward-flow into `dotnet/dotnet`.
cc @max-charlamb (author of #126972)
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Steve Pfister <steveisok@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@max-charlamb@jkoritzinsky@jkotas@MichalStrehovsky
, '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

[NativeAOT] Add cDAC data descriptor infrastructure - #126972

Merged
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors
May 1, 2026
Merged

[NativeAOT] Add cDAC data descriptor infrastructure#126972
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors

Conversation

@max-charlamb

@max-charlambmax-charlamb commented Apr 15, 2026

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame, thread link
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • StressLog/ThreadStressLog: Stress log infrastructure (guarded by STRESS_LOG)
  • Globals: ThreadStore static pointer, free object MethodTable, GC bounds, thread state flags, object unmask, stress log
  • Contracts: Thread (n1), Exception (c1), RuntimeTypeSystem (n1), StressLog (c2)
  • Sub-descriptors: GC (workstation + server) and managed type descriptors

ILC managed type descriptor (ManagedDataDescriptorNode)

  • Computes managed type field offsets at compile time in ILC
  • Emits a ContractDescriptor (DotNetManagedContractDescriptor) with JSON-encoded type layouts using Utf8JsonWriter
  • Types and fields discovered via [DataContract] attribute on types in MetadataManager.GetTypesWithEETypes()
  • Type name mangling: System.Threading.Thread -> System_Threading_Thread
  • Referenced by the native descriptor as a sub-descriptor via CDAC_GLOBAL_SUB_DESCRIPTOR
  • Currently registers System.Threading.Thread fields (ManagedThreadId, Name)

GC sub-descriptor

  • Enabled GC sub-descriptor for NativeAOT by setting GC_INTERFACE_*_VERSION before GC_Initialize
  • Added GC_DESCRIPTOR compile definition (guarded on non-WASM)
  • Linked both WKS and SVR GC descriptor objects into Runtime.ServerGC (ServerGC compiles both paths)
  • Added #ifdef HEAP_ANALYZE guards in shared GC datadescriptor files (NativeAOT disables HEAP_ANALYZE)

Attribute-based type discovery

  • [DataContract] attribute in System.Diagnostics namespace (internal, targets Class/Struct/Field)
  • Applied to System.Threading.Thread fields in Thread.NativeAot.cs
  • ILC scans for annotated types in GetTypesWithEETypes() ensuring only types with MethodTables are included

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • nativeaot_runtime_includes interface library captures all Runtime include paths for cross-target compilation
  • Separate GC descriptor targets for workstation and server GC
  • cdac-build-tool enabled for NativeAOT via ClrNativeAotSubset in runtime.proj
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets (WASM excluded)
  • Local copy of cdacdata.h template in Runtime/inc/ (matching GC pattern for self-contained builds)

Key design decisions

  • Contract versions: n1 for NativeAOT-specific contracts, c1/c2 for contracts shared with CoreCLR (same version)
  • ThreadStore: Uses SPTR_DECL/SPTR_IMPL for s_pThreadStore static member, matching CoreCLR pattern
  • Singleton node: ManagedDataDescriptorNode does not override CompareToImpl — follows the ILC singleton pattern (base class throws on duplicates)
  • SList: Unified slist.h shared between CoreCLR VM and NativeAOT Runtime

Validation

  • Build: build.cmd clr.aot+libs -rc release — 0 errors, 0 warnings
  • Symbol verified in Runtime.WorkstationGC.lib via dumpbin
  • cDAC reader tests: 1586/1586 passed
  • tools.cdac tests: All passed
  • Dump inspection: All 3 sub-descriptors verified (main: 4 contracts/11 types/20 globals, managed: System_Threading_Thread with fields, GC: 1 contract/10 types/41 globals)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds cDAC contract descriptor generation to the NativeAOT runtime, plus an ILC-emitted managed sub-descriptor so diagnostic tools can inspect NativeAOT runtime/managed state via the shared contract mechanism.

Changes:

  • Integrates NativeAOT cDAC contract descriptor (and GC sub-descriptors) into the NativeAOT CMake build and runtime libraries.
  • Introduces a managed type layout sub-descriptor emitted by ILC (DotNetManagedContractDescriptor) and wires it into the NativeAOT descriptor as a sub-descriptor.
  • Exposes select private NativeAOT runtime offsets/constants to the descriptor via the cdac_data<T> friend pattern and exports the main contract descriptor symbol for diagnostics.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/coreclr/tools/aot/ILCompiler/Program.csAdds the managed descriptor root provider to ILC compilation roots.
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csprojIncludes new managed descriptor provider/node sources in the build.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ManagedDataDescriptorProvider.csRegisters managed types to be described and roots the descriptor + JSON blob.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ManagedDataDescriptorNode.csEmits a ContractDescriptor-shaped symbol containing JSON type layout data.
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore private offsets for descriptor generation via cdac_data<>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable offsets and flag constants for descriptor consumption via cdac_data<>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incDefines the NativeAOT data descriptor types/globals/contracts and sub-descriptors.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hProvides includes and declares the managed sub-descriptor symbol address for inclusion.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds descriptor generation targets for NativeAOT runtime + GC (wks/svr).
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance private offsets via cdac_data<>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor libraries into WorkstationGC/ServerGC runtime libs.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the datadescriptor subdirectory to the NativeAOT runtime build (non-WASM).
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor symbol for diagnostics on all OSes.
Comments suppressed due to low confidence (1)

src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt:73

  • target_compile_definitions entries should be raw preprocessor symbols (e.g., SERVER_GC), not compiler flags. Passing -DSERVER_GC here will typically result in an invalid definition being forwarded to the compiler. Use SERVER_GC (or SERVER_GC=1) instead.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets Outdated
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlambforce-pushed the dev/max-charlamb/managed-type-descriptors branch from 9462d5c to f226bc3CompareApril 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:53
@max-charlamb
max-charlamb restored the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:54

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 7 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
@github-actions

This comment has been minimized.

CopilotAI review requested due to automatic review settings April 17, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.h
Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.cpp Outdated
CopilotAI review requested due to automatic review settings April 17, 2026 19:44
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 28, 2026 18:35

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MichalStrehovsky Could you please signoff as well?

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

@github-actions

This comment has been minimized.

…ed descriptor
- Remove MethodTable flag constant globals from datadescriptor.inc
and cdac_data<MethodTable> in MethodTable.h — these are already
defined as part of the contract in MethodTableFlags_1.cs
- Add baseline and contracts properties to managed sub-descriptor
JSON for self-describing format consistency
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Copilot Code Review — PR #126972

Note

This review was generated by GitHub Copilot.

Holistic Assessment

Motivation: This PR adds cDAC (data access component) data descriptor infrastructure to NativeAOT, enabling diagnostic tools (debuggers, crash dump analyzers) to inspect NativeAOT runtime state without symbols. This is well-motivated — it's a prerequisite for cDAC support in NativeAOT, analogous to what already exists for CoreCLR.

Approach: The approach is sound — it reuses the existing generate_data_descriptors() CMake infrastructure and shared datadescriptor.cpp machinery. Moving ThreadStore from RuntimeInstance::m_pThreadStore to a static ThreadStore::s_pThreadStore matches the CoreCLR pattern. The managed type descriptor emitted by ILC as a sub-descriptor integrates cleanly with the existing ContractDescriptorParser. The HEAP_ANALYZE guards fix real compilation errors for NativeAOT GC builds.

Summary: ⚠️ Needs Human Review. The implementation is largely correct and well-structured, but there are design questions around contract versioning (n1 vs c1) and its interaction with the cDAC reader that a domain expert should verify. A human reviewer should confirm whether n1 contracts are intentionally non-functional placeholders or need corresponding reader support.


Detailed Findings

⚠️ Contract Versions — n1 not registered in cDAC reader (advisory, not merge-blocking)

The NativeAOT descriptor declares:

CDAC_GLOBAL_CONTRACT(Thread, n1)
CDAC_GLOBAL_CONTRACT(RuntimeTypeSystem, n1)

However, the managed cDAC reader (CoreCLRContracts.cs:38) only registers c1 versions:

registry.Register<IThread>("c1",static t =>newThread_1(t));

There is no n1 handler anywhere in src/native/managed/cdac/. This means these contracts will not be resolved when diagnosing a NativeAOT process. If this is intentional (placeholder for future NativeAOT-specific contract implementations), consider adding a comment. If it's expected to work now, corresponding contract factories are needed.

Files:src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc (lines ~155-158)

✅ HEAP_ANALYZE guards — Correct fix

HEAP_ANALYZE is only defined when FEATURE_NATIVEAOT is NOT set (gcpriv.h:200-203). Without these guards, the GC data descriptor would fail to compile for NativeAOT. The guards are correctly placed in both datadescriptor.h and datadescriptor.inc, with proper #endif comments.

✅ ThreadStore refactoring — Correct and well-versioned

Moving m_pThreadStore from RuntimeInstance to ThreadStore::s_pThreadStore is consistent with CoreCLR's cDAC pattern. The DebugHeader major version is correctly bumped from 5→6 with appropriate documentation. The SPTR_DECL/SPTR_IMPL pattern matches existing DAC infrastructure. The initialization order in RuntimeInstance::Initialize() correctly assigns the static after g_pTheRuntimeInstance is set.

✅ ManagedDataDescriptorNode — JSON format matches reader expectations

The emitted JSON uses:

  • "!" sigil for value type sizes (matches TypeDescriptorSizeSigil in ContractDescriptorParser)
  • Plain numbers for field offsets (matches FieldDescriptorConverter compact format)
  • "version": 0, "baseline": "empty" top-level properties (match ContractDescriptor schema)

The ContractDescriptor C struct layout (magic, flags, descriptor_size, descriptor ptr, pointer_data_count, pad, pointer_data ptr) matches the shared contract-descriptor.h definition.

✅ WASM exclusion — Consistent

WASM is excluded via if(NOT CLR_CMAKE_TARGET_ARCH_WASM) for both the GC_DESCRIPTOR define and the datadescriptor subdirectory in CMake, and via '$(_targetOS)' != 'browser' for the export in MSBuild targets. This matches the broader WASM exclusion pattern in the NativeAOT Runtime CMakeLists.txt.

✅ GC version initialization — Correct

Adding g_gc_dac_vars.major_version_number and minor_version_number before GC_Initialize matches the CoreCLR pattern and ensures the GC sub-descriptor has version information.

✅ Build system integration — Well structured

The new datadescriptor/CMakeLists.txt correctly uses include(${CLR_DIR}/clrdatadescriptors.cmake), creates separate interface libraries for WKS/SVR GC descriptors, uses EXPORT_VISIBLE only for the main contract descriptor, and properly propagates include directories via nativeaot_runtime_includes.

💡 ManagedDataDescriptorProvider unconditionally added for WASM

ManagedDataDescriptorProvider is always added in Program.cs (lines 266, 278), even for WASM targets where the native datadescriptor isn't built. The ILC-emitted DotNetManagedContractDescriptor symbol is unused dead data on WASM. Non-blocking, but could be gated on !TargetsBrowser for binary size if desired. (Follow-up improvement, not in-scope for this PR.)

💡 DataContractAttribute naming overlap

System.Diagnostics.DataContractAttribute shares its short name with System.Runtime.Serialization.DataContractAttribute. No actual conflict exists (different namespaces, the new one is internal), but it could cause momentary confusion. The naming aligns with cDAC "data contract" terminology so it's appropriate — just noting for awareness.

Generated by Code Review for issue #126972 ·

@MichalStrehovskyMichalStrehovsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Comment threadsrc/coreclr/tools/aot/ILCompiler/Program.cs Outdated
@max-charlamb

Copy link
Copy Markdown
MemberAuthor

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Some of these values are read by the existing cDAC contracts, some will be read by new contracts (in a different repo). We don't have tests automated yet, but it is one of the next items I am working on.

- Simplify GetSection to always use ReadOnlyDataSection
- Add Debug.Assert for header size before emitting JSON
- Remove Phase override (default unordered is fine)
- Gate ManagedDataDescriptorProvider on EnableDebugInfo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 30, 2026 18:33

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/DebugHeader.cpp
Revert GetSection to use DataSection on non-Windows platforms.
Nodes with pointer relocations require writable sections on ELF.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@max-charlamb
max-charlamb merged commit e883467 into mainMay 1, 2026
110 checks passed
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch May 1, 2026 05:02
steveisok added a commit that referenced this pull request May 6, 2026
)
> [!NOTE]
> This PR was authored with assistance from GitHub Copilot.
## Problem
The OBJECT libraries created by `generate_data_descriptors()` in
`src/coreclr/clrdatadescriptors.cmake` compile `contract-descriptor.c`
and `contractpointerdata.cpp` with MSVC defaults, which routes debug
info into the compiler-default `vc140.pdb`. That PDB does not travel
with the `.obj` files when they are archived into a static library such
as `Runtime.ServerGC.lib`.
Downstream linkers — in particular the NativeAOT publish of
`ILCompiler`, `crossgen2`, and `ilasm` on Windows — then emit `LNK4099`
("PDB 'vc140.pdb' was not found") for each affected object, which is
fatal under `/WX`.
## Symptom
The `dotnet/runtime` → `dotnet/dotnet` codeflow PR
[dotnet/dotnet#6423](dotnet/dotnet#6423) is
blocked: the **VMR Vertical Build Windows_x64** and **VMR Vertical Build
Windows_x86** legs both fail with 22 `LNK4099` errors apiece, e.g.:
```
Runtime.ServerGC.lib(contract-descriptor.c.obj) : error LNK4099:
PDB 'vc140.pdb' was not found with 'Runtime.ServerGC.lib(contract-descriptor.c.obj)'
or at '...\artifacts\bin\ILCompiler_publish\x64\Release\native\vc140.pdb';
linking object as if no debug info
[src\coreclr\tools\aot\ILCompiler\ILCompiler_publish.csproj]
Runtime.ServerGC.lib(contractpointerdata.cpp.obj) : error LNK4099: ...
```
repeated for `crossgen2_publish.csproj` and `ilasm.csproj`.
Linux/macOS/WASM/iOS/Android verticals all pass — `LNK4099` is
MSVC-specific.
The regression was introduced by #126972 ("[NativeAOT] Add cDAC data
descriptor infrastructure"), which wired the new descriptor `OBJECT`
libraries into the NativeAOT runtime so they end up archived inside
`Runtime.ServerGC.lib`.
## Fix
Set `COMPILE_PDB_NAME` and `COMPILE_PDB_OUTPUT_DIRECTORY` on
`${LIBRARY}` so each descriptor library produces its own deterministic
PDB that the consuming linker can locate. This matches the convention
already used by `install_static_library` in
`eng/native/functions.cmake`.
## Validation
- CMake reconfigures cleanly.
- Ninja built `nativeaot_gc_svr_descriptor`,
`nativeaot_gc_wks_descriptor`, `nativeaot_cdac_contract_descriptor`, and
`cdac_contract_descriptor` without errors on linux-x64.
- The actual `LNK4099` resolution can only be verified on a Windows
NativeAOT publish leg in CI; please pay particular attention to the
Windows legs and to the next forward-flow into `dotnet/dotnet`.
cc @max-charlamb (author of #126972)
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Steve Pfister <steveisok@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@max-charlamb@jkoritzinsky@jkotas@MichalStrehovsky
, '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

[NativeAOT] Add cDAC data descriptor infrastructure - #126972

Merged
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors
May 1, 2026
Merged

[NativeAOT] Add cDAC data descriptor infrastructure#126972
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors

Conversation

@max-charlamb

@max-charlambmax-charlamb commented Apr 15, 2026

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame, thread link
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • StressLog/ThreadStressLog: Stress log infrastructure (guarded by STRESS_LOG)
  • Globals: ThreadStore static pointer, free object MethodTable, GC bounds, thread state flags, object unmask, stress log
  • Contracts: Thread (n1), Exception (c1), RuntimeTypeSystem (n1), StressLog (c2)
  • Sub-descriptors: GC (workstation + server) and managed type descriptors

ILC managed type descriptor (ManagedDataDescriptorNode)

  • Computes managed type field offsets at compile time in ILC
  • Emits a ContractDescriptor (DotNetManagedContractDescriptor) with JSON-encoded type layouts using Utf8JsonWriter
  • Types and fields discovered via [DataContract] attribute on types in MetadataManager.GetTypesWithEETypes()
  • Type name mangling: System.Threading.Thread -> System_Threading_Thread
  • Referenced by the native descriptor as a sub-descriptor via CDAC_GLOBAL_SUB_DESCRIPTOR
  • Currently registers System.Threading.Thread fields (ManagedThreadId, Name)

GC sub-descriptor

  • Enabled GC sub-descriptor for NativeAOT by setting GC_INTERFACE_*_VERSION before GC_Initialize
  • Added GC_DESCRIPTOR compile definition (guarded on non-WASM)
  • Linked both WKS and SVR GC descriptor objects into Runtime.ServerGC (ServerGC compiles both paths)
  • Added #ifdef HEAP_ANALYZE guards in shared GC datadescriptor files (NativeAOT disables HEAP_ANALYZE)

Attribute-based type discovery

  • [DataContract] attribute in System.Diagnostics namespace (internal, targets Class/Struct/Field)
  • Applied to System.Threading.Thread fields in Thread.NativeAot.cs
  • ILC scans for annotated types in GetTypesWithEETypes() ensuring only types with MethodTables are included

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • nativeaot_runtime_includes interface library captures all Runtime include paths for cross-target compilation
  • Separate GC descriptor targets for workstation and server GC
  • cdac-build-tool enabled for NativeAOT via ClrNativeAotSubset in runtime.proj
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets (WASM excluded)
  • Local copy of cdacdata.h template in Runtime/inc/ (matching GC pattern for self-contained builds)

Key design decisions

  • Contract versions: n1 for NativeAOT-specific contracts, c1/c2 for contracts shared with CoreCLR (same version)
  • ThreadStore: Uses SPTR_DECL/SPTR_IMPL for s_pThreadStore static member, matching CoreCLR pattern
  • Singleton node: ManagedDataDescriptorNode does not override CompareToImpl — follows the ILC singleton pattern (base class throws on duplicates)
  • SList: Unified slist.h shared between CoreCLR VM and NativeAOT Runtime

Validation

  • Build: build.cmd clr.aot+libs -rc release — 0 errors, 0 warnings
  • Symbol verified in Runtime.WorkstationGC.lib via dumpbin
  • cDAC reader tests: 1586/1586 passed
  • tools.cdac tests: All passed
  • Dump inspection: All 3 sub-descriptors verified (main: 4 contracts/11 types/20 globals, managed: System_Threading_Thread with fields, GC: 1 contract/10 types/41 globals)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds cDAC contract descriptor generation to the NativeAOT runtime, plus an ILC-emitted managed sub-descriptor so diagnostic tools can inspect NativeAOT runtime/managed state via the shared contract mechanism.

Changes:

  • Integrates NativeAOT cDAC contract descriptor (and GC sub-descriptors) into the NativeAOT CMake build and runtime libraries.
  • Introduces a managed type layout sub-descriptor emitted by ILC (DotNetManagedContractDescriptor) and wires it into the NativeAOT descriptor as a sub-descriptor.
  • Exposes select private NativeAOT runtime offsets/constants to the descriptor via the cdac_data<T> friend pattern and exports the main contract descriptor symbol for diagnostics.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/coreclr/tools/aot/ILCompiler/Program.csAdds the managed descriptor root provider to ILC compilation roots.
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csprojIncludes new managed descriptor provider/node sources in the build.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ManagedDataDescriptorProvider.csRegisters managed types to be described and roots the descriptor + JSON blob.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ManagedDataDescriptorNode.csEmits a ContractDescriptor-shaped symbol containing JSON type layout data.
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore private offsets for descriptor generation via cdac_data<>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable offsets and flag constants for descriptor consumption via cdac_data<>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incDefines the NativeAOT data descriptor types/globals/contracts and sub-descriptors.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hProvides includes and declares the managed sub-descriptor symbol address for inclusion.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds descriptor generation targets for NativeAOT runtime + GC (wks/svr).
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance private offsets via cdac_data<>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor libraries into WorkstationGC/ServerGC runtime libs.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the datadescriptor subdirectory to the NativeAOT runtime build (non-WASM).
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor symbol for diagnostics on all OSes.
Comments suppressed due to low confidence (1)

src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt:73

  • target_compile_definitions entries should be raw preprocessor symbols (e.g., SERVER_GC), not compiler flags. Passing -DSERVER_GC here will typically result in an invalid definition being forwarded to the compiler. Use SERVER_GC (or SERVER_GC=1) instead.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets Outdated
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlambforce-pushed the dev/max-charlamb/managed-type-descriptors branch from 9462d5c to f226bc3CompareApril 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:53
@max-charlamb
max-charlamb restored the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:54

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 7 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
@github-actions

This comment has been minimized.

CopilotAI review requested due to automatic review settings April 17, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.h
Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.cpp Outdated
CopilotAI review requested due to automatic review settings April 17, 2026 19:44
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 28, 2026 18:35

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MichalStrehovsky Could you please signoff as well?

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

@github-actions

This comment has been minimized.

…ed descriptor
- Remove MethodTable flag constant globals from datadescriptor.inc
and cdac_data<MethodTable> in MethodTable.h — these are already
defined as part of the contract in MethodTableFlags_1.cs
- Add baseline and contracts properties to managed sub-descriptor
JSON for self-describing format consistency
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Copilot Code Review — PR #126972

Note

This review was generated by GitHub Copilot.

Holistic Assessment

Motivation: This PR adds cDAC (data access component) data descriptor infrastructure to NativeAOT, enabling diagnostic tools (debuggers, crash dump analyzers) to inspect NativeAOT runtime state without symbols. This is well-motivated — it's a prerequisite for cDAC support in NativeAOT, analogous to what already exists for CoreCLR.

Approach: The approach is sound — it reuses the existing generate_data_descriptors() CMake infrastructure and shared datadescriptor.cpp machinery. Moving ThreadStore from RuntimeInstance::m_pThreadStore to a static ThreadStore::s_pThreadStore matches the CoreCLR pattern. The managed type descriptor emitted by ILC as a sub-descriptor integrates cleanly with the existing ContractDescriptorParser. The HEAP_ANALYZE guards fix real compilation errors for NativeAOT GC builds.

Summary: ⚠️ Needs Human Review. The implementation is largely correct and well-structured, but there are design questions around contract versioning (n1 vs c1) and its interaction with the cDAC reader that a domain expert should verify. A human reviewer should confirm whether n1 contracts are intentionally non-functional placeholders or need corresponding reader support.


Detailed Findings

⚠️ Contract Versions — n1 not registered in cDAC reader (advisory, not merge-blocking)

The NativeAOT descriptor declares:

CDAC_GLOBAL_CONTRACT(Thread, n1)
CDAC_GLOBAL_CONTRACT(RuntimeTypeSystem, n1)

However, the managed cDAC reader (CoreCLRContracts.cs:38) only registers c1 versions:

registry.Register<IThread>("c1",static t =>newThread_1(t));

There is no n1 handler anywhere in src/native/managed/cdac/. This means these contracts will not be resolved when diagnosing a NativeAOT process. If this is intentional (placeholder for future NativeAOT-specific contract implementations), consider adding a comment. If it's expected to work now, corresponding contract factories are needed.

Files:src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc (lines ~155-158)

✅ HEAP_ANALYZE guards — Correct fix

HEAP_ANALYZE is only defined when FEATURE_NATIVEAOT is NOT set (gcpriv.h:200-203). Without these guards, the GC data descriptor would fail to compile for NativeAOT. The guards are correctly placed in both datadescriptor.h and datadescriptor.inc, with proper #endif comments.

✅ ThreadStore refactoring — Correct and well-versioned

Moving m_pThreadStore from RuntimeInstance to ThreadStore::s_pThreadStore is consistent with CoreCLR's cDAC pattern. The DebugHeader major version is correctly bumped from 5→6 with appropriate documentation. The SPTR_DECL/SPTR_IMPL pattern matches existing DAC infrastructure. The initialization order in RuntimeInstance::Initialize() correctly assigns the static after g_pTheRuntimeInstance is set.

✅ ManagedDataDescriptorNode — JSON format matches reader expectations

The emitted JSON uses:

  • "!" sigil for value type sizes (matches TypeDescriptorSizeSigil in ContractDescriptorParser)
  • Plain numbers for field offsets (matches FieldDescriptorConverter compact format)
  • "version": 0, "baseline": "empty" top-level properties (match ContractDescriptor schema)

The ContractDescriptor C struct layout (magic, flags, descriptor_size, descriptor ptr, pointer_data_count, pad, pointer_data ptr) matches the shared contract-descriptor.h definition.

✅ WASM exclusion — Consistent

WASM is excluded via if(NOT CLR_CMAKE_TARGET_ARCH_WASM) for both the GC_DESCRIPTOR define and the datadescriptor subdirectory in CMake, and via '$(_targetOS)' != 'browser' for the export in MSBuild targets. This matches the broader WASM exclusion pattern in the NativeAOT Runtime CMakeLists.txt.

✅ GC version initialization — Correct

Adding g_gc_dac_vars.major_version_number and minor_version_number before GC_Initialize matches the CoreCLR pattern and ensures the GC sub-descriptor has version information.

✅ Build system integration — Well structured

The new datadescriptor/CMakeLists.txt correctly uses include(${CLR_DIR}/clrdatadescriptors.cmake), creates separate interface libraries for WKS/SVR GC descriptors, uses EXPORT_VISIBLE only for the main contract descriptor, and properly propagates include directories via nativeaot_runtime_includes.

💡 ManagedDataDescriptorProvider unconditionally added for WASM

ManagedDataDescriptorProvider is always added in Program.cs (lines 266, 278), even for WASM targets where the native datadescriptor isn't built. The ILC-emitted DotNetManagedContractDescriptor symbol is unused dead data on WASM. Non-blocking, but could be gated on !TargetsBrowser for binary size if desired. (Follow-up improvement, not in-scope for this PR.)

💡 DataContractAttribute naming overlap

System.Diagnostics.DataContractAttribute shares its short name with System.Runtime.Serialization.DataContractAttribute. No actual conflict exists (different namespaces, the new one is internal), but it could cause momentary confusion. The naming aligns with cDAC "data contract" terminology so it's appropriate — just noting for awareness.

Generated by Code Review for issue #126972 ·

@MichalStrehovskyMichalStrehovsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Comment threadsrc/coreclr/tools/aot/ILCompiler/Program.cs Outdated
@max-charlamb

Copy link
Copy Markdown
MemberAuthor

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Some of these values are read by the existing cDAC contracts, some will be read by new contracts (in a different repo). We don't have tests automated yet, but it is one of the next items I am working on.

- Simplify GetSection to always use ReadOnlyDataSection
- Add Debug.Assert for header size before emitting JSON
- Remove Phase override (default unordered is fine)
- Gate ManagedDataDescriptorProvider on EnableDebugInfo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 30, 2026 18:33

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/DebugHeader.cpp
Revert GetSection to use DataSection on non-Windows platforms.
Nodes with pointer relocations require writable sections on ELF.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@max-charlamb
max-charlamb merged commit e883467 into mainMay 1, 2026
110 checks passed
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch May 1, 2026 05:02
steveisok added a commit that referenced this pull request May 6, 2026
)
> [!NOTE]
> This PR was authored with assistance from GitHub Copilot.
## Problem
The OBJECT libraries created by `generate_data_descriptors()` in
`src/coreclr/clrdatadescriptors.cmake` compile `contract-descriptor.c`
and `contractpointerdata.cpp` with MSVC defaults, which routes debug
info into the compiler-default `vc140.pdb`. That PDB does not travel
with the `.obj` files when they are archived into a static library such
as `Runtime.ServerGC.lib`.
Downstream linkers — in particular the NativeAOT publish of
`ILCompiler`, `crossgen2`, and `ilasm` on Windows — then emit `LNK4099`
("PDB 'vc140.pdb' was not found") for each affected object, which is
fatal under `/WX`.
## Symptom
The `dotnet/runtime` → `dotnet/dotnet` codeflow PR
[dotnet/dotnet#6423](dotnet/dotnet#6423) is
blocked: the **VMR Vertical Build Windows_x64** and **VMR Vertical Build
Windows_x86** legs both fail with 22 `LNK4099` errors apiece, e.g.:
```
Runtime.ServerGC.lib(contract-descriptor.c.obj) : error LNK4099:
PDB 'vc140.pdb' was not found with 'Runtime.ServerGC.lib(contract-descriptor.c.obj)'
or at '...\artifacts\bin\ILCompiler_publish\x64\Release\native\vc140.pdb';
linking object as if no debug info
[src\coreclr\tools\aot\ILCompiler\ILCompiler_publish.csproj]
Runtime.ServerGC.lib(contractpointerdata.cpp.obj) : error LNK4099: ...
```
repeated for `crossgen2_publish.csproj` and `ilasm.csproj`.
Linux/macOS/WASM/iOS/Android verticals all pass — `LNK4099` is
MSVC-specific.
The regression was introduced by #126972 ("[NativeAOT] Add cDAC data
descriptor infrastructure"), which wired the new descriptor `OBJECT`
libraries into the NativeAOT runtime so they end up archived inside
`Runtime.ServerGC.lib`.
## Fix
Set `COMPILE_PDB_NAME` and `COMPILE_PDB_OUTPUT_DIRECTORY` on
`${LIBRARY}` so each descriptor library produces its own deterministic
PDB that the consuming linker can locate. This matches the convention
already used by `install_static_library` in
`eng/native/functions.cmake`.
## Validation
- CMake reconfigures cleanly.
- Ninja built `nativeaot_gc_svr_descriptor`,
`nativeaot_gc_wks_descriptor`, `nativeaot_cdac_contract_descriptor`, and
`cdac_contract_descriptor` without errors on linux-x64.
- The actual `LNK4099` resolution can only be verified on a Windows
NativeAOT publish leg in CI; please pay particular attention to the
Windows legs and to the next forward-flow into `dotnet/dotnet`.
cc @max-charlamb (author of #126972)
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Steve Pfister <steveisok@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@max-charlamb@jkoritzinsky@jkotas@MichalStrehovsky
, '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

[NativeAOT] Add cDAC data descriptor infrastructure - #126972

Merged
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors
May 1, 2026
Merged

[NativeAOT] Add cDAC data descriptor infrastructure#126972
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors

Conversation

@max-charlamb

@max-charlambmax-charlamb commented Apr 15, 2026

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame, thread link
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • StressLog/ThreadStressLog: Stress log infrastructure (guarded by STRESS_LOG)
  • Globals: ThreadStore static pointer, free object MethodTable, GC bounds, thread state flags, object unmask, stress log
  • Contracts: Thread (n1), Exception (c1), RuntimeTypeSystem (n1), StressLog (c2)
  • Sub-descriptors: GC (workstation + server) and managed type descriptors

ILC managed type descriptor (ManagedDataDescriptorNode)

  • Computes managed type field offsets at compile time in ILC
  • Emits a ContractDescriptor (DotNetManagedContractDescriptor) with JSON-encoded type layouts using Utf8JsonWriter
  • Types and fields discovered via [DataContract] attribute on types in MetadataManager.GetTypesWithEETypes()
  • Type name mangling: System.Threading.Thread -> System_Threading_Thread
  • Referenced by the native descriptor as a sub-descriptor via CDAC_GLOBAL_SUB_DESCRIPTOR
  • Currently registers System.Threading.Thread fields (ManagedThreadId, Name)

GC sub-descriptor

  • Enabled GC sub-descriptor for NativeAOT by setting GC_INTERFACE_*_VERSION before GC_Initialize
  • Added GC_DESCRIPTOR compile definition (guarded on non-WASM)
  • Linked both WKS and SVR GC descriptor objects into Runtime.ServerGC (ServerGC compiles both paths)
  • Added #ifdef HEAP_ANALYZE guards in shared GC datadescriptor files (NativeAOT disables HEAP_ANALYZE)

Attribute-based type discovery

  • [DataContract] attribute in System.Diagnostics namespace (internal, targets Class/Struct/Field)
  • Applied to System.Threading.Thread fields in Thread.NativeAot.cs
  • ILC scans for annotated types in GetTypesWithEETypes() ensuring only types with MethodTables are included

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • nativeaot_runtime_includes interface library captures all Runtime include paths for cross-target compilation
  • Separate GC descriptor targets for workstation and server GC
  • cdac-build-tool enabled for NativeAOT via ClrNativeAotSubset in runtime.proj
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets (WASM excluded)
  • Local copy of cdacdata.h template in Runtime/inc/ (matching GC pattern for self-contained builds)

Key design decisions

  • Contract versions: n1 for NativeAOT-specific contracts, c1/c2 for contracts shared with CoreCLR (same version)
  • ThreadStore: Uses SPTR_DECL/SPTR_IMPL for s_pThreadStore static member, matching CoreCLR pattern
  • Singleton node: ManagedDataDescriptorNode does not override CompareToImpl — follows the ILC singleton pattern (base class throws on duplicates)
  • SList: Unified slist.h shared between CoreCLR VM and NativeAOT Runtime

Validation

  • Build: build.cmd clr.aot+libs -rc release — 0 errors, 0 warnings
  • Symbol verified in Runtime.WorkstationGC.lib via dumpbin
  • cDAC reader tests: 1586/1586 passed
  • tools.cdac tests: All passed
  • Dump inspection: All 3 sub-descriptors verified (main: 4 contracts/11 types/20 globals, managed: System_Threading_Thread with fields, GC: 1 contract/10 types/41 globals)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds cDAC contract descriptor generation to the NativeAOT runtime, plus an ILC-emitted managed sub-descriptor so diagnostic tools can inspect NativeAOT runtime/managed state via the shared contract mechanism.

Changes:

  • Integrates NativeAOT cDAC contract descriptor (and GC sub-descriptors) into the NativeAOT CMake build and runtime libraries.
  • Introduces a managed type layout sub-descriptor emitted by ILC (DotNetManagedContractDescriptor) and wires it into the NativeAOT descriptor as a sub-descriptor.
  • Exposes select private NativeAOT runtime offsets/constants to the descriptor via the cdac_data<T> friend pattern and exports the main contract descriptor symbol for diagnostics.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/coreclr/tools/aot/ILCompiler/Program.csAdds the managed descriptor root provider to ILC compilation roots.
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csprojIncludes new managed descriptor provider/node sources in the build.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ManagedDataDescriptorProvider.csRegisters managed types to be described and roots the descriptor + JSON blob.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ManagedDataDescriptorNode.csEmits a ContractDescriptor-shaped symbol containing JSON type layout data.
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore private offsets for descriptor generation via cdac_data<>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable offsets and flag constants for descriptor consumption via cdac_data<>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incDefines the NativeAOT data descriptor types/globals/contracts and sub-descriptors.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hProvides includes and declares the managed sub-descriptor symbol address for inclusion.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds descriptor generation targets for NativeAOT runtime + GC (wks/svr).
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance private offsets via cdac_data<>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor libraries into WorkstationGC/ServerGC runtime libs.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the datadescriptor subdirectory to the NativeAOT runtime build (non-WASM).
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor symbol for diagnostics on all OSes.
Comments suppressed due to low confidence (1)

src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt:73

  • target_compile_definitions entries should be raw preprocessor symbols (e.g., SERVER_GC), not compiler flags. Passing -DSERVER_GC here will typically result in an invalid definition being forwarded to the compiler. Use SERVER_GC (or SERVER_GC=1) instead.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets Outdated
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlambforce-pushed the dev/max-charlamb/managed-type-descriptors branch from 9462d5c to f226bc3CompareApril 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:53
@max-charlamb
max-charlamb restored the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:54

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 7 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
@github-actions

This comment has been minimized.

CopilotAI review requested due to automatic review settings April 17, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.h
Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.cpp Outdated
CopilotAI review requested due to automatic review settings April 17, 2026 19:44
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 28, 2026 18:35

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MichalStrehovsky Could you please signoff as well?

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

@github-actions

This comment has been minimized.

…ed descriptor
- Remove MethodTable flag constant globals from datadescriptor.inc
and cdac_data<MethodTable> in MethodTable.h — these are already
defined as part of the contract in MethodTableFlags_1.cs
- Add baseline and contracts properties to managed sub-descriptor
JSON for self-describing format consistency
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Copilot Code Review — PR #126972

Note

This review was generated by GitHub Copilot.

Holistic Assessment

Motivation: This PR adds cDAC (data access component) data descriptor infrastructure to NativeAOT, enabling diagnostic tools (debuggers, crash dump analyzers) to inspect NativeAOT runtime state without symbols. This is well-motivated — it's a prerequisite for cDAC support in NativeAOT, analogous to what already exists for CoreCLR.

Approach: The approach is sound — it reuses the existing generate_data_descriptors() CMake infrastructure and shared datadescriptor.cpp machinery. Moving ThreadStore from RuntimeInstance::m_pThreadStore to a static ThreadStore::s_pThreadStore matches the CoreCLR pattern. The managed type descriptor emitted by ILC as a sub-descriptor integrates cleanly with the existing ContractDescriptorParser. The HEAP_ANALYZE guards fix real compilation errors for NativeAOT GC builds.

Summary: ⚠️ Needs Human Review. The implementation is largely correct and well-structured, but there are design questions around contract versioning (n1 vs c1) and its interaction with the cDAC reader that a domain expert should verify. A human reviewer should confirm whether n1 contracts are intentionally non-functional placeholders or need corresponding reader support.


Detailed Findings

⚠️ Contract Versions — n1 not registered in cDAC reader (advisory, not merge-blocking)

The NativeAOT descriptor declares:

CDAC_GLOBAL_CONTRACT(Thread, n1)
CDAC_GLOBAL_CONTRACT(RuntimeTypeSystem, n1)

However, the managed cDAC reader (CoreCLRContracts.cs:38) only registers c1 versions:

registry.Register<IThread>("c1",static t =>newThread_1(t));

There is no n1 handler anywhere in src/native/managed/cdac/. This means these contracts will not be resolved when diagnosing a NativeAOT process. If this is intentional (placeholder for future NativeAOT-specific contract implementations), consider adding a comment. If it's expected to work now, corresponding contract factories are needed.

Files:src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc (lines ~155-158)

✅ HEAP_ANALYZE guards — Correct fix

HEAP_ANALYZE is only defined when FEATURE_NATIVEAOT is NOT set (gcpriv.h:200-203). Without these guards, the GC data descriptor would fail to compile for NativeAOT. The guards are correctly placed in both datadescriptor.h and datadescriptor.inc, with proper #endif comments.

✅ ThreadStore refactoring — Correct and well-versioned

Moving m_pThreadStore from RuntimeInstance to ThreadStore::s_pThreadStore is consistent with CoreCLR's cDAC pattern. The DebugHeader major version is correctly bumped from 5→6 with appropriate documentation. The SPTR_DECL/SPTR_IMPL pattern matches existing DAC infrastructure. The initialization order in RuntimeInstance::Initialize() correctly assigns the static after g_pTheRuntimeInstance is set.

✅ ManagedDataDescriptorNode — JSON format matches reader expectations

The emitted JSON uses:

  • "!" sigil for value type sizes (matches TypeDescriptorSizeSigil in ContractDescriptorParser)
  • Plain numbers for field offsets (matches FieldDescriptorConverter compact format)
  • "version": 0, "baseline": "empty" top-level properties (match ContractDescriptor schema)

The ContractDescriptor C struct layout (magic, flags, descriptor_size, descriptor ptr, pointer_data_count, pad, pointer_data ptr) matches the shared contract-descriptor.h definition.

✅ WASM exclusion — Consistent

WASM is excluded via if(NOT CLR_CMAKE_TARGET_ARCH_WASM) for both the GC_DESCRIPTOR define and the datadescriptor subdirectory in CMake, and via '$(_targetOS)' != 'browser' for the export in MSBuild targets. This matches the broader WASM exclusion pattern in the NativeAOT Runtime CMakeLists.txt.

✅ GC version initialization — Correct

Adding g_gc_dac_vars.major_version_number and minor_version_number before GC_Initialize matches the CoreCLR pattern and ensures the GC sub-descriptor has version information.

✅ Build system integration — Well structured

The new datadescriptor/CMakeLists.txt correctly uses include(${CLR_DIR}/clrdatadescriptors.cmake), creates separate interface libraries for WKS/SVR GC descriptors, uses EXPORT_VISIBLE only for the main contract descriptor, and properly propagates include directories via nativeaot_runtime_includes.

💡 ManagedDataDescriptorProvider unconditionally added for WASM

ManagedDataDescriptorProvider is always added in Program.cs (lines 266, 278), even for WASM targets where the native datadescriptor isn't built. The ILC-emitted DotNetManagedContractDescriptor symbol is unused dead data on WASM. Non-blocking, but could be gated on !TargetsBrowser for binary size if desired. (Follow-up improvement, not in-scope for this PR.)

💡 DataContractAttribute naming overlap

System.Diagnostics.DataContractAttribute shares its short name with System.Runtime.Serialization.DataContractAttribute. No actual conflict exists (different namespaces, the new one is internal), but it could cause momentary confusion. The naming aligns with cDAC "data contract" terminology so it's appropriate — just noting for awareness.

Generated by Code Review for issue #126972 ·

@MichalStrehovskyMichalStrehovsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Comment threadsrc/coreclr/tools/aot/ILCompiler/Program.cs Outdated
@max-charlamb

Copy link
Copy Markdown
MemberAuthor

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Some of these values are read by the existing cDAC contracts, some will be read by new contracts (in a different repo). We don't have tests automated yet, but it is one of the next items I am working on.

- Simplify GetSection to always use ReadOnlyDataSection
- Add Debug.Assert for header size before emitting JSON
- Remove Phase override (default unordered is fine)
- Gate ManagedDataDescriptorProvider on EnableDebugInfo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 30, 2026 18:33

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/DebugHeader.cpp
Revert GetSection to use DataSection on non-Windows platforms.
Nodes with pointer relocations require writable sections on ELF.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@max-charlamb
max-charlamb merged commit e883467 into mainMay 1, 2026
110 checks passed
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch May 1, 2026 05:02
steveisok added a commit that referenced this pull request May 6, 2026
)
> [!NOTE]
> This PR was authored with assistance from GitHub Copilot.
## Problem
The OBJECT libraries created by `generate_data_descriptors()` in
`src/coreclr/clrdatadescriptors.cmake` compile `contract-descriptor.c`
and `contractpointerdata.cpp` with MSVC defaults, which routes debug
info into the compiler-default `vc140.pdb`. That PDB does not travel
with the `.obj` files when they are archived into a static library such
as `Runtime.ServerGC.lib`.
Downstream linkers — in particular the NativeAOT publish of
`ILCompiler`, `crossgen2`, and `ilasm` on Windows — then emit `LNK4099`
("PDB 'vc140.pdb' was not found") for each affected object, which is
fatal under `/WX`.
## Symptom
The `dotnet/runtime` → `dotnet/dotnet` codeflow PR
[dotnet/dotnet#6423](dotnet/dotnet#6423) is
blocked: the **VMR Vertical Build Windows_x64** and **VMR Vertical Build
Windows_x86** legs both fail with 22 `LNK4099` errors apiece, e.g.:
```
Runtime.ServerGC.lib(contract-descriptor.c.obj) : error LNK4099:
PDB 'vc140.pdb' was not found with 'Runtime.ServerGC.lib(contract-descriptor.c.obj)'
or at '...\artifacts\bin\ILCompiler_publish\x64\Release\native\vc140.pdb';
linking object as if no debug info
[src\coreclr\tools\aot\ILCompiler\ILCompiler_publish.csproj]
Runtime.ServerGC.lib(contractpointerdata.cpp.obj) : error LNK4099: ...
```
repeated for `crossgen2_publish.csproj` and `ilasm.csproj`.
Linux/macOS/WASM/iOS/Android verticals all pass — `LNK4099` is
MSVC-specific.
The regression was introduced by #126972 ("[NativeAOT] Add cDAC data
descriptor infrastructure"), which wired the new descriptor `OBJECT`
libraries into the NativeAOT runtime so they end up archived inside
`Runtime.ServerGC.lib`.
## Fix
Set `COMPILE_PDB_NAME` and `COMPILE_PDB_OUTPUT_DIRECTORY` on
`${LIBRARY}` so each descriptor library produces its own deterministic
PDB that the consuming linker can locate. This matches the convention
already used by `install_static_library` in
`eng/native/functions.cmake`.
## Validation
- CMake reconfigures cleanly.
- Ninja built `nativeaot_gc_svr_descriptor`,
`nativeaot_gc_wks_descriptor`, `nativeaot_cdac_contract_descriptor`, and
`cdac_contract_descriptor` without errors on linux-x64.
- The actual `LNK4099` resolution can only be verified on a Windows
NativeAOT publish leg in CI; please pay particular attention to the
Windows legs and to the next forward-flow into `dotnet/dotnet`.
cc @max-charlamb (author of #126972)
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Steve Pfister <steveisok@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@max-charlamb@jkoritzinsky@jkotas@MichalStrehovsky
, '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

[NativeAOT] Add cDAC data descriptor infrastructure - #126972

Merged
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors
May 1, 2026
Merged

[NativeAOT] Add cDAC data descriptor infrastructure#126972
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors

Conversation

@max-charlamb

@max-charlambmax-charlamb commented Apr 15, 2026

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame, thread link
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • StressLog/ThreadStressLog: Stress log infrastructure (guarded by STRESS_LOG)
  • Globals: ThreadStore static pointer, free object MethodTable, GC bounds, thread state flags, object unmask, stress log
  • Contracts: Thread (n1), Exception (c1), RuntimeTypeSystem (n1), StressLog (c2)
  • Sub-descriptors: GC (workstation + server) and managed type descriptors

ILC managed type descriptor (ManagedDataDescriptorNode)

  • Computes managed type field offsets at compile time in ILC
  • Emits a ContractDescriptor (DotNetManagedContractDescriptor) with JSON-encoded type layouts using Utf8JsonWriter
  • Types and fields discovered via [DataContract] attribute on types in MetadataManager.GetTypesWithEETypes()
  • Type name mangling: System.Threading.Thread -> System_Threading_Thread
  • Referenced by the native descriptor as a sub-descriptor via CDAC_GLOBAL_SUB_DESCRIPTOR
  • Currently registers System.Threading.Thread fields (ManagedThreadId, Name)

GC sub-descriptor

  • Enabled GC sub-descriptor for NativeAOT by setting GC_INTERFACE_*_VERSION before GC_Initialize
  • Added GC_DESCRIPTOR compile definition (guarded on non-WASM)
  • Linked both WKS and SVR GC descriptor objects into Runtime.ServerGC (ServerGC compiles both paths)
  • Added #ifdef HEAP_ANALYZE guards in shared GC datadescriptor files (NativeAOT disables HEAP_ANALYZE)

Attribute-based type discovery

  • [DataContract] attribute in System.Diagnostics namespace (internal, targets Class/Struct/Field)
  • Applied to System.Threading.Thread fields in Thread.NativeAot.cs
  • ILC scans for annotated types in GetTypesWithEETypes() ensuring only types with MethodTables are included

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • nativeaot_runtime_includes interface library captures all Runtime include paths for cross-target compilation
  • Separate GC descriptor targets for workstation and server GC
  • cdac-build-tool enabled for NativeAOT via ClrNativeAotSubset in runtime.proj
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets (WASM excluded)
  • Local copy of cdacdata.h template in Runtime/inc/ (matching GC pattern for self-contained builds)

Key design decisions

  • Contract versions: n1 for NativeAOT-specific contracts, c1/c2 for contracts shared with CoreCLR (same version)
  • ThreadStore: Uses SPTR_DECL/SPTR_IMPL for s_pThreadStore static member, matching CoreCLR pattern
  • Singleton node: ManagedDataDescriptorNode does not override CompareToImpl — follows the ILC singleton pattern (base class throws on duplicates)
  • SList: Unified slist.h shared between CoreCLR VM and NativeAOT Runtime

Validation

  • Build: build.cmd clr.aot+libs -rc release — 0 errors, 0 warnings
  • Symbol verified in Runtime.WorkstationGC.lib via dumpbin
  • cDAC reader tests: 1586/1586 passed
  • tools.cdac tests: All passed
  • Dump inspection: All 3 sub-descriptors verified (main: 4 contracts/11 types/20 globals, managed: System_Threading_Thread with fields, GC: 1 contract/10 types/41 globals)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds cDAC contract descriptor generation to the NativeAOT runtime, plus an ILC-emitted managed sub-descriptor so diagnostic tools can inspect NativeAOT runtime/managed state via the shared contract mechanism.

Changes:

  • Integrates NativeAOT cDAC contract descriptor (and GC sub-descriptors) into the NativeAOT CMake build and runtime libraries.
  • Introduces a managed type layout sub-descriptor emitted by ILC (DotNetManagedContractDescriptor) and wires it into the NativeAOT descriptor as a sub-descriptor.
  • Exposes select private NativeAOT runtime offsets/constants to the descriptor via the cdac_data<T> friend pattern and exports the main contract descriptor symbol for diagnostics.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/coreclr/tools/aot/ILCompiler/Program.csAdds the managed descriptor root provider to ILC compilation roots.
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csprojIncludes new managed descriptor provider/node sources in the build.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ManagedDataDescriptorProvider.csRegisters managed types to be described and roots the descriptor + JSON blob.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ManagedDataDescriptorNode.csEmits a ContractDescriptor-shaped symbol containing JSON type layout data.
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore private offsets for descriptor generation via cdac_data<>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable offsets and flag constants for descriptor consumption via cdac_data<>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incDefines the NativeAOT data descriptor types/globals/contracts and sub-descriptors.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hProvides includes and declares the managed sub-descriptor symbol address for inclusion.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds descriptor generation targets for NativeAOT runtime + GC (wks/svr).
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance private offsets via cdac_data<>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor libraries into WorkstationGC/ServerGC runtime libs.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the datadescriptor subdirectory to the NativeAOT runtime build (non-WASM).
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor symbol for diagnostics on all OSes.
Comments suppressed due to low confidence (1)

src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt:73

  • target_compile_definitions entries should be raw preprocessor symbols (e.g., SERVER_GC), not compiler flags. Passing -DSERVER_GC here will typically result in an invalid definition being forwarded to the compiler. Use SERVER_GC (or SERVER_GC=1) instead.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets Outdated
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlambforce-pushed the dev/max-charlamb/managed-type-descriptors branch from 9462d5c to f226bc3CompareApril 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:53
@max-charlamb
max-charlamb restored the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:54

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 7 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
@github-actions

This comment has been minimized.

CopilotAI review requested due to automatic review settings April 17, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.h
Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.cpp Outdated
CopilotAI review requested due to automatic review settings April 17, 2026 19:44
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 28, 2026 18:35

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MichalStrehovsky Could you please signoff as well?

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

@github-actions

This comment has been minimized.

…ed descriptor
- Remove MethodTable flag constant globals from datadescriptor.inc
and cdac_data<MethodTable> in MethodTable.h — these are already
defined as part of the contract in MethodTableFlags_1.cs
- Add baseline and contracts properties to managed sub-descriptor
JSON for self-describing format consistency
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Copilot Code Review — PR #126972

Note

This review was generated by GitHub Copilot.

Holistic Assessment

Motivation: This PR adds cDAC (data access component) data descriptor infrastructure to NativeAOT, enabling diagnostic tools (debuggers, crash dump analyzers) to inspect NativeAOT runtime state without symbols. This is well-motivated — it's a prerequisite for cDAC support in NativeAOT, analogous to what already exists for CoreCLR.

Approach: The approach is sound — it reuses the existing generate_data_descriptors() CMake infrastructure and shared datadescriptor.cpp machinery. Moving ThreadStore from RuntimeInstance::m_pThreadStore to a static ThreadStore::s_pThreadStore matches the CoreCLR pattern. The managed type descriptor emitted by ILC as a sub-descriptor integrates cleanly with the existing ContractDescriptorParser. The HEAP_ANALYZE guards fix real compilation errors for NativeAOT GC builds.

Summary: ⚠️ Needs Human Review. The implementation is largely correct and well-structured, but there are design questions around contract versioning (n1 vs c1) and its interaction with the cDAC reader that a domain expert should verify. A human reviewer should confirm whether n1 contracts are intentionally non-functional placeholders or need corresponding reader support.


Detailed Findings

⚠️ Contract Versions — n1 not registered in cDAC reader (advisory, not merge-blocking)

The NativeAOT descriptor declares:

CDAC_GLOBAL_CONTRACT(Thread, n1)
CDAC_GLOBAL_CONTRACT(RuntimeTypeSystem, n1)

However, the managed cDAC reader (CoreCLRContracts.cs:38) only registers c1 versions:

registry.Register<IThread>("c1",static t =>newThread_1(t));

There is no n1 handler anywhere in src/native/managed/cdac/. This means these contracts will not be resolved when diagnosing a NativeAOT process. If this is intentional (placeholder for future NativeAOT-specific contract implementations), consider adding a comment. If it's expected to work now, corresponding contract factories are needed.

Files:src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc (lines ~155-158)

✅ HEAP_ANALYZE guards — Correct fix

HEAP_ANALYZE is only defined when FEATURE_NATIVEAOT is NOT set (gcpriv.h:200-203). Without these guards, the GC data descriptor would fail to compile for NativeAOT. The guards are correctly placed in both datadescriptor.h and datadescriptor.inc, with proper #endif comments.

✅ ThreadStore refactoring — Correct and well-versioned

Moving m_pThreadStore from RuntimeInstance to ThreadStore::s_pThreadStore is consistent with CoreCLR's cDAC pattern. The DebugHeader major version is correctly bumped from 5→6 with appropriate documentation. The SPTR_DECL/SPTR_IMPL pattern matches existing DAC infrastructure. The initialization order in RuntimeInstance::Initialize() correctly assigns the static after g_pTheRuntimeInstance is set.

✅ ManagedDataDescriptorNode — JSON format matches reader expectations

The emitted JSON uses:

  • "!" sigil for value type sizes (matches TypeDescriptorSizeSigil in ContractDescriptorParser)
  • Plain numbers for field offsets (matches FieldDescriptorConverter compact format)
  • "version": 0, "baseline": "empty" top-level properties (match ContractDescriptor schema)

The ContractDescriptor C struct layout (magic, flags, descriptor_size, descriptor ptr, pointer_data_count, pad, pointer_data ptr) matches the shared contract-descriptor.h definition.

✅ WASM exclusion — Consistent

WASM is excluded via if(NOT CLR_CMAKE_TARGET_ARCH_WASM) for both the GC_DESCRIPTOR define and the datadescriptor subdirectory in CMake, and via '$(_targetOS)' != 'browser' for the export in MSBuild targets. This matches the broader WASM exclusion pattern in the NativeAOT Runtime CMakeLists.txt.

✅ GC version initialization — Correct

Adding g_gc_dac_vars.major_version_number and minor_version_number before GC_Initialize matches the CoreCLR pattern and ensures the GC sub-descriptor has version information.

✅ Build system integration — Well structured

The new datadescriptor/CMakeLists.txt correctly uses include(${CLR_DIR}/clrdatadescriptors.cmake), creates separate interface libraries for WKS/SVR GC descriptors, uses EXPORT_VISIBLE only for the main contract descriptor, and properly propagates include directories via nativeaot_runtime_includes.

💡 ManagedDataDescriptorProvider unconditionally added for WASM

ManagedDataDescriptorProvider is always added in Program.cs (lines 266, 278), even for WASM targets where the native datadescriptor isn't built. The ILC-emitted DotNetManagedContractDescriptor symbol is unused dead data on WASM. Non-blocking, but could be gated on !TargetsBrowser for binary size if desired. (Follow-up improvement, not in-scope for this PR.)

💡 DataContractAttribute naming overlap

System.Diagnostics.DataContractAttribute shares its short name with System.Runtime.Serialization.DataContractAttribute. No actual conflict exists (different namespaces, the new one is internal), but it could cause momentary confusion. The naming aligns with cDAC "data contract" terminology so it's appropriate — just noting for awareness.

Generated by Code Review for issue #126972 ·

@MichalStrehovskyMichalStrehovsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Comment threadsrc/coreclr/tools/aot/ILCompiler/Program.cs Outdated
@max-charlamb

Copy link
Copy Markdown
MemberAuthor

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Some of these values are read by the existing cDAC contracts, some will be read by new contracts (in a different repo). We don't have tests automated yet, but it is one of the next items I am working on.

- Simplify GetSection to always use ReadOnlyDataSection
- Add Debug.Assert for header size before emitting JSON
- Remove Phase override (default unordered is fine)
- Gate ManagedDataDescriptorProvider on EnableDebugInfo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 30, 2026 18:33

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/DebugHeader.cpp
Revert GetSection to use DataSection on non-Windows platforms.
Nodes with pointer relocations require writable sections on ELF.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@max-charlamb
max-charlamb merged commit e883467 into mainMay 1, 2026
110 checks passed
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch May 1, 2026 05:02
steveisok added a commit that referenced this pull request May 6, 2026
)
> [!NOTE]
> This PR was authored with assistance from GitHub Copilot.
## Problem
The OBJECT libraries created by `generate_data_descriptors()` in
`src/coreclr/clrdatadescriptors.cmake` compile `contract-descriptor.c`
and `contractpointerdata.cpp` with MSVC defaults, which routes debug
info into the compiler-default `vc140.pdb`. That PDB does not travel
with the `.obj` files when they are archived into a static library such
as `Runtime.ServerGC.lib`.
Downstream linkers — in particular the NativeAOT publish of
`ILCompiler`, `crossgen2`, and `ilasm` on Windows — then emit `LNK4099`
("PDB 'vc140.pdb' was not found") for each affected object, which is
fatal under `/WX`.
## Symptom
The `dotnet/runtime` → `dotnet/dotnet` codeflow PR
[dotnet/dotnet#6423](dotnet/dotnet#6423) is
blocked: the **VMR Vertical Build Windows_x64** and **VMR Vertical Build
Windows_x86** legs both fail with 22 `LNK4099` errors apiece, e.g.:
```
Runtime.ServerGC.lib(contract-descriptor.c.obj) : error LNK4099:
PDB 'vc140.pdb' was not found with 'Runtime.ServerGC.lib(contract-descriptor.c.obj)'
or at '...\artifacts\bin\ILCompiler_publish\x64\Release\native\vc140.pdb';
linking object as if no debug info
[src\coreclr\tools\aot\ILCompiler\ILCompiler_publish.csproj]
Runtime.ServerGC.lib(contractpointerdata.cpp.obj) : error LNK4099: ...
```
repeated for `crossgen2_publish.csproj` and `ilasm.csproj`.
Linux/macOS/WASM/iOS/Android verticals all pass — `LNK4099` is
MSVC-specific.
The regression was introduced by #126972 ("[NativeAOT] Add cDAC data
descriptor infrastructure"), which wired the new descriptor `OBJECT`
libraries into the NativeAOT runtime so they end up archived inside
`Runtime.ServerGC.lib`.
## Fix
Set `COMPILE_PDB_NAME` and `COMPILE_PDB_OUTPUT_DIRECTORY` on
`${LIBRARY}` so each descriptor library produces its own deterministic
PDB that the consuming linker can locate. This matches the convention
already used by `install_static_library` in
`eng/native/functions.cmake`.
## Validation
- CMake reconfigures cleanly.
- Ninja built `nativeaot_gc_svr_descriptor`,
`nativeaot_gc_wks_descriptor`, `nativeaot_cdac_contract_descriptor`, and
`cdac_contract_descriptor` without errors on linux-x64.
- The actual `LNK4099` resolution can only be verified on a Windows
NativeAOT publish leg in CI; please pay particular attention to the
Windows legs and to the next forward-flow into `dotnet/dotnet`.
cc @max-charlamb (author of #126972)
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Steve Pfister <steveisok@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@max-charlamb@jkoritzinsky@jkotas@MichalStrehovsky
, '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

[NativeAOT] Add cDAC data descriptor infrastructure - #126972

Merged
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors
May 1, 2026
Merged

[NativeAOT] Add cDAC data descriptor infrastructure#126972
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors

Conversation

@max-charlamb

@max-charlambmax-charlamb commented Apr 15, 2026

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame, thread link
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • StressLog/ThreadStressLog: Stress log infrastructure (guarded by STRESS_LOG)
  • Globals: ThreadStore static pointer, free object MethodTable, GC bounds, thread state flags, object unmask, stress log
  • Contracts: Thread (n1), Exception (c1), RuntimeTypeSystem (n1), StressLog (c2)
  • Sub-descriptors: GC (workstation + server) and managed type descriptors

ILC managed type descriptor (ManagedDataDescriptorNode)

  • Computes managed type field offsets at compile time in ILC
  • Emits a ContractDescriptor (DotNetManagedContractDescriptor) with JSON-encoded type layouts using Utf8JsonWriter
  • Types and fields discovered via [DataContract] attribute on types in MetadataManager.GetTypesWithEETypes()
  • Type name mangling: System.Threading.Thread -> System_Threading_Thread
  • Referenced by the native descriptor as a sub-descriptor via CDAC_GLOBAL_SUB_DESCRIPTOR
  • Currently registers System.Threading.Thread fields (ManagedThreadId, Name)

GC sub-descriptor

  • Enabled GC sub-descriptor for NativeAOT by setting GC_INTERFACE_*_VERSION before GC_Initialize
  • Added GC_DESCRIPTOR compile definition (guarded on non-WASM)
  • Linked both WKS and SVR GC descriptor objects into Runtime.ServerGC (ServerGC compiles both paths)
  • Added #ifdef HEAP_ANALYZE guards in shared GC datadescriptor files (NativeAOT disables HEAP_ANALYZE)

Attribute-based type discovery

  • [DataContract] attribute in System.Diagnostics namespace (internal, targets Class/Struct/Field)
  • Applied to System.Threading.Thread fields in Thread.NativeAot.cs
  • ILC scans for annotated types in GetTypesWithEETypes() ensuring only types with MethodTables are included

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • nativeaot_runtime_includes interface library captures all Runtime include paths for cross-target compilation
  • Separate GC descriptor targets for workstation and server GC
  • cdac-build-tool enabled for NativeAOT via ClrNativeAotSubset in runtime.proj
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets (WASM excluded)
  • Local copy of cdacdata.h template in Runtime/inc/ (matching GC pattern for self-contained builds)

Key design decisions

  • Contract versions: n1 for NativeAOT-specific contracts, c1/c2 for contracts shared with CoreCLR (same version)
  • ThreadStore: Uses SPTR_DECL/SPTR_IMPL for s_pThreadStore static member, matching CoreCLR pattern
  • Singleton node: ManagedDataDescriptorNode does not override CompareToImpl — follows the ILC singleton pattern (base class throws on duplicates)
  • SList: Unified slist.h shared between CoreCLR VM and NativeAOT Runtime

Validation

  • Build: build.cmd clr.aot+libs -rc release — 0 errors, 0 warnings
  • Symbol verified in Runtime.WorkstationGC.lib via dumpbin
  • cDAC reader tests: 1586/1586 passed
  • tools.cdac tests: All passed
  • Dump inspection: All 3 sub-descriptors verified (main: 4 contracts/11 types/20 globals, managed: System_Threading_Thread with fields, GC: 1 contract/10 types/41 globals)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds cDAC contract descriptor generation to the NativeAOT runtime, plus an ILC-emitted managed sub-descriptor so diagnostic tools can inspect NativeAOT runtime/managed state via the shared contract mechanism.

Changes:

  • Integrates NativeAOT cDAC contract descriptor (and GC sub-descriptors) into the NativeAOT CMake build and runtime libraries.
  • Introduces a managed type layout sub-descriptor emitted by ILC (DotNetManagedContractDescriptor) and wires it into the NativeAOT descriptor as a sub-descriptor.
  • Exposes select private NativeAOT runtime offsets/constants to the descriptor via the cdac_data<T> friend pattern and exports the main contract descriptor symbol for diagnostics.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/coreclr/tools/aot/ILCompiler/Program.csAdds the managed descriptor root provider to ILC compilation roots.
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csprojIncludes new managed descriptor provider/node sources in the build.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ManagedDataDescriptorProvider.csRegisters managed types to be described and roots the descriptor + JSON blob.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ManagedDataDescriptorNode.csEmits a ContractDescriptor-shaped symbol containing JSON type layout data.
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore private offsets for descriptor generation via cdac_data<>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable offsets and flag constants for descriptor consumption via cdac_data<>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incDefines the NativeAOT data descriptor types/globals/contracts and sub-descriptors.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hProvides includes and declares the managed sub-descriptor symbol address for inclusion.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds descriptor generation targets for NativeAOT runtime + GC (wks/svr).
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance private offsets via cdac_data<>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor libraries into WorkstationGC/ServerGC runtime libs.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the datadescriptor subdirectory to the NativeAOT runtime build (non-WASM).
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor symbol for diagnostics on all OSes.
Comments suppressed due to low confidence (1)

src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt:73

  • target_compile_definitions entries should be raw preprocessor symbols (e.g., SERVER_GC), not compiler flags. Passing -DSERVER_GC here will typically result in an invalid definition being forwarded to the compiler. Use SERVER_GC (or SERVER_GC=1) instead.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets Outdated
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlambforce-pushed the dev/max-charlamb/managed-type-descriptors branch from 9462d5c to f226bc3CompareApril 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:53
@max-charlamb
max-charlamb restored the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:54

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 7 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
@github-actions

This comment has been minimized.

CopilotAI review requested due to automatic review settings April 17, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.h
Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.cpp Outdated
CopilotAI review requested due to automatic review settings April 17, 2026 19:44
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 28, 2026 18:35

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MichalStrehovsky Could you please signoff as well?

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

@github-actions

This comment has been minimized.

…ed descriptor
- Remove MethodTable flag constant globals from datadescriptor.inc
and cdac_data<MethodTable> in MethodTable.h — these are already
defined as part of the contract in MethodTableFlags_1.cs
- Add baseline and contracts properties to managed sub-descriptor
JSON for self-describing format consistency
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Copilot Code Review — PR #126972

Note

This review was generated by GitHub Copilot.

Holistic Assessment

Motivation: This PR adds cDAC (data access component) data descriptor infrastructure to NativeAOT, enabling diagnostic tools (debuggers, crash dump analyzers) to inspect NativeAOT runtime state without symbols. This is well-motivated — it's a prerequisite for cDAC support in NativeAOT, analogous to what already exists for CoreCLR.

Approach: The approach is sound — it reuses the existing generate_data_descriptors() CMake infrastructure and shared datadescriptor.cpp machinery. Moving ThreadStore from RuntimeInstance::m_pThreadStore to a static ThreadStore::s_pThreadStore matches the CoreCLR pattern. The managed type descriptor emitted by ILC as a sub-descriptor integrates cleanly with the existing ContractDescriptorParser. The HEAP_ANALYZE guards fix real compilation errors for NativeAOT GC builds.

Summary: ⚠️ Needs Human Review. The implementation is largely correct and well-structured, but there are design questions around contract versioning (n1 vs c1) and its interaction with the cDAC reader that a domain expert should verify. A human reviewer should confirm whether n1 contracts are intentionally non-functional placeholders or need corresponding reader support.


Detailed Findings

⚠️ Contract Versions — n1 not registered in cDAC reader (advisory, not merge-blocking)

The NativeAOT descriptor declares:

CDAC_GLOBAL_CONTRACT(Thread, n1)
CDAC_GLOBAL_CONTRACT(RuntimeTypeSystem, n1)

However, the managed cDAC reader (CoreCLRContracts.cs:38) only registers c1 versions:

registry.Register<IThread>("c1",static t =>newThread_1(t));

There is no n1 handler anywhere in src/native/managed/cdac/. This means these contracts will not be resolved when diagnosing a NativeAOT process. If this is intentional (placeholder for future NativeAOT-specific contract implementations), consider adding a comment. If it's expected to work now, corresponding contract factories are needed.

Files:src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc (lines ~155-158)

✅ HEAP_ANALYZE guards — Correct fix

HEAP_ANALYZE is only defined when FEATURE_NATIVEAOT is NOT set (gcpriv.h:200-203). Without these guards, the GC data descriptor would fail to compile for NativeAOT. The guards are correctly placed in both datadescriptor.h and datadescriptor.inc, with proper #endif comments.

✅ ThreadStore refactoring — Correct and well-versioned

Moving m_pThreadStore from RuntimeInstance to ThreadStore::s_pThreadStore is consistent with CoreCLR's cDAC pattern. The DebugHeader major version is correctly bumped from 5→6 with appropriate documentation. The SPTR_DECL/SPTR_IMPL pattern matches existing DAC infrastructure. The initialization order in RuntimeInstance::Initialize() correctly assigns the static after g_pTheRuntimeInstance is set.

✅ ManagedDataDescriptorNode — JSON format matches reader expectations

The emitted JSON uses:

  • "!" sigil for value type sizes (matches TypeDescriptorSizeSigil in ContractDescriptorParser)
  • Plain numbers for field offsets (matches FieldDescriptorConverter compact format)
  • "version": 0, "baseline": "empty" top-level properties (match ContractDescriptor schema)

The ContractDescriptor C struct layout (magic, flags, descriptor_size, descriptor ptr, pointer_data_count, pad, pointer_data ptr) matches the shared contract-descriptor.h definition.

✅ WASM exclusion — Consistent

WASM is excluded via if(NOT CLR_CMAKE_TARGET_ARCH_WASM) for both the GC_DESCRIPTOR define and the datadescriptor subdirectory in CMake, and via '$(_targetOS)' != 'browser' for the export in MSBuild targets. This matches the broader WASM exclusion pattern in the NativeAOT Runtime CMakeLists.txt.

✅ GC version initialization — Correct

Adding g_gc_dac_vars.major_version_number and minor_version_number before GC_Initialize matches the CoreCLR pattern and ensures the GC sub-descriptor has version information.

✅ Build system integration — Well structured

The new datadescriptor/CMakeLists.txt correctly uses include(${CLR_DIR}/clrdatadescriptors.cmake), creates separate interface libraries for WKS/SVR GC descriptors, uses EXPORT_VISIBLE only for the main contract descriptor, and properly propagates include directories via nativeaot_runtime_includes.

💡 ManagedDataDescriptorProvider unconditionally added for WASM

ManagedDataDescriptorProvider is always added in Program.cs (lines 266, 278), even for WASM targets where the native datadescriptor isn't built. The ILC-emitted DotNetManagedContractDescriptor symbol is unused dead data on WASM. Non-blocking, but could be gated on !TargetsBrowser for binary size if desired. (Follow-up improvement, not in-scope for this PR.)

💡 DataContractAttribute naming overlap

System.Diagnostics.DataContractAttribute shares its short name with System.Runtime.Serialization.DataContractAttribute. No actual conflict exists (different namespaces, the new one is internal), but it could cause momentary confusion. The naming aligns with cDAC "data contract" terminology so it's appropriate — just noting for awareness.

Generated by Code Review for issue #126972 ·

@MichalStrehovskyMichalStrehovsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Comment threadsrc/coreclr/tools/aot/ILCompiler/Program.cs Outdated
@max-charlamb

Copy link
Copy Markdown
MemberAuthor

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Some of these values are read by the existing cDAC contracts, some will be read by new contracts (in a different repo). We don't have tests automated yet, but it is one of the next items I am working on.

- Simplify GetSection to always use ReadOnlyDataSection
- Add Debug.Assert for header size before emitting JSON
- Remove Phase override (default unordered is fine)
- Gate ManagedDataDescriptorProvider on EnableDebugInfo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 30, 2026 18:33

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/DebugHeader.cpp
Revert GetSection to use DataSection on non-Windows platforms.
Nodes with pointer relocations require writable sections on ELF.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@max-charlamb
max-charlamb merged commit e883467 into mainMay 1, 2026
110 checks passed
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch May 1, 2026 05:02
steveisok added a commit that referenced this pull request May 6, 2026
)
> [!NOTE]
> This PR was authored with assistance from GitHub Copilot.
## Problem
The OBJECT libraries created by `generate_data_descriptors()` in
`src/coreclr/clrdatadescriptors.cmake` compile `contract-descriptor.c`
and `contractpointerdata.cpp` with MSVC defaults, which routes debug
info into the compiler-default `vc140.pdb`. That PDB does not travel
with the `.obj` files when they are archived into a static library such
as `Runtime.ServerGC.lib`.
Downstream linkers — in particular the NativeAOT publish of
`ILCompiler`, `crossgen2`, and `ilasm` on Windows — then emit `LNK4099`
("PDB 'vc140.pdb' was not found") for each affected object, which is
fatal under `/WX`.
## Symptom
The `dotnet/runtime` → `dotnet/dotnet` codeflow PR
[dotnet/dotnet#6423](dotnet/dotnet#6423) is
blocked: the **VMR Vertical Build Windows_x64** and **VMR Vertical Build
Windows_x86** legs both fail with 22 `LNK4099` errors apiece, e.g.:
```
Runtime.ServerGC.lib(contract-descriptor.c.obj) : error LNK4099:
PDB 'vc140.pdb' was not found with 'Runtime.ServerGC.lib(contract-descriptor.c.obj)'
or at '...\artifacts\bin\ILCompiler_publish\x64\Release\native\vc140.pdb';
linking object as if no debug info
[src\coreclr\tools\aot\ILCompiler\ILCompiler_publish.csproj]
Runtime.ServerGC.lib(contractpointerdata.cpp.obj) : error LNK4099: ...
```
repeated for `crossgen2_publish.csproj` and `ilasm.csproj`.
Linux/macOS/WASM/iOS/Android verticals all pass — `LNK4099` is
MSVC-specific.
The regression was introduced by #126972 ("[NativeAOT] Add cDAC data
descriptor infrastructure"), which wired the new descriptor `OBJECT`
libraries into the NativeAOT runtime so they end up archived inside
`Runtime.ServerGC.lib`.
## Fix
Set `COMPILE_PDB_NAME` and `COMPILE_PDB_OUTPUT_DIRECTORY` on
`${LIBRARY}` so each descriptor library produces its own deterministic
PDB that the consuming linker can locate. This matches the convention
already used by `install_static_library` in
`eng/native/functions.cmake`.
## Validation
- CMake reconfigures cleanly.
- Ninja built `nativeaot_gc_svr_descriptor`,
`nativeaot_gc_wks_descriptor`, `nativeaot_cdac_contract_descriptor`, and
`cdac_contract_descriptor` without errors on linux-x64.
- The actual `LNK4099` resolution can only be verified on a Windows
NativeAOT publish leg in CI; please pay particular attention to the
Windows legs and to the next forward-flow into `dotnet/dotnet`.
cc @max-charlamb (author of #126972)
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Steve Pfister <steveisok@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@max-charlamb@jkoritzinsky@jkotas@MichalStrehovsky
, '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

[NativeAOT] Add cDAC data descriptor infrastructure - #126972

Merged
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors
May 1, 2026
Merged

[NativeAOT] Add cDAC data descriptor infrastructure#126972
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors

Conversation

@max-charlamb

@max-charlambmax-charlamb commented Apr 15, 2026

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame, thread link
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • StressLog/ThreadStressLog: Stress log infrastructure (guarded by STRESS_LOG)
  • Globals: ThreadStore static pointer, free object MethodTable, GC bounds, thread state flags, object unmask, stress log
  • Contracts: Thread (n1), Exception (c1), RuntimeTypeSystem (n1), StressLog (c2)
  • Sub-descriptors: GC (workstation + server) and managed type descriptors

ILC managed type descriptor (ManagedDataDescriptorNode)

  • Computes managed type field offsets at compile time in ILC
  • Emits a ContractDescriptor (DotNetManagedContractDescriptor) with JSON-encoded type layouts using Utf8JsonWriter
  • Types and fields discovered via [DataContract] attribute on types in MetadataManager.GetTypesWithEETypes()
  • Type name mangling: System.Threading.Thread -> System_Threading_Thread
  • Referenced by the native descriptor as a sub-descriptor via CDAC_GLOBAL_SUB_DESCRIPTOR
  • Currently registers System.Threading.Thread fields (ManagedThreadId, Name)

GC sub-descriptor

  • Enabled GC sub-descriptor for NativeAOT by setting GC_INTERFACE_*_VERSION before GC_Initialize
  • Added GC_DESCRIPTOR compile definition (guarded on non-WASM)
  • Linked both WKS and SVR GC descriptor objects into Runtime.ServerGC (ServerGC compiles both paths)
  • Added #ifdef HEAP_ANALYZE guards in shared GC datadescriptor files (NativeAOT disables HEAP_ANALYZE)

Attribute-based type discovery

  • [DataContract] attribute in System.Diagnostics namespace (internal, targets Class/Struct/Field)
  • Applied to System.Threading.Thread fields in Thread.NativeAot.cs
  • ILC scans for annotated types in GetTypesWithEETypes() ensuring only types with MethodTables are included

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • nativeaot_runtime_includes interface library captures all Runtime include paths for cross-target compilation
  • Separate GC descriptor targets for workstation and server GC
  • cdac-build-tool enabled for NativeAOT via ClrNativeAotSubset in runtime.proj
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets (WASM excluded)
  • Local copy of cdacdata.h template in Runtime/inc/ (matching GC pattern for self-contained builds)

Key design decisions

  • Contract versions: n1 for NativeAOT-specific contracts, c1/c2 for contracts shared with CoreCLR (same version)
  • ThreadStore: Uses SPTR_DECL/SPTR_IMPL for s_pThreadStore static member, matching CoreCLR pattern
  • Singleton node: ManagedDataDescriptorNode does not override CompareToImpl — follows the ILC singleton pattern (base class throws on duplicates)
  • SList: Unified slist.h shared between CoreCLR VM and NativeAOT Runtime

Validation

  • Build: build.cmd clr.aot+libs -rc release — 0 errors, 0 warnings
  • Symbol verified in Runtime.WorkstationGC.lib via dumpbin
  • cDAC reader tests: 1586/1586 passed
  • tools.cdac tests: All passed
  • Dump inspection: All 3 sub-descriptors verified (main: 4 contracts/11 types/20 globals, managed: System_Threading_Thread with fields, GC: 1 contract/10 types/41 globals)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds cDAC contract descriptor generation to the NativeAOT runtime, plus an ILC-emitted managed sub-descriptor so diagnostic tools can inspect NativeAOT runtime/managed state via the shared contract mechanism.

Changes:

  • Integrates NativeAOT cDAC contract descriptor (and GC sub-descriptors) into the NativeAOT CMake build and runtime libraries.
  • Introduces a managed type layout sub-descriptor emitted by ILC (DotNetManagedContractDescriptor) and wires it into the NativeAOT descriptor as a sub-descriptor.
  • Exposes select private NativeAOT runtime offsets/constants to the descriptor via the cdac_data<T> friend pattern and exports the main contract descriptor symbol for diagnostics.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/coreclr/tools/aot/ILCompiler/Program.csAdds the managed descriptor root provider to ILC compilation roots.
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csprojIncludes new managed descriptor provider/node sources in the build.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ManagedDataDescriptorProvider.csRegisters managed types to be described and roots the descriptor + JSON blob.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ManagedDataDescriptorNode.csEmits a ContractDescriptor-shaped symbol containing JSON type layout data.
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore private offsets for descriptor generation via cdac_data<>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable offsets and flag constants for descriptor consumption via cdac_data<>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incDefines the NativeAOT data descriptor types/globals/contracts and sub-descriptors.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hProvides includes and declares the managed sub-descriptor symbol address for inclusion.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds descriptor generation targets for NativeAOT runtime + GC (wks/svr).
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance private offsets via cdac_data<>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor libraries into WorkstationGC/ServerGC runtime libs.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the datadescriptor subdirectory to the NativeAOT runtime build (non-WASM).
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor symbol for diagnostics on all OSes.
Comments suppressed due to low confidence (1)

src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt:73

  • target_compile_definitions entries should be raw preprocessor symbols (e.g., SERVER_GC), not compiler flags. Passing -DSERVER_GC here will typically result in an invalid definition being forwarded to the compiler. Use SERVER_GC (or SERVER_GC=1) instead.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets Outdated
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlambforce-pushed the dev/max-charlamb/managed-type-descriptors branch from 9462d5c to f226bc3CompareApril 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:53
@max-charlamb
max-charlamb restored the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:54

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 7 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
@github-actions

This comment has been minimized.

CopilotAI review requested due to automatic review settings April 17, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.h
Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.cpp Outdated
CopilotAI review requested due to automatic review settings April 17, 2026 19:44
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 28, 2026 18:35

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MichalStrehovsky Could you please signoff as well?

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

@github-actions

This comment has been minimized.

…ed descriptor
- Remove MethodTable flag constant globals from datadescriptor.inc
and cdac_data<MethodTable> in MethodTable.h — these are already
defined as part of the contract in MethodTableFlags_1.cs
- Add baseline and contracts properties to managed sub-descriptor
JSON for self-describing format consistency
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Copilot Code Review — PR #126972

Note

This review was generated by GitHub Copilot.

Holistic Assessment

Motivation: This PR adds cDAC (data access component) data descriptor infrastructure to NativeAOT, enabling diagnostic tools (debuggers, crash dump analyzers) to inspect NativeAOT runtime state without symbols. This is well-motivated — it's a prerequisite for cDAC support in NativeAOT, analogous to what already exists for CoreCLR.

Approach: The approach is sound — it reuses the existing generate_data_descriptors() CMake infrastructure and shared datadescriptor.cpp machinery. Moving ThreadStore from RuntimeInstance::m_pThreadStore to a static ThreadStore::s_pThreadStore matches the CoreCLR pattern. The managed type descriptor emitted by ILC as a sub-descriptor integrates cleanly with the existing ContractDescriptorParser. The HEAP_ANALYZE guards fix real compilation errors for NativeAOT GC builds.

Summary: ⚠️ Needs Human Review. The implementation is largely correct and well-structured, but there are design questions around contract versioning (n1 vs c1) and its interaction with the cDAC reader that a domain expert should verify. A human reviewer should confirm whether n1 contracts are intentionally non-functional placeholders or need corresponding reader support.


Detailed Findings

⚠️ Contract Versions — n1 not registered in cDAC reader (advisory, not merge-blocking)

The NativeAOT descriptor declares:

CDAC_GLOBAL_CONTRACT(Thread, n1)
CDAC_GLOBAL_CONTRACT(RuntimeTypeSystem, n1)

However, the managed cDAC reader (CoreCLRContracts.cs:38) only registers c1 versions:

registry.Register<IThread>("c1",static t =>newThread_1(t));

There is no n1 handler anywhere in src/native/managed/cdac/. This means these contracts will not be resolved when diagnosing a NativeAOT process. If this is intentional (placeholder for future NativeAOT-specific contract implementations), consider adding a comment. If it's expected to work now, corresponding contract factories are needed.

Files:src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc (lines ~155-158)

✅ HEAP_ANALYZE guards — Correct fix

HEAP_ANALYZE is only defined when FEATURE_NATIVEAOT is NOT set (gcpriv.h:200-203). Without these guards, the GC data descriptor would fail to compile for NativeAOT. The guards are correctly placed in both datadescriptor.h and datadescriptor.inc, with proper #endif comments.

✅ ThreadStore refactoring — Correct and well-versioned

Moving m_pThreadStore from RuntimeInstance to ThreadStore::s_pThreadStore is consistent with CoreCLR's cDAC pattern. The DebugHeader major version is correctly bumped from 5→6 with appropriate documentation. The SPTR_DECL/SPTR_IMPL pattern matches existing DAC infrastructure. The initialization order in RuntimeInstance::Initialize() correctly assigns the static after g_pTheRuntimeInstance is set.

✅ ManagedDataDescriptorNode — JSON format matches reader expectations

The emitted JSON uses:

  • "!" sigil for value type sizes (matches TypeDescriptorSizeSigil in ContractDescriptorParser)
  • Plain numbers for field offsets (matches FieldDescriptorConverter compact format)
  • "version": 0, "baseline": "empty" top-level properties (match ContractDescriptor schema)

The ContractDescriptor C struct layout (magic, flags, descriptor_size, descriptor ptr, pointer_data_count, pad, pointer_data ptr) matches the shared contract-descriptor.h definition.

✅ WASM exclusion — Consistent

WASM is excluded via if(NOT CLR_CMAKE_TARGET_ARCH_WASM) for both the GC_DESCRIPTOR define and the datadescriptor subdirectory in CMake, and via '$(_targetOS)' != 'browser' for the export in MSBuild targets. This matches the broader WASM exclusion pattern in the NativeAOT Runtime CMakeLists.txt.

✅ GC version initialization — Correct

Adding g_gc_dac_vars.major_version_number and minor_version_number before GC_Initialize matches the CoreCLR pattern and ensures the GC sub-descriptor has version information.

✅ Build system integration — Well structured

The new datadescriptor/CMakeLists.txt correctly uses include(${CLR_DIR}/clrdatadescriptors.cmake), creates separate interface libraries for WKS/SVR GC descriptors, uses EXPORT_VISIBLE only for the main contract descriptor, and properly propagates include directories via nativeaot_runtime_includes.

💡 ManagedDataDescriptorProvider unconditionally added for WASM

ManagedDataDescriptorProvider is always added in Program.cs (lines 266, 278), even for WASM targets where the native datadescriptor isn't built. The ILC-emitted DotNetManagedContractDescriptor symbol is unused dead data on WASM. Non-blocking, but could be gated on !TargetsBrowser for binary size if desired. (Follow-up improvement, not in-scope for this PR.)

💡 DataContractAttribute naming overlap

System.Diagnostics.DataContractAttribute shares its short name with System.Runtime.Serialization.DataContractAttribute. No actual conflict exists (different namespaces, the new one is internal), but it could cause momentary confusion. The naming aligns with cDAC "data contract" terminology so it's appropriate — just noting for awareness.

Generated by Code Review for issue #126972 ·

@MichalStrehovskyMichalStrehovsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Comment threadsrc/coreclr/tools/aot/ILCompiler/Program.cs Outdated
@max-charlamb

Copy link
Copy Markdown
MemberAuthor

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Some of these values are read by the existing cDAC contracts, some will be read by new contracts (in a different repo). We don't have tests automated yet, but it is one of the next items I am working on.

- Simplify GetSection to always use ReadOnlyDataSection
- Add Debug.Assert for header size before emitting JSON
- Remove Phase override (default unordered is fine)
- Gate ManagedDataDescriptorProvider on EnableDebugInfo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 30, 2026 18:33

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/DebugHeader.cpp
Revert GetSection to use DataSection on non-Windows platforms.
Nodes with pointer relocations require writable sections on ELF.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@max-charlamb
max-charlamb merged commit e883467 into mainMay 1, 2026
110 checks passed
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch May 1, 2026 05:02
steveisok added a commit that referenced this pull request May 6, 2026
)
> [!NOTE]
> This PR was authored with assistance from GitHub Copilot.
## Problem
The OBJECT libraries created by `generate_data_descriptors()` in
`src/coreclr/clrdatadescriptors.cmake` compile `contract-descriptor.c`
and `contractpointerdata.cpp` with MSVC defaults, which routes debug
info into the compiler-default `vc140.pdb`. That PDB does not travel
with the `.obj` files when they are archived into a static library such
as `Runtime.ServerGC.lib`.
Downstream linkers — in particular the NativeAOT publish of
`ILCompiler`, `crossgen2`, and `ilasm` on Windows — then emit `LNK4099`
("PDB 'vc140.pdb' was not found") for each affected object, which is
fatal under `/WX`.
## Symptom
The `dotnet/runtime` → `dotnet/dotnet` codeflow PR
[dotnet/dotnet#6423](dotnet/dotnet#6423) is
blocked: the **VMR Vertical Build Windows_x64** and **VMR Vertical Build
Windows_x86** legs both fail with 22 `LNK4099` errors apiece, e.g.:
```
Runtime.ServerGC.lib(contract-descriptor.c.obj) : error LNK4099:
PDB 'vc140.pdb' was not found with 'Runtime.ServerGC.lib(contract-descriptor.c.obj)'
or at '...\artifacts\bin\ILCompiler_publish\x64\Release\native\vc140.pdb';
linking object as if no debug info
[src\coreclr\tools\aot\ILCompiler\ILCompiler_publish.csproj]
Runtime.ServerGC.lib(contractpointerdata.cpp.obj) : error LNK4099: ...
```
repeated for `crossgen2_publish.csproj` and `ilasm.csproj`.
Linux/macOS/WASM/iOS/Android verticals all pass — `LNK4099` is
MSVC-specific.
The regression was introduced by #126972 ("[NativeAOT] Add cDAC data
descriptor infrastructure"), which wired the new descriptor `OBJECT`
libraries into the NativeAOT runtime so they end up archived inside
`Runtime.ServerGC.lib`.
## Fix
Set `COMPILE_PDB_NAME` and `COMPILE_PDB_OUTPUT_DIRECTORY` on
`${LIBRARY}` so each descriptor library produces its own deterministic
PDB that the consuming linker can locate. This matches the convention
already used by `install_static_library` in
`eng/native/functions.cmake`.
## Validation
- CMake reconfigures cleanly.
- Ninja built `nativeaot_gc_svr_descriptor`,
`nativeaot_gc_wks_descriptor`, `nativeaot_cdac_contract_descriptor`, and
`cdac_contract_descriptor` without errors on linux-x64.
- The actual `LNK4099` resolution can only be verified on a Windows
NativeAOT publish leg in CI; please pay particular attention to the
Windows legs and to the next forward-flow into `dotnet/dotnet`.
cc @max-charlamb (author of #126972)
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Steve Pfister <steveisok@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@max-charlamb@jkoritzinsky@jkotas@MichalStrehovsky
, '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

[NativeAOT] Add cDAC data descriptor infrastructure - #126972

Merged
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors
May 1, 2026
Merged

[NativeAOT] Add cDAC data descriptor infrastructure#126972
max-charlamb merged 29 commits into
mainfrom
dev/max-charlamb/managed-type-descriptors

Conversation

@max-charlamb

@max-charlambmax-charlamb commented Apr 15, 2026

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame, thread link
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • StressLog/ThreadStressLog: Stress log infrastructure (guarded by STRESS_LOG)
  • Globals: ThreadStore static pointer, free object MethodTable, GC bounds, thread state flags, object unmask, stress log
  • Contracts: Thread (n1), Exception (c1), RuntimeTypeSystem (n1), StressLog (c2)
  • Sub-descriptors: GC (workstation + server) and managed type descriptors

ILC managed type descriptor (ManagedDataDescriptorNode)

  • Computes managed type field offsets at compile time in ILC
  • Emits a ContractDescriptor (DotNetManagedContractDescriptor) with JSON-encoded type layouts using Utf8JsonWriter
  • Types and fields discovered via [DataContract] attribute on types in MetadataManager.GetTypesWithEETypes()
  • Type name mangling: System.Threading.Thread -> System_Threading_Thread
  • Referenced by the native descriptor as a sub-descriptor via CDAC_GLOBAL_SUB_DESCRIPTOR
  • Currently registers System.Threading.Thread fields (ManagedThreadId, Name)

GC sub-descriptor

  • Enabled GC sub-descriptor for NativeAOT by setting GC_INTERFACE_*_VERSION before GC_Initialize
  • Added GC_DESCRIPTOR compile definition (guarded on non-WASM)
  • Linked both WKS and SVR GC descriptor objects into Runtime.ServerGC (ServerGC compiles both paths)
  • Added #ifdef HEAP_ANALYZE guards in shared GC datadescriptor files (NativeAOT disables HEAP_ANALYZE)

Attribute-based type discovery

  • [DataContract] attribute in System.Diagnostics namespace (internal, targets Class/Struct/Field)
  • Applied to System.Threading.Thread fields in Thread.NativeAot.cs
  • ILC scans for annotated types in GetTypesWithEETypes() ensuring only types with MethodTables are included

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • nativeaot_runtime_includes interface library captures all Runtime include paths for cross-target compilation
  • Separate GC descriptor targets for workstation and server GC
  • cdac-build-tool enabled for NativeAOT via ClrNativeAotSubset in runtime.proj
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets (WASM excluded)
  • Local copy of cdacdata.h template in Runtime/inc/ (matching GC pattern for self-contained builds)

Key design decisions

  • Contract versions: n1 for NativeAOT-specific contracts, c1/c2 for contracts shared with CoreCLR (same version)
  • ThreadStore: Uses SPTR_DECL/SPTR_IMPL for s_pThreadStore static member, matching CoreCLR pattern
  • Singleton node: ManagedDataDescriptorNode does not override CompareToImpl — follows the ILC singleton pattern (base class throws on duplicates)
  • SList: Unified slist.h shared between CoreCLR VM and NativeAOT Runtime

Validation

  • Build: build.cmd clr.aot+libs -rc release — 0 errors, 0 warnings
  • Symbol verified in Runtime.WorkstationGC.lib via dumpbin
  • cDAC reader tests: 1586/1586 passed
  • tools.cdac tests: All passed
  • Dump inspection: All 3 sub-descriptors verified (main: 4 contracts/11 types/20 globals, managed: System_Threading_Thread with fields, GC: 1 contract/10 types/41 globals)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds cDAC contract descriptor generation to the NativeAOT runtime, plus an ILC-emitted managed sub-descriptor so diagnostic tools can inspect NativeAOT runtime/managed state via the shared contract mechanism.

Changes:

  • Integrates NativeAOT cDAC contract descriptor (and GC sub-descriptors) into the NativeAOT CMake build and runtime libraries.
  • Introduces a managed type layout sub-descriptor emitted by ILC (DotNetManagedContractDescriptor) and wires it into the NativeAOT descriptor as a sub-descriptor.
  • Exposes select private NativeAOT runtime offsets/constants to the descriptor via the cdac_data<T> friend pattern and exports the main contract descriptor symbol for diagnostics.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/coreclr/tools/aot/ILCompiler/Program.csAdds the managed descriptor root provider to ILC compilation roots.
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csprojIncludes new managed descriptor provider/node sources in the build.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ManagedDataDescriptorProvider.csRegisters managed types to be described and roots the descriptor + JSON blob.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ManagedDataDescriptorNode.csEmits a ContractDescriptor-shaped symbol containing JSON type layout data.
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore private offsets for descriptor generation via cdac_data<>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable offsets and flag constants for descriptor consumption via cdac_data<>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incDefines the NativeAOT data descriptor types/globals/contracts and sub-descriptors.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hProvides includes and declares the managed sub-descriptor symbol address for inclusion.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds descriptor generation targets for NativeAOT runtime + GC (wks/svr).
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance private offsets via cdac_data<>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor libraries into WorkstationGC/ServerGC runtime libs.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the datadescriptor subdirectory to the NativeAOT runtime build (non-WASM).
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor symbol for diagnostics on all OSes.
Comments suppressed due to low confidence (1)

src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt:73

  • target_compile_definitions entries should be raw preprocessor symbols (e.g., SERVER_GC), not compiler flags. Passing -DSERVER_GC here will typically result in an invalid definition being forwarded to the compiler. Use SERVER_GC (or SERVER_GC=1) instead.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets Outdated
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlambforce-pushed the dev/max-charlamb/managed-type-descriptors branch from 9462d5c to f226bc3CompareApril 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:53
@max-charlamb
max-charlamb restored the dev/max-charlamb/managed-type-descriptors branch April 16, 2026 20:54

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 7 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt
@github-actions

This comment has been minimized.

CopilotAI review requested due to automatic review settings April 17, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.h
Comment threadsrc/coreclr/nativeaot/Runtime/RuntimeInstance.cpp Outdated
CopilotAI review requested due to automatic review settings April 17, 2026 19:44
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 28, 2026 18:35

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MichalStrehovsky Could you please signoff as well?

Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

@github-actions

This comment has been minimized.

…ed descriptor
- Remove MethodTable flag constant globals from datadescriptor.inc
and cdac_data<MethodTable> in MethodTable.h — these are already
defined as part of the contract in MethodTableFlags_1.cs
- Add baseline and contracts properties to managed sub-descriptor
JSON for self-describing format consistency
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Copilot Code Review — PR #126972

Note

This review was generated by GitHub Copilot.

Holistic Assessment

Motivation: This PR adds cDAC (data access component) data descriptor infrastructure to NativeAOT, enabling diagnostic tools (debuggers, crash dump analyzers) to inspect NativeAOT runtime state without symbols. This is well-motivated — it's a prerequisite for cDAC support in NativeAOT, analogous to what already exists for CoreCLR.

Approach: The approach is sound — it reuses the existing generate_data_descriptors() CMake infrastructure and shared datadescriptor.cpp machinery. Moving ThreadStore from RuntimeInstance::m_pThreadStore to a static ThreadStore::s_pThreadStore matches the CoreCLR pattern. The managed type descriptor emitted by ILC as a sub-descriptor integrates cleanly with the existing ContractDescriptorParser. The HEAP_ANALYZE guards fix real compilation errors for NativeAOT GC builds.

Summary: ⚠️ Needs Human Review. The implementation is largely correct and well-structured, but there are design questions around contract versioning (n1 vs c1) and its interaction with the cDAC reader that a domain expert should verify. A human reviewer should confirm whether n1 contracts are intentionally non-functional placeholders or need corresponding reader support.


Detailed Findings

⚠️ Contract Versions — n1 not registered in cDAC reader (advisory, not merge-blocking)

The NativeAOT descriptor declares:

CDAC_GLOBAL_CONTRACT(Thread, n1)
CDAC_GLOBAL_CONTRACT(RuntimeTypeSystem, n1)

However, the managed cDAC reader (CoreCLRContracts.cs:38) only registers c1 versions:

registry.Register<IThread>("c1",static t =>newThread_1(t));

There is no n1 handler anywhere in src/native/managed/cdac/. This means these contracts will not be resolved when diagnosing a NativeAOT process. If this is intentional (placeholder for future NativeAOT-specific contract implementations), consider adding a comment. If it's expected to work now, corresponding contract factories are needed.

Files:src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc (lines ~155-158)

✅ HEAP_ANALYZE guards — Correct fix

HEAP_ANALYZE is only defined when FEATURE_NATIVEAOT is NOT set (gcpriv.h:200-203). Without these guards, the GC data descriptor would fail to compile for NativeAOT. The guards are correctly placed in both datadescriptor.h and datadescriptor.inc, with proper #endif comments.

✅ ThreadStore refactoring — Correct and well-versioned

Moving m_pThreadStore from RuntimeInstance to ThreadStore::s_pThreadStore is consistent with CoreCLR's cDAC pattern. The DebugHeader major version is correctly bumped from 5→6 with appropriate documentation. The SPTR_DECL/SPTR_IMPL pattern matches existing DAC infrastructure. The initialization order in RuntimeInstance::Initialize() correctly assigns the static after g_pTheRuntimeInstance is set.

✅ ManagedDataDescriptorNode — JSON format matches reader expectations

The emitted JSON uses:

  • "!" sigil for value type sizes (matches TypeDescriptorSizeSigil in ContractDescriptorParser)
  • Plain numbers for field offsets (matches FieldDescriptorConverter compact format)
  • "version": 0, "baseline": "empty" top-level properties (match ContractDescriptor schema)

The ContractDescriptor C struct layout (magic, flags, descriptor_size, descriptor ptr, pointer_data_count, pad, pointer_data ptr) matches the shared contract-descriptor.h definition.

✅ WASM exclusion — Consistent

WASM is excluded via if(NOT CLR_CMAKE_TARGET_ARCH_WASM) for both the GC_DESCRIPTOR define and the datadescriptor subdirectory in CMake, and via '$(_targetOS)' != 'browser' for the export in MSBuild targets. This matches the broader WASM exclusion pattern in the NativeAOT Runtime CMakeLists.txt.

✅ GC version initialization — Correct

Adding g_gc_dac_vars.major_version_number and minor_version_number before GC_Initialize matches the CoreCLR pattern and ensures the GC sub-descriptor has version information.

✅ Build system integration — Well structured

The new datadescriptor/CMakeLists.txt correctly uses include(${CLR_DIR}/clrdatadescriptors.cmake), creates separate interface libraries for WKS/SVR GC descriptors, uses EXPORT_VISIBLE only for the main contract descriptor, and properly propagates include directories via nativeaot_runtime_includes.

💡 ManagedDataDescriptorProvider unconditionally added for WASM

ManagedDataDescriptorProvider is always added in Program.cs (lines 266, 278), even for WASM targets where the native datadescriptor isn't built. The ILC-emitted DotNetManagedContractDescriptor symbol is unused dead data on WASM. Non-blocking, but could be gated on !TargetsBrowser for binary size if desired. (Follow-up improvement, not in-scope for this PR.)

💡 DataContractAttribute naming overlap

System.Diagnostics.DataContractAttribute shares its short name with System.Runtime.Serialization.DataContractAttribute. No actual conflict exists (different namespaces, the new one is internal), but it could cause momentary confusion. The naming aligns with cDAC "data contract" terminology so it's appropriate — just noting for awareness.

Generated by Code Review for issue #126972 ·

@MichalStrehovskyMichalStrehovsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Comment threadsrc/coreclr/tools/aot/ILCompiler/Program.cs Outdated
@max-charlamb

Copy link
Copy Markdown
MemberAuthor

Looks good otherwise! What is the testing strategy for this? The DotNetRuntimeDebugHeader was pretty much untested because the code to read it lived elsewhere. Do we have the ability to test this in the dotnet/runtime repo?

Some of these values are read by the existing cDAC contracts, some will be read by new contracts (in a different repo). We don't have tests automated yet, but it is one of the next items I am working on.

- Simplify GetSection to always use ReadOnlyDataSection
- Add Debug.Assert for header size before emitting JSON
- Remove Phase override (default unordered is fine)
- Gate ManagedDataDescriptorProvider on EnableDebugInfo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 30, 2026 18:33

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/DebugHeader.cpp
Revert GetSection to use DataSection on non-Windows platforms.
Nodes with pointer relocations require writable sections on ELF.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@max-charlamb
max-charlamb merged commit e883467 into mainMay 1, 2026
110 checks passed
@max-charlamb
max-charlamb deleted the dev/max-charlamb/managed-type-descriptors branch May 1, 2026 05:02
steveisok added a commit that referenced this pull request May 6, 2026
)
> [!NOTE]
> This PR was authored with assistance from GitHub Copilot.
## Problem
The OBJECT libraries created by `generate_data_descriptors()` in
`src/coreclr/clrdatadescriptors.cmake` compile `contract-descriptor.c`
and `contractpointerdata.cpp` with MSVC defaults, which routes debug
info into the compiler-default `vc140.pdb`. That PDB does not travel
with the `.obj` files when they are archived into a static library such
as `Runtime.ServerGC.lib`.
Downstream linkers — in particular the NativeAOT publish of
`ILCompiler`, `crossgen2`, and `ilasm` on Windows — then emit `LNK4099`
("PDB 'vc140.pdb' was not found") for each affected object, which is
fatal under `/WX`.
## Symptom
The `dotnet/runtime` → `dotnet/dotnet` codeflow PR
[dotnet/dotnet#6423](dotnet/dotnet#6423) is
blocked: the **VMR Vertical Build Windows_x64** and **VMR Vertical Build
Windows_x86** legs both fail with 22 `LNK4099` errors apiece, e.g.:
```
Runtime.ServerGC.lib(contract-descriptor.c.obj) : error LNK4099:
PDB 'vc140.pdb' was not found with 'Runtime.ServerGC.lib(contract-descriptor.c.obj)'
or at '...\artifacts\bin\ILCompiler_publish\x64\Release\native\vc140.pdb';
linking object as if no debug info
[src\coreclr\tools\aot\ILCompiler\ILCompiler_publish.csproj]
Runtime.ServerGC.lib(contractpointerdata.cpp.obj) : error LNK4099: ...
```
repeated for `crossgen2_publish.csproj` and `ilasm.csproj`.
Linux/macOS/WASM/iOS/Android verticals all pass — `LNK4099` is
MSVC-specific.
The regression was introduced by #126972 ("[NativeAOT] Add cDAC data
descriptor infrastructure"), which wired the new descriptor `OBJECT`
libraries into the NativeAOT runtime so they end up archived inside
`Runtime.ServerGC.lib`.
## Fix
Set `COMPILE_PDB_NAME` and `COMPILE_PDB_OUTPUT_DIRECTORY` on
`${LIBRARY}` so each descriptor library produces its own deterministic
PDB that the consuming linker can locate. This matches the convention
already used by `install_static_library` in
`eng/native/functions.cmake`.
## Validation
- CMake reconfigures cleanly.
- Ninja built `nativeaot_gc_svr_descriptor`,
`nativeaot_gc_wks_descriptor`, `nativeaot_cdac_contract_descriptor`, and
`cdac_contract_descriptor` without errors on linux-x64.
- The actual `LNK4099` resolution can only be verified on a Windows
NativeAOT publish leg in CI; please pay particular attention to the
Windows legs and to the next forward-flow into `dotnet/dotnet`.
cc @max-charlamb (author of #126972)
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Steve Pfister <steveisok@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@max-charlamb@jkoritzinsky@jkotas@MichalStrehovsky