1 //===- ExecutionContextTest.cpp - Debug Execution Context first impl ------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "mlir/Debug/ExecutionContext.h"
10 #include "mlir/Debug/BreakpointManagers/TagBreakpointManager.h"
11 #include "llvm/ADT/MapVector.h"
12 #include "gmock/gmock.h"
15 using namespace mlir::tracing
;
18 struct DebuggerAction
: public ActionImpl
<DebuggerAction
> {
19 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(DebuggerAction
)
20 static constexpr StringLiteral tag
= "debugger-action";
22 struct OtherAction
: public ActionImpl
<OtherAction
> {
23 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OtherAction
)
24 static constexpr StringLiteral tag
= "other-action";
26 struct ThirdAction
: public ActionImpl
<ThirdAction
> {
27 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ThirdAction
)
28 static constexpr StringLiteral tag
= "third-action";
31 // Simple action that does nothing.
34 /// This test executes a stack of nested action and check that the backtrace is
36 TEST(ExecutionContext
, ActionActiveStackTest
) {
38 // We'll break three time, once on each action, the backtraces should match
39 // each of the entries here.
40 std::vector
<std::vector
<StringRef
>> expectedStacks
= {
41 {DebuggerAction::tag
},
42 {OtherAction::tag
, DebuggerAction::tag
},
43 {ThirdAction::tag
, OtherAction::tag
, DebuggerAction::tag
}};
45 auto checkStacks
= [&](const ActionActiveStack
*backtrace
,
46 const std::vector
<StringRef
> ¤tStack
) {
47 ASSERT_EQ((int)currentStack
.size(), backtrace
->getDepth() + 1);
48 for (StringRef stackEntry
: currentStack
) {
49 ASSERT_NE(backtrace
, nullptr);
50 ASSERT_EQ(stackEntry
, backtrace
->getAction().getTag());
51 backtrace
= backtrace
->getParent();
55 std::vector
<ExecutionContext::Control
> controlSequence
= {
56 ExecutionContext::Step
, ExecutionContext::Step
, ExecutionContext::Apply
};
59 int currentDepth
= -1;
60 auto onBreakpoint
= [&](const ActionActiveStack
*backtrace
) {
61 current
= backtrace
->getAction().getTag();
62 currentDepth
= backtrace
->getDepth();
63 checkStacks(backtrace
, expectedStacks
[idx
]);
64 return controlSequence
[idx
++];
67 TagBreakpointManager simpleManager
;
68 ExecutionContext
executionCtx(onBreakpoint
);
69 executionCtx
.addBreakpointManager(&simpleManager
);
70 std::vector
<TagBreakpoint
*> breakpoints
;
71 breakpoints
.push_back(simpleManager
.addBreakpoint(DebuggerAction::tag
));
72 breakpoints
.push_back(simpleManager
.addBreakpoint(OtherAction::tag
));
73 breakpoints
.push_back(simpleManager
.addBreakpoint(ThirdAction::tag
));
76 EXPECT_EQ(current
, ThirdAction::tag
);
77 EXPECT_EQ(currentDepth
, 2);
80 EXPECT_EQ(current
, OtherAction::tag
);
81 EXPECT_EQ(currentDepth
, 1);
82 executionCtx(third
, ThirdAction
{});
84 auto original
= [&]() {
85 EXPECT_EQ(current
, DebuggerAction::tag
);
86 EXPECT_EQ(currentDepth
, 0);
87 executionCtx(nested
, OtherAction
{});
91 executionCtx(original
, DebuggerAction
{});
94 TEST(ExecutionContext
, DebuggerTest
) {
95 // Check matching and non matching breakpoints, with various enable/disable
98 auto onBreakpoint
= [&match
](const ActionActiveStack
*backtrace
) {
100 return ExecutionContext::Skip
;
102 TagBreakpointManager simpleManager
;
103 ExecutionContext
executionCtx(onBreakpoint
);
104 executionCtx
.addBreakpointManager(&simpleManager
);
106 executionCtx(noOp
, DebuggerAction
{});
109 Breakpoint
*dbgBreakpoint
= simpleManager
.addBreakpoint(DebuggerAction::tag
);
110 executionCtx(noOp
, DebuggerAction
{});
113 dbgBreakpoint
->disable();
114 executionCtx(noOp
, DebuggerAction
{});
117 dbgBreakpoint
->enable();
118 executionCtx(noOp
, DebuggerAction
{});
121 executionCtx(noOp
, OtherAction
{});
125 TEST(ExecutionContext
, ApplyTest
) {
126 // Test the "apply" control.
127 std::vector
<StringRef
> tagSequence
= {DebuggerAction::tag
};
128 std::vector
<ExecutionContext::Control
> controlSequence
= {
129 ExecutionContext::Apply
};
130 int idx
= 0, counter
= 0;
131 auto onBreakpoint
= [&](const ActionActiveStack
*backtrace
) {
133 EXPECT_EQ(tagSequence
[idx
], backtrace
->getAction().getTag());
134 return controlSequence
[idx
++];
136 auto callback
= [&]() { EXPECT_EQ(counter
, 1); };
137 TagBreakpointManager simpleManager
;
138 ExecutionContext
executionCtx(onBreakpoint
);
139 executionCtx
.addBreakpointManager(&simpleManager
);
140 simpleManager
.addBreakpoint(DebuggerAction::tag
);
142 executionCtx(callback
, DebuggerAction
{});
143 EXPECT_EQ(counter
, 1);
146 TEST(ExecutionContext
, SkipTest
) {
147 // Test the "skip" control.
148 std::vector
<StringRef
> tagSequence
= {DebuggerAction::tag
,
149 DebuggerAction::tag
};
150 std::vector
<ExecutionContext::Control
> controlSequence
= {
151 ExecutionContext::Apply
, ExecutionContext::Skip
};
152 int idx
= 0, counter
= 0, executionCounter
= 0;
153 auto onBreakpoint
= [&](const ActionActiveStack
*backtrace
) {
155 EXPECT_EQ(tagSequence
[idx
], backtrace
->getAction().getTag());
156 return controlSequence
[idx
++];
158 auto callback
= [&]() { ++executionCounter
; };
159 TagBreakpointManager simpleManager
;
160 ExecutionContext
executionCtx(onBreakpoint
);
161 executionCtx
.addBreakpointManager(&simpleManager
);
162 simpleManager
.addBreakpoint(DebuggerAction::tag
);
164 executionCtx(callback
, DebuggerAction
{});
165 executionCtx(callback
, DebuggerAction
{});
166 EXPECT_EQ(counter
, 2);
167 EXPECT_EQ(executionCounter
, 1);
170 TEST(ExecutionContext
, StepApplyTest
) {
171 // Test the "step" control with a nested action.
172 std::vector
<StringRef
> tagSequence
= {DebuggerAction::tag
, OtherAction::tag
};
173 std::vector
<ExecutionContext::Control
> controlSequence
= {
174 ExecutionContext::Step
, ExecutionContext::Apply
};
175 int idx
= 0, counter
= 0;
176 auto onBreakpoint
= [&](const ActionActiveStack
*backtrace
) {
178 EXPECT_EQ(tagSequence
[idx
], backtrace
->getAction().getTag());
179 return controlSequence
[idx
++];
181 TagBreakpointManager simpleManager
;
182 ExecutionContext
executionCtx(onBreakpoint
);
183 executionCtx
.addBreakpointManager(&simpleManager
);
184 simpleManager
.addBreakpoint(DebuggerAction::tag
);
185 auto nested
= [&]() { EXPECT_EQ(counter
, 2); };
186 auto original
= [&]() {
187 EXPECT_EQ(counter
, 1);
188 executionCtx(nested
, OtherAction
{});
191 executionCtx(original
, DebuggerAction
{});
192 EXPECT_EQ(counter
, 2);
195 TEST(ExecutionContext
, StepNothingInsideTest
) {
196 // Test the "step" control without a nested action.
197 std::vector
<StringRef
> tagSequence
= {DebuggerAction::tag
,
198 DebuggerAction::tag
};
199 std::vector
<ExecutionContext::Control
> controlSequence
= {
200 ExecutionContext::Step
, ExecutionContext::Step
};
201 int idx
= 0, counter
= 0;
202 auto onBreakpoint
= [&](const ActionActiveStack
*backtrace
) {
204 EXPECT_EQ(tagSequence
[idx
], backtrace
->getAction().getTag());
205 return controlSequence
[idx
++];
207 auto callback
= [&]() { EXPECT_EQ(counter
, 1); };
208 TagBreakpointManager simpleManager
;
209 ExecutionContext
executionCtx(onBreakpoint
);
210 executionCtx
.addBreakpointManager(&simpleManager
);
211 simpleManager
.addBreakpoint(DebuggerAction::tag
);
213 executionCtx(callback
, DebuggerAction
{});
214 EXPECT_EQ(counter
, 2);
217 TEST(ExecutionContext
, NextTest
) {
218 // Test the "next" control.
219 std::vector
<StringRef
> tagSequence
= {DebuggerAction::tag
,
220 DebuggerAction::tag
};
221 std::vector
<ExecutionContext::Control
> controlSequence
= {
222 ExecutionContext::Next
, ExecutionContext::Next
};
223 int idx
= 0, counter
= 0;
224 auto onBreakpoint
= [&](const ActionActiveStack
*backtrace
) {
226 EXPECT_EQ(tagSequence
[idx
], backtrace
->getAction().getTag());
227 return controlSequence
[idx
++];
229 auto callback
= [&]() { EXPECT_EQ(counter
, 1); };
230 TagBreakpointManager simpleManager
;
231 ExecutionContext
executionCtx(onBreakpoint
);
232 executionCtx
.addBreakpointManager(&simpleManager
);
233 simpleManager
.addBreakpoint(DebuggerAction::tag
);
235 executionCtx(callback
, DebuggerAction
{});
236 EXPECT_EQ(counter
, 2);
239 TEST(ExecutionContext
, FinishTest
) {
240 // Test the "finish" control.
241 std::vector
<StringRef
> tagSequence
= {DebuggerAction::tag
, OtherAction::tag
,
242 DebuggerAction::tag
};
243 std::vector
<ExecutionContext::Control
> controlSequence
= {
244 ExecutionContext::Step
, ExecutionContext::Finish
,
245 ExecutionContext::Apply
};
246 int idx
= 0, counter
= 0;
247 auto onBreakpoint
= [&](const ActionActiveStack
*backtrace
) {
249 EXPECT_EQ(tagSequence
[idx
], backtrace
->getAction().getTag());
250 return controlSequence
[idx
++];
252 TagBreakpointManager simpleManager
;
253 ExecutionContext
executionCtx(onBreakpoint
);
254 executionCtx
.addBreakpointManager(&simpleManager
);
255 simpleManager
.addBreakpoint(DebuggerAction::tag
);
256 auto nested
= [&]() { EXPECT_EQ(counter
, 2); };
257 auto original
= [&]() {
258 EXPECT_EQ(counter
, 1);
259 executionCtx(nested
, OtherAction
{});
260 EXPECT_EQ(counter
, 2);
263 executionCtx(original
, DebuggerAction
{});
264 EXPECT_EQ(counter
, 3);
267 TEST(ExecutionContext
, FinishBreakpointInNestedTest
) {
268 // Test the "finish" control with a breakpoint in the nested action.
269 std::vector
<StringRef
> tagSequence
= {OtherAction::tag
, DebuggerAction::tag
};
270 std::vector
<ExecutionContext::Control
> controlSequence
= {
271 ExecutionContext::Finish
, ExecutionContext::Apply
};
272 int idx
= 0, counter
= 0;
273 auto onBreakpoint
= [&](const ActionActiveStack
*backtrace
) {
275 EXPECT_EQ(tagSequence
[idx
], backtrace
->getAction().getTag());
276 return controlSequence
[idx
++];
278 TagBreakpointManager simpleManager
;
279 ExecutionContext
executionCtx(onBreakpoint
);
280 executionCtx
.addBreakpointManager(&simpleManager
);
281 simpleManager
.addBreakpoint(OtherAction::tag
);
283 auto nested
= [&]() { EXPECT_EQ(counter
, 1); };
284 auto original
= [&]() {
285 EXPECT_EQ(counter
, 0);
286 executionCtx(nested
, OtherAction
{});
287 EXPECT_EQ(counter
, 1);
290 executionCtx(original
, DebuggerAction
{});
291 EXPECT_EQ(counter
, 2);
294 TEST(ExecutionContext
, FinishNothingBackTest
) {
295 // Test the "finish" control without a nested action.
296 std::vector
<StringRef
> tagSequence
= {DebuggerAction::tag
};
297 std::vector
<ExecutionContext::Control
> controlSequence
= {
298 ExecutionContext::Finish
};
299 int idx
= 0, counter
= 0;
300 auto onBreakpoint
= [&](const ActionActiveStack
*backtrace
) {
302 EXPECT_EQ(tagSequence
[idx
], backtrace
->getAction().getTag());
303 return controlSequence
[idx
++];
305 auto callback
= [&]() { EXPECT_EQ(counter
, 1); };
306 TagBreakpointManager simpleManager
;
307 ExecutionContext
executionCtx(onBreakpoint
);
308 executionCtx
.addBreakpointManager(&simpleManager
);
309 simpleManager
.addBreakpoint(DebuggerAction::tag
);
311 executionCtx(callback
, DebuggerAction
{});
312 EXPECT_EQ(counter
, 1);
315 TEST(ExecutionContext
, EnableDisableBreakpointOnCallback
) {
316 // Test enabling and disabling breakpoints while executing the action.
317 std::vector
<StringRef
> tagSequence
= {DebuggerAction::tag
, ThirdAction::tag
,
318 OtherAction::tag
, DebuggerAction::tag
};
319 std::vector
<ExecutionContext::Control
> controlSequence
= {
320 ExecutionContext::Apply
, ExecutionContext::Finish
,
321 ExecutionContext::Finish
, ExecutionContext::Apply
};
322 int idx
= 0, counter
= 0;
323 auto onBreakpoint
= [&](const ActionActiveStack
*backtrace
) {
325 EXPECT_EQ(tagSequence
[idx
], backtrace
->getAction().getTag());
326 return controlSequence
[idx
++];
329 TagBreakpointManager simpleManager
;
330 ExecutionContext
executionCtx(onBreakpoint
);
331 executionCtx
.addBreakpointManager(&simpleManager
);
332 simpleManager
.addBreakpoint(DebuggerAction::tag
);
333 Breakpoint
*toBeDisabled
= simpleManager
.addBreakpoint(OtherAction::tag
);
335 auto third
= [&]() { EXPECT_EQ(counter
, 2); };
336 auto nested
= [&]() {
337 EXPECT_EQ(counter
, 1);
338 executionCtx(third
, ThirdAction
{});
339 EXPECT_EQ(counter
, 2);
341 auto original
= [&]() {
342 EXPECT_EQ(counter
, 1);
343 toBeDisabled
->disable();
344 simpleManager
.addBreakpoint(ThirdAction::tag
);
345 executionCtx(nested
, OtherAction
{});
346 EXPECT_EQ(counter
, 3);
349 executionCtx(original
, DebuggerAction
{});
350 EXPECT_EQ(counter
, 4);