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