Track line reachability on a step-by-step basis.
Since we know the entire flow of execution ahead of time, at any point during trace playback, we can know if a line will be reached again or not. We no longer highlight lines as reachable (or allow setting breakpoints) if the line will not be reached again during trace playback. Change-Id: Iff563b13e2f6efb5d4f2ff37215f2ff4fb5945ed Bug: skia:12666 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/486496 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
This commit is contained in:
parent
1ba283e6b4
commit
87ced29082
@ -13,6 +13,7 @@ void SkVMDebugTracePlayer::reset(sk_sp<SkVMDebugTrace> debugTrace) {
|
||||
size_t nslots = debugTrace ? debugTrace->fSlotInfo.size() : 0;
|
||||
fDebugTrace = debugTrace;
|
||||
fCursor = 0;
|
||||
fScope = 0;
|
||||
fSlots.clear();
|
||||
fSlots.resize(nslots, {/*fValue=*/0,
|
||||
/*fScope=*/INT_MAX,
|
||||
@ -32,7 +33,7 @@ void SkVMDebugTracePlayer::reset(sk_sp<SkVMDebugTrace> debugTrace) {
|
||||
|
||||
for (const SkVMTraceInfo& trace : fDebugTrace->fTraceInfo) {
|
||||
if (trace.op == SkVMTraceInfo::Op::kLine) {
|
||||
fLineNumbers.insert(trace.data[0]);
|
||||
fLineNumbers[trace.data[0]] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -193,7 +194,9 @@ bool SkVMDebugTracePlayer::execute(size_t position) {
|
||||
int lineNumber = trace.data[0];
|
||||
SkASSERT(lineNumber >= 0);
|
||||
SkASSERT((size_t)lineNumber < fDebugTrace->fSource.size());
|
||||
SkASSERT(fLineNumbers[lineNumber] > 0);
|
||||
fStack.back().fLine = lineNumber;
|
||||
fLineNumbers[lineNumber] -= 1;
|
||||
return true;
|
||||
}
|
||||
case SkVMTraceInfo::Op::kVar: { // data: slot, value
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "src/sksl/tracing/SkVMDebugTrace.h"
|
||||
#include "src/utils/SkBitSet.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace SkSL {
|
||||
@ -43,7 +44,8 @@ public:
|
||||
void setBreakpoints(std::unordered_set<int> breakpointLines);
|
||||
void addBreakpoint(int line);
|
||||
void removeBreakpoint(int line);
|
||||
const std::unordered_set<int>& getBreakpoints() { return fBreakpointLines; }
|
||||
using BreakpointSet = std::unordered_set<int>;
|
||||
const BreakpointSet& getBreakpoints() { return fBreakpointLines; }
|
||||
|
||||
/** Returns true if we have reached the end of the trace. */
|
||||
bool traceHasCompleted() const;
|
||||
@ -63,8 +65,12 @@ public:
|
||||
/** Returns the size of the call stack. */
|
||||
int getStackDepth() const;
|
||||
|
||||
/** Returns every line number actually reached in the debug trace. */
|
||||
const std::unordered_set<int>& getLineNumbersReached() const { return fLineNumbers; }
|
||||
/**
|
||||
* Returns every line number reached inside this debug trace, along with the remaining number of
|
||||
* times that this trace will reach it. e.g. {100, 2} means line 100 will be reached twice.
|
||||
*/
|
||||
using LineNumberMap = std::unordered_map<int, int>;
|
||||
const LineNumberMap& getLineNumbersReached() const { return fLineNumbers; }
|
||||
|
||||
/** Returns variables from a stack frame, or from global scope. */
|
||||
struct VariableData {
|
||||
@ -104,17 +110,18 @@ private:
|
||||
size_t fWriteTime; // when was the variable in this slot most recently written?
|
||||
// (by cursor position)
|
||||
};
|
||||
sk_sp<SkVMDebugTrace> fDebugTrace;
|
||||
size_t fCursor = 0; // position of the read head
|
||||
int fScope = 0; // the current scope depth (as tracked by
|
||||
// trace_scope)
|
||||
std::vector<Slot> fSlots; // the array of all slots
|
||||
std::vector<StackFrame> fStack; // the execution stack
|
||||
skstd::optional<SkBitSet> fDirtyMask; // variable slots touched during the most-recently
|
||||
// executed step
|
||||
skstd::optional<SkBitSet> fReturnValues; // variable slots containing return values
|
||||
std::unordered_set<int> fLineNumbers; // every line number reached during execution
|
||||
std::unordered_set<int> fBreakpointLines; // all breakpoints set by setBreakpointLines
|
||||
sk_sp<SkVMDebugTrace> fDebugTrace;
|
||||
size_t fCursor = 0; // position of the read head
|
||||
int fScope = 0; // the current scope depth (as tracked by
|
||||
// trace_scope)
|
||||
std::vector<Slot> fSlots; // the array of all slots
|
||||
std::vector<StackFrame> fStack; // the execution stack
|
||||
skstd::optional<SkBitSet> fDirtyMask; // variable slots touched during the most-recently
|
||||
// executed step
|
||||
skstd::optional<SkBitSet> fReturnValues; // variable slots containing return values
|
||||
LineNumberMap fLineNumbers; // holds [line number, the remaining number of
|
||||
// times to reach this line during the trace]
|
||||
BreakpointSet fBreakpointLines; // all breakpoints set by setBreakpointLines
|
||||
};
|
||||
|
||||
} // namespace SkSL
|
||||
|
@ -13,6 +13,8 @@
|
||||
|
||||
#include "tests/Test.h"
|
||||
|
||||
using LineNumberMap = SkSL::SkVMDebugTracePlayer::LineNumberMap;
|
||||
|
||||
static sk_sp<SkSL::SkVMDebugTrace> make_trace(skiatest::Reporter* r, SkSL::String src) {
|
||||
SkSL::ShaderCaps caps;
|
||||
SkSL::Compiler compiler(&caps);
|
||||
@ -110,7 +112,7 @@ int main() { // Line 2
|
||||
REPORTER_ASSERT(r, !player.traceHasCompleted());
|
||||
REPORTER_ASSERT(r, player.getCallStack().empty());
|
||||
REPORTER_ASSERT(r, player.getGlobalVariables().empty());
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == std::unordered_set<int>{3});
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}}));
|
||||
|
||||
player.step();
|
||||
|
||||
@ -190,7 +192,7 @@ int main() { // Line 8
|
||||
REPORTER_ASSERT(r, !player.traceHasCompleted());
|
||||
REPORTER_ASSERT(r, player.getCallStack().empty());
|
||||
REPORTER_ASSERT(r, player.getGlobalVariables().empty());
|
||||
REPORTER_ASSERT(r, (player.getLineNumbersReached() == std::unordered_set<int>{3, 6, 9}));
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}, {6, 1}, {9, 1}}));
|
||||
|
||||
player.step();
|
||||
|
||||
@ -261,8 +263,9 @@ int main() { // Line 6
|
||||
SkSL::SkVMDebugTracePlayer player;
|
||||
player.reset(trace);
|
||||
|
||||
REPORTER_ASSERT(r, (player.getLineNumbersReached() ==
|
||||
std::unordered_set<int>{3, 4, 7, 8, 9, 10, 11, 12}));
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}, {4, 1}, {7, 1},
|
||||
{8, 1}, {9, 1}, {10, 1},
|
||||
{11, 1}, {12, 1}}));
|
||||
player.step();
|
||||
|
||||
REPORTER_ASSERT(r, player.getCurrentLine() == 7);
|
||||
@ -345,8 +348,9 @@ int main() { // Line 2
|
||||
SkSL::SkVMDebugTracePlayer player;
|
||||
player.reset(trace);
|
||||
|
||||
REPORTER_ASSERT(r, (player.getLineNumbersReached() ==
|
||||
std::unordered_set<int>{3, 4, 5, 6, 10, 14, 16}));
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}, {4, 1}, {5, 1},
|
||||
{6, 1}, {10, 1}, {14, 1},
|
||||
{16, 1}}));
|
||||
player.step();
|
||||
|
||||
REPORTER_ASSERT(r, player.getCurrentLine() == 3);
|
||||
@ -397,34 +401,49 @@ int main() { // Line 2
|
||||
SkSL::SkVMDebugTracePlayer player;
|
||||
player.reset(trace);
|
||||
|
||||
REPORTER_ASSERT(r, (player.getLineNumbersReached() == std::unordered_set<int>{3, 4, 5, 7}));
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}, {4, 3}, {5, 2},
|
||||
{7, 1}}));
|
||||
player.step();
|
||||
|
||||
REPORTER_ASSERT(r, player.getCurrentLine() == 3);
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 3}, {5, 2},
|
||||
{7, 1}}));
|
||||
REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "");
|
||||
player.step();
|
||||
|
||||
REPORTER_ASSERT(r, player.getCurrentLine() == 4);
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 2}, {5, 2},
|
||||
{7, 1}}));
|
||||
REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##val = 0");
|
||||
player.step();
|
||||
|
||||
REPORTER_ASSERT(r, player.getCurrentLine() == 5);
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 2}, {5, 1},
|
||||
{7, 1}}));
|
||||
REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##x = 1, val = 0");
|
||||
player.step();
|
||||
|
||||
REPORTER_ASSERT(r, player.getCurrentLine() == 4);
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 1}, {5, 1},
|
||||
{7, 1}}));
|
||||
REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##val = 1, x = 1");
|
||||
player.step();
|
||||
|
||||
REPORTER_ASSERT(r, player.getCurrentLine() == 5);
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 1}, {5, 0},
|
||||
{7, 1}}));
|
||||
REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##x = 2, val = 1");
|
||||
player.step();
|
||||
|
||||
REPORTER_ASSERT(r, player.getCurrentLine() == 4);
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 0}, {5, 0},
|
||||
{7, 1}}));
|
||||
REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##val = 2, x = 2");
|
||||
player.step();
|
||||
|
||||
REPORTER_ASSERT(r, player.getCurrentLine() == 7);
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 0}, {5, 0},
|
||||
{7, 0}}));
|
||||
REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "val = 2");
|
||||
player.step();
|
||||
|
||||
@ -448,8 +467,8 @@ int main() { // Line 9
|
||||
)");
|
||||
SkSL::SkVMDebugTracePlayer player;
|
||||
player.reset(trace);
|
||||
REPORTER_ASSERT(r, (player.getLineNumbersReached() ==
|
||||
std::unordered_set<int>{3, 4, 5, 6, 7, 10}));
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}, {4, 1}, {5, 1},
|
||||
{6, 1}, {7, 1}, {10, 1}}));
|
||||
player.step();
|
||||
|
||||
// We should now be inside main.
|
||||
@ -510,8 +529,10 @@ int main() { // Line 2
|
||||
)");
|
||||
SkSL::SkVMDebugTracePlayer player;
|
||||
player.reset(trace);
|
||||
REPORTER_ASSERT(r, (player.getLineNumbersReached() ==
|
||||
std::unordered_set<int>{3, 5, 7, 9, 11, 13, 15, 17, 19, 20}));
|
||||
REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}, {5, 1}, {7, 1},
|
||||
{9, 1}, {11, 1}, {13, 1},
|
||||
{15, 1}, {17, 1}, {19, 1},
|
||||
{20, 1}}));
|
||||
player.step();
|
||||
|
||||
// We should now be inside main.
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "imgui.h"
|
||||
|
||||
using namespace sk_app;
|
||||
using LineNumberMap = SkSL::SkVMDebugTracePlayer::LineNumberMap;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -130,8 +131,10 @@ void SkSLDebuggerSlide::showCodeTable() {
|
||||
|
||||
// Show line numbers and breakpoints.
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
bool reachable = fPlayer.getLineNumbersReached().count(humanReadableLine);
|
||||
bool breakpointOn = reachable && fPlayer.getBreakpoints().count(humanReadableLine);
|
||||
const LineNumberMap& lineNumberMap = fPlayer.getLineNumbersReached();
|
||||
LineNumberMap::const_iterator iter = lineNumberMap.find(humanReadableLine);
|
||||
bool reachable = iter != lineNumberMap.end() && iter->second > 0;
|
||||
bool breakpointOn = fPlayer.getBreakpoints().count(humanReadableLine);
|
||||
if (breakpointOn) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 0.0f, 0.0f, 0.70f));
|
||||
|
Loading…
Reference in New Issue
Block a user