From: Andy Ayers Date: Thu, 25 Oct 2018 15:02:24 +0000 (-0700) Subject: JIT: emit debug info for locals for minopts/tier0 (#20466) X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=55520b9d64b360ff52c75317faf27890c241f4ff;p=platform%2Fupstream%2Fcoreclr.git JIT: emit debug info for locals for minopts/tier0 (#20466) The jit no longer tracks locals when running at minopts. But untracked local debug emission was tied to `cmpDebugCode. Change untracked local debug emission to instead check if there are no tracked locals. Fixes #20421. Note we could improve things further in the case where there is a mixture of tracked and untracked locals. I have opened #20465 for that as my first attempts here had that ambition but ran into problems. --- diff --git a/src/jit/flowgraph.cpp b/src/jit/flowgraph.cpp index 003ed3c7f8..a7f91dea57 100644 --- a/src/jit/flowgraph.cpp +++ b/src/jit/flowgraph.cpp @@ -10977,6 +10977,14 @@ void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable) /* First update the loop table and bbWeights */ optUpdateLoopsBeforeRemoveBlock(block, skipUnmarkLoop); + // Update successor block start IL offset, if empty predecessor + // covers the immediately preceding range. + if ((block->bbCodeOffsEnd == succBlock->bbCodeOffs) && (block->bbCodeOffs != BAD_IL_OFFSET)) + { + assert(block->bbCodeOffs <= succBlock->bbCodeOffs); + succBlock->bbCodeOffs = block->bbCodeOffs; + } + /* Remove the block */ if (bPrev == nullptr) diff --git a/src/jit/scopeinfo.cpp b/src/jit/scopeinfo.cpp index 748d7ffbcb..88e1eef9d5 100644 --- a/src/jit/scopeinfo.cpp +++ b/src/jit/scopeinfo.cpp @@ -259,12 +259,15 @@ void CodeGen::siEndScope(unsigned varNum) } } - // At this point, we probably have a bad LocalVarTab + JITDUMP("siEndScope: Failed to end scope for V%02u\n"); + // At this point, we probably have a bad LocalVarTab if (compiler->opts.compDbgCode) { - // LocalVarTab is good?? If we reached here implies that we are in a - // bad state, so pretend that we don't have any scope info. + JITDUMP("...checking var tab validity\n", varNum); + + // Note the following assert is saying that we expect + // the VM supplied info to be invalid... assert(!siVerifyLocalVarTab()); compiler->opts.compScopeInfo = false; @@ -456,16 +459,16 @@ void CodeGen::siBeginBlock(BasicBlock* block) return; } - if (!compiler->opts.compDbgCode) + // If we have tracked locals, use liveness to update the debug state. + // + // Note: we can improve on this some day -- if there are any tracked + // locals, untracked locals will fail to be reported. + if (compiler->lvaTrackedCount > 0) { - /* For non-debuggable code */ - // End scope of variables which are not live for this block - siUpdate(); // Check that vars which are live on entry have an open scope - VarSetOps::Iter iter(compiler, block->bbLiveIn); unsigned varIndex = 0; while (iter.NextElem(&varIndex)) @@ -484,71 +487,86 @@ void CodeGen::siBeginBlock(BasicBlock* block) } else { - // For debuggable code, scopes can begin only on block boundaries. - // Check if there are any scopes on the current block's start boundary. - - VarScopeDsc* varScope; + // There aren't any tracked locals. + // + // For debuggable or minopts code, scopes can begin only on block boundaries. + // For other codegen modes (eg minopts/tier0) we currently won't report any + // untracked locals. + if (compiler->opts.compDbgCode || compiler->opts.MinOpts()) + { + // Check if there are any scopes on the current block's start boundary. + VarScopeDsc* varScope = nullptr; #if FEATURE_EH_FUNCLETS - // If we find a spot where the code offset isn't what we expect, because - // there is a gap, it might be because we've moved the funclets out of - // line. Catch up with the enter and exit scopes of the current block. - // Ignore the enter/exit scope changes of the missing scopes, which for - // funclets must be matched. - - if (siLastEndOffs != beginOffs) - { - assert(beginOffs > 0); - assert(siLastEndOffs < beginOffs); + // If we find a spot where the code offset isn't what we expect, because + // there is a gap, it might be because we've moved the funclets out of + // line. Catch up with the enter and exit scopes of the current block. + // Ignore the enter/exit scope changes of the missing scopes, which for + // funclets must be matched. + if (siLastEndOffs != beginOffs) + { + assert(beginOffs > 0); + assert(siLastEndOffs < beginOffs); - JITDUMP("Scope info: found offset hole. lastOffs=%u, currOffs=%u\n", siLastEndOffs, beginOffs); + JITDUMP("Scope info: found offset hole. lastOffs=%u, currOffs=%u\n", siLastEndOffs, beginOffs); - // Skip enter scopes - while ((varScope = compiler->compGetNextEnterScope(beginOffs - 1, true)) != nullptr) - { - /* do nothing */ - JITDUMP("Scope info: skipping enter scope, LVnum=%u\n", varScope->vsdLVnum); - } + // Skip enter scopes + while ((varScope = compiler->compGetNextEnterScope(beginOffs - 1, true)) != nullptr) + { + /* do nothing */ + JITDUMP("Scope info: skipping enter scope, LVnum=%u\n", varScope->vsdLVnum); + } - // Skip exit scopes - while ((varScope = compiler->compGetNextExitScope(beginOffs - 1, true)) != nullptr) - { - /* do nothing */ - JITDUMP("Scope info: skipping exit scope, LVnum=%u\n", varScope->vsdLVnum); + // Skip exit scopes + while ((varScope = compiler->compGetNextExitScope(beginOffs - 1, true)) != nullptr) + { + /* do nothing */ + JITDUMP("Scope info: skipping exit scope, LVnum=%u\n", varScope->vsdLVnum); + } } - } #else // FEATURE_EH_FUNCLETS - if (siLastEndOffs != beginOffs) - { - assert(siLastEndOffs < beginOffs); - return; - } + if (siLastEndOffs != beginOffs) + { + assert(siLastEndOffs < beginOffs); + return; + } #endif // FEATURE_EH_FUNCLETS - while ((varScope = compiler->compGetNextEnterScope(beginOffs)) != nullptr) - { - // brace-matching editor workaround for following line: ( - JITDUMP("Scope info: opening scope, LVnum=%u [%03X..%03X)\n", varScope->vsdLVnum, varScope->vsdLifeBeg, - varScope->vsdLifeEnd); + while ((varScope = compiler->compGetNextEnterScope(beginOffs)) != nullptr) + { + LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varScope->vsdVarNum]; - siNewScope(varScope->vsdLVnum, varScope->vsdVarNum); + // Only report locals that were referenced, if we're not doing debug codegen + if (compiler->opts.compDbgCode || (lclVarDsc1->lvRefCnt() > 0)) + { + // brace-matching editor workaround for following line: ( + JITDUMP("Scope info: opening scope, LVnum=%u [%03X..%03X)\n", varScope->vsdLVnum, + varScope->vsdLifeBeg, varScope->vsdLifeEnd); + + siNewScope(varScope->vsdLVnum, varScope->vsdVarNum); #ifdef DEBUG - LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varScope->vsdVarNum]; - if (VERBOSE) - { - printf("Scope info: >> new scope, VarNum=%u, tracked? %s, VarIndex=%u, bbLiveIn=%s ", - varScope->vsdVarNum, lclVarDsc1->lvTracked ? "yes" : "no", lclVarDsc1->lvVarIndex, - VarSetOps::ToString(compiler, block->bbLiveIn)); - dumpConvertedVarSet(compiler, block->bbLiveIn); - printf("\n"); - } - assert(!lclVarDsc1->lvTracked || VarSetOps::IsMember(compiler, block->bbLiveIn, lclVarDsc1->lvVarIndex)); + if (VERBOSE) + { + printf("Scope info: >> new scope, VarNum=%u, tracked? %s, VarIndex=%u, bbLiveIn=%s ", + varScope->vsdVarNum, lclVarDsc1->lvTracked ? "yes" : "no", lclVarDsc1->lvVarIndex, + VarSetOps::ToString(compiler, block->bbLiveIn)); + dumpConvertedVarSet(compiler, block->bbLiveIn); + printf("\n"); + } + assert(!lclVarDsc1->lvTracked || + VarSetOps::IsMember(compiler, block->bbLiveIn, lclVarDsc1->lvVarIndex)); #endif // DEBUG + } + else + { + JITDUMP("Skipping open scope for V%02u, unreferenced\n", varScope->vsdVarNum); + } + } } }