diff --git a/src/coreclr/inc/cordebuginfo.h b/src/coreclr/inc/cordebuginfo.h index 16b8b7a85c9887..e5e2cef2a62f7d 100644 --- a/src/coreclr/inc/cordebuginfo.h +++ b/src/coreclr/inc/cordebuginfo.h @@ -388,7 +388,9 @@ class ICorDebugInfo UNKNOWN_ILNUM = -4, // Unknown variable - MAX_ILNUM = -4 // Sentinel value. This should be set to the largest magnitude value in th enum + CALL_RETURN_ILNUM = -5, // The return value of a call + + MAX_ILNUM = -5 // Sentinel value. This should be set to the largest magnitude value in th enum // so that the compression routines know the enum's range. }; @@ -403,6 +405,7 @@ class ICorDebugInfo { uint32_t startOffset; uint32_t endOffset; + uint32_t callReturnValueILOffset; uint32_t varNumber; VarLoc loc; }; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 9f9fadfc081037..85d8a8682bf489 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -37,11 +37,11 @@ #include -constexpr GUID JITEEVersionIdentifier = { /* 5635ae9d-ffa5-4336-b027-a383971e3918 */ - 0x5635ae9d, - 0xffa5, - 0x4336, - {0xb0, 0x27, 0xa3, 0x83, 0x97, 0x1e, 0x39, 0x18} +constexpr GUID JITEEVersionIdentifier = { /* 59df85b8-c0fd-4e40-aea1-68cb2cd916cc */ + 0x59df85b8, + 0xc0fd, + 0x4e40, + {0xae, 0xa1, 0x68, 0xcb, 0x2c, 0xd9, 0x16, 0xcc} }; #endif // JIT_EE_VERSIONING_GUID_H diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp index c637154a6ed3fa..197966de26ebff 100644 --- a/src/coreclr/jit/codegenarmarch.cpp +++ b/src/coreclr/jit/codegenarmarch.cpp @@ -3255,17 +3255,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call) params.isJump = call->IsFastTailCall(); params.hasAsyncRet = call->IsAsync(); - - // We need to propagate the debug information to the call instruction, so we can emit - // an IL to native mapping record for the call, to support managed return value debugging. - // We don't want tail call helper calls that were converted from normal calls to get a record, - // so we skip this hash table lookup logic in that case. - if (m_compiler->opts.compDbgInfo && m_compiler->genCallSite2DebugInfoMap != nullptr && !call->IsTailCall()) - { - DebugInfo di; - (void)m_compiler->genCallSite2DebugInfoMap->Lookup(call, &di); - params.debugInfo = di; - } + params.returnValueCall = call; #ifdef DEBUG // Pass the call signature information down into the emitter so the emitter can associate diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 8a542e1185284b..1adf37528d2a50 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -1759,6 +1759,98 @@ void CodeGen::genEmitCallWithCurrentGC(EmitCallParams& params) params.gcrefRegs = gcInfo.gcRegGCrefSetCur; params.byrefRegs = gcInfo.gcRegByrefSetCur; GetEmitter()->emitIns_Call(params); + + // 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; + } + + if (call->gtReturnType == TYP_VOID) + { + return; + } + + DebugInfo di; + if (!m_compiler->genCallSite2DebugInfoMap->Lookup(call, &di)) + { + return; + } + + emitLocation retLoc; + retLoc.CaptureLocation(GetEmitter()); + + CodeGenInterface::EmittedCallReturnInfo info; + info.callILOffset = di.GetRoot().GetLocation().GetOffset(); + info.returnLocation = retLoc; + + CallArg* retBuf = call->gtArgs.GetRetBufferArg(); + if (retBuf != nullptr) + { + GenTree* node = retBuf->GetNode(); + assert(node->OperIsPutArg()); + + node = node->gtGetOp1()->gtSkipReloadOrCopy(); + if (!node->OperIs(GT_LCL_ADDR)) + { + return; + } + + unsigned lclNum = node->AsLclVarCommon()->GetLclNum(); + unsigned lclOffs = node->AsLclVarCommon()->GetLclOffs(); + int stackLevelBias = 0; +#ifdef TARGET_X86 + stackLevelBias = getCurrentStackLevel(); + if (params.argSize > 0) + { + // Call popped these but stack level hasn't been adjusted yet, account for it here + stackLevelBias -= params.argSize; + } +#endif + + info.returnValueLoc = getSiVarLoc(m_compiler->lvaGetDesc(lclNum), lclOffs, stackLevelBias); + } + else if (call->HasMultiRegRetVal()) + { + const ReturnTypeDesc* retDesc = call->GetReturnTypeDesc(); + unsigned numRegs = retDesc->GetReturnRegCount(); + if (numRegs > 2) + { + // Cannot encode more than 2 registers. + return; + } + + assert(numRegs == 2); + info.returnValueLoc.storeVariableInRegisters( + retDesc->GetABIReturnReg(0, call->GetUnmanagedCallConv()), + retDesc->GetABIReturnReg(1, call->GetUnmanagedCallConv())); + } + else if (varTypeIsFloating(call)) + { +#ifdef TARGET_X86 + info.returnValueLoc.vlType = VLT_FPSTK; + info.returnValueLoc.vlFPstk.vlfReg = 0; +#else + info.returnValueLoc.storeVariableInRegisters(REG_FLOATRET, REG_NA); +#endif + } + else if (varTypeUsesFloatReg(call)) + { + info.returnValueLoc.storeVariableInRegisters(REG_FLOATRET, REG_NA); + } + else + { + info.returnValueLoc.storeVariableInRegisters(REG_INTRET, REG_NA); + } + + if (emittedCallReturnInfo == nullptr) + { + emittedCallReturnInfo = new (m_compiler, CMK_DebugInfo) jitstd::vector(m_compiler->getAllocator(CMK_DebugInfo)); + } + + emittedCallReturnInfo->push_back(info); } /***************************************************************************** diff --git a/src/coreclr/jit/codegeninterface.h b/src/coreclr/jit/codegeninterface.h index ea160060717233..f279e371948dd6 100644 --- a/src/coreclr/jit/codegeninterface.h +++ b/src/coreclr/jit/codegeninterface.h @@ -646,8 +646,15 @@ class CodeGenInterface const LclVarDsc* varDsc, var_types type, regNumber baseReg, int offset, bool isFramePointerUsed); }; + struct EmittedCallReturnInfo + { + IL_OFFSET callILOffset; + emitLocation returnLocation; + siVarLoc returnValueLoc; + }; + public: - siVarLoc getSiVarLoc(const LclVarDsc* varDsc, unsigned int stackLevel) const; + siVarLoc getSiVarLoc(const LclVarDsc* varDsc, unsigned offset, unsigned stackLevel) const; #ifdef DEBUG void dumpSiVarLoc(const siVarLoc* varLoc) const; @@ -858,6 +865,8 @@ class CodeGenInterface protected: VariableLiveKeeper* varLiveKeeper; // Used to manage VariableLiveRanges of variables + jitstd::vector* emittedCallReturnInfo; + #ifdef LATE_DISASM public: virtual const char* siRegVarName(size_t offs, size_t size, unsigned reg) = 0; diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index 9ab94d99448c94..2ea8e5a259181d 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -91,6 +91,7 @@ void CodeGen::genInitialize() } initializeVariableLiveKeeper(); + emittedCallReturnInfo = new (m_compiler, CMK_DebugInfo) jitstd::vector(m_compiler->getAllocator(CMK_DebugInfo)); genPendingCallLabel = nullptr; diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 650e27db737fee..c89efd918c5dc0 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -2473,17 +2473,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call) EmitCallParams params; params.isJump = call->IsFastTailCall(); params.hasAsyncRet = call->IsAsync(); - - // We need to propagate the debug information to the call instruction, so we can emit - // an IL to native mapping record for the call, to support managed return value debugging. - // We don't want tail call helper calls that were converted from normal calls to get a record, - // so we skip this hash table lookup logic in that case. - if (m_compiler->opts.compDbgInfo && m_compiler->genCallSite2DebugInfoMap != nullptr && !call->IsTailCall()) - { - DebugInfo di; - (void)m_compiler->genCallSite2DebugInfoMap->Lookup(call, &di); - params.debugInfo = di; - } + params.returnValueCall = call; #ifdef DEBUG // Pass the call signature information down into the emitter so the emitter can associate diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 2ee68ebbe42318..e4e40e9886625f 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -6196,18 +6196,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackA params.isJump = call->IsFastTailCall(); params.hasAsyncRet = call->IsAsync(); - - // We need to propagate the IL offset information to the call instruction, so we can emit - // an IL to native mapping record for the call, to support managed return value debugging. - // We don't want tail call helper calls that were converted from normal calls to get a record, - // so we skip this hash table lookup logic in that case. - - if (m_compiler->opts.compDbgInfo && m_compiler->genCallSite2DebugInfoMap != nullptr && !call->IsTailCall()) - { - DebugInfo di; - (void)m_compiler->genCallSite2DebugInfoMap->Lookup(call, &di); - params.debugInfo = di; - } + params.returnValueCall = call; #ifdef DEBUG // Pass the call signature information down into the emitter so the emitter can associate diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 583892ca426796..26e6ce1f2d5a2d 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -9516,19 +9516,22 @@ class Compiler void eeGetVars(); - unsigned eeVarsCount; + unsigned eeVarsCount = 0; + unsigned eeVarsCapacity = 0; struct VarResultInfo { UNATIVE_OFFSET startOffset; UNATIVE_OFFSET endOffset; + uint32_t callReturnValueILOffset; DWORD varNumber; CodeGenInterface::siVarLoc loc; }* eeVars; void eeSetLVcount(unsigned count); void eeSetLVinfo(unsigned which, UNATIVE_OFFSET startOffs, - UNATIVE_OFFSET length, + UNATIVE_OFFSET endOffs, + uint32_t callReturnValILOffs, unsigned varNum, const CodeGenInterface::siVarLoc& loc); void eeSetLVdone(); diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index b8835143440fbc..9db995cdbaa9e3 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -670,10 +670,10 @@ void Compiler::eeSetLVcount(unsigned count) JITDUMP("VarLocInfo count is %d\n", count); - eeVarsCount = count; - if (eeVarsCount) + eeVarsCapacity = count; + if (count > 0) { - eeVars = (VarResultInfo*)info.compCompHnd->allocateArray(eeVarsCount * sizeof(eeVars[0])); + eeVars = (VarResultInfo*)info.compCompHnd->allocateArray(count * sizeof(eeVars[0])); } else { @@ -683,7 +683,8 @@ void Compiler::eeSetLVcount(unsigned count) void Compiler::eeSetLVinfo(unsigned which, UNATIVE_OFFSET startOffs, - UNATIVE_OFFSET length, + UNATIVE_OFFSET endOffs, + uint32_t callReturnValueILOffset, unsigned varNum, const CodeGenInterface::siVarLoc& varLoc) { @@ -691,13 +692,13 @@ void Compiler::eeSetLVinfo(unsigned which, // This is checked in siInit() assert(opts.compScopeInfo); - assert(eeVarsCount > 0); - assert(which < eeVarsCount); + assert(which < eeVarsCapacity); if (eeVars != nullptr) { eeVars[which].startOffset = startOffs; - eeVars[which].endOffset = startOffs + length; + eeVars[which].endOffset = endOffs; + eeVars[which].callReturnValueILOffset = callReturnValueILOffset; eeVars[which].varNumber = varNum; eeVars[which].loc = varLoc; } @@ -870,7 +871,12 @@ void Compiler::eeDispVar(ICorDebugInfo::NativeVarInfo* var) { name = "typeCtx"; } - if (0 <= var->varNumber && var->varNumber < lvaCount) + + if (var->varNumber == (DWORD)ICorDebugInfo::CALL_RETURN_ILNUM) + { + int printed = printf("(call %03u)", var->callReturnValueILOffset); + } + else if (0 <= var->varNumber && var->varNumber < lvaCount) { printf("("); gtDispLclVar(var->varNumber, false); @@ -878,7 +884,7 @@ void Compiler::eeDispVar(ICorDebugInfo::NativeVarInfo* var) } else { - printf("(%10s)", (VarNameToStr(name) == nullptr) ? "UNKNOWN" : VarNameToStr(name)); + printf("(%8s)", (VarNameToStr(name) == nullptr) ? "UNKNOWN" : VarNameToStr(name)); } printf(" : From %08Xh to %08Xh, in ", var->startOffset, var->endOffset); diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index 08326526046229..690572766f6135 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -482,13 +482,14 @@ struct EmitCallParams BitVec ptrVars = BitVecOps::UninitVal(); regMaskTP gcrefRegs = RBM_NONE; regMaskTP byrefRegs = RBM_NONE; - DebugInfo debugInfo; 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 diff --git a/src/coreclr/jit/emitarm.cpp b/src/coreclr/jit/emitarm.cpp index 8532b6dbdb3cea..e3c00969d1d226 100644 --- a/src/coreclr/jit/emitarm.cpp +++ b/src/coreclr/jit/emitarm.cpp @@ -4683,12 +4683,6 @@ void emitter::emitIns_Call(const EmitCallParams& params) } #endif - /* Managed RetVal: emit sequence point for the call */ - if (m_compiler->opts.compDbgInfo && params.debugInfo.GetLocation().IsValid()) - { - codeGen->genIPmappingAdd(IPmappingDscKind::Normal, params.debugInfo, false); - } - /* We need to allocate the appropriate instruction descriptor based on whether this is a direct/indirect call, and whether we need to diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index ec30c012bd5ee5..df868fd3d7d137 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -9493,12 +9493,6 @@ void emitter::emitIns_Call(const EmitCallParams& params) } #endif - /* Managed RetVal: emit sequence point for the call */ - if (m_compiler->opts.compDbgInfo && params.debugInfo.GetLocation().IsValid()) - { - codeGen->genIPmappingAdd(IPmappingDscKind::Normal, params.debugInfo, false); - } - /* We need to allocate the appropriate instruction descriptor based on whether this is a direct/indirect call, and whether we need to diff --git a/src/coreclr/jit/emitloongarch64.cpp b/src/coreclr/jit/emitloongarch64.cpp index 716e15f392627f..dedb4aaf034795 100644 --- a/src/coreclr/jit/emitloongarch64.cpp +++ b/src/coreclr/jit/emitloongarch64.cpp @@ -2460,12 +2460,6 @@ void emitter::emitIns_Call(const EmitCallParams& params) } #endif - /* Managed RetVal: emit sequence point for the call */ - if (m_compiler->opts.compDbgInfo && params.debugInfo.GetLocation().IsValid()) - { - codeGen->genIPmappingAdd(IPmappingDscKind::Normal, params.debugInfo, false); - } - /* We need to allocate the appropriate instruction descriptor based on whether this is a direct/indirect call, and whether we need to diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp index f1de046359846e..6ecd43185f330b 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp @@ -1941,12 +1941,6 @@ void emitter::emitIns_Call(const EmitCallParams& params) emitLoadImmediate(EA_PTRSIZE, params.ireg, imm); // upper bits } - /* Managed RetVal: emit sequence point for the call */ - if (m_compiler->opts.compDbgInfo && params.debugInfo.GetLocation().IsValid()) - { - codeGen->genIPmappingAdd(IPmappingDscKind::Normal, params.debugInfo, false); - } - /* We need to allocate the appropriate instruction descriptor based on whether this is a direct/indirect call, and whether we need to diff --git a/src/coreclr/jit/emitwasm.cpp b/src/coreclr/jit/emitwasm.cpp index e897fd1126a255..2a26a49a8683b1 100644 --- a/src/coreclr/jit/emitwasm.cpp +++ b/src/coreclr/jit/emitwasm.cpp @@ -179,12 +179,6 @@ void emitter::emitIns_Call(const EmitCallParams& params) assert(params.callType < EC_COUNT); assert((params.callType == EC_FUNC_TOKEN) || (params.addr == nullptr)); - /* Managed RetVal: emit sequence point for the call */ - if (m_compiler->opts.compDbgInfo && params.debugInfo.GetLocation().IsValid()) - { - codeGen->genIPmappingAdd(IPmappingDscKind::Normal, params.debugInfo, false); - } - assert(params.wasmSignature != nullptr); /* diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 57e520a12818a4..3be7f7c4b0f13b 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -11352,12 +11352,6 @@ void emitter::emitIns_Call(const EmitCallParams& params) } #endif - /* Managed RetVal: emit sequence point for the call */ - if (m_compiler->opts.compDbgInfo && params.debugInfo.IsValid()) - { - codeGen->genIPmappingAdd(IPmappingDscKind::Normal, params.debugInfo, false); - } - /* We need to allocate the appropriate instruction descriptor based on whether this is a direct/indirect call, and whether we need to diff --git a/src/coreclr/jit/scopeinfo.cpp b/src/coreclr/jit/scopeinfo.cpp index 9fc32e0fb48798..e21eb70c9fcfee 100644 --- a/src/coreclr/jit/scopeinfo.cpp +++ b/src/coreclr/jit/scopeinfo.cpp @@ -486,6 +486,7 @@ CodeGenInterface::siVarLoc::siVarLoc(const LclVarDsc* varDsc, regNumber baseReg, // // Arguments: // varDsc - the variable it is desired to build the "siVarLoc". +// offset - offset into the variable to add // stackLevel - the current stack level. If the stack pointer changes in // the function, we must adjust stack pointer-based local // variable offsets to compensate. @@ -494,12 +495,12 @@ CodeGenInterface::siVarLoc::siVarLoc(const LclVarDsc* varDsc, regNumber baseReg, // A "siVarLoc" representing the variable location, which could live // in a register, an stack position, or a combination of both. // -CodeGenInterface::siVarLoc CodeGenInterface::getSiVarLoc(const LclVarDsc* varDsc, unsigned int stackLevel) const +CodeGenInterface::siVarLoc CodeGenInterface::getSiVarLoc(const LclVarDsc* varDsc, unsigned offset, unsigned stackLevel) const { // For stack vars, find the base register, and offset regNumber baseReg; - signed offset = varDsc->GetStackOffset(); + offset += varDsc->GetStackOffset(); if (!varDsc->lvFramePointerBased) { @@ -1080,7 +1081,7 @@ void CodeGenInterface::VariableLiveKeeper::siStartVariableLiveRange(const LclVar { // Build siVarLoc for this born "varDsc" CodeGenInterface::siVarLoc varLocation = - m_compiler->codeGen->getSiVarLoc(varDsc, m_compiler->codeGen->getCurrentStackLevel()); + m_compiler->codeGen->getSiVarLoc(varDsc, 0, m_compiler->codeGen->getCurrentStackLevel()); VariableLiveDescriptor* varLiveDsc = &m_vlrLiveDsc[varNum]; // this variable live range is valid from this point @@ -1149,7 +1150,7 @@ void CodeGenInterface::VariableLiveKeeper::siUpdateVariableLiveRange(const LclVa { // Build the location of the variable CodeGenInterface::siVarLoc siVarLoc = - m_compiler->codeGen->getSiVarLoc(varDsc, m_compiler->codeGen->getCurrentStackLevel()); + m_compiler->codeGen->getSiVarLoc(varDsc, 0, m_compiler->codeGen->getCurrentStackLevel()); // Report the home change for this variable VariableLiveDescriptor* varLiveDsc = &m_vlrLiveDsc[varNum]; @@ -1781,9 +1782,7 @@ void CodeGen::genSetScopeInfo() } #endif - unsigned varsLocationsCount = 0; - - varsLocationsCount = (unsigned int)varLiveKeeper->getLiveRangesCount(); + unsigned varsLocationsCount = (unsigned int)(varLiveKeeper->getLiveRangesCount() + emittedCallReturnInfo->size()); if (varsLocationsCount == 0) { @@ -1812,6 +1811,18 @@ void CodeGen::genSetScopeInfo() genSetScopeInfoUsingVariableRanges(); + for (const EmittedCallReturnInfo& callReturnInfo : *emittedCallReturnInfo) + { + UNATIVE_OFFSET retOffset = callReturnInfo.returnLocation.CodeOffset(GetEmitter()); + + m_compiler->eeSetLVinfo( + m_compiler->eeVarsCount++, + retOffset, retOffset + 1, + callReturnInfo.callILOffset, + ICorDebugInfo::CALL_RETURN_ILNUM, + callReturnInfo.returnValueLoc); + } + m_compiler->eeSetLVdone(); } @@ -2001,7 +2012,7 @@ void CodeGen::genSetScopeInfo(unsigned which, #endif // DEBUG - m_compiler->eeSetLVinfo(which, startOffs, length, ilVarNum, *varLoc); + m_compiler->eeSetLVinfo(which, startOffs, startOffs + length, 0, ilVarNum, *varLoc); } /*****************************************************************************/ diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.VarInfo.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.VarInfo.cs index cd6d82f8f511e8..e307bcb2844616 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.VarInfo.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.VarInfo.cs @@ -34,6 +34,7 @@ public struct NativeVarInfo { public uint startOffset; public uint endOffset; + public uint callReturnValueILOffset; public uint varNumber; public VarLoc varLoc; }; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index f9166214b67a68..ba6d2e9812280c 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1371,7 +1371,9 @@ public enum ILNum UNKNOWN_ILNUM = -4, // Unknown variable - MAX_ILNUM = -4 // Sentinel value. This should be set to the largest magnitude value in the enum + CALL_RETURN_ILNUM = -5, // The return value of a call + + MAX_ILNUM = -5 // Sentinel value. This should be set to the largest magnitude value in the enum // so that the compression routines know the enum's range. }; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugInfoTableNode.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugInfoTableNode.cs index f2a1484bdeea91..0f58b1e2c97780 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugInfoTableNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugInfoTableNode.cs @@ -254,9 +254,17 @@ public static byte[] CreateVarBlobForMethod(NativeVarInfo[] varInfos, TargetDeta foreach (var nativeVarInfo in varInfos) { - writer.WriteUInt(nativeVarInfo.startOffset); - writer.WriteUInt(nativeVarInfo.endOffset - nativeVarInfo.startOffset); writer.WriteUInt((uint)(nativeVarInfo.varNumber - (int)ILNum.MAX_ILNUM)); + writer.WriteUInt(nativeVarInfo.startOffset); + + if (nativeVarInfo.varNumber == unchecked((uint)ILNum.CALL_RETURN_ILNUM)) + { + writer.WriteUInt(nativeVarInfo.callReturnValueILOffset); + } + else + { + writer.WriteUInt(nativeVarInfo.endOffset - nativeVarInfo.startOffset); + } VarLocType varLocType = nativeVarInfo.varLoc.LocationType; diff --git a/src/coreclr/vm/debuginfostore.cpp b/src/coreclr/vm/debuginfostore.cpp index 585bdabf8de52d..dc5133e052240c 100644 --- a/src/coreclr/vm/debuginfostore.cpp +++ b/src/coreclr/vm/debuginfostore.cpp @@ -143,6 +143,9 @@ class TransferWriter void DoEncodedVarLocType(ICorDebugInfo::VarLocType & dw) { m_w.WriteEncodedU32(dw); } void DoEncodedUnsigned(unsigned & dw) { m_w.WriteEncodedU32(dw); } + void DoImplicitCallReturnValueILOffset(uint32_t& ilOffset) { } + void DoImplicitEndOffset(uint32_t& endOffset, uint32_t startOffset) { } + // Stack offsets are aligned on a DWORD boundary, so that lets us shave off 2 bits. void DoEncodedStackOffset(signed & dwOffset) { @@ -250,6 +253,17 @@ class TransferReader dw = (unsigned) m_r.ReadEncodedU32_NoThrow(); } + void DoImplicitCallReturnValueILOffset(uint32_t& ilOffset) + { + SUPPORTS_DAC; + ilOffset = 0; + } + + void DoImplicitEndOffset(uint32_t& endOffset, uint32_t startOffset) + { + SUPPORTS_DAC; + endOffset = startOffset + 1; + } // Stack offsets are aligned on a DWORD boundary, so that lets us shave off 2 bits. void DoEncodedStackOffset(signed & dwOffset) @@ -340,14 +354,21 @@ static void DoNativeVarInfo( // - VarLoc information. This is a tagged variant. // The entries aren't sorted in any particular order. trans.DoCookie(0xB); - trans.DoEncodedU32(pVar->startOffset); - - - trans.DoEncodedDeltaU32(pVar->endOffset, pVar->startOffset); - // record var number. trans.DoEncodedAdjustedU32(pVar->varNumber, (DWORD) ICorDebugInfo::MAX_ILNUM); + trans.DoEncodedU32(pVar->startOffset); + + if (pVar->varNumber == ICorDebugInfo::CALL_RETURN_ILNUM) + { + trans.DoEncodedU32(pVar->callReturnValueILOffset); + trans.DoImplicitEndOffset(pVar->endOffset, pVar->startOffset); + } + else + { + trans.DoEncodedDeltaU32(pVar->endOffset, pVar->startOffset); + trans.DoImplicitCallReturnValueILOffset(pVar->callReturnValueILOffset); + } // Now write the VarLoc... This is a variant like structure and so we'll get different // compressioned depending on what we've got.