Skip to content

[cDAC] Map entry point to code start in GetMethodVarInfo; make ReJIT optional in IsVersionable - #135430

Open
lewing wants to merge 2 commits into
dotnet:mainfrom
lewing:lewing-cdac-varinfo-entrypoint
Open

lewing wants to merge 2 commits into
dotnet:mainfrom
lewing:lewing-cdac-varinfo-entrypoint

Conversation

@lewing

@lewing lewing commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Two IDebugInfo.GetMethodVarInfo fixes for targets that use portable entry points, such as CoreCLR WebAssembly.

GetMethodVarInfo code offset

codeOffset was computed relative to ICodeVersions.GetNativeCode, which is the method's entry point. On portable-entrypoint targets that is not the code start, so the offset was wrong. The entry point is now mapped with IExecutionManager.GetDiagnosticCodeStartFromEntryPoint (#134827), the cDAC mirror of the runtime's GetDiagnosticCodeStartFromEntryPoint. It returns:

  • the interpreter bytecode for an interpreted method;
  • the R2R virtual IP for a portable entry point;
  • otherwise the address unchanged.

Native ClrDataAccess::GetMethodVarInfo maps only interpreter entry points (GetInterpreterCodeFromEntryPointIfPresent). The native DAC does not support wasm, so the R2R portable-entrypoint case has no native DAC behavior to compare against.

IsVersionable without the ReJIT contract

GetMethodVarInfo → GetNativeCodeVersionForIP → IsVersionable required the ReJIT contract. The runtime advertises that contract only under PROFILING_SUPPORTED, which is off on wasm, so GetMethodVarInfo threw ContractMissingException there. Wasm also lacks FEATURE_REJIT, so native IsEligibleForReJIT is false. A missing contract is now treated as not ReJIT-eligible, using TryGetContract.

An alternative is to advertise ReJIT on wasm, with IsEnabled() returning false; I'm happy to switch if reviewers prefer that. Separately, CoreCLRContracts.ValidateForDataAccess still requires IReJIT, so on wasm the official DAC entry point would fail validation. That is not changed here and needs its own follow-up.

Validation

  • ./build.sh -s tools.cdactests -test: passed (Unit tests 3293/3293, DataGenerator 46/46, Usage 4/4).
  • generate-docs.ps1 -Check: up to date.
  • New tests:
    • GetMethodVarInfo_CodeOffsetIsRelativeToDiagnosticCodeStart (theory: identity mapping, and an entry point mapped to a different code start).
    • IsVersionable_ReJITContractOptional (theory: no ReJIT contract, ReJIT disabled, ReJIT enabled).
  • GetDebugInfo_R2R_NoDebugInfoSection_ReturnsNull now registers FeatureFlags and PrecodeStubs, which the mapping requires.
  • Mutation checks, each confirmed applied by diff and restored afterwards:
    • Revert to cv.GetNativeCode(ncvh) → GetMethodVarInfo_CodeOffset…(0x400000→0x80010100) fails with Assert.Equal.
    • Revert to _target.Contracts.ReJIT.IsEnabled() → IsVersionable_ReJITContractOptional(advertiseReJIT: False) fails with ContractMissingException.
  • I also checked against a live CoreCLR browser-wasm target with R2R. Entry point 0x41ADC1C maps to diagnostic start 0x800104B3, and GetMethodVarInfo returns offset 0x2. That is the same result as a wasm-only offset computation used in an earlier prototype. That target used a producer-side branch with variable debug info ([wasm] Preserve R2R variable debug information #133086); there is no automated test for this case.

Note

This PR description was generated with GitHub Copilot.

…onal in IsVersionable

GetMethodVarInfo computed codeOffset relative to the native-code entry point.
With portable entry points the entry point is not the code start, so map it
with IExecutionManager.GetDiagnosticCodeStartFromEntryPoint (the cDAC mirror of
the runtime's GetDiagnosticCodeStartFromEntryPoint).

IsVersionable required the ReJIT contract, which is only advertised with
profiling support. Without it, native IsEligibleForReJIT is false, so treat a
missing ReJIT contract as not ReJIT-eligible.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

@rcj1

rcj1 commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Entry point 0x41ADC1C maps to diagnostic start 0x800104B3, and GetMethodVarInfo returns offset 0x2.

Are you able to select the correct debug info with offset 0x2 - for example, as this API is being used here?

{
if (varInfo.StartOffset <= codeOffset &&
varInfo.EndOffset >= codeOffset &&
varInfo.VarNumber == varNumber)
{
IPlatformAgnosticContext platformContext = IPlatformAgnosticContext.GetContextForPlatform(target);

lewing added a commit to lewing/runtime that referenced this pull request Oct 9, 2026
…onal in IsVersionable

Cherry-pick of dotnet#135430. GetMethodVarInfo maps the native code version's entry
point with IExecutionManager.GetDiagnosticCodeStartFromEntryPoint, and
IsVersionable treats a missing ReJIT contract as not ReJIT-eligible.

This replaces the wasm-only GetMethodCodeOffset branch (and its unit test):
WASM now takes the shared path.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@lewing

lewing commented Oct 9, 2026

Copy link
Copy Markdown
Member Author

Are you able to select the correct debug info with offset 0x2 - for example, as this API is being used here?

Not in general on WASM. The 0x2 is in the R2R virtual-IP space: WASM virtual IPs are synthetic per-call/try counters assigned by fgWasmVirtualIP, and the GC info uses the same space (codeSize = 2 * maxVirtualIP). The variable ranges, on the other hand, are recorded at JIT emitter offsets (m_StartEmitLocation.CodeOffset), so StartOffset <= codeOffset <= EndOffset in FindAndResolveVarLocation compares two different offset spaces.

It works today only because unoptimized WASM scopes are method-wide (#133086 opens them in the first emitted block), so any offset inside the method selects them. A variable whose location changes mid-method, for example a parameter homed from its wasm local in the prolog, can select the wrong record. Fixing that needs either virtual-IP-space ranges from the producer or a virtual-IP → native-offset map. It's listed as a limitation on #133890.

This PR doesn't change that: on WASM, the shared path now returns the same offset the wasm-specific path in #133890 did, and #133890 now uses this path instead.

Note

This comment was generated with GitHub Copilot.

@rcj1

rcj1 commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Are you able to select the correct debug info with offset 0x2 - for example, as this API is being used here?

Not in general on WASM. The 0x2 is in the R2R virtual-IP space: WASM virtual IPs are synthetic per-call/try counters assigned by fgWasmVirtualIP, and the GC info uses the same space (codeSize = 2 * maxVirtualIP). The variable ranges, on the other hand, are recorded at JIT emitter offsets (m_StartEmitLocation.CodeOffset), so StartOffset <= codeOffset <= EndOffset in FindAndResolveVarLocation compares two different offset spaces.

It works today only because unoptimized WASM scopes are method-wide (#133086 opens them in the first emitted block), so any offset inside the method selects them. A variable whose location changes mid-method, for example a parameter homed from its wasm local in the prolog, can select the wrong record. Fixing that needs either virtual-IP-space ranges from the producer or a virtual-IP → native-offset map. It's listed as a limitation on #133890.

This PR doesn't change that: on WASM, the shared path now returns the same offset the wasm-specific path in #133890 did, and #133890 now uses this path instead.

Note

This comment was generated with GitHub Copilot.

Makes sense, I’ll approve this for now then.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@lewing

lewing commented Oct 12, 2026

Copy link
Copy Markdown
Member Author

@rcj1 I had to commit again to merge main

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants