[cDAC][wasm] Map portable entry points to interpreter code and R2R virtual IPs - #134827
Merged
Merged
Conversation
…rtual IPs > [!IMPORTANT] > Stacked on #134754 (targets its branch). Only the commits above #134754's head belong to this PR; retarget to `main` once #134754 merges. ## Problem On `FEATURE_PORTABLE_ENTRYPOINTS` targets (WebAssembly), a method's entry point slot holds a `PortableEntryPoint` address. Native maps it before handing it to diagnostics (`GetInterpreterCodeFromEntryPointIfPresent` / `GetDiagnosticCodeStartFromEntryPoint` in `precode.cpp`), but the cDAC returned the raw address. SOS values such as `DacpMethodDescData.NativeCodeAddr` and rejit `NativeCodeAddr`, plus the DBI/`ClrDataMethodInstance` paths, therefore reported an address that doesn't resolve through `ExecutionManager` for both interpreted and R2R methods. ## Change Adds `IExecutionManager.GetDiagnosticCodeStartFromEntryPoint`, which mirrors the native `GetDiagnosticCodeStartFromEntryPoint`: - **Without portable entrypoints:** delegates to `PrecodeStubs.GetInterpreterCodeFromInterpreterPrecodeIfPresent`. Behavior is unchanged. - **With portable entrypoints:** 1. Returns the address unchanged if it lies in a code range. This is the native `FindCodeRange` check and includes Wasm R2R virtual-IP ranges from #133917. 2. Maps interpreted methods to `MethodDesc::m_interpreterCode`. 3. Maps native R2R methods from the function-table index in `PortableEntryPoint._pActualCode` to the synthetic virtual IP, stepping back past funclet entries. This matches `ExecutionManager::GetWasmVirtualIPFromFunctionTableIndex`. As in native code, it applies only to the method's own (temporary) entry point, and only when the entry point doesn't prefer the interpreter. The mapping lives in ExecutionManager rather than PrecodeStubs because ExecutionManager owns the virtual-IP ranges and R2R lookup. ExecutionManager already depends on PrecodeStubs, so this adds no contract cycle. Function-table-index resolution moves into `ExecutionManagerHelpers.WasmFunctionTableIndexLookup`, which now bounds the list walk and detects cycles, like the virtual-IP list walk. The stack walk's `WasmR2RInfo` becomes a thin wrapper over it. The Legacy SOS/DBI callers (`SOSDacImpl`, `ClrDataMethodInstance`, `DacDbiImpl`) now call the new API. `DacDbiImpl.EnumerateAsyncLocals` also maps its code address before querying async debug info. The native DAC's `EnumerateAsyncLocals` gets the matching `GetInterpreterCodeFromEntryPointIfPresent` mapping (as `GetMethodVarInfo` already does), so the debug-build cDAC/DAC cross-check stays consistent. ### Data descriptors - `PortableEntryPoint.ActualCode` and `PortableEntryPoint.Flags` (only under `FEATURE_PORTABLE_ENTRYPOINTS`). - `MethodDesc.InterpreterCode` (only under `FEATURE_INTERPRETER`). - The contract relies on `kPrefersInterpreterEntryPoint` and `INTERPRETER_CODE_POISON`; the native side now has `[cDAC]` comments marking that dependency. ### Interaction with #133890 #133890 adds `TryGetFunctionIdentity` and `TryIsFunclet` to `WasmR2RInfo`. Whichever PR lands second should add those two methods to `WasmFunctionTableIndexLookup` and have `WasmR2RInfo` forward to them. The `FunctionTableIndexRange*` descriptor meanings here already use #133890's exact wording, so that JSON should merge cleanly. ## Validation - cDAC: `./build.sh -s tools.cdac+tools.cdactests -c Debug -test` passes: 3196 unit tests (17 new), usage tests (contract cycles and generated docs up to date), and generator tests. - New ExecutionManager tests cover: - interpreted, R2R, funclet, poison, prefers-interpreter, not-own-entry-point and unknown-index cases; - an end-to-end check that the resolved virtual IP maps back to the MethodDesc through `GetCodeBlockHandle`; - readable `PortableEntryPoint`-shaped bytes inside a registered code range staying unchanged. This test fails if the range check is removed. - a cyclic function-table range list; - the non-portable delegation path. - CoreCLR `clr.runtime` builds for osx-arm64 Debug (with `FEATURE_INTERPRETER`) and browser-wasm Debug. The generated wasm descriptor has `PortableEntryPoint {ActualCode@0, MethodDesc@4, Flags@12}`. - A new `DacDbiImplTests` test covers `EnumerateAsyncLocals` mapping for both the code-address and MethodDesc paths. It fails without the fix. - cDAC dump tests (osx-arm64, local runtime): 260 passed, 0 failed. The 746 skips are net10.0 configurations plus by-design skips (Windows-only COM debuggees, and dump types a debuggee doesn't produce). - CoreCLR `clr.runtime` Release (osx-arm64) builds with the `dacdbiimpl.cpp` change. - Not run: any check against a live wasm target. Fixes #134753 > [!NOTE] > This PR description was generated with GitHub Copilot. --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
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. |
Contributor
|
Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag |
Contributor
|
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara |
rcj1
approved these changes
Sep 29, 2026
lewing
enabled auto-merge (squash)
September 29, 2026 20:29
This was referenced Sep 29, 2026
Member
Author
|
/ba-g all failures have been identified |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This replaces #134756, which was merged into #134754's branch by mistake and reverted there. The change is otherwise identical (cherry-picked onto
main).Problem
On
FEATURE_PORTABLE_ENTRYPOINTStargets (WebAssembly), a method's entry point slot holds aPortableEntryPointaddress. Native maps it before handing it to diagnostics (GetInterpreterCodeFromEntryPointIfPresent/GetDiagnosticCodeStartFromEntryPointinprecode.cpp), but the cDAC returned the raw address. SOS values such asDacpMethodDescData.NativeCodeAddrand rejitNativeCodeAddr, plus the DBI/ClrDataMethodInstancepaths, therefore reported an address that doesn't resolve throughExecutionManagerfor both interpreted and R2R methods.Change
Adds
IExecutionManager.GetDiagnosticCodeStartFromEntryPoint, which mirrors the nativeGetDiagnosticCodeStartFromEntryPoint:PrecodeStubs.GetInterpreterCodeFromInterpreterPrecodeIfPresent. Behavior is unchanged.FindCodeRangecheck and includes Wasm R2R virtual-IP ranges from [cDAC][wasm] Resolve ReadyToRun virtual IP ranges #133917.MethodDesc::m_interpreterCode.PortableEntryPoint._pActualCodeto the synthetic virtual IP, stepping back past funclet entries. This matchesExecutionManager::GetWasmVirtualIPFromFunctionTableIndex. As in native code, it applies only to the method's own (temporary) entry point, and only when the entry point doesn't prefer the interpreter.The mapping lives in ExecutionManager rather than PrecodeStubs because ExecutionManager owns the virtual-IP ranges and R2R lookup. ExecutionManager already depends on PrecodeStubs, so this adds no contract cycle.
Function-table-index resolution moves into
ExecutionManagerHelpers.WasmFunctionTableIndexLookup, which now bounds the list walk and detects cycles, like the virtual-IP list walk. The stack walk'sWasmR2RInfobecomes a thin wrapper over it.The Legacy SOS/DBI callers (
SOSDacImpl,ClrDataMethodInstance,DacDbiImpl) now call the new API.DacDbiImpl.EnumerateAsyncLocalsalso maps its code address before querying async debug info. The native DAC'sEnumerateAsyncLocalsgets the matchingGetInterpreterCodeFromEntryPointIfPresentmapping (asGetMethodVarInfoalready does), so the debug-build cDAC/DAC cross-check stays consistent.Data descriptors
PortableEntryPoint.ActualCodeandPortableEntryPoint.Flags(only underFEATURE_PORTABLE_ENTRYPOINTS).MethodDesc.InterpreterCode(only underFEATURE_INTERPRETER).kPrefersInterpreterEntryPointandINTERPRETER_CODE_POISON; the native side now has[cDAC]comments marking that dependency.Interaction with #133890
#133890 adds
TryGetFunctionIdentityandTryIsFunclettoWasmR2RInfo. Whichever PR lands second should add those two methods toWasmFunctionTableIndexLookupand haveWasmR2RInfoforward to them. TheFunctionTableIndexRange*descriptor meanings here already use #133890's exact wording, so that JSON should merge cleanly.Validation
./build.sh -s tools.cdac+tools.cdactests -c Debug -testpasses: 3196 unit tests (17 new), usage tests (contract cycles and generated docs up to date), and generator tests.GetCodeBlockHandle;PortableEntryPoint-shaped bytes inside a registered code range staying unchanged. This test fails if the range check is removed.clr.runtimebuilds for osx-arm64 Debug (withFEATURE_INTERPRETER) and browser-wasm Debug. The generated wasm descriptor hasPortableEntryPoint {ActualCode@0, MethodDesc@4, Flags@12}.DacDbiImplTeststest coversEnumerateAsyncLocalsmapping for both the code-address and MethodDesc paths. It fails without the fix.clr.runtimeRelease (osx-arm64) builds with thedacdbiimpl.cppchange.main:./build.sh clr -c Debug(osx-arm64) builds, and./build.sh -s tools.cdac+tools.cdactests -c Debug -testpasses (3196 unit tests, 46 generator tests, 4 usage tests; 0 failed).Resolves #134753
Note
This PR description was generated with GitHub Copilot.