Uh oh!
There was an error while loading. Please reload this page.
[clr-interp] Report async-suspension locals to the debugger via GetAsyncLocals - #127757
Conversation
35b435b to
d41eea4CompareThere was a problem hiding this comment.
Pull request overview
This PR extends CoreCLR’s interpreter async-debugging support so the right-side debugger can retrieve live async locals/arguments for interpreted async frames via DacDbiInterfaceImpl::GetAsyncLocals, analogous to the existing JIT DebugInfoStore pipeline.
Changes:
- Introduces
InterpAsyncDebugVarand adds a per-suspension-point{ ilVarNum, dataOffset }table toInterpAsyncSuspendData. - Emits and persists interpreter async-local debug metadata during
EmitSuspend, storing the debug-var tables in the finalized method data. - Updates the DAC
GetAsyncLocalsimplementation to detect interpreted methods, decode the suspension-point bytecode viastate, and surface interpreter async locals to the debugger.
Show a summary per file
| File | Description |
|---|---|
| src/coreclr/interpreter/inc/interpretershared.h | Adds interpreter async debug-var metadata types/fields carried per suspension point. |
| src/coreclr/interpreter/compiler.cpp | Captures IL var → continuation offset mappings at suspend points and persists them into the unified method allocation. |
| src/coreclr/debug/daccess/dacdbiimpl.cpp | Implements interpreter-aware GetAsyncLocals decoding to return async locals for interpreted frames. |
Copilot's findings
- Files reviewed: 3/3 changed files
- Comments generated: 3
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
d41eea4 to
c873f5aComparec873f5a to
59cef97CompareUh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
59cef97 to
8207ffcCompareUh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
8207ffc to
a275e72Comparea275e72 to
1f75069Compare1f75069 to
f1be050Compare
noahfalk
left a comment
There was a problem hiding this comment.
Looks good to me modulo maybe special variables are missing from the encoding.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
9f75709 to
593d29bCompare…ocals Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…bug info In InterpCompiler::EmitSuspend, the AsyncContinuationVarInfo emission was guarded by var < m_numILVars, which excluded the hidden generics-context arg stored at m_paramArgIndex. Shared-generic async methods would therefore miss the type context and the debugger could fail to resolve generic types in suspended frames. Match the JIT's compMap2ILvarNum behavior by emitting an entry for the param arg with VarNumber = ICorDebugInfo::TYPECTXT_ILNUM when m_methodInfo->args.hasTypeArg(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
593d29b to
38ef4deCompareUh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…ying on emission order EmitCode reorders BBs in waves by overlappingEHClauseCount, so the order INTOP_HANDLE_CONTINUATION_SUSPEND opcodes are emitted does not match the order EmitSuspend assigned suspensionPointIndex. The previous code appended to m_suspensionPointIPOffsets via Add() in emission order, which produced a mismatched index->IP table whenever a method had two awaits at different EH wave depths. In checked builds the assert caught it; in release the runtime would resume at the wrong bytecode offset. Pre-size the table in EmitCode and write entries by suspensionPointIndex. Add an explicit size assert in FinalizeMethodData. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Description
When a managed async method is suspended at an await, the right-side debugger asks for the live values of the user's locals and arguments at that suspension point so they can be displayed on the call stack. The JIT path supplies this through
ICorJitInfo::reportAsyncDebugInfo. The interpreter compiler never hits that path, soICorDebugAsyncFrame::GetArgumentreturnedCORDBG_E_IL_VAR_NOT_AVAILABLEfor every IL variable on every interpreted async frame.This adds a small parallel pipeline for the interpreter.
InterpAsyncSuspendDatanow carries a per suspension point table of{ilVarNum, dataOffset}entries. On the DAC side,GetAsyncLocalsdetects an interpreter method and decodes the bytecode atstartIp + state.This fixes the following interpreter debugger test failures:
Async.AsyncSimpleAsync.AsyncBreakpointAsync.AsyncBreakpointJmcAsync.AsyncGenericAsync.AsyncRecursiveAsync.AsyncSharedGenericAsync.AsyncV2CallingAsyncV1IteratorAsync.AsyncGenericStepInto