diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index 7a1a9d7d84d1e1..7262a2c4ce2bf7 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -1092,6 +1092,15 @@ int32_t* InterpCompiler::EmitCodeIns(int32_t *ip, InterpInst *ins, TArrayflags & INTERP_INST_FLAG_DBG_CALL_INSTRUCTION) + { + InterpCallReturnInfo info; + info.ilOffset = ilOffset; + info.postCallNativeOffset = ConvertOffset(ins->nativeOffset + GetInsLength(ins)); + info.returnValueVarOffset = m_pVars[ins->dVar].offset; + m_callReturnInfos.Add(info); + } } } @@ -1258,10 +1267,12 @@ void InterpCompiler::EmitCode() PatchRelocations(&relocs); - if (m_numILVars > 0) + int32_t callReturnCount = m_callReturnInfos.GetSize(); + int32_t totalVarCount = m_numILVars + callReturnCount; + if (totalVarCount > 0) { // This will eventually be freed by the VM, using freeArray. - ICorDebugInfo::NativeVarInfo* eeVars = (ICorDebugInfo::NativeVarInfo*)m_compHnd->allocateArray(m_numILVars * sizeof(ICorDebugInfo::NativeVarInfo)); + ICorDebugInfo::NativeVarInfo* eeVars = (ICorDebugInfo::NativeVarInfo*)m_compHnd->allocateArray(totalVarCount * sizeof(ICorDebugInfo::NativeVarInfo)); int j = 0; for (int i = 0; i < m_numILVars; i++) @@ -1276,7 +1287,22 @@ void InterpCompiler::EmitCode() j++; } - m_compHnd->setVars(m_methodInfo->ftn, m_numILVars, eeVars); + // Append a CALL_RETURN_ILNUM entry per managed call site so the debugger can read the + // return value when stepping out of the callee. + for (int i = 0; i < callReturnCount; i++) + { + const InterpCallReturnInfo& callReturn = m_callReturnInfos.Get(i); + eeVars[j].startOffset = callReturn.postCallNativeOffset; + eeVars[j].endOffset = callReturn.postCallNativeOffset + 1; // implicit, recomputed on decode + eeVars[j].varNumber = (uint32_t)ICorDebugInfo::CALL_RETURN_ILNUM; + eeVars[j].callReturnValueILOffset = callReturn.ilOffset; + eeVars[j].loc.vlType = ICorDebugInfo::VLT_STK; + eeVars[j].loc.vlStk.vlsBaseReg = ICorDebugInfo::REGNUM_FP; + eeVars[j].loc.vlStk.vlsOffset = callReturn.returnValueVarOffset; + j++; + } + + m_compHnd->setVars(m_methodInfo->ftn, totalVarCount, eeVars); } if (m_ILToNativeMapSize == 0 && m_pILToNativeMap != NULL) @@ -2187,6 +2213,7 @@ InterpCompiler::InterpCompiler(COMP_HANDLE compHnd, , m_initLocals(false) , m_unmanagedCallersOnly(false) , m_publishSecretStubParam(false) + , m_callReturnInfos(GetMemPoolAllocator(IMK_NativeToILMapping)) , m_globalVarsWithRefsStackTop(0) , m_varIntervalMaps(GetMemPoolAllocator(IMK_IntervalMap)) #ifdef DEBUG @@ -5645,6 +5672,8 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re m_pLastNewIns->SetSVar(CALL_ARGS_SVAR); m_pLastNewIns->flags |= INTERP_INST_FLAG_CALL; + if (!tailcall && !newObj && !isCalli && callInfo.sig.retType != CORINFO_TYPE_VOID) + m_pLastNewIns->flags |= INTERP_INST_FLAG_DBG_CALL_INSTRUCTION; m_pLastNewIns->info.pCallInfo = new (getAllocator(IMK_CallInfo)) InterpCallInfo(); m_pLastNewIns->info.pCallInfo->pCallArgs = callArgs; diff --git a/src/coreclr/interpreter/compiler.h b/src/coreclr/interpreter/compiler.h index 3b5acb11c47a3a..2d7a58561df114 100644 --- a/src/coreclr/interpreter/compiler.h +++ b/src/coreclr/interpreter/compiler.h @@ -241,7 +241,16 @@ enum InterpInstFlags // Flag used internally by the var offset allocator INTERP_INST_FLAG_ACTIVE_CALL = 0x02, // The IL stack is empty at this instruction - INTERP_INST_FLAG_EMPTY_IL_STACK = 0x04 + INTERP_INST_FLAG_EMPTY_IL_STACK = 0x04, + // Marks a value-returning managed call site whose return value is reportable to the debugger + INTERP_INST_FLAG_DBG_CALL_INSTRUCTION = 0x08 +}; + +struct InterpCallReturnInfo +{ + uint32_t ilOffset; + uint32_t postCallNativeOffset; + int32_t returnValueVarOffset; }; struct InterpInst @@ -861,6 +870,8 @@ class InterpCompiler #endif int32_t m_ILToNativeMapSize = 0; + TArray m_callReturnInfos; + InterpBasicBlock* AllocBB(int32_t ilOffset); InterpBasicBlock* GetBB(int32_t ilOffset); void LinkBBs(InterpBasicBlock *from, InterpBasicBlock *to);