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