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
8 #include "include/core/SkRefCnt.h"
9 #include "include/core/SkSpan.h"
10 #include "include/private/SkSLProgramKind.h"
11 #include "include/private/SkSLString.h"
12 #include "src/core/SkVM.h"
13 #include "src/sksl/SkSLCompiler.h"
14 #include "src/sksl/SkSLProgramSettings.h"
15 #include "src/sksl/SkSLUtil.h"
16 #include "src/sksl/codegen/SkSLVMCodeGenerator.h"
17 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
18 #include "src/sksl/ir/SkSLProgram.h"
19 #include "src/sksl/tracing/SkSLDebugInfo.h"
20 #include "src/sksl/tracing/SkVMDebugTrace.h"
21 #include "src/sksl/tracing/SkVMDebugTracePlayer.h"
22 #include "tests/Test.h"
23
24 #include <cstddef>
25 #include <memory>
26 #include <string>
27 #include <unordered_map>
28 #include <unordered_set>
29 #include <vector>
30
31 using LineNumberMap = SkSL::SkVMDebugTracePlayer::LineNumberMap;
32
make_trace(skiatest::Reporter * r,std::string src)33 static sk_sp<SkSL::SkVMDebugTrace> make_trace(skiatest::Reporter* r, std::string src) {
34 SkSL::ShaderCaps caps;
35 SkSL::Compiler compiler(&caps);
36 SkSL::ProgramSettings settings;
37 settings.fOptimize = false;
38
39 skvm::Builder b;
40 std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::ProgramKind::kGeneric,
41 src, settings);
42 REPORTER_ASSERT(r, program);
43
44 const SkSL::FunctionDeclaration* main = program->getFunction("main");
45 auto debugTrace = sk_make_sp<SkSL::SkVMDebugTrace>();
46 SkSL::ProgramToSkVM(*program, *main->definition(), &b, debugTrace.get(), /*uniforms=*/{});
47 skvm::Program p = b.done();
48 REPORTER_ASSERT(r, p.nargs() == 1);
49
50 int result;
51 p.eval(1, &result);
52
53 return debugTrace;
54 }
55
make_stack_string(const SkSL::SkVMDebugTrace & trace,const SkSL::SkVMDebugTracePlayer & player)56 static std::string make_stack_string(const SkSL::SkVMDebugTrace& trace,
57 const SkSL::SkVMDebugTracePlayer& player) {
58 std::vector<int> callStack = player.getCallStack();
59 std::string text;
60 const char* separator = "";
61 for (int frame : callStack) {
62 text += separator;
63 separator = " -> ";
64
65 if (frame >= 0 && (size_t)frame < trace.fFuncInfo.size()) {
66 text += trace.fFuncInfo[frame].name;
67 } else {
68 text += "???";
69 }
70 }
71
72 return text;
73 }
74
make_vars_string(const SkSL::SkVMDebugTrace & trace,const std::vector<SkSL::SkVMDebugTracePlayer::VariableData> & vars)75 static std::string make_vars_string(
76 const SkSL::SkVMDebugTrace& trace,
77 const std::vector<SkSL::SkVMDebugTracePlayer::VariableData>& vars) {
78 std::string text;
79 auto separator = SkSL::String::Separator();
80 for (const SkSL::SkVMDebugTracePlayer::VariableData& var : vars) {
81 text += separator();
82
83 if (var.fSlotIndex < 0 || (size_t)var.fSlotIndex >= trace.fSlotInfo.size()) {
84 text += "???";
85 continue;
86 }
87
88 const SkSL::SlotDebugInfo& slot = trace.fSlotInfo[var.fSlotIndex];
89 text += var.fDirty ? "##": "";
90 text += slot.name;
91 text += trace.getSlotComponentSuffix(var.fSlotIndex);
92 text += " = ";
93 text += trace.slotValueToString(var.fSlotIndex, var.fValue);
94 }
95
96 return text;
97 }
98
make_local_vars_string(const SkSL::SkVMDebugTrace & trace,const SkSL::SkVMDebugTracePlayer & player)99 static std::string make_local_vars_string(const SkSL::SkVMDebugTrace& trace,
100 const SkSL::SkVMDebugTracePlayer& player) {
101 int frame = player.getStackDepth() - 1;
102 return make_vars_string(trace, player.getLocalVariables(frame));
103 }
104
make_global_vars_string(const SkSL::SkVMDebugTrace & trace,const SkSL::SkVMDebugTracePlayer & player)105 static std::string make_global_vars_string(const SkSL::SkVMDebugTrace& trace,
106 const SkSL::SkVMDebugTracePlayer& player) {
107 return make_vars_string(trace, player.getGlobalVariables());
108 }
109
DEF_TEST(SkSLTracePlayerCanResetToNull,r)110 DEF_TEST(SkSLTracePlayerCanResetToNull, r) {
111 SkSL::SkVMDebugTracePlayer player;
112 player.reset(nullptr);
113
114 // We should be in a reasonable state.
115 REPORTER_ASSERT(r, player.cursor() == 0);
116 REPORTER_ASSERT(r, player.getCurrentLine() == -1);
117 REPORTER_ASSERT(r, player.traceHasCompleted());
118 REPORTER_ASSERT(r, player.getCallStack().empty());
119 REPORTER_ASSERT(r, player.getGlobalVariables().empty());
120 REPORTER_ASSERT(r, player.getLineNumbersReached().empty());
121 }
122
DEF_TEST(SkSLTracePlayerHelloWorld,r)123 DEF_TEST(SkSLTracePlayerHelloWorld, r) {
124 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
125 R"( // Line 1
126 int main() { // Line 2
127 return 2 + 2; // Line 3
128 } // Line 4
129 )");
130 SkSL::SkVMDebugTracePlayer player;
131 player.reset(trace);
132
133 // We have not started tracing yet.
134 REPORTER_ASSERT(r, player.cursor() == 0);
135 REPORTER_ASSERT(r, player.getCurrentLine() == -1);
136 REPORTER_ASSERT(r, !player.traceHasCompleted());
137 REPORTER_ASSERT(r, player.getCallStack().empty());
138 REPORTER_ASSERT(r, player.getGlobalVariables().empty());
139 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}}));
140
141 player.step();
142
143 // We should now be inside main.
144 REPORTER_ASSERT(r, player.cursor() > 0);
145 REPORTER_ASSERT(r, !player.traceHasCompleted());
146 REPORTER_ASSERT(r, player.getCurrentLine() == 3);
147 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
148 REPORTER_ASSERT(r, player.getGlobalVariables().empty());
149 REPORTER_ASSERT(r, player.getLocalVariables(0).empty());
150
151 player.step();
152
153 // We have now completed the trace.
154 REPORTER_ASSERT(r, player.cursor() > 0);
155 REPORTER_ASSERT(r, player.traceHasCompleted());
156 REPORTER_ASSERT(r, player.getCurrentLine() == -1);
157 REPORTER_ASSERT(r, player.getCallStack().empty());
158 REPORTER_ASSERT(r, make_global_vars_string(*trace, player) == "##[main].result = 4");
159 }
160
DEF_TEST(SkSLTracePlayerReset,r)161 DEF_TEST(SkSLTracePlayerReset, r) {
162 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
163 R"( // Line 1
164 int main() { // Line 2
165 return 2 + 2; // Line 3
166 } // Line 4
167 )");
168 SkSL::SkVMDebugTracePlayer player;
169 player.reset(trace);
170
171 // We have not started tracing yet.
172 REPORTER_ASSERT(r, player.cursor() == 0);
173 REPORTER_ASSERT(r, player.getCurrentLine() == -1);
174 REPORTER_ASSERT(r, !player.traceHasCompleted());
175 REPORTER_ASSERT(r, player.getCallStack().empty());
176 REPORTER_ASSERT(r, player.getGlobalVariables().empty());
177
178 player.step();
179
180 // We should now be inside main.
181 REPORTER_ASSERT(r, player.cursor() > 0);
182 REPORTER_ASSERT(r, player.getCurrentLine() == 3);
183 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
184 REPORTER_ASSERT(r, player.getGlobalVariables().empty());
185 REPORTER_ASSERT(r, player.getLocalVariables(0).empty());
186
187 player.reset(trace);
188
189 // We should be back to square one.
190 REPORTER_ASSERT(r, player.cursor() == 0);
191 REPORTER_ASSERT(r, player.getCurrentLine() == -1);
192 REPORTER_ASSERT(r, !player.traceHasCompleted());
193 REPORTER_ASSERT(r, player.getCallStack().empty());
194 REPORTER_ASSERT(r, player.getGlobalVariables().empty());
195 }
196
DEF_TEST(SkSLTracePlayerFunctions,r)197 DEF_TEST(SkSLTracePlayerFunctions, r) {
198 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
199 R"( // Line 1
200 int fnB() { // Line 2
201 return 2 + 2; // Line 3
202 } // Line 4
203 int fnA() { // Line 5
204 return fnB(); // Line 6
205 } // Line 7
206 int main() { // Line 8
207 return fnA(); // Line 9
208 } // Line 10
209 )");
210 SkSL::SkVMDebugTracePlayer player;
211 player.reset(trace);
212
213 // We have not started tracing yet.
214 REPORTER_ASSERT(r, player.cursor() == 0);
215 REPORTER_ASSERT(r, player.getCurrentLine() == -1);
216 REPORTER_ASSERT(r, !player.traceHasCompleted());
217 REPORTER_ASSERT(r, player.getCallStack().empty());
218 REPORTER_ASSERT(r, player.getGlobalVariables().empty());
219 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}, {6, 1}, {9, 1}}));
220
221 player.step();
222
223 // We should now be inside main.
224 REPORTER_ASSERT(r, !player.traceHasCompleted());
225 REPORTER_ASSERT(r, player.getCurrentLine() == 9);
226 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
227 REPORTER_ASSERT(r, player.getGlobalVariables().empty());
228 REPORTER_ASSERT(r, player.getLocalVariables(0).empty());
229
230 player.stepOver();
231
232 // We should now have completed execution.
233 REPORTER_ASSERT(r, player.traceHasCompleted());
234 REPORTER_ASSERT(r, player.getCurrentLine() == -1);
235 REPORTER_ASSERT(r, player.getCallStack().empty());
236 REPORTER_ASSERT(r, make_global_vars_string(*trace, player) == "##[main].result = 4");
237
238 // Watch the stack grow and shrink as single-step.
239 player.reset(trace);
240 player.step();
241
242 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
243 REPORTER_ASSERT(r, player.getCurrentLineInStackFrame(0) == 9);
244 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "");
245 REPORTER_ASSERT(r, make_global_vars_string(*trace, player) == "");
246 player.step();
247
248 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main() -> int fnA()");
249 REPORTER_ASSERT(r, player.getCurrentLineInStackFrame(0) == 9);
250 REPORTER_ASSERT(r, player.getCurrentLineInStackFrame(1) == 6);
251 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "");
252 REPORTER_ASSERT(r, make_global_vars_string(*trace, player) == "");
253 player.step();
254
255 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main() -> int fnA() -> int fnB()");
256 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "");
257 REPORTER_ASSERT(r, make_global_vars_string(*trace, player) == "");
258 REPORTER_ASSERT(r, player.getCurrentLineInStackFrame(0) == 9);
259 REPORTER_ASSERT(r, player.getCurrentLineInStackFrame(1) == 6);
260 REPORTER_ASSERT(r, player.getCurrentLineInStackFrame(2) == 3);
261 player.step();
262
263 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main() -> int fnA()");
264 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##[fnB].result = 4");
265 REPORTER_ASSERT(r, make_global_vars_string(*trace, player) == "");
266 player.step();
267
268 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
269 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##[fnA].result = 4");
270 REPORTER_ASSERT(r, make_global_vars_string(*trace, player) == "");
271
272 player.step();
273 REPORTER_ASSERT(r, player.traceHasCompleted());
274 REPORTER_ASSERT(r, make_global_vars_string(*trace, player) == "##[main].result = 4");
275 }
276
DEF_TEST(SkSLTracePlayerVariables,r)277 DEF_TEST(SkSLTracePlayerVariables, r) {
278 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
279 R"( // Line 1
280 float func() { // Line 2
281 float x = 4, y = 5, z = 6; // Line 3
282 return z; // Line 4
283 } // Line 5
284 int main() { // Line 6
285 int a = 123; // Line 7
286 bool b = true; // Line 8
287 func(); // Line 9
288 float4 c = float4(0, 0.5, 1, -1); // Line 10
289 float3x3 d = float3x3(2); // Line 11
290 return a; // Line 12
291 } // Line 13
292 )");
293 SkSL::SkVMDebugTracePlayer player;
294 player.reset(trace);
295
296 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}, {4, 1}, {7, 1},
297 {8, 1}, {9, 1}, {10, 1},
298 {11, 1}, {12, 1}}));
299 player.step();
300
301 REPORTER_ASSERT(r, player.getCurrentLine() == 7);
302 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
303 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "");
304 player.step();
305
306 REPORTER_ASSERT(r, player.getCurrentLine() == 8);
307 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
308 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##a = 123");
309 player.step();
310
311 REPORTER_ASSERT(r, player.getCurrentLine() == 9);
312 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
313 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##b = true, a = 123");
314 player.step();
315
316 REPORTER_ASSERT(r, player.getCurrentLine() == 3);
317 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main() -> float func()");
318 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "");
319 player.step();
320
321 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
322 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main() -> float func()");
323 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##z = 6, ##y = 5, ##x = 4");
324 player.step();
325
326 REPORTER_ASSERT(r, player.getCurrentLine() == 9);
327 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
328 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) ==
329 "##[func].result = 6, b = true, a = 123");
330 player.step();
331
332 REPORTER_ASSERT(r, player.getCurrentLine() == 10);
333 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
334 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "b = true, a = 123");
335 player.step();
336
337 REPORTER_ASSERT(r, player.getCurrentLine() == 11);
338 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
339 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) ==
340 "##c.x = 0, ##c.y = 0.5, ##c.z = 1, ##c.w = -1, b = true, a = 123");
341 player.step();
342
343 REPORTER_ASSERT(r, player.getCurrentLine() == 12);
344 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
345 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) ==
346 "##d[0][0] = 2, ##d[0][1] = 0, ##d[0][2] = 0, "
347 "##d[1][0] = 0, ##d[1][1] = 2, ##d[1][2] = 0, "
348 "##d[2][0] = 0, ##d[2][1] = 0, ##d[2][2] = 2, "
349 "c.x = 0, c.y = 0.5, c.z = 1, c.w = -1, b = true, a = 123");
350
351
352 player.step();
353 REPORTER_ASSERT(r, player.traceHasCompleted());
354 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "");
355 REPORTER_ASSERT(r, make_global_vars_string(*trace, player) == "##[main].result = 123");
356 }
357
DEF_TEST(SkSLTracePlayerVariableGroups,r)358 DEF_TEST(SkSLTracePlayerVariableGroups, r) {
359 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
360 R"( // Line 1
361 struct S { int x, y, z; }; // Line 2
362 int main() { // Line 3
363 S s; // Line 4
364 int arr[3]; // Line 5
365 s.y = 1; // Line 6
366 arr[1] = 2; // Line 7
367 s.x = 3; // Line 8
368 arr[2] = 4; // Line 9
369 return 0; // Line 10
370 } // Line 11
371 )");
372 SkSL::SkVMDebugTracePlayer player;
373 player.reset(trace);
374 player.step();
375
376 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
377 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
378 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "");
379 player.step();
380
381 REPORTER_ASSERT(r, player.getCurrentLine() == 5);
382 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##s.x = 0, ##s.y = 0, ##s.z = 0");
383 player.step();
384
385 REPORTER_ASSERT(r, player.getCurrentLine() == 6);
386 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) ==
387 "##arr[0] = 0, ##arr[1] = 0, ##arr[2] = 0, s.x = 0, s.y = 0, s.z = 0");
388 player.step();
389
390 REPORTER_ASSERT(r, player.getCurrentLine() == 7);
391 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) ==
392 "s.x = 0, ##s.y = 1, s.z = 0, arr[0] = 0, arr[1] = 0, arr[2] = 0");
393 player.step();
394
395 REPORTER_ASSERT(r, player.getCurrentLine() == 8);
396 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) ==
397 "arr[0] = 0, ##arr[1] = 2, arr[2] = 0, s.x = 0, s.y = 1, s.z = 0");
398 player.step();
399
400 REPORTER_ASSERT(r, player.getCurrentLine() == 9);
401 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) ==
402 "##s.x = 3, s.y = 1, s.z = 0, arr[0] = 0, arr[1] = 2, arr[2] = 0");
403 player.step();
404
405 REPORTER_ASSERT(r, player.getCurrentLine() == 10);
406 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) ==
407 "arr[0] = 0, arr[1] = 2, ##arr[2] = 4, s.x = 3, s.y = 1, s.z = 0");
408 }
409
410
DEF_TEST(SkSLTracePlayerIfStatement,r)411 DEF_TEST(SkSLTracePlayerIfStatement, r) {
412 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
413 R"( // Line 1
414 int main() { // Line 2
415 int val; // Line 3
416 if (true) { // Line 4
417 int temp = 1; // Line 5
418 val = temp; // Line 6
419 } else { // Line 7
420 val = 2; // Line 8
421 } // Line 9
422 if (false) { // Line 10
423 int temp = 3; // Line 11
424 val = temp; // Line 12
425 } else { // Line 13
426 val = 4; // Line 14
427 } // Line 15
428 return val; // Line 16
429 } // Line 17
430 )");
431 SkSL::SkVMDebugTracePlayer player;
432 player.reset(trace);
433
434 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}, {4, 1}, {5, 1},
435 {6, 1}, {10, 1}, {14, 1},
436 {16, 1}}));
437 player.step();
438
439 REPORTER_ASSERT(r, player.getCurrentLine() == 3);
440 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "");
441 player.step();
442
443 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
444 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##val = 0");
445 player.step();
446
447 REPORTER_ASSERT(r, player.getCurrentLine() == 5);
448 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "val = 0");
449 player.step();
450
451 REPORTER_ASSERT(r, player.getCurrentLine() == 6);
452 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##temp = 1, val = 0");
453 player.step();
454
455 // We skip over the false-branch.
456 REPORTER_ASSERT(r, player.getCurrentLine() == 10);
457 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##val = 1");
458 player.step();
459
460 // We skip over the true-branch.
461 REPORTER_ASSERT(r, player.getCurrentLine() == 14);
462 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "val = 1");
463 player.step();
464
465 REPORTER_ASSERT(r, player.getCurrentLine() == 16);
466 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##val = 4");
467 player.step();
468
469 REPORTER_ASSERT(r, player.traceHasCompleted());
470 REPORTER_ASSERT(r, make_global_vars_string(*trace, player) == "##[main].result = 4");
471 }
472
DEF_TEST(SkSLTracePlayerForLoop,r)473 DEF_TEST(SkSLTracePlayerForLoop, r) {
474 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
475 R"( // Line 1
476 int main() { // Line 2
477 int val = 0; // Line 3
478 for (int x = 1; x < 3; ++x) { // Line 4
479 val = x; // Line 5
480 } // Line 6
481 return val; // Line 7
482 } // Line 8
483 )");
484 SkSL::SkVMDebugTracePlayer player;
485 player.reset(trace);
486
487 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}, {4, 3}, {5, 2},
488 {7, 1}}));
489 player.step();
490
491 REPORTER_ASSERT(r, player.getCurrentLine() == 3);
492 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 3}, {5, 2},
493 {7, 1}}));
494 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "");
495 player.step();
496
497 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
498 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 2}, {5, 2},
499 {7, 1}}));
500 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##val = 0");
501 player.step();
502
503 REPORTER_ASSERT(r, player.getCurrentLine() == 5);
504 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 2}, {5, 1},
505 {7, 1}}));
506 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##x = 1, val = 0");
507 player.step();
508
509 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
510 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 1}, {5, 1},
511 {7, 1}}));
512 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##val = 1, x = 1");
513 player.step();
514
515 REPORTER_ASSERT(r, player.getCurrentLine() == 5);
516 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 1}, {5, 0},
517 {7, 1}}));
518 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##x = 2, val = 1");
519 player.step();
520
521 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
522 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 0}, {5, 0},
523 {7, 1}}));
524 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##val = 2, x = 2");
525 player.step();
526
527 REPORTER_ASSERT(r, player.getCurrentLine() == 7);
528 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 0}, {4, 0}, {5, 0},
529 {7, 0}}));
530 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "val = 2");
531 player.step();
532
533 REPORTER_ASSERT(r, player.traceHasCompleted());
534 REPORTER_ASSERT(r, make_global_vars_string(*trace, player) == "##[main].result = 2");
535 }
536
DEF_TEST(SkSLTracePlayerStepOut,r)537 DEF_TEST(SkSLTracePlayerStepOut, r) {
538 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
539 R"( // Line 1
540 int fn() { // Line 2
541 int a = 11; // Line 3
542 int b = 22; // Line 4
543 int c = 33; // Line 5
544 int d = 44; // Line 6
545 return d; // Line 7
546 } // Line 8
547 int main() { // Line 9
548 return fn(); // Line 10
549 } // Line 11
550 )");
551 SkSL::SkVMDebugTracePlayer player;
552 player.reset(trace);
553 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}, {4, 1}, {5, 1},
554 {6, 1}, {7, 1}, {10, 1}}));
555 player.step();
556
557 // We should now be inside main.
558 REPORTER_ASSERT(r, player.getCurrentLine() == 10);
559 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
560 player.step();
561
562 // We should now be inside fn.
563 REPORTER_ASSERT(r, player.getCurrentLine() == 3);
564 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main() -> int fn()");
565 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "");
566 player.step();
567
568 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
569 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main() -> int fn()");
570 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##a = 11");
571 player.step();
572
573 REPORTER_ASSERT(r, player.getCurrentLine() == 5);
574 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main() -> int fn()");
575 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##b = 22, a = 11");
576 player.stepOut();
577
578 // We should now be back inside main(), right where we left off.
579 REPORTER_ASSERT(r, player.getCurrentLine() == 10);
580 REPORTER_ASSERT(r, make_stack_string(*trace, player) == "int main()");
581 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##[fn].result = 44");
582 player.stepOut();
583
584 REPORTER_ASSERT(r, player.traceHasCompleted());
585 REPORTER_ASSERT(r, make_global_vars_string(*trace, player) == "##[main].result = 44");
586 }
587
DEF_TEST(SkSLTracePlayerVariableScope,r)588 DEF_TEST(SkSLTracePlayerVariableScope, r) {
589 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
590 R"( // Line 1
591 int main() { // Line 2
592 int a = 1; // Line 3
593 { // Line 4
594 int b = 2; // Line 5
595 { // Line 6
596 int c = 3; // Line 7
597 } // Line 8
598 int d = 4; // Line 9
599 } // Line 10
600 int e = 5; // Line 11
601 { // Line 12
602 int f = 6; // Line 13
603 { // Line 14
604 int g = 7; // Line 15
605 } // Line 16
606 int h = 8; // Line 17
607 } // Line 18
608 int i = 9; // Line 19
609 return 0; // Line 20
610 }
611 )");
612 SkSL::SkVMDebugTracePlayer player;
613 player.reset(trace);
614 REPORTER_ASSERT(r, player.getLineNumbersReached() == LineNumberMap({{3, 1}, {5, 1}, {7, 1},
615 {9, 1}, {11, 1}, {13, 1},
616 {15, 1}, {17, 1}, {19, 1},
617 {20, 1}}));
618 player.step();
619
620 // We should now be inside main.
621 REPORTER_ASSERT(r, player.getCurrentLine() == 3);
622 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "");
623 player.step();
624
625 REPORTER_ASSERT(r, player.getCurrentLine() == 5);
626 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##a = 1");
627 player.step();
628
629 REPORTER_ASSERT(r, player.getCurrentLine() == 7);
630 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##b = 2, a = 1");
631 player.step();
632
633 REPORTER_ASSERT(r, player.getCurrentLine() == 9);
634 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "b = 2, a = 1");
635 player.step();
636
637 REPORTER_ASSERT(r, player.getCurrentLine() == 11);
638 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "a = 1");
639 player.step();
640
641 REPORTER_ASSERT(r, player.getCurrentLine() == 13);
642 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##e = 5, a = 1");
643 player.step();
644
645 REPORTER_ASSERT(r, player.getCurrentLine() == 15);
646 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##f = 6, e = 5, a = 1");
647 player.step();
648
649 REPORTER_ASSERT(r, player.getCurrentLine() == 17);
650 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "f = 6, e = 5, a = 1");
651 player.step();
652
653 REPORTER_ASSERT(r, player.getCurrentLine() == 19);
654 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "e = 5, a = 1");
655 player.step();
656
657 REPORTER_ASSERT(r, player.getCurrentLine() == 20);
658 REPORTER_ASSERT(r, make_local_vars_string(*trace, player) == "##i = 9, e = 5, a = 1");
659 player.step();
660
661 REPORTER_ASSERT(r, player.traceHasCompleted());
662 }
663
DEF_TEST(SkSLTracePlayerNestedBlocks,r)664 DEF_TEST(SkSLTracePlayerNestedBlocks, r) {
665 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
666 R"( // Line 1
667 int main() { // Line 2
668 {{{{{{{ // Line 3
669 int a, b; // Line 4
670 }}}}}}} // Line 5
671 return 0; // Line 6
672 }
673 )");
674 SkSL::SkVMDebugTracePlayer player;
675 player.reset(trace);
676 player.step();
677
678 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
679 player.step();
680
681 REPORTER_ASSERT(r, player.getCurrentLine() == 6);
682 player.step();
683
684 REPORTER_ASSERT(r, player.traceHasCompleted());
685 }
686
DEF_TEST(SkSLTracePlayerSwitchStatement,r)687 DEF_TEST(SkSLTracePlayerSwitchStatement, r) {
688 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
689 R"( // Line 1
690 int main() { // Line 2
691 int x = 2; // Line 3
692 switch (x) { // Line 4
693 case 1: // Line 5
694 break; // Line 6
695 case 2: // Line 7
696 ++x; // Line 8
697 case 3: // Line 9
698 break; // Line 10
699 case 4: // Line 11
700 } // Line 12
701 return x; // Line 13
702 }
703 )");
704 SkSL::SkVMDebugTracePlayer player;
705 player.reset(trace);
706 player.step();
707
708 REPORTER_ASSERT(r, player.getCurrentLine() == 3);
709 player.step();
710
711 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
712 player.step();
713
714 REPORTER_ASSERT(r, player.getCurrentLine() == 8);
715 player.step();
716
717 REPORTER_ASSERT(r, player.getCurrentLine() == 10);
718 player.step();
719
720 REPORTER_ASSERT(r, player.getCurrentLine() == 13);
721 player.step();
722
723 REPORTER_ASSERT(r, player.traceHasCompleted());
724 }
725
DEF_TEST(SkSLTracePlayerBreakpoint,r)726 DEF_TEST(SkSLTracePlayerBreakpoint, r) {
727 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
728 R"( // Line 1
729 int counter = 0; // Line 2
730 void func() { // Line 3
731 --counter; // Line 4 BREAKPOINT 4 5
732 } // Line 5
733 int main() { // Line 6
734 for (int x = 1; x <= 3; ++x) { // Line 7
735 ++counter; // Line 8 BREAKPOINT 1 2 3
736 } // Line 9
737 func(); // Line 10
738 func(); // Line 11
739 ++counter; // Line 12 BREAKPOINT 6
740 return counter; // Line 13
741 } // Line 14
742 )");
743 // Run the simulation with a variety of breakpoints set.
744 SkSL::SkVMDebugTracePlayer player;
745 player.reset(trace);
746 player.setBreakpoints(std::unordered_set<int>{8, 13, 20});
747 player.run();
748 REPORTER_ASSERT(r, player.getCurrentLine() == 8);
749
750 player.run();
751 REPORTER_ASSERT(r, player.getCurrentLine() == 8);
752
753 player.setBreakpoints(std::unordered_set<int>{1, 4, 8});
754 player.run();
755 REPORTER_ASSERT(r, player.getCurrentLine() == 8);
756
757 player.run();
758 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
759
760 player.setBreakpoints(std::unordered_set<int>{4, 12, 14});
761 player.run();
762 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
763
764 player.run();
765 REPORTER_ASSERT(r, player.getCurrentLine() == 12);
766
767 player.run();
768 REPORTER_ASSERT(r, player.traceHasCompleted());
769
770 // Run the simulation again with no breakpoints set. We should reach the end of the trace
771 // instantly.
772 player.reset(trace);
773 player.setBreakpoints(std::unordered_set<int>{});
774 REPORTER_ASSERT(r, !player.traceHasCompleted());
775
776 player.run();
777 REPORTER_ASSERT(r, player.traceHasCompleted());
778 }
779
DEF_TEST(SkSLTracePlayerStepOverWithBreakpoint,r)780 DEF_TEST(SkSLTracePlayerStepOverWithBreakpoint, r) {
781 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
782 R"( // Line 1
783 int counter = 0; // Line 2
784 void func() { // Line 3
785 ++counter; // Line 4 BREAKPOINT
786 } // Line 5
787 int main() { // Line 6
788 func(); // Line 7
789 return counter; // Line 8
790 } // Line 9
791 )");
792 // Try stepping over with no breakpoint set; we will step over.
793 SkSL::SkVMDebugTracePlayer player;
794 player.reset(trace);
795 player.step();
796 REPORTER_ASSERT(r, player.getCurrentLine() == 7);
797
798 player.stepOver();
799 REPORTER_ASSERT(r, player.getCurrentLine() == 8);
800
801 // Try stepping over with a breakpoint set; we will stop at the breakpoint.
802 player.reset(trace);
803 player.setBreakpoints(std::unordered_set<int>{4});
804 player.step();
805 REPORTER_ASSERT(r, player.getCurrentLine() == 7);
806
807 player.stepOver();
808 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
809 }
810
DEF_TEST(SkSLTracePlayerStepOutWithBreakpoint,r)811 DEF_TEST(SkSLTracePlayerStepOutWithBreakpoint, r) {
812 sk_sp<SkSL::SkVMDebugTrace> trace = make_trace(r,
813 R"( // Line 1
814 int counter = 0; // Line 2
815 void func() { // Line 3
816 ++counter; // Line 4
817 ++counter; // Line 5
818 ++counter; // Line 6 BREAKPOINT
819 } // Line 7
820 int main() { // Line 8
821 func(); // Line 9
822 return counter; // Line 10
823 } // Line 11
824 )");
825 // Try stepping out with no breakpoint set; we will step out.
826 SkSL::SkVMDebugTracePlayer player;
827 player.reset(trace);
828 player.step();
829 REPORTER_ASSERT(r, player.getCurrentLine() == 9);
830
831 player.step();
832 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
833
834 player.stepOut();
835 REPORTER_ASSERT(r, player.getCurrentLine() == 9);
836
837 // Try stepping out with a breakpoint set; we will stop at the breakpoint.
838 player.reset(trace);
839 player.setBreakpoints(std::unordered_set<int>{6});
840 player.step();
841 REPORTER_ASSERT(r, player.getCurrentLine() == 9);
842
843 player.step();
844 REPORTER_ASSERT(r, player.getCurrentLine() == 4);
845
846 player.stepOut();
847 REPORTER_ASSERT(r, player.getCurrentLine() == 6);
848 }
849