Skip to content

Populate runtime-async DiagnosticIP for Wasm R2R - #133768

Merged
davidwrighton merged 1 commit into
dotnet:mainfrom
davidwrighton:wasm-runtime-async-diagnostic-ip
Sep 14, 2026
Merged

davidwrighton merged 1 commit into
dotnet:mainfrom
davidwrighton:wasm-runtime-async-diagnostic-ip

Conversation

@davidwrighton

Copy link
Copy Markdown
Member

Fixes #133626

Summary

  • populate Wasm ReadyToRun CORINFO_AsyncResumeInfo.DiagnosticIP with the virtual IP of the containing method's start
  • add a compact ReadyToRun fixup section that records DiagnosticIP slots as delta/count/stride ULEB128 chunks
  • validate the section and apply the module virtual-IP base after ExecutionManager::AddVirtualIPRange
  • advance the ReadyToRun format to 29.0 so older runtimes reject images containing method-relative diagnostic IPs
  • preserve retry correctness by publishing fixup locations only after successful JIT code/data publication

Testing

  • dotnet test src\coreclr\tools\aot\ILCompiler.ReadyToRun.Tests\ILCompiler.ReadyToRun.Tests.csproj -c Release --filter RuntimeAsyncWasmDiagnosticIPFixups -p:TargetOS=browser -p:TargetArchitecture=wasm -p:CoreCLRConfiguration=Debug (1 passed, with --determinism-stress=2)
  • src\tests\build.cmd -Test async\async.csproj browser Debug (build succeeded; exactly one child test project selected)
  • rebuilt Wasm native runtime and Core_Root, then ran the generated async.cmd wrapper with ReadyToRun enabled (1 passed)
  • python src\coreclr\scripts\jitformat.py -r . -o windows -a x64
  • git diff --check

The exception regression test uses a synchronous test entry point to resume a runtime-async chain, prints Exception.StackTrace, and verifies these frames in order:

ThrowAfterResume
Level4
Level3
Level2
Level1
TestEntryPoint

With the old null DiagnosticIP behavior, the same test only reported ThrowAfterResume and TestEntryPoint and failed the frame assertions.

Note

This pull request description was generated by GitHub Copilot.

Add a ReadyToRun fixup table for async resume DiagnosticIP fields and apply the virtual IP image base during module registration. Cover compiler emission and exception stack traces.

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

Copilot-Session: c034420d-d7b3-4e5f-8337-c29f33b3257e
@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 @dotnet/jit-contrib for JIT-EE GUID update

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Copilot AI 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.

🟡 Changes recommended

The regression test must assert the claimed TestEntryPoint stack-frame boundary.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds WebAssembly ReadyToRun DiagnosticIP fixups for accurate runtime-async stack traces, including format version 29 and regression coverage.

Changes:

  • Adds method-relative virtual-IP relocations and compact fixup sections.
  • Validates and applies fixups at runtime.
  • Adds Wasm build configuration and stack-trace tests.
File summaries
File Reviewed change
src/tests/async/Directory.Build.targets Adds opt-in Wasm runtime-async builds.
src/tests/async/diagnostic-ip-stacktrace/diagnostic-ip-stacktrace.csproj Defines the Wasm regression test project.
src/tests/async/diagnostic-ip-stacktrace/diagnostic-ip-stacktrace.cs Adds async stack-trace regression coverage.
src/tests/async/async.csproj Controls property propagation to child tests.
src/coreclr/vm/wasm/helpers.cpp Handles missing Wasm frame pointers.
src/coreclr/vm/readytoruninfo.cpp Validates and applies runtime fixups.
src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs Adds the managed relocation enum.
src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Integrates fixup handling and publication.
src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs Updates managed format constants.
src/coreclr/tools/Common/Compiler/ObjectWriter/WebCilObjectWriter.cs Encodes compact async fixup sections.
src/coreclr/tools/Common/Compiler/ObjectWriter/WasmRelocatableObjectWriter.cs Resolves Wasm virtual-IP relocations.
src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs Defines relocation metadata and encoding.
src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs Supports new relocation data.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs Publishes method virtual-IP fixups.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj Includes the new ReadyToRun sources.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs Registers fixup nodes.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/WasmMethodRelativeVirtualIPNode.cs Represents method-relative virtual-IP symbols.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/WasmAsyncResumeInfoFixupsNode.cs Generates compact fixup chunks.
src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/WasmR2RAssert.cs Validates emitted fixup data.
src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs Registers fixup validation tests.
src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h Updates the NativeAOT format version.
src/coreclr/jit/emit.cpp Emits Wasm diagnostic-IP relocations.
src/coreclr/inc/readytorun.h Updates ReadyToRun format definitions.
src/coreclr/inc/jiteeversionguid.h Updates JIT/EE interface versioning.
src/coreclr/inc/corinfo.h Adds the JIT relocation type.

Review note: expectedMethods omits nameof(TestEntryPoint), so the regression test does not verify the claimed entry-point boundary.

Review details
  • Files reviewed: 25/25 changed files
  • Comments generated: 1
  • Review effort level: Lite

@lewing

lewing commented Sep 12, 2026 •

Copy link
Copy Markdown
Member

I verified on the libraries test, the fix converts all three selected RuntimeAsync V2 cases to passes, including the runtime-async ValueTask case.

@davidwrighton

Copy link
Copy Markdown
Member Author

/ba-g Failures are mono and #133798, both of which are unrelated.

@davidwrighton
davidwrighton merged commit e377ef8 into dotnet:main Sep 14, 2026
145 of 147 checks passed
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 12.0-preview1 milestone Sep 15, 2026
@jkotas

jkotas commented Sep 15, 2026

Copy link
Copy Markdown
Member

Failures are mono and #133798, both of which are unrelated.

The failure in async test was related and appears to be new in this PR. Opened ##133931

lewing added a commit that referenced this pull request Sep 16, 2026
## Summary

- use the caller shadow stack's virtual IP as the return address for the
Wasm `ResumeInterpreterContinuation` transition frame
- enable the full runtime-async runner on Wasm while filtering only
tests that require multithreading
- use class-level capability conditions where every test in a class
requires multithreading and method-level conditions for mixed classes
- quarantine only the exact unsupported cases:
`Async2PInvoke.TestEntryPoint` under #124219 and `Async2CollectibleAlc`
under #134001
- run the diagnostic stack-trace scenario twice to cover cold and warm
FCall paths
- make reflection method ordering deterministic with
`StringComparer.Ordinal`

## Root cause

The Wasm FCall supplied the managed caller's R2R shadow stack pointer
but used the native `ResumeInterpreterContinuation` entrypoint as the
transition block return address. On the warm path, stack walking paired
those unrelated values and failed the
`GetWasmVirtualIPFromStackPointer(sp) == controlPC` invariant.

#133768 also enabled the full `src/tests/async` runner on Wasm. Many
tests intentionally block on incomplete tasks and therefore require
multithreading; those tests now use
`PlatformDetection.IsMultithreadingSupported` rather than disabling the
whole runner.

## Validation

- browser-Wasm Checked CoreCLR build
- browser-Wasm interpreter runner: 142 discovered, 42 passed, 0 failed,
100 capability/issue filtered
- browser-Wasm R2R-CG2 runner: 142 discovered, 42 passed, 0 failed, 100
capability/issue filtered
- WASI runner: 142 discovered, 44 passed, 0 failed, 98 capability/issue
filtered
- native macOS arm64 runner: 142 passed, 0 failed
- the diagnostic test fails on the old runtime's warm path and passes
after the fix

Resolves #133931

> [!NOTE]
> This pull request description was generated with GitHub Copilot
assistance.

---------

Copilot-Session: 8a57fff8-6c30-4d3c-ac72-a80975122a96
jtschuster pushed a commit to jtschuster/runtime that referenced this pull request Sep 18, 2026
Fixes dotnet#133626

## Summary

- populate Wasm ReadyToRun `CORINFO_AsyncResumeInfo.DiagnosticIP` with
the virtual IP of the containing method's start
- add a compact ReadyToRun fixup section that records `DiagnosticIP`
slots as delta/count/stride ULEB128 chunks
- validate the section and apply the module virtual-IP base after
`ExecutionManager::AddVirtualIPRange`
- advance the ReadyToRun format to 29.0 so older runtimes reject images
containing method-relative diagnostic IPs
- preserve retry correctness by publishing fixup locations only after
successful JIT code/data publication

## Testing

- `dotnet test
src\coreclr\tools\aot\ILCompiler.ReadyToRun.Tests\ILCompiler.ReadyToRun.Tests.csproj
-c Release --filter RuntimeAsyncWasmDiagnosticIPFixups
-p:TargetOS=browser -p:TargetArchitecture=wasm
-p:CoreCLRConfiguration=Debug` (1 passed, with `--determinism-stress=2`)
- `src\tests\build.cmd -Test async\async.csproj browser Debug` (build
succeeded; exactly one child test project selected)
- rebuilt Wasm native runtime and Core_Root, then ran the generated
`async.cmd` wrapper with ReadyToRun enabled (1 passed)
- `python src\coreclr\scripts\jitformat.py -r . -o windows -a x64`
- `git diff --check`

The exception regression test uses a synchronous test entry point to
resume a runtime-async chain, prints `Exception.StackTrace`, and
verifies these frames in order:

```text
ThrowAfterResume
Level4
Level3
Level2
Level1
TestEntryPoint
```

With the old null `DiagnosticIP` behavior, the same test only reported
`ThrowAfterResume` and `TestEntryPoint` and failed the frame assertions.

> [!NOTE]
> This pull request description was generated by GitHub Copilot.

Copilot-Session: c034420d-d7b3-4e5f-8337-c29f33b3257e
jtschuster pushed a commit to jtschuster/runtime that referenced this pull request Sep 18, 2026
## Summary

- use the caller shadow stack's virtual IP as the return address for the
Wasm `ResumeInterpreterContinuation` transition frame
- enable the full runtime-async runner on Wasm while filtering only
tests that require multithreading
- use class-level capability conditions where every test in a class
requires multithreading and method-level conditions for mixed classes
- quarantine only the exact unsupported cases:
`Async2PInvoke.TestEntryPoint` under dotnet#124219 and `Async2CollectibleAlc`
under dotnet#134001
- run the diagnostic stack-trace scenario twice to cover cold and warm
FCall paths
- make reflection method ordering deterministic with
`StringComparer.Ordinal`

## Root cause

The Wasm FCall supplied the managed caller's R2R shadow stack pointer
but used the native `ResumeInterpreterContinuation` entrypoint as the
transition block return address. On the warm path, stack walking paired
those unrelated values and failed the
`GetWasmVirtualIPFromStackPointer(sp) == controlPC` invariant.

dotnet#133768 also enabled the full `src/tests/async` runner on Wasm. Many
tests intentionally block on incomplete tasks and therefore require
multithreading; those tests now use
`PlatformDetection.IsMultithreadingSupported` rather than disabling the
whole runner.

## Validation

- browser-Wasm Checked CoreCLR build
- browser-Wasm interpreter runner: 142 discovered, 42 passed, 0 failed,
100 capability/issue filtered
- browser-Wasm R2R-CG2 runner: 142 discovered, 42 passed, 0 failed, 100
capability/issue filtered
- WASI runner: 142 discovered, 44 passed, 0 failed, 98 capability/issue
filtered
- native macOS arm64 runner: 142 passed, 0 failed
- the diagnostic test fails on the old runtime's warm path and passes
after the fix

Resolves dotnet#133931

> [!NOTE]
> This pull request description was generated with GitHub Copilot
assistance.

---------

Copilot-Session: 8a57fff8-6c30-4d3c-ac72-a80975122a96
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.

[browser][CoreCLR][R2R] AsyncProfiler callstack identities are missing: Wasm ResumeInfo.DiagnosticIP is null

4 participants