Flutter Engine
The Flutter Engine
SkSLDebugTracePlayer.h
Go to the documentation of this file.
1/*
2 * Copyright 2021 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#ifndef SkSLDebugTracePlayer_DEFINED
8#define SkSLDebugTracePlayer_DEFINED
9
11
14#include "src/utils/SkBitSet.h"
15
16#include <cstddef>
17#include <cstdint>
18#include <optional>
19#include <unordered_map>
20#include <unordered_set>
21#include <vector>
22
23namespace SkSL {
24
25/**
26 * Plays back a SkSL debug trace, allowing its contents to be viewed like a traditional debugger.
27 */
29public:
30 /** Resets playback to the start of the trace. Breakpoints are not cleared. */
31 void reset(sk_sp<DebugTracePriv> trace);
32
33 /** Advances the simulation to the next Line op. */
34 void step();
35
36 /**
37 * Advances the simulation to the next Line op, skipping past matched Enter/Exit pairs.
38 * Breakpoints will also stop the simulation even if we haven't reached an Exit.
39 */
40 void stepOver();
41
42 /**
43 * Advances the simulation until we exit from the current stack frame.
44 * Breakpoints will also stop the simulation even if we haven't left the stack frame.
45 */
46 void stepOut();
47
48 /** Advances the simulation until we hit a breakpoint, or the trace completes. */
49 void run();
50
51 /** Breakpoints will force the simulation to stop whenever a desired line is reached. */
52 void setBreakpoints(std::unordered_set<int> breakpointLines);
53 void addBreakpoint(int line);
54 void removeBreakpoint(int line);
55 using BreakpointSet = std::unordered_set<int>;
56 const BreakpointSet& getBreakpoints() { return fBreakpointLines; }
57
58 /** Returns true if we have reached the end of the trace. */
59 bool traceHasCompleted() const;
60
61 /** Returns true if there is a breakpoint set at the current line. */
62 bool atBreakpoint() const;
63
64 /** Retrieves the cursor position. */
65 size_t cursor() { return fCursor; }
66
67 /** Retrieves the current line. */
68 int32_t getCurrentLine() const;
69
70 /** Retrieves the current line for a given stack frame. */
71 int32_t getCurrentLineInStackFrame(int stackFrameIndex) const;
72
73 /** Returns the call stack as an array of FunctionInfo indices. */
74 std::vector<int> getCallStack() const;
75
76 /** Returns the size of the call stack. */
77 int getStackDepth() const;
78
79 /**
80 * Returns every line number reached inside this debug trace, along with the remaining number of
81 * times that this trace will reach it. e.g. {100, 2} means line 100 will be reached twice.
82 */
83 using LineNumberMap = std::unordered_map<int, int>;
84 const LineNumberMap& getLineNumbersReached() const { return fLineNumbers; }
85
86 /** Returns variables from a stack frame, or from global scope. */
87 struct VariableData {
89 bool fDirty; // has this slot been written-to since the last step call?
90 double fValue; // value in slot (with type-conversion applied)
91 };
92 std::vector<VariableData> getLocalVariables(int stackFrameIndex) const;
93 std::vector<VariableData> getGlobalVariables() const;
94
95private:
96 /**
97 * Executes the trace op at the passed-in cursor position. Returns true if we've reached a line
98 * or exit trace op, which indicate a stopping point.
99 */
100 bool execute(size_t position);
101
102 /**
103 * Cleans up temporary state between steps, such as the dirty mask and function return values.
104 */
105 void tidyState();
106
107 /** Updates fWriteTime for the entire variable at a given slot. */
108 void updateVariableWriteTime(int slotIdx, size_t writeTime);
109
110 /** Returns a vector of the indices and values of each slot that is enabled in `bits`. */
111 std::vector<VariableData> getVariablesForDisplayMask(const SkBitSet& bits) const;
112
113 struct StackFrame {
114 int32_t fFunction; // from fFuncInfo
115 int32_t fLine; // our current line number within the function
116 SkBitSet fDisplayMask; // the variable slots which have been touched in this function
117 };
118 struct Slot {
119 int32_t fValue; // values in each slot
120 int fScope; // the scope value of each slot
121 size_t fWriteTime; // when was the variable in this slot most recently written?
122 // (by cursor position)
123 };
124 sk_sp<DebugTracePriv> fDebugTrace;
125 size_t fCursor = 0; // position of the read head
126 int fScope = 0; // the current scope depth (as tracked by
127 // trace_scope)
128 std::vector<Slot> fSlots; // the array of all slots
129 std::vector<StackFrame> fStack; // the execution stack
130 std::optional<SkBitSet> fDirtyMask; // variable slots touched during the most-recently
131 // executed step
132 std::optional<SkBitSet> fReturnValues; // variable slots containing return values
133 LineNumberMap fLineNumbers; // holds [line number, the remaining number of
134 // times to reach this line during the trace]
135 BreakpointSet fBreakpointLines; // all breakpoints set by setBreakpointLines
136};
137
138} // namespace SkSL
139
140#endif // SkSLDebugTracePlayer_DEFINED
SkSL::SkSLDebugTracePlayer::LineNumberMap LineNumberMap
const BreakpointSet & getBreakpoints()
const LineNumberMap & getLineNumbersReached() const
void reset(sk_sp< DebugTracePriv > trace)
std::vector< VariableData > getGlobalVariables() const
std::unordered_set< int > BreakpointSet
std::vector< VariableData > getLocalVariables(int stackFrameIndex) const
int32_t getCurrentLineInStackFrame(int stackFrameIndex) const
std::unordered_map< int, int > LineNumberMap
void setBreakpoints(std::unordered_set< int > breakpointLines)
std::vector< int > getCallStack() const