Skip to content

[wasm] Preserve R2R variable debug information - #133086

Open
lewing wants to merge 6 commits into
dotnet:mainfrom
lewing:lewing-r2r-wasm-debug-info
Open

lewing wants to merge 6 commits into
dotnet:mainfrom
lewing:lewing-r2r-wasm-debug-info

Conversation

@lewing

@lewing lewing commented Sep 2, 2026 •

Copy link
Copy Markdown
Member

Summary

Preserve variable debug information produced by RyuJIT for ReadyToRun WebAssembly code and define the producer-owned encoding and stack-base contracts used by downstream diagnostic readers.

  • Preserve optimized tracked-variable ranges as well as unoptimized/relooper scopes.
  • Preserve packed wasm local register values and exact frame-resident stack locations.
  • Centralize the register encoding in ICorDebugInfo and advertise its shift/count through target data descriptors.
  • Exclude the hidden portable-entry-pointer argument from source variables.
  • Pin the current wasm stack VarLoc base encoding to 2.
  • Validate optimized locals, GC roots, same-type slot identity, legitimate null, leaf/calling/localloc/funclet frame shapes, and complete exact tuples.

This remains a draft. The producer changes are here; cDAC decoding and live consumer validation remain in dependent draft #133890.

Producer-owned encoding contract

WASM register locations pack a JIT-local index and WasmValueType into the 32-bit ICorDebugInfo::RegNum payload:

packedRegister = localIndex | ((uint)valueType << registerTypeShift)

Current values:

WASM_REG_TYPE_BITS    = 3
WASM_REG_TYPE_SHIFT   = 29
WASM_VALUE_TYPE_COUNT = 7

The JIT derives its masks from these constants and statically asserts the register-width and WasmValueType::Count relationships. The wasm target descriptor publishes WasmDebugRegisterTypeShift=29 and WasmDebugValueTypeCount=7 as uint8 globals. Readers must reject missing or unsupported values rather than plausibly misdecode another local/type.

The static ReadyToRun image reader has no live target descriptor, so a future width/count change requires a format-aware, versioned R2R debug-info update.

Stack base versus engine locals

Three distinct concepts must not be conflated:

  1. DebugVarInfo stack base literal 2.
  2. The absolute logical frame address reconstructed by runtime/cDAC from shadow-stack linear memory and unwind state.
  3. The per-function engine local currently holding SP/FP.

The producer now statically asserts:

REG_FPBASE == REG_SPBASE == REG_NA == REGNUM_AMBIENT_SP == 2

Therefore current VLT_STK/VLT_STK2 records are logical-frame-relative and do not encode a V8 $varN local. If the producer changes away from base 2, the reader needs a coordinated fail-loud update.

Measured WasmRegAlloc rule:

  • An FP value is allocated when there are frame locals, localloc, or funclets.
  • Root without localloc: FP aliases SP, including methods that make calls.
  • Root with localloc: FP is distinct so later SP movement does not move frame homes.
  • Funclet: SP and parent establishing FP are distinct; with localloc, the funclet receives the root's pre-adjustment frame base.
  • Numeric engine-local indices vary with parameters/allocation and are observation, not format. This PR does not advertise SP/FP local-index metadata.

Exact current-output matrix:

Shape Function signature / locals Observed frame access
Leaf, frame local, no call, no localloc 3 i32 params, no declared wasm locals root FP aliases SP; frame loads use current local 0
One-arg calling root (SumStaticData) 3 i32 params, 7 declared i32 locals calls do not split FP; frame loads use current local 0
Two-arg calling optimized root 4 i32 params, 3 declared i32 locals root FP still aliases SP at current local 0; current parameter 3 is the hidden portable-entry pointer, not FP
localloc, no funclet 3 i32 params; i32 locals 3-5, i64 local 6 SP is current local 0; distinct root FP is current local 3; frame loads use 3
Funclet, no localloc root: 3 params + 2 i32 locals; funclet: 2 params + i32 local 2 root FP aliases current SP 0; funclet current SP is 0 and parent FP is 1
Funclet + localloc root: i32 locals 3-5 + i64 local 6; funclet: i32 locals 2-3 + i64 local 4 distinct root FP is current local 3; funclet parent establishing FP is current local 1

No stable case was found where compiler-created locals precede the unique FP: current localloc roots allocate FP as the first declared i32 local after parameters, and funclets receive FP as a parameter before declared locals. Arity can still move the root localloc FP index, so these indices are deliberately not a contract.

C1: optimized tracked-variable gate

OptimizedTrackedVariables(int left, int right) is [NoInlining] only and exercises FullOpts/tracked liveness. Its IL declares sum and difference; difference is optimized away, while sum has two exact control-flow ranges.

Complete output:

var 0 Parameter 0 [0x00,0x3C) VLT_REG $1 i32
var 1 Parameter 1 [0x00,0x3C) VLT_REG $2 i32
var 1 Parameter 1 [0x59,0x74) VLT_REG $2 i32
var 2 Local 0     [0x2F,0x51) VLT_REG $4 i32
var 2 Local 0     [0x59,0x74) VLT_REG $4 i32

There is no record for optimized-away IL local 1. This proves the feature is active on the production optimized path, not only behind OptimizationDisabled().

Mutation proof: suppressing optimized non-parameter live-range starts was confirmed in scopeinfo.cpp; WasmWebcilModule became red and crossgen2 detected invalid optimized debug ranges in OptimizedTrackedVariables. Restoring the path returned the full suite to green.

C2: same-type slot identity and legitimate null

GcSlotIdentity creates two distinct movable GcMarker instances with sentinel values 17 and 29, plus a separately stored legitimate-null GcMarker local. IL opcodes are asserted to bind 17 to local 0, 29 to local 1, and ldnull to local 2.

Complete output:

var 0 Local 0 [0x36,0x2B1) VLT_STK base=2 offset=0x48  (marker 17)
var 1 Local 1 [0x36,0x2B1) VLT_STK base=2 offset=0x44  (marker 29)
var 2 Local 2 [0x36,0x2B1) VLT_STK base=2 offset=0x40  (legitimate null)
var 3 Local 3 [0x36,0x2B1) VLT_STK base=2 offset=0x3C  (result)

The two non-null offsets are distinct. All three reference offsets also exist as GC_FRAMEREG_REL pinned/untracked GC slots. The GC.Collect call at native 0x18C lies inside all three reference ranges.

Mutation proof: swapping only the expected 17/29 offsets (0x48 and 0x44) made the exact named test fail; restoring the identity mapping returned green.

Current limitation: the minopts wasm siWasmOpenedScopes latch opens each synthesized source scope once and closes it at method end. Consequently these distinct IL locals share the exact [0x36,0x2B1) end range. Slot/value identity is covered here; disjoint lexical range ends require a focused producer follow-up rather than a semantic change hidden in this PR.

Existing hard cases

Portable-entry-pointer exclusion

Stacked validation found hidden ABI argument $3 reported as source local 0. The fix records lvaWasmPortableEntryPtrArg, maps it to UNKNOWN_ILNUM, and accounts for it in reverse local-number mapping.

Frame-resident GC local across a funclet

GcLocalAcrossFinally allocates a real GcMarker, enters a finally, calls GC.Collect, and keeps the marker alive afterward. IL proves local 0 is Webcil.WasmWebcilModule+GcMarker; debug info reports VLT_STK base=2 offset=0x24; GC info independently reports GC_FRAMEREG_REL+0x24; and the GC call at native 0x161 is inside its live range.

The root frame currently accesses the slot through its SP/FP alias. The funclet uses its distinct parent-FP parameter to load offset 0x24. This remains a suitable #133890 live specimen, but cDAC stack-variable resolution uses reconstructed absolute FP rather than hardcoding either engine-local index.

Existing exact tuples

AddDoubles retains its exact two-parameter register-to-stack transition oracle, and SumWithFinally retains its exact parameter/local stack tuples and no-funclet-DebugInfo assertion.

Stack status and ownership

#132650 merged as 09b4a18f8a6ce1f8eea9636e497a07bd7c50d887. This branch was rewritten onto main at 608580557f7c32e9787164ad78b889108d04faa5 and contains six producer-side commits only.

No src/native/managed/cdac/** reader or implementation files are included. The cDAC consumer is dependent draft #133890.

Validation

  • Native clr+libs+host baseline before this matrix: 0 warnings / 0 errors, 10m06s.
  • Checked browser-wasm clr+libs after the stack-base invariants: 0 warnings / 0 errors, 11m21s.
  • Final browser wasm R2R suite: 85 passed / 0 failed / 37 skipped / 122 total.
  • C1 optimized-path mutation: named test red; restored green.
  • C2 17/29 slot-swap mutation: 1 failed, restored green.
  • Wrong presumed funclet FP local mutation (1 to 3): 1 failed with missing exact wasm instruction sequence, restored green.
  • Previous mutations remain non-vacuous: packed local $1 to $2, GC stack base 2 to 3, and encoding value-count 7 to 6 all fail their respective gates.
  • Descriptor scrape remains exactly shift 29, count 7.
  • JIT formatting and git diff --check are clean.

Final kept artifacts:

artifacts/bin/ILCompiler.ReadyToRun.Tests/Checked/Checked_CLR/browser-wasm/R2RTestCases/WasmWebcilModule/619d979d/IL/WasmWebcilModule.dll
artifacts/bin/ILCompiler.ReadyToRun.Tests/Checked/Checked_CLR/browser-wasm/R2RTestCases/WasmWebcilModule/619d979d/CG2/WasmWebcilModule.wasm
artifacts/pr133086-final-matrix-objdump.txt
artifacts/pr133086-final-OptimizedTrackedVariables-r2rdump.txt
artifacts/pr133086-final-GcSlotIdentity-r2rdump.txt

Note

This pull request description was updated with the assistance of GitHub Copilot.

@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.

@lewing lewing changed the title [wasm] Preserve R2R variable debug information [wip][wasm] Preserve R2R variable debug information Sep 2, 2026
@lewing lewing added the arch-wasm WebAssembly architecture label Sep 2, 2026
@lewing
lewing requested a review from davidwrighton September 2, 2026 16:26
Comment thread src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/NativeHashtable.cs Outdated
@lewing
lewing requested a review from AndyAyersMS September 3, 2026 17:26

@AndyAyersMS AndyAyersMS 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.

Does this handle describing locals that are on the linear stack? Last I looked those SP/FP based encodings were wonky for Wasm.

Note the exact Wasm locals that hold SP/FP can vary and may even vary between main method and its funclets, which I doubt we can encode.

An easy test for this is to look at any GC-typed local, these are always on the linear stack.

@davidwrighton

Copy link
Copy Markdown
Member

@lewing, what value does this debugging data provide? Given my understanding that debugging is likely to only be supported on mostly interpreted scenarios, why should we make this correct for R2R scenarios. (I expect that nativeaot will make good use of this data, so I think overall its goodness, but I don't see why its particularly useful for R2RDump.)

@lewing

lewing commented Sep 5, 2026

Copy link
Copy Markdown
Member Author

It came out of the DWARF discussion and I'm working on something in the nesm debugger and I'm trying to plumb out more info, it is isn't meant to be user facing currently.

lewing and others added 2 commits September 14, 2026 09:18
Preserve variable debug information produced by RyuJIT for ReadyToRun WebAssembly code, including scope ranges across relooper block ordering and packed wasm local register locations.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The end-to-end variable-debug-info validation exposed the hidden wasm
portable-entry-pointer argument as a source local. The argument is appended
after user arguments, but unlike the wasm stack-pointer argument it was not
recorded or excluded by compMap2ILvarNum. AddDoubles therefore reported the
hidden i32 argument as source local 0, alongside the real f64 parameters.

Record the argument's local number when it is created, map it to
UNKNOWN_ILNUM, and account for it when mapping later internal locals back to
IL variable numbers.

Replace the count-only wasm R2R checks with complete exact records for the
AddDoubles parameters and SumWithFinally local: variable identity, native
range, location kind, packed wasm local, and frame-pointer-relative offset.
Mutate the local-index bits of one packed register and prove the exact oracle
rejects the corrupted record.

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

lewing commented Sep 14, 2026

Copy link
Copy Markdown
Member Author

I opened #133890 (which includes these commits) with cDAC consumer side changes

Define the packed WASM debug-register bit layout in ICorDebugInfo and have
the JIT derive its register masks from that shared encoding contract. Assert
that the JIT register representation and WasmValueType count remain
compatible with the debug-info format.

Document that the static ReadyToRun reader's compiled-in shift must move
with a versioned R2R debug-info format change, since it has no live target
descriptor from which to discover a different layout.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
lewing and others added 3 commits September 14, 2026 13:45
Publish the shared WASM register type shift and value-type count through the target data descriptor so version-skewed readers can reject incompatible variable debug information.

Document the producer-owned encoding and extend the static ReadyToRun reader coverage for reserved and unsupported value-type codes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add a no-opt object local that remains live across a GC call in a finally funclet. Assert its IL class type, complete ReadyToRun variable tuples, frame-relative GC slot, and safepoint coverage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add exact optimized tracked-variable coverage, frame-base ABI variations including localloc and funclets, and same-type GC slot identity with a legitimate null reference.

Pin the current stack VarLoc base encoding and document that absolute frame reconstruction is independent of unstable wasm local indices.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@lewing lewing changed the title [wip][wasm] Preserve R2R variable debug information [wasm] Preserve R2R variable debug information Sep 14, 2026
@lewing
lewing marked this pull request as ready for review September 14, 2026 23:41
Copilot AI lite review requested due to automatic review settings September 14, 2026 23:41
@azure-pipelines

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

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.

Copilot review overview

🔵 Needs a closer look

scopeinfo.cpp has unresolved issues with BAD_IL_OFFSET handling and method-wide scope latching that can produce incorrect ranges.

Review tier: Lite
Findings: None

What changed in this PR

Preserves WebAssembly ReadyToRun variable debug information and defines register and stack-location contracts for diagnostic readers.

Changes:

  • Emits optimized and unoptimized WASM variable locations while excluding hidden ABI arguments.
  • Centralizes packed register encoding and publishes target metadata.
  • Adds R2R validation for locals, GC roots, stack frames, funclets, and localloc.
File Reviewed changes
src/​coreclr/​vm/​datadescriptor/​datadescriptor.inc Publishes WASM encoding metadata.
src/​coreclr/​tools/​aot/​ILCompiler.Reflection.ReadyToRun/​DebugInfo.cs Decodes packed WASM registers.
src/​coreclr/​tools/​aot/​ILCompiler.ReadyToRun.Tests/​TestCases/​Webcil/​WasmWebcilModule.cs Adds WASM debug-information test cases.
src/​coreclr/​tools/​aot/​ILCompiler.ReadyToRun.Tests/​TestCases/​R2RTestSuites.cs Validates exact debug-information records.
src/​coreclr/​jit/​scopeinfo.cpp Emits WASM variable ranges and locations; requires offset-sentinel guarding and per-block scope closure.
src/​coreclr/​jit/​registeropswasm.cpp Uses centralized register encoding constants.
src/​coreclr/​jit/​lclvars.cpp Excludes hidden portable-entry arguments.
src/​coreclr/​jit/​compiler.h Tracks the portable-entry argument index.
src/​coreclr/​jit/​compiler.cpp Enables WASM scope information.
src/​coreclr/​jit/​codegen.h Adds WASM scope-tracking state.
src/​coreclr/​inc/​cordebuginfo.h Defines WASM debug-register encoding constants.
docs/​design/​datacontracts/​DebugInfo.md Documents encoding and stack-base contracts.

@lewing

lewing commented Sep 25, 2026

Copy link
Copy Markdown
Member Author

#134689 will remove this information by default

lewing added a commit that referenced this pull request Sep 26, 2026
…ish (#134689)

## Summary

Pass `--strip-debug-info` to crossgen2 for CoreCLR browser-wasm
ReadyToRun publish. This drops the R2R `DebugInfo` section (native-to-IL
offset maps and variable locations) from shipped images. Opt out with
`PublishReadyToRunStripDebugInfo=false` to keep the data for debugging
R2R code (e.g. the cDAC work in #133086 / #133890).

Also makes crossgen2 argument changes invalidate per-app R2R images.
`_CreateR2RImages` only tracks file inputs, so toggling
`PublishReadyToRunStripDebugInfo` (or any
`PublishReadyToRunCrossgen2ExtraArgs` change) previously left stale
images in `obj/R2R`. The arguments are now written to
`obj/wasm-r2r-args.stamp` (only when different) and added to
`_ReadyToRunCompilerInputs`, mirroring the existing P/Invoke manifest
input.

> [!IMPORTANT]
> Stacked on #134618, which rewrites the same targets file. Retarget to
`main` after it merges.

## Size impact

Per-assembly R2R images compiled directly with crossgen2 using the SDK's
browser-wasm arguments (`--obj-format:wasm --opt-cross-module:*
--codegenopt:JitWasm*NyiToR2RUnsupported=1`), with and without
`--strip-debug-info`. Total for System.Private.CoreLib,
System.Text.Json, System.Linq, and System.Collections:

| Compiler | Raw saved | gzip -9 saved | brotli -q 11 saved |
| --- | --- | --- | --- |
| Current (#134618 base) | 859,712 B (2.4%) | 624,690 B (7.1%) | 565,366
B (9.4%) |
| With #133086 variable info | 2,105,520 B (5.6%) | 1,332,733 B (13.9%)
| 1,121,574 B (17.0%) |

<details>
<summary>Per-assembly brotli sizes (bytes, keep → strip)</summary>

| Assembly | Current | With #133086 |
| --- | --- | --- |
| System.Private.CoreLib | 4,822,231 → 4,347,541 | 5,331,799 → 4,403,849
|
| System.Text.Json | 823,314 → 761,533 | 887,982 → 754,444 |
| System.Linq | 219,177 → 200,471 | 238,853 → 200,441 |
| System.Collections | 119,635 → 109,446 | 130,742 → 109,068 |

The #133086 compiler is based on an older commit, so compare keep vs.
strip within a column rather than across columns.
</details>

## Validation

- MSBuild evaluation: `--strip-debug-info` is present by default, absent
with `PublishReadyToRunStripDebugInfo=false`, and absent when
`PublishReadyToRun` is off.
- Incremental harness: `_CreateR2RImages` runs on first build, skips
when unchanged, reruns on opt-out, skips when repeated, and reruns when
switching back.
- Not yet run: an end-to-end browser-wasm publish loading stripped
images in a browser (Wasm.Build.Tests in CI will cover this).

Runtime-pack framework R2R images (used only by the dev-loop build) are
unchanged; publish recompiles the whole closure through these targets.
`--strip-inlining-info` is intentionally not included: it removes
`CrossModuleInlineInfo`, and cross-module inlining is load-bearing on
wasm, so it needs separate validation.

> [!NOTE]
> This pull request was created with assistance from GitHub Copilot.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
lewing added a commit that referenced this pull request Sep 26, 2026
## Summary

Fix cDAC live resolution of WebAssembly ReadyToRun virtual IPs by
matching the runtime's existing lookup model:

- expose `ExecutionManager::s_pVirtualIPRangeList` and
`VirtualIPRangeSection` through the data descriptor;
- resolve encoded virtual IPs through that intrusive list using cycle
detection and a 65,536-node per-lookup reader resource budget, with no
map fallback when an encoded VIP is absent;
- mask the WebAssembly funclet flag from `RUNTIME_FUNCTION.BeginAddress`
for ordering and address arithmetic while preserving funclet identity;
- keep the virtual code base (`MinVirtualIP`) separate from the
loaded-image base used for unwind, debug, GC, exception, and thunk RVA
reads;
- handle the actual WASM descriptor shape, where hot/cold metadata and
delay-load thunk metadata are absent;
- classify WASM filter funclets by mapping the executable filter entry
to its containing runtime function.

## Root cause

The model added in #130988 was already false when that PR merged. On
`TARGET_WASM`, ReadyToRun modules are not added to `RangeSectionMap`;
`ReadyToRunInfo::RegisterVirtualIPRange` registers them in
`ExecutionManager::s_pVirtualIPRangeList`, and native `FindCodeRange`
checks that list first.

The prior unit test synthesized a `RangeSectionMap` entry with an
address that did not satisfy native `IsVirtualIP`, so it validated a
mock-only model rather than the live runtime layout. This is a
test-model gap, not a reviewer fault. The prior review explicitly noted
that the WebAssembly specifics had not been run locally and should be
added to cDAC CI:
#130988 (review).

## Blast radius and scope

This affects ReadyToRun code on all CoreCLR WebAssembly hosts, including
browser and WASI. Interpreter code is unaffected.

The list lookup, descriptor feature gating, funclet masking, and
image-base separation are inseparable: exposing the list alone would
still throw while reading absent WASM fields, or could return the wrong
method or read RVA data from the synthetic virtual address space.

This PR is independent of #133086 and intentionally excludes variable
producer/decoder work. #133890 depends on this PR for correct shared
code lookup and function identity.

On WASM, `FilterOffset` is the executable filter entry and can follow a
synthetic funclet prolog. cDAC now mirrors the corrected native
classification in #133932 by resolving that entry to its containing
runtime function before comparing funclet starts. The PRs remain
independent; #133917 does not depend on changing the producer offset.

## Validation

- `./build.sh clr+libs+host`
- `PATH="/opt/homebrew/bin:$PATH" ./build.sh -os browser -c Debug
-subset clr+libs`
- cDAC UnitTests: **3162 passed**
- cDAC DataGeneratorTests: **46 passed**
- cDAC UsageTests: **4 passed**
- generated contract documentation check: **up to date**
- focused ExecutionManager / RuntimeFunction / WasmR2R tests: **221
passed**

The durable tests cover:

- captured/live-shaped VIP `0x80010109`, exact `MethodDesc`, module, and
runtime-function index;
- the actual WASM descriptor shape: 8-byte `RUNTIME_FUNCTION` records
with no `EndAddress`, and absent hot/cold and delay-load thunk fields;
- start/end boundaries and adjacent ranges;
- encoded VIP absent from the list with no `RangeSectionMap` fallback;
- self-cycle, two-node cycle, inverted range, null module, and
overlapping ambiguity;
- unrelated partially registered nodes not blocking initialized ranges,
while an uninitialized candidate fails closed;
- valid 1,024/1,025-node lists, exact 65,536-node budget success, and
budget+1 fail-closed behavior even when the head matches, with a read
counter proving the extra node is never dereferenced;
- root/funclet resolution with a flagged funclet entry that breaks raw
ordering;
- exact loaded-image debug, unwind, GC, and exception-clause reads while
entrypoint lookup uses `MinVirtualIP`;
- filter-funclet classification where `FilterOffset` follows the flagged
funclet start but resolves to the same containing runtime function;
- missing list capability and unchanged ordinary architecture behavior.

Mutation proofs were applied, confirmed in source, run red, restored,
and rerun green:

1. Removing the VIP-list branch fails the captured `0x80010109` test at
the exact code-block assertion.
2. Using raw `BeginAddress` fails the funclet identity test.
3. Using `startVIP` as the loaded-image base fails the GC/unwind test
with a read at `0x80010081` instead of the loaded image.
4. Raising the reader budget from 65,536 to 65,537 makes the budget+1
test fail at its read-boundary assertion (highest node index 65,536
instead of 65,535); restoring the budget returns the suite to green.
5. Replacing WASM filter-entry containing-function resolution with raw
`FilterOffset == funcletStartOffset` comparison makes the filter
regression fail with expected `true` and actual `false`.

The finite list cutoff is an intentional diagnostic-reader resource
policy, not a native registration limit or a claim that an over-budget
list is corrupt.

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

---------

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

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

Labels

arch-wasm WebAssembly architecture area-ReadyToRun

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants