Skip to content

JIT: Report managed-return-values as a native var#128479

Draft
jakobbotsch wants to merge 3 commits into
dotnet:mainfrom
jakobbotsch:mrv-return-vars
Draft

JIT: Report managed-return-values as a native var#128479
jakobbotsch wants to merge 3 commits into
dotnet:mainfrom
jakobbotsch:mrv-return-vars

Conversation

@jakobbotsch
Copy link
Copy Markdown
Member

JIT and compression side of #128397

Copilot AI review requested due to automatic review settings May 22, 2026 12:01
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label May 22, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates CoreCLR JIT/VM debug-info plumbing to represent managed call return values as explicit ICorDebugInfo::NativeVarInfo entries (via a new CALL_RETURN_ILNUM sentinel plus a callReturnValueILOffset field), instead of relying on CALL_INSTRUCTION IP mapping entries. It also updates the compression/writer paths to encode this new data.

Changes:

  • Extended NativeVarInfo (and the shared JIT interface model) with callReturnValueILOffset, and added CALL_RETURN_ILNUM / updated MAX_ILNUM.
  • Updated debug info encoding/compression to treat CALL_RETURN_ILNUM specially (encode call IL offset; implicit native end offset).
  • Updated the JIT to collect per-call return-value location info and removed call-site CALL_INSTRUCTION mapping emission in multiple emitters.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/coreclr/vm/debuginfostore.cpp Adds special-case encoding/decoding for CALL_RETURN_ILNUM and implicit fields.
src/coreclr/tools/Common/JitInterface/CorInfoTypes.VarInfo.cs Extends NativeVarInfo model with callReturnValueILOffset.
src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs Adds CALL_RETURN_ILNUM and updates MAX_ILNUM.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugInfoTableNode.cs Updates R2R var blob writer to encode call-return entries differently.
src/coreclr/jit/scopeinfo.cpp Adds emission of call-return var entries; updates getSiVarLoc signature/use.
src/coreclr/jit/emitxarch.cpp Removes call-site mapping emission previously used for return value reporting.
src/coreclr/jit/emitwasm.cpp Removes call-site mapping emission previously used for return value reporting.
src/coreclr/jit/emitriscv64.cpp Removes call-site mapping emission previously used for return value reporting.
src/coreclr/jit/emitloongarch64.cpp Removes call-site mapping emission previously used for return value reporting.
src/coreclr/jit/emitarm64.cpp Removes call-site mapping emission previously used for return value reporting.
src/coreclr/jit/emitarm.cpp Removes call-site mapping emission previously used for return value reporting.
src/coreclr/jit/emit.h Replaces EmitCallParams.debugInfo with returnValueCall.
src/coreclr/jit/ee_il_dll.cpp Updates var reporting storage to carry call IL offset; improves display of call-return entries.
src/coreclr/jit/compiler.h Extends VarResultInfo and updates eeSetLVinfo signature for call return metadata.
src/coreclr/jit/codegenxarch.cpp Switches call emission plumbing to pass returnValueCall.
src/coreclr/jit/codegenwasm.cpp Switches call emission plumbing to pass returnValueCall.
src/coreclr/jit/codegenlinear.cpp Initializes storage for emitted call-return info.
src/coreclr/jit/codegeninterface.h Adds EmittedCallReturnInfo container and updates getSiVarLoc signature.
src/coreclr/jit/codegencommon.cpp Captures return-value location after emitting a call and records it for scope info.
src/coreclr/jit/codegenarmarch.cpp Switches call emission plumbing to pass returnValueCall.
src/coreclr/inc/cordebuginfo.h Adds CALL_RETURN_ILNUM and extends NativeVarInfo with callReturnValueILOffset.
Comments suppressed due to low confidence (2)

src/coreclr/jit/scopeinfo.cpp:516

  • getSiVarLoc now takes unsigned offset and then adds varDsc->GetStackOffset() (a signed stack offset that can be negative). This can underflow/wrap for typical frame-pointer locals (negative offsets), and then gets converted to int when constructing siVarLoc, producing incorrect stack locations in debug info.
CodeGenInterface::siVarLoc CodeGenInterface::getSiVarLoc(const LclVarDsc* varDsc, unsigned offset, unsigned stackLevel) const
{
    // For stack vars, find the base register, and offset

    regNumber baseReg;
    offset += varDsc->GetStackOffset();

    if (!varDsc->lvFramePointerBased)
    {
        baseReg = REG_SPBASE;
        offset += stackLevel;
    }
    else
    {
        baseReg = REG_FPBASE;
    }

    return CodeGenInterface::siVarLoc(varDsc, baseReg, offset, isFramePointerUsed());
}

src/coreclr/jit/emit.h:496

  • EmitCallParams removed the debugInfo field, but there are still target-specific codegen paths assigning params.debugInfo (e.g., in codegenloongarch64.cpp and codegenriscv64.cpp). This will break builds for those targets unless they are updated to the new returnValueCall mechanism.
struct EmitCallParams
{
    EmitCallType          callType = EC_COUNT;
    CORINFO_METHOD_HANDLE methHnd  = NO_METHOD_HANDLE;
#ifdef DEBUG
    // Used to report call sites to the EE
    CORINFO_SIG_INFO* sigInfo = nullptr;
#endif
    void*    addr    = nullptr;
    ssize_t  argSize = 0;
    emitAttr retSize = EA_PTRSIZE;
    // For multi-reg args with GC returns in the second arg
    emitAttr  secondRetSize = EA_UNKNOWN;
    bool      hasAsyncRet   = false;
    BitVec    ptrVars       = BitVecOps::UninitVal();
    regMaskTP gcrefRegs     = RBM_NONE;
    regMaskTP byrefRegs     = RBM_NONE;
    regNumber ireg        = REG_NA;
    regNumber xreg        = REG_NA;
    unsigned  xmul        = 0;
    ssize_t   disp        = 0;
    bool      isJump      = false;
    bool      noSafePoint = false;
    // If this call should have managed return value debug info associated with it, this is the call to associate it with.
    GenTreeCall* returnValueCall = nullptr;
#ifdef TARGET_WASM
    CORINFO_WASM_TYPE_SYMBOL_HANDLE wasmSignature = nullptr;
#endif
};

Comment on lines +1763 to +1769
// Emit an entry for managed return value reporting, if needed.
GenTreeCall* call = params.returnValueCall;
JITDUMP("Emit ret val for [%06u]\n", call == nullptr ? 0 : Compiler::dspTreeID(call));
if ((call == nullptr) || !m_compiler->opts.compDbgInfo || (m_compiler->genCallSite2DebugInfoMap == nullptr) || params.isJump)
{
return;
}
Comment on lines +1801 to +1804
unsigned lclNum = node->AsLclVarCommon()->GetLclNum();
unsigned lclOffs = node->AsLclVarCommon()->GetLclOffs();
info.returnValueLoc = getSiVarLoc(m_compiler->lvaGetDesc(lclNum), lclOffs, 0);
}
Comment on lines +875 to +878
if (var->varNumber == (DWORD)ICorDebugInfo::CALL_RETURN_ILNUM)
{
int printed = printf("(call %03u)", var->callReturnValueILOffset);
}
Comment on lines +146 to +147
void DoImplicitCallReturnValueILOffset(uint32_t& ilOffset) { }
void DoImplicitEndOffset(uint32_t& endOffset, uint32_t startOffset) { }
Comment on lines 89 to 96
{
siInit();
}

initializeVariableLiveKeeper();
emittedCallReturnInfo = new (m_compiler, CMK_DebugInfo) jitstd::vector<EmittedCallReturnInfo>(m_compiler->getAllocator(CMK_DebugInfo));

genPendingCallLabel = nullptr;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants