Line data Source code
1 : // Copyright 2012 the V8 project authors. All rights reserved.
2 : // Redistribution and use in source and binary forms, with or without
3 : // modification, are permitted provided that the following conditions are
4 : // met:
5 : //
6 : // * Redistributions of source code must retain the above copyright
7 : // notice, this list of conditions and the following disclaimer.
8 : // * Redistributions in binary form must reproduce the above
9 : // copyright notice, this list of conditions and the following
10 : // disclaimer in the documentation and/or other materials provided
11 : // with the distribution.
12 : // * Neither the name of Google Inc. nor the names of its
13 : // contributors may be used to endorse or promote products derived
14 : // from this software without specific prior written permission.
15 : //
16 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 :
28 : #include <stdlib.h>
29 :
30 : #include "src/v8.h"
31 :
32 : #include "src/api-inl.h"
33 : #include "src/compilation-cache.h"
34 : #include "src/debug/debug-interface.h"
35 : #include "src/debug/debug.h"
36 : #include "src/deoptimizer.h"
37 : #include "src/frames.h"
38 : #include "src/objects-inl.h"
39 : #include "src/snapshot/natives.h"
40 : #include "src/snapshot/snapshot.h"
41 : #include "src/utils.h"
42 : #include "test/cctest/cctest.h"
43 :
44 : using ::v8::internal::Handle;
45 : using ::v8::internal::StepNone; // From StepAction enum
46 : using ::v8::internal::StepIn; // From StepAction enum
47 : using ::v8::internal::StepNext; // From StepAction enum
48 : using ::v8::internal::StepOut; // From StepAction enum
49 :
50 : // --- H e l p e r F u n c t i o n s
51 :
52 : // Compile and run the supplied source and return the requested function.
53 320 : static v8::Local<v8::Function> CompileFunction(v8::Isolate* isolate,
54 : const char* source,
55 : const char* function_name) {
56 320 : CompileRunChecked(isolate, source);
57 320 : v8::Local<v8::String> name = v8_str(isolate, function_name);
58 320 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
59 : v8::MaybeLocal<v8::Value> maybe_function =
60 640 : context->Global()->Get(context, name);
61 320 : return v8::Local<v8::Function>::Cast(maybe_function.ToLocalChecked());
62 : }
63 :
64 :
65 : // Compile and run the supplied source and return the requested function.
66 280 : static v8::Local<v8::Function> CompileFunction(LocalContext* env,
67 : const char* source,
68 : const char* function_name) {
69 280 : return CompileFunction((*env)->GetIsolate(), source, function_name);
70 : }
71 :
72 : // Is there any debug info for the function?
73 50 : static bool HasBreakInfo(v8::Local<v8::Function> fun) {
74 : Handle<v8::internal::JSFunction> f =
75 50 : Handle<v8::internal::JSFunction>::cast(v8::Utils::OpenHandle(*fun));
76 100 : Handle<v8::internal::SharedFunctionInfo> shared(f->shared(), f->GetIsolate());
77 50 : return shared->HasBreakInfo();
78 : }
79 :
80 : // Set a break point in a function with a position relative to function start,
81 : // and return the associated break point number.
82 350 : static i::Handle<i::BreakPoint> SetBreakPoint(v8::Local<v8::Function> fun,
83 : int position,
84 : const char* condition = nullptr) {
85 : i::Handle<i::JSFunction> function =
86 350 : i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*fun));
87 350 : position += function->shared()->StartPosition();
88 : static int break_point_index = 0;
89 350 : i::Isolate* isolate = function->GetIsolate();
90 : i::Handle<i::String> condition_string =
91 : condition ? isolate->factory()->NewStringFromAsciiChecked(condition)
92 655 : : isolate->factory()->empty_string();
93 : i::Debug* debug = isolate->debug();
94 : i::Handle<i::BreakPoint> break_point =
95 350 : isolate->factory()->NewBreakPoint(++break_point_index, condition_string);
96 :
97 350 : debug->SetBreakPoint(function, break_point, &position);
98 350 : return break_point;
99 : }
100 :
101 :
102 175 : static void ClearBreakPoint(i::Handle<i::BreakPoint> break_point) {
103 175 : v8::internal::Isolate* isolate = CcTest::i_isolate();
104 : v8::internal::Debug* debug = isolate->debug();
105 175 : debug->ClearBreakPoint(break_point);
106 175 : }
107 :
108 :
109 : // Change break on exception.
110 15 : static void ChangeBreakOnException(bool caught, bool uncaught) {
111 15 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
112 15 : debug->ChangeBreakOnException(v8::internal::BreakException, caught);
113 15 : debug->ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
114 15 : }
115 :
116 :
117 : // Prepare to step to next break location.
118 11980 : static void PrepareStep(i::StepAction step_action) {
119 11980 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
120 11980 : debug->PrepareStep(step_action);
121 11980 : }
122 :
123 : // This function is in namespace v8::internal to be friend with class
124 : // v8::internal::Debug.
125 : namespace v8 {
126 : namespace internal {
127 :
128 : // Collect the currently debugged functions.
129 25 : Handle<FixedArray> GetDebuggedFunctions() {
130 25 : Debug* debug = CcTest::i_isolate()->debug();
131 :
132 45 : v8::internal::DebugInfoListNode* node = debug->debug_info_list_;
133 :
134 : // Find the number of debugged functions.
135 : int count = 0;
136 70 : while (node) {
137 20 : count++;
138 : node = node->next();
139 : }
140 :
141 : // Allocate array for the debugged functions
142 : Handle<FixedArray> debugged_functions =
143 25 : CcTest::i_isolate()->factory()->NewFixedArray(count);
144 :
145 : // Run through the debug info objects and collect all functions.
146 : count = 0;
147 50 : while (node) {
148 0 : debugged_functions->set(count++, *node->debug_info());
149 : node = node->next();
150 : }
151 :
152 25 : return debugged_functions;
153 : }
154 :
155 :
156 : // Check that the debugger has been fully unloaded.
157 410 : void CheckDebuggerUnloaded() {
158 : // Check that the debugger context is cleared and that there is no debug
159 : // information stored for the debugger.
160 410 : CHECK(!CcTest::i_isolate()->debug()->debug_info_list_);
161 :
162 : // Collect garbage to ensure weak handles are cleared.
163 410 : CcTest::CollectAllGarbage();
164 410 : CcTest::CollectAllGarbage();
165 :
166 : // Iterate the heap and check that there are no debugger related objects left.
167 410 : HeapIterator iterator(CcTest::heap());
168 5559088 : for (HeapObject obj = iterator.next(); !obj.is_null();
169 : obj = iterator.next()) {
170 2779134 : CHECK(!obj->IsDebugInfo());
171 410 : }
172 410 : }
173 :
174 :
175 : } // namespace internal
176 : } // namespace v8
177 :
178 :
179 : // Check that the debugger has been fully unloaded.
180 410 : static void CheckDebuggerUnloaded() { v8::internal::CheckDebuggerUnloaded(); }
181 :
182 : // --- D e b u g E v e n t H a n d l e r s
183 : // ---
184 : // --- The different tests uses a number of debug event handlers.
185 : // ---
186 :
187 : // Debug event handler which counts a number of events.
188 : int break_point_hit_count = 0;
189 : int break_point_hit_count_deoptimize = 0;
190 300 : class DebugEventCounter : public v8::debug::DebugDelegate {
191 : public:
192 12765 : void BreakProgramRequested(
193 : v8::Local<v8::Context>,
194 : const std::vector<v8::debug::BreakpointId>&) override {
195 12765 : break_point_hit_count++;
196 : // Perform a full deoptimization when the specified number of
197 : // breaks have been hit.
198 12765 : if (break_point_hit_count == break_point_hit_count_deoptimize) {
199 0 : i::Deoptimizer::DeoptimizeAll(CcTest::i_isolate());
200 : }
201 12765 : if (step_action_ != StepNone) PrepareStep(step_action_);
202 12765 : }
203 :
204 : void set_step_action(i::StepAction step_action) {
205 180 : step_action_ = step_action;
206 : }
207 :
208 : private:
209 : i::StepAction step_action_ = StepNone;
210 : };
211 :
212 : // Debug event handler which performs a garbage collection.
213 15 : class DebugEventBreakPointCollectGarbage : public v8::debug::DebugDelegate {
214 : public:
215 420 : void BreakProgramRequested(
216 : v8::Local<v8::Context>,
217 : const std::vector<v8::debug::BreakpointId>&) override {
218 : // Perform a garbage collection when break point is hit and continue. Based
219 : // on the number of break points hit either scavenge or mark compact
220 : // collector is used.
221 420 : break_point_hit_count++;
222 420 : if (break_point_hit_count % 2 == 0) {
223 : // Scavenge.
224 205 : CcTest::CollectGarbage(v8::internal::NEW_SPACE);
225 : } else {
226 : // Mark sweep compact.
227 215 : CcTest::CollectAllGarbage();
228 : }
229 420 : }
230 : };
231 :
232 : // Debug event handler which re-issues a debug break and calls the garbage
233 : // collector to have the heap verified.
234 10 : class DebugEventBreak : public v8::debug::DebugDelegate {
235 : public:
236 85 : void BreakProgramRequested(
237 : v8::Local<v8::Context>,
238 : const std::vector<v8::debug::BreakpointId>&) override {
239 : // Count the number of breaks.
240 85 : break_point_hit_count++;
241 :
242 : // Run the garbage collector to enforce heap verification if option
243 : // --verify-heap is set.
244 85 : CcTest::CollectGarbage(v8::internal::NEW_SPACE);
245 :
246 : // Set the break flag again to come back here as soon as possible.
247 85 : v8::debug::SetBreakOnNextFunctionCall(CcTest::isolate());
248 85 : }
249 : };
250 :
251 59905 : static void BreakRightNow(v8::Isolate* isolate, void*) {
252 59905 : v8::debug::BreakRightNow(isolate);
253 59905 : }
254 :
255 : // Debug event handler which re-issues a debug break until a limit has been
256 : // reached.
257 : int max_break_point_hit_count = 0;
258 : bool terminate_after_max_break_point_hit = false;
259 65 : class DebugEventBreakMax : public v8::debug::DebugDelegate {
260 : public:
261 60895 : void BreakProgramRequested(
262 : v8::Local<v8::Context>,
263 : const std::vector<v8::debug::BreakpointId>&) override {
264 60895 : v8::Isolate* v8_isolate = CcTest::isolate();
265 : v8::internal::Isolate* isolate = CcTest::i_isolate();
266 60895 : if (break_point_hit_count < max_break_point_hit_count) {
267 : // Count the number of breaks.
268 59900 : break_point_hit_count++;
269 :
270 : // Set the break flag again to come back here as soon as possible.
271 59900 : v8_isolate->RequestInterrupt(BreakRightNow, nullptr);
272 :
273 995 : } else if (terminate_after_max_break_point_hit) {
274 : // Terminate execution after the last break if requested.
275 990 : v8_isolate->TerminateExecution();
276 : }
277 :
278 : // Perform a full deoptimization when the specified number of
279 : // breaks have been hit.
280 60895 : if (break_point_hit_count == break_point_hit_count_deoptimize) {
281 990 : i::Deoptimizer::DeoptimizeAll(isolate);
282 : }
283 60895 : }
284 : };
285 :
286 : // --- T h e A c t u a l T e s t s
287 :
288 : // Test that the debug info in the VM is in sync with the functions being
289 : // debugged.
290 25880 : TEST(DebugInfo) {
291 5 : LocalContext env;
292 10 : v8::HandleScope scope(env->GetIsolate());
293 : // Create a couple of functions for the test.
294 : v8::Local<v8::Function> foo =
295 5 : CompileFunction(&env, "function foo(){}", "foo");
296 : v8::Local<v8::Function> bar =
297 5 : CompileFunction(&env, "function bar(){}", "bar");
298 : // Initially no functions are debugged.
299 10 : CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
300 5 : CHECK(!HasBreakInfo(foo));
301 5 : CHECK(!HasBreakInfo(bar));
302 5 : EnableDebugger(env->GetIsolate());
303 : // One function (foo) is debugged.
304 5 : i::Handle<i::BreakPoint> bp1 = SetBreakPoint(foo, 0);
305 10 : CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
306 5 : CHECK(HasBreakInfo(foo));
307 5 : CHECK(!HasBreakInfo(bar));
308 : // Two functions are debugged.
309 5 : i::Handle<i::BreakPoint> bp2 = SetBreakPoint(bar, 0);
310 10 : CHECK_EQ(2, v8::internal::GetDebuggedFunctions()->length());
311 5 : CHECK(HasBreakInfo(foo));
312 5 : CHECK(HasBreakInfo(bar));
313 : // One function (bar) is debugged.
314 5 : ClearBreakPoint(bp1);
315 10 : CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
316 5 : CHECK(!HasBreakInfo(foo));
317 5 : CHECK(HasBreakInfo(bar));
318 : // No functions are debugged.
319 5 : ClearBreakPoint(bp2);
320 5 : DisableDebugger(env->GetIsolate());
321 10 : CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
322 5 : CHECK(!HasBreakInfo(foo));
323 10 : CHECK(!HasBreakInfo(bar));
324 5 : }
325 :
326 :
327 : // Test that a break point can be set at an IC store location.
328 25880 : TEST(BreakPointICStore) {
329 5 : break_point_hit_count = 0;
330 5 : LocalContext env;
331 10 : v8::HandleScope scope(env->GetIsolate());
332 :
333 5 : DebugEventCounter delegate;
334 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
335 : v8::Local<v8::Function> foo =
336 5 : CompileFunction(&env, "function foo(){bar=0;}", "foo");
337 :
338 : // Run without breakpoints.
339 15 : foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
340 5 : CHECK_EQ(0, break_point_hit_count);
341 :
342 : // Run with breakpoint
343 5 : i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
344 15 : foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
345 5 : CHECK_EQ(1, break_point_hit_count);
346 15 : foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
347 5 : CHECK_EQ(2, break_point_hit_count);
348 :
349 : // Run without breakpoints.
350 5 : ClearBreakPoint(bp);
351 15 : foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
352 5 : CHECK_EQ(2, break_point_hit_count);
353 :
354 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
355 5 : CheckDebuggerUnloaded();
356 5 : }
357 :
358 : // Test that a break point can be set at an IC store location.
359 25880 : TEST(BreakPointCondition) {
360 5 : break_point_hit_count = 0;
361 5 : LocalContext env;
362 10 : v8::HandleScope scope(env->GetIsolate());
363 :
364 5 : DebugEventCounter delegate;
365 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
366 : CompileRun("var a = false");
367 : v8::Local<v8::Function> foo =
368 5 : CompileFunction(&env, "function foo() { return 1 }", "foo");
369 : // Run without breakpoints.
370 : CompileRun("foo()");
371 5 : CHECK_EQ(0, break_point_hit_count);
372 :
373 : // Run with breakpoint
374 5 : i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0, "a == true");
375 : CompileRun("foo()");
376 5 : CHECK_EQ(0, break_point_hit_count);
377 :
378 : CompileRun("a = true");
379 : CompileRun("foo()");
380 5 : CHECK_EQ(1, break_point_hit_count);
381 :
382 : // Run without breakpoints.
383 5 : ClearBreakPoint(bp);
384 : CompileRun("foo()");
385 5 : CHECK_EQ(1, break_point_hit_count);
386 :
387 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
388 5 : CheckDebuggerUnloaded();
389 5 : }
390 :
391 : // Test that a break point can be set at an IC load location.
392 25880 : TEST(BreakPointICLoad) {
393 5 : break_point_hit_count = 0;
394 5 : LocalContext env;
395 10 : v8::HandleScope scope(env->GetIsolate());
396 5 : DebugEventCounter delegate;
397 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
398 :
399 5 : CompileRunChecked(env->GetIsolate(), "bar=1");
400 : v8::Local<v8::Function> foo =
401 5 : CompileFunction(&env, "function foo(){var x=bar;}", "foo");
402 :
403 : // Run without breakpoints.
404 15 : foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
405 5 : CHECK_EQ(0, break_point_hit_count);
406 :
407 : // Run with breakpoint.
408 5 : i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
409 15 : foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
410 5 : CHECK_EQ(1, break_point_hit_count);
411 15 : foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
412 5 : CHECK_EQ(2, break_point_hit_count);
413 :
414 : // Run without breakpoints.
415 5 : ClearBreakPoint(bp);
416 15 : foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
417 5 : CHECK_EQ(2, break_point_hit_count);
418 :
419 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
420 5 : CheckDebuggerUnloaded();
421 5 : }
422 :
423 :
424 : // Test that a break point can be set at an IC call location.
425 25880 : TEST(BreakPointICCall) {
426 5 : break_point_hit_count = 0;
427 5 : LocalContext env;
428 10 : v8::HandleScope scope(env->GetIsolate());
429 5 : DebugEventCounter delegate;
430 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
431 5 : CompileRunChecked(env->GetIsolate(), "function bar(){}");
432 : v8::Local<v8::Function> foo =
433 5 : CompileFunction(&env, "function foo(){bar();}", "foo");
434 :
435 : // Run without breakpoints.
436 15 : foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
437 5 : CHECK_EQ(0, break_point_hit_count);
438 :
439 : // Run with breakpoint
440 5 : i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
441 15 : foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
442 5 : CHECK_EQ(1, break_point_hit_count);
443 15 : foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
444 5 : CHECK_EQ(2, break_point_hit_count);
445 :
446 : // Run without breakpoints.
447 5 : ClearBreakPoint(bp);
448 15 : foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
449 5 : CHECK_EQ(2, break_point_hit_count);
450 :
451 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
452 5 : CheckDebuggerUnloaded();
453 5 : }
454 :
455 :
456 : // Test that a break point can be set at an IC call location and survive a GC.
457 25880 : TEST(BreakPointICCallWithGC) {
458 5 : break_point_hit_count = 0;
459 5 : LocalContext env;
460 10 : v8::HandleScope scope(env->GetIsolate());
461 5 : DebugEventBreakPointCollectGarbage delegate;
462 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
463 5 : CompileRunChecked(env->GetIsolate(), "function bar(){return 1;}");
464 : v8::Local<v8::Function> foo =
465 5 : CompileFunction(&env, "function foo(){return bar();}", "foo");
466 5 : v8::Local<v8::Context> context = env.local();
467 :
468 : // Run without breakpoints.
469 20 : CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
470 : .ToLocalChecked()
471 : ->Int32Value(context)
472 : .FromJust());
473 5 : CHECK_EQ(0, break_point_hit_count);
474 :
475 : // Run with breakpoint.
476 5 : i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
477 20 : CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
478 : .ToLocalChecked()
479 : ->Int32Value(context)
480 : .FromJust());
481 5 : CHECK_EQ(1, break_point_hit_count);
482 20 : CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
483 : .ToLocalChecked()
484 : ->Int32Value(context)
485 : .FromJust());
486 5 : CHECK_EQ(2, break_point_hit_count);
487 :
488 : // Run without breakpoints.
489 5 : ClearBreakPoint(bp);
490 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
491 5 : CHECK_EQ(2, break_point_hit_count);
492 :
493 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
494 5 : CheckDebuggerUnloaded();
495 5 : }
496 :
497 :
498 : // Test that a break point can be set at an IC call location and survive a GC.
499 25880 : TEST(BreakPointConstructCallWithGC) {
500 5 : break_point_hit_count = 0;
501 5 : LocalContext env;
502 10 : v8::HandleScope scope(env->GetIsolate());
503 5 : DebugEventBreakPointCollectGarbage delegate;
504 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
505 5 : CompileRunChecked(env->GetIsolate(), "function bar(){ this.x = 1;}");
506 : v8::Local<v8::Function> foo =
507 5 : CompileFunction(&env, "function foo(){return new bar(1).x;}", "foo");
508 5 : v8::Local<v8::Context> context = env.local();
509 :
510 : // Run without breakpoints.
511 20 : CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
512 : .ToLocalChecked()
513 : ->Int32Value(context)
514 : .FromJust());
515 5 : CHECK_EQ(0, break_point_hit_count);
516 :
517 : // Run with breakpoint.
518 5 : i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
519 20 : CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
520 : .ToLocalChecked()
521 : ->Int32Value(context)
522 : .FromJust());
523 5 : CHECK_EQ(1, break_point_hit_count);
524 20 : CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
525 : .ToLocalChecked()
526 : ->Int32Value(context)
527 : .FromJust());
528 5 : CHECK_EQ(2, break_point_hit_count);
529 :
530 : // Run without breakpoints.
531 5 : ClearBreakPoint(bp);
532 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
533 5 : CHECK_EQ(2, break_point_hit_count);
534 :
535 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
536 5 : CheckDebuggerUnloaded();
537 5 : }
538 :
539 :
540 25880 : TEST(BreakPointBuiltin) {
541 5 : LocalContext env;
542 10 : v8::HandleScope scope(env->GetIsolate());
543 :
544 5 : DebugEventCounter delegate;
545 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
546 :
547 : v8::Local<v8::Function> builtin;
548 : i::Handle<i::BreakPoint> bp;
549 :
550 : // === Test simple builtin ===
551 5 : break_point_hit_count = 0;
552 5 : builtin = CompileRun("String.prototype.repeat").As<v8::Function>();
553 :
554 : // Run with breakpoint.
555 5 : bp = SetBreakPoint(builtin, 0);
556 5 : ExpectString("'b'.repeat(10)", "bbbbbbbbbb");
557 5 : CHECK_EQ(1, break_point_hit_count);
558 :
559 5 : ExpectString("'b'.repeat(10)", "bbbbbbbbbb");
560 5 : CHECK_EQ(2, break_point_hit_count);
561 :
562 : // Run without breakpoints.
563 5 : ClearBreakPoint(bp);
564 5 : ExpectString("'b'.repeat(10)", "bbbbbbbbbb");
565 5 : CHECK_EQ(2, break_point_hit_count);
566 :
567 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
568 5 : CheckDebuggerUnloaded();
569 5 : }
570 :
571 25880 : TEST(BreakPointJSBuiltin) {
572 5 : LocalContext env;
573 10 : v8::HandleScope scope(env->GetIsolate());
574 :
575 5 : DebugEventCounter delegate;
576 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
577 :
578 : v8::Local<v8::Function> builtin;
579 : i::Handle<i::BreakPoint> bp;
580 :
581 : // === Test JS builtin ===
582 5 : break_point_hit_count = 0;
583 5 : builtin = CompileRun("Array.prototype.sort").As<v8::Function>();
584 :
585 : // Run with breakpoint.
586 5 : bp = SetBreakPoint(builtin, 0);
587 : CompileRun("[1,2,3].sort()");
588 5 : CHECK_EQ(1, break_point_hit_count);
589 :
590 : CompileRun("[1,2,3].sort()");
591 5 : CHECK_EQ(2, break_point_hit_count);
592 :
593 : // Run without breakpoints.
594 5 : ClearBreakPoint(bp);
595 : CompileRun("[1,2,3].sort()");
596 5 : CHECK_EQ(2, break_point_hit_count);
597 :
598 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
599 5 : CheckDebuggerUnloaded();
600 5 : }
601 :
602 25880 : TEST(BreakPointBoundBuiltin) {
603 5 : LocalContext env;
604 10 : v8::HandleScope scope(env->GetIsolate());
605 :
606 5 : DebugEventCounter delegate;
607 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
608 :
609 : v8::Local<v8::Function> builtin;
610 : i::Handle<i::BreakPoint> bp;
611 :
612 : // === Test bound function from a builtin ===
613 5 : break_point_hit_count = 0;
614 : builtin = CompileRun(
615 : "var boundrepeat = String.prototype.repeat.bind('a');"
616 : "String.prototype.repeat")
617 5 : .As<v8::Function>();
618 5 : ExpectString("boundrepeat(10)", "aaaaaaaaaa");
619 5 : CHECK_EQ(0, break_point_hit_count);
620 :
621 : // Run with breakpoint.
622 5 : bp = SetBreakPoint(builtin, 0);
623 5 : ExpectString("boundrepeat(10)", "aaaaaaaaaa");
624 5 : CHECK_EQ(1, break_point_hit_count);
625 :
626 : // Run without breakpoints.
627 5 : ClearBreakPoint(bp);
628 5 : ExpectString("boundrepeat(10)", "aaaaaaaaaa");
629 5 : CHECK_EQ(1, break_point_hit_count);
630 :
631 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
632 5 : CheckDebuggerUnloaded();
633 5 : }
634 :
635 25880 : TEST(BreakPointConstructorBuiltin) {
636 5 : LocalContext env;
637 10 : v8::HandleScope scope(env->GetIsolate());
638 :
639 5 : DebugEventCounter delegate;
640 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
641 :
642 : v8::Local<v8::Function> builtin;
643 : i::Handle<i::BreakPoint> bp;
644 :
645 : // === Test Promise constructor ===
646 5 : break_point_hit_count = 0;
647 5 : builtin = CompileRun("Promise").As<v8::Function>();
648 5 : ExpectString("(new Promise(()=>{})).toString()", "[object Promise]");
649 5 : CHECK_EQ(0, break_point_hit_count);
650 :
651 : // Run with breakpoint.
652 5 : bp = SetBreakPoint(builtin, 0);
653 5 : ExpectString("(new Promise(()=>{})).toString()", "[object Promise]");
654 5 : CHECK_EQ(1, break_point_hit_count);
655 :
656 : // Run without breakpoints.
657 5 : ClearBreakPoint(bp);
658 5 : ExpectString("(new Promise(()=>{})).toString()", "[object Promise]");
659 5 : CHECK_EQ(1, break_point_hit_count);
660 :
661 : // === Test Object constructor ===
662 5 : break_point_hit_count = 0;
663 5 : builtin = CompileRun("Object").As<v8::Function>();
664 : CompileRun("new Object()");
665 5 : CHECK_EQ(0, break_point_hit_count);
666 :
667 : // Run with breakpoint.
668 5 : bp = SetBreakPoint(builtin, 0);
669 : CompileRun("new Object()");
670 5 : CHECK_EQ(1, break_point_hit_count);
671 :
672 : // Run without breakpoints.
673 5 : ClearBreakPoint(bp);
674 : CompileRun("new Object()");
675 5 : CHECK_EQ(1, break_point_hit_count);
676 :
677 : // === Test Number constructor ===
678 5 : break_point_hit_count = 0;
679 5 : builtin = CompileRun("Number").As<v8::Function>();
680 : CompileRun("new Number()");
681 5 : CHECK_EQ(0, break_point_hit_count);
682 :
683 : // Run with breakpoint.
684 5 : bp = SetBreakPoint(builtin, 0);
685 : CompileRun("new Number()");
686 5 : CHECK_EQ(1, break_point_hit_count);
687 :
688 : // Run without breakpoints.
689 5 : ClearBreakPoint(bp);
690 : CompileRun("new Number()");
691 5 : CHECK_EQ(1, break_point_hit_count);
692 :
693 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
694 5 : CheckDebuggerUnloaded();
695 5 : }
696 :
697 25880 : TEST(BreakPointInlinedBuiltin) {
698 5 : i::FLAG_allow_natives_syntax = true;
699 5 : LocalContext env;
700 10 : v8::HandleScope scope(env->GetIsolate());
701 :
702 5 : DebugEventCounter delegate;
703 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
704 :
705 : v8::Local<v8::Function> builtin;
706 : i::Handle<i::BreakPoint> bp;
707 :
708 : // === Test inlined builtin ===
709 5 : break_point_hit_count = 0;
710 5 : builtin = CompileRun("Math.sin").As<v8::Function>();
711 : CompileRun("function test(x) { return 1 + Math.sin(x) }");
712 : CompileRun(
713 : "test(0.5); test(0.6);"
714 : "%OptimizeFunctionOnNextCall(test); test(0.7);");
715 5 : CHECK_EQ(0, break_point_hit_count);
716 :
717 : // Run with breakpoint.
718 5 : bp = SetBreakPoint(builtin, 0);
719 : CompileRun("Math.sin(0.1);");
720 5 : CHECK_EQ(1, break_point_hit_count);
721 : CompileRun("test(0.2);");
722 5 : CHECK_EQ(2, break_point_hit_count);
723 :
724 : // Re-optimize.
725 : CompileRun("%OptimizeFunctionOnNextCall(test);");
726 5 : ExpectBoolean("test(0.3) < 2", true);
727 5 : CHECK_EQ(3, break_point_hit_count);
728 :
729 : // Run without breakpoints.
730 5 : ClearBreakPoint(bp);
731 : CompileRun("test(0.3);");
732 5 : CHECK_EQ(3, break_point_hit_count);
733 :
734 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
735 5 : CheckDebuggerUnloaded();
736 5 : }
737 :
738 25880 : TEST(BreakPointInlineBoundBuiltin) {
739 5 : i::FLAG_allow_natives_syntax = true;
740 5 : LocalContext env;
741 10 : v8::HandleScope scope(env->GetIsolate());
742 :
743 5 : DebugEventCounter delegate;
744 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
745 :
746 : v8::Local<v8::Function> builtin;
747 : i::Handle<i::BreakPoint> bp;
748 :
749 : // === Test inlined bound builtin ===
750 5 : break_point_hit_count = 0;
751 :
752 : builtin = CompileRun(
753 : "var boundrepeat = String.prototype.repeat.bind('a');"
754 : "String.prototype.repeat")
755 5 : .As<v8::Function>();
756 : CompileRun("function test(x) { return 'a' + boundrepeat(x) }");
757 : CompileRun(
758 : "test(4); test(5);"
759 : "%OptimizeFunctionOnNextCall(test); test(6);");
760 5 : CHECK_EQ(0, break_point_hit_count);
761 :
762 : // Run with breakpoint.
763 5 : bp = SetBreakPoint(builtin, 0);
764 : CompileRun("'a'.repeat(2);");
765 5 : CHECK_EQ(1, break_point_hit_count);
766 : CompileRun("test(7);");
767 5 : CHECK_EQ(2, break_point_hit_count);
768 :
769 : // Re-optimize.
770 : CompileRun("%OptimizeFunctionOnNextCall(test);");
771 : CompileRun("test(8);");
772 5 : CHECK_EQ(3, break_point_hit_count);
773 :
774 : // Run without breakpoints.
775 5 : ClearBreakPoint(bp);
776 : CompileRun("test(9);");
777 5 : CHECK_EQ(3, break_point_hit_count);
778 :
779 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
780 5 : CheckDebuggerUnloaded();
781 5 : }
782 :
783 25880 : TEST(BreakPointInlinedConstructorBuiltin) {
784 5 : i::FLAG_allow_natives_syntax = true;
785 5 : i::FLAG_experimental_inline_promise_constructor = true;
786 5 : LocalContext env;
787 10 : v8::HandleScope scope(env->GetIsolate());
788 :
789 5 : DebugEventCounter delegate;
790 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
791 :
792 : v8::Local<v8::Function> builtin;
793 : i::Handle<i::BreakPoint> bp;
794 :
795 : // === Test inlined constructor builtin (regular construct builtin) ===
796 5 : break_point_hit_count = 0;
797 5 : builtin = CompileRun("Promise").As<v8::Function>();
798 : CompileRun("function test(x) { return new Promise(()=>x); }");
799 : CompileRun(
800 : "test(4); test(5);"
801 : "%OptimizeFunctionOnNextCall(test); test(6);");
802 5 : CHECK_EQ(0, break_point_hit_count);
803 :
804 : // Run with breakpoint.
805 5 : bp = SetBreakPoint(builtin, 0);
806 : CompileRun("new Promise(()=>{});");
807 5 : CHECK_EQ(1, break_point_hit_count);
808 : CompileRun("test(7);");
809 5 : CHECK_EQ(2, break_point_hit_count);
810 :
811 : // Re-optimize.
812 : CompileRun("%OptimizeFunctionOnNextCall(test);");
813 : CompileRun("test(8);");
814 5 : CHECK_EQ(3, break_point_hit_count);
815 :
816 : // Run without breakpoints.
817 5 : ClearBreakPoint(bp);
818 : CompileRun("test(9);");
819 5 : CHECK_EQ(3, break_point_hit_count);
820 :
821 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
822 5 : CheckDebuggerUnloaded();
823 5 : }
824 :
825 25880 : TEST(BreakPointBuiltinConcurrentOpt) {
826 5 : i::FLAG_allow_natives_syntax = true;
827 5 : i::FLAG_block_concurrent_recompilation = true;
828 5 : LocalContext env;
829 10 : v8::HandleScope scope(env->GetIsolate());
830 :
831 5 : DebugEventCounter delegate;
832 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
833 :
834 : v8::Local<v8::Function> builtin;
835 : i::Handle<i::BreakPoint> bp;
836 :
837 : // === Test concurrent optimization ===
838 5 : break_point_hit_count = 0;
839 5 : builtin = CompileRun("Math.sin").As<v8::Function>();
840 : CompileRun("function test(x) { return 1 + Math.sin(x) }");
841 : // Trigger concurrent compile job. It is suspended until unblock.
842 : CompileRun(
843 : "test(0.5); test(0.6);"
844 : "%OptimizeFunctionOnNextCall(test, 'concurrent'); test(0.7);");
845 5 : CHECK_EQ(0, break_point_hit_count);
846 :
847 : // Run with breakpoint.
848 5 : bp = SetBreakPoint(builtin, 0);
849 : // Have the concurrent compile job finish now.
850 : CompileRun(
851 : "%UnblockConcurrentRecompilation();"
852 : "%GetOptimizationStatus(test, 'sync');");
853 : CompileRun("test(0.2);");
854 5 : CHECK_EQ(1, break_point_hit_count);
855 :
856 : // Run without breakpoints.
857 5 : ClearBreakPoint(bp);
858 : CompileRun("test(0.3);");
859 5 : CHECK_EQ(1, break_point_hit_count);
860 :
861 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
862 5 : CheckDebuggerUnloaded();
863 5 : }
864 :
865 25880 : TEST(BreakPointBuiltinTFOperator) {
866 5 : i::FLAG_allow_natives_syntax = true;
867 5 : LocalContext env;
868 10 : v8::HandleScope scope(env->GetIsolate());
869 :
870 5 : DebugEventCounter delegate;
871 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
872 :
873 : v8::Local<v8::Function> builtin;
874 : i::Handle<i::BreakPoint> bp;
875 :
876 : // === Test builtin represented as operator ===
877 5 : break_point_hit_count = 0;
878 5 : builtin = CompileRun("String.prototype.indexOf").As<v8::Function>();
879 : CompileRun("function test(x) { return 1 + 'foo'.indexOf(x) }");
880 : CompileRun(
881 : "test('a'); test('b');"
882 : "%OptimizeFunctionOnNextCall(test); test('c');");
883 5 : CHECK_EQ(0, break_point_hit_count);
884 :
885 : // Run with breakpoint.
886 5 : bp = SetBreakPoint(builtin, 0);
887 : CompileRun("'bar'.indexOf('x');");
888 5 : CHECK_EQ(1, break_point_hit_count);
889 : CompileRun("test('d');");
890 5 : CHECK_EQ(2, break_point_hit_count);
891 :
892 : // Re-optimize.
893 : CompileRun("%OptimizeFunctionOnNextCall(test);");
894 : CompileRun("test('e');");
895 5 : CHECK_EQ(3, break_point_hit_count);
896 :
897 : // Run without breakpoints.
898 5 : ClearBreakPoint(bp);
899 : CompileRun("test('f');");
900 5 : CHECK_EQ(3, break_point_hit_count);
901 :
902 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
903 5 : CheckDebuggerUnloaded();
904 5 : }
905 :
906 25880 : TEST(BreakPointBuiltinNewContext) {
907 5 : LocalContext env;
908 10 : v8::HandleScope scope(env->GetIsolate());
909 :
910 5 : DebugEventCounter delegate;
911 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
912 :
913 : v8::Local<v8::Function> builtin;
914 : i::Handle<i::BreakPoint> bp;
915 :
916 : // === Test builtin from a new context ===
917 : // This does not work with no-snapshot build.
918 : #ifdef V8_USE_SNAPSHOT
919 5 : break_point_hit_count = 0;
920 5 : builtin = CompileRun("String.prototype.repeat").As<v8::Function>();
921 : CompileRun("'a'.repeat(10)");
922 5 : CHECK_EQ(0, break_point_hit_count);
923 : // Set breakpoint.
924 5 : bp = SetBreakPoint(builtin, 0);
925 :
926 : {
927 : // Create and use new context after breakpoint has been set.
928 5 : v8::HandleScope handle_scope(env->GetIsolate());
929 5 : v8::Local<v8::Context> new_context = v8::Context::New(env->GetIsolate());
930 : v8::Context::Scope context_scope(new_context);
931 :
932 : // Run with breakpoint.
933 : CompileRun("'b'.repeat(10)");
934 5 : CHECK_EQ(1, break_point_hit_count);
935 :
936 : CompileRun("'b'.repeat(10)");
937 5 : CHECK_EQ(2, break_point_hit_count);
938 :
939 : // Run without breakpoints.
940 5 : ClearBreakPoint(bp);
941 : CompileRun("'b'.repeat(10)");
942 10 : CHECK_EQ(2, break_point_hit_count);
943 : }
944 : #endif
945 :
946 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
947 5 : CheckDebuggerUnloaded();
948 5 : }
949 :
950 810 : void NoOpFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
951 405 : args.GetReturnValue().Set(v8_num(2));
952 405 : }
953 :
954 25880 : TEST(BreakPointApiFunction) {
955 5 : LocalContext env;
956 10 : v8::HandleScope scope(env->GetIsolate());
957 :
958 5 : DebugEventCounter delegate;
959 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
960 :
961 : i::Handle<i::BreakPoint> bp;
962 :
963 : v8::Local<v8::FunctionTemplate> function_template =
964 5 : v8::FunctionTemplate::New(env->GetIsolate(), NoOpFunctionCallback);
965 :
966 : v8::Local<v8::Function> function =
967 10 : function_template->GetFunction(env.local()).ToLocalChecked();
968 :
969 25 : env->Global()->Set(env.local(), v8_str("f"), function).ToChecked();
970 :
971 : // === Test simple builtin ===
972 5 : break_point_hit_count = 0;
973 :
974 : // Run with breakpoint.
975 5 : bp = SetBreakPoint(function, 0);
976 5 : ExpectInt32("f()", 2);
977 5 : CHECK_EQ(1, break_point_hit_count);
978 :
979 5 : ExpectInt32("f()", 2);
980 5 : CHECK_EQ(2, break_point_hit_count);
981 :
982 : // Run without breakpoints.
983 5 : ClearBreakPoint(bp);
984 5 : ExpectInt32("f()", 2);
985 5 : CHECK_EQ(2, break_point_hit_count);
986 :
987 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
988 5 : CheckDebuggerUnloaded();
989 5 : }
990 :
991 30 : void GetWrapperCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
992 : args.GetReturnValue().Set(
993 : args[0]
994 : .As<v8::Object>()
995 10 : ->Get(args.GetIsolate()->GetCurrentContext(), args[1])
996 10 : .ToLocalChecked());
997 10 : }
998 :
999 25880 : TEST(BreakPointApiGetter) {
1000 5 : LocalContext env;
1001 10 : v8::HandleScope scope(env->GetIsolate());
1002 :
1003 5 : DebugEventCounter delegate;
1004 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1005 :
1006 : i::Handle<i::BreakPoint> bp;
1007 :
1008 : v8::Local<v8::FunctionTemplate> function_template =
1009 5 : v8::FunctionTemplate::New(env->GetIsolate(), NoOpFunctionCallback);
1010 : v8::Local<v8::FunctionTemplate> get_template =
1011 5 : v8::FunctionTemplate::New(env->GetIsolate(), GetWrapperCallback);
1012 :
1013 : v8::Local<v8::Function> function =
1014 10 : function_template->GetFunction(env.local()).ToLocalChecked();
1015 : v8::Local<v8::Function> get =
1016 10 : get_template->GetFunction(env.local()).ToLocalChecked();
1017 :
1018 25 : env->Global()->Set(env.local(), v8_str("f"), function).ToChecked();
1019 25 : env->Global()->Set(env.local(), v8_str("get_wrapper"), get).ToChecked();
1020 : CompileRun(
1021 : "var o = {};"
1022 : "Object.defineProperty(o, 'f', { get: f, enumerable: true });");
1023 :
1024 : // === Test API builtin as getter ===
1025 5 : break_point_hit_count = 0;
1026 :
1027 : // Run with breakpoint.
1028 5 : bp = SetBreakPoint(function, 0);
1029 : CompileRun("get_wrapper(o, 'f')");
1030 5 : CHECK_EQ(1, break_point_hit_count);
1031 :
1032 : CompileRun("o.f");
1033 5 : CHECK_EQ(2, break_point_hit_count);
1034 :
1035 : // Run without breakpoints.
1036 5 : ClearBreakPoint(bp);
1037 : CompileRun("get_wrapper(o, 'f', 2)");
1038 5 : CHECK_EQ(2, break_point_hit_count);
1039 :
1040 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1041 5 : CheckDebuggerUnloaded();
1042 5 : }
1043 :
1044 40 : void SetWrapperCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1045 60 : CHECK(args[0]
1046 : .As<v8::Object>()
1047 : ->Set(args.GetIsolate()->GetCurrentContext(), args[1], args[2])
1048 : .FromJust());
1049 20 : }
1050 :
1051 25880 : TEST(BreakPointApiSetter) {
1052 5 : LocalContext env;
1053 10 : v8::HandleScope scope(env->GetIsolate());
1054 :
1055 5 : DebugEventCounter delegate;
1056 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1057 :
1058 : i::Handle<i::BreakPoint> bp;
1059 :
1060 : v8::Local<v8::FunctionTemplate> function_template =
1061 5 : v8::FunctionTemplate::New(env->GetIsolate(), NoOpFunctionCallback);
1062 : v8::Local<v8::FunctionTemplate> set_template =
1063 5 : v8::FunctionTemplate::New(env->GetIsolate(), SetWrapperCallback);
1064 :
1065 : v8::Local<v8::Function> function =
1066 10 : function_template->GetFunction(env.local()).ToLocalChecked();
1067 : v8::Local<v8::Function> set =
1068 10 : set_template->GetFunction(env.local()).ToLocalChecked();
1069 :
1070 25 : env->Global()->Set(env.local(), v8_str("f"), function).ToChecked();
1071 25 : env->Global()->Set(env.local(), v8_str("set_wrapper"), set).ToChecked();
1072 :
1073 : CompileRun(
1074 : "var o = {};"
1075 : "Object.defineProperty(o, 'f', { set: f, enumerable: true });");
1076 :
1077 : // === Test API builtin as setter ===
1078 5 : break_point_hit_count = 0;
1079 :
1080 : // Run with breakpoint.
1081 5 : bp = SetBreakPoint(function, 0);
1082 :
1083 : CompileRun("o.f = 3");
1084 5 : CHECK_EQ(1, break_point_hit_count);
1085 :
1086 : CompileRun("set_wrapper(o, 'f', 2)");
1087 5 : CHECK_EQ(2, break_point_hit_count);
1088 :
1089 : // Run without breakpoints.
1090 5 : ClearBreakPoint(bp);
1091 : CompileRun("o.f = 3");
1092 5 : CHECK_EQ(2, break_point_hit_count);
1093 :
1094 : // === Test API builtin as setter, with condition ===
1095 5 : break_point_hit_count = 0;
1096 :
1097 : // Run with breakpoint.
1098 5 : bp = SetBreakPoint(function, 0, "arguments[0] == 3");
1099 : CompileRun("set_wrapper(o, 'f', 2)");
1100 5 : CHECK_EQ(0, break_point_hit_count);
1101 :
1102 : CompileRun("set_wrapper(o, 'f', 3)");
1103 5 : CHECK_EQ(1, break_point_hit_count);
1104 :
1105 : CompileRun("o.f = 3");
1106 5 : CHECK_EQ(2, break_point_hit_count);
1107 :
1108 : // Run without breakpoints.
1109 5 : ClearBreakPoint(bp);
1110 : CompileRun("set_wrapper(o, 'f', 2)");
1111 5 : CHECK_EQ(2, break_point_hit_count);
1112 :
1113 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1114 5 : CheckDebuggerUnloaded();
1115 5 : }
1116 :
1117 25880 : TEST(BreakPointApiAccessor) {
1118 5 : LocalContext env;
1119 10 : v8::HandleScope scope(env->GetIsolate());
1120 :
1121 5 : DebugEventCounter delegate;
1122 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1123 :
1124 : i::Handle<i::BreakPoint> bp;
1125 :
1126 : // Create 'foo' class, with a hidden property.
1127 : v8::Local<v8::ObjectTemplate> obj_template =
1128 5 : v8::ObjectTemplate::New(env->GetIsolate());
1129 : v8::Local<v8::FunctionTemplate> accessor_template =
1130 5 : v8::FunctionTemplate::New(env->GetIsolate(), NoOpFunctionCallback);
1131 : obj_template->SetAccessorProperty(v8_str("f"), accessor_template,
1132 10 : accessor_template);
1133 : v8::Local<v8::Object> obj =
1134 5 : obj_template->NewInstance(env.local()).ToLocalChecked();
1135 25 : env->Global()->Set(env.local(), v8_str("o"), obj).ToChecked();
1136 :
1137 : v8::Local<v8::Function> function =
1138 : CompileRun("Object.getOwnPropertyDescriptor(o, 'f').set")
1139 5 : .As<v8::Function>();
1140 :
1141 : // === Test API accessor ===
1142 5 : break_point_hit_count = 0;
1143 :
1144 : CompileRun("function get_loop() { for (var i = 0; i < 10; i++) o.f }");
1145 : CompileRun("function set_loop() { for (var i = 0; i < 10; i++) o.f = 2 }");
1146 :
1147 : CompileRun("get_loop(); set_loop();"); // Initialize ICs.
1148 :
1149 : // Run with breakpoint.
1150 5 : bp = SetBreakPoint(function, 0);
1151 :
1152 : CompileRun("o.f = 3");
1153 5 : CHECK_EQ(1, break_point_hit_count);
1154 :
1155 : CompileRun("o.f");
1156 5 : CHECK_EQ(2, break_point_hit_count);
1157 :
1158 : CompileRun("for (var i = 0; i < 10; i++) o.f");
1159 5 : CHECK_EQ(12, break_point_hit_count);
1160 :
1161 : CompileRun("get_loop();");
1162 5 : CHECK_EQ(22, break_point_hit_count);
1163 :
1164 : CompileRun("for (var i = 0; i < 10; i++) o.f = 2");
1165 5 : CHECK_EQ(32, break_point_hit_count);
1166 :
1167 : CompileRun("set_loop();");
1168 5 : CHECK_EQ(42, break_point_hit_count);
1169 :
1170 : // Run without breakpoints.
1171 5 : ClearBreakPoint(bp);
1172 : CompileRun("o.f = 3");
1173 : CompileRun("o.f");
1174 5 : CHECK_EQ(42, break_point_hit_count);
1175 :
1176 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1177 5 : CheckDebuggerUnloaded();
1178 5 : }
1179 :
1180 25880 : TEST(BreakPointInlineApiFunction) {
1181 5 : i::FLAG_allow_natives_syntax = true;
1182 5 : LocalContext env;
1183 10 : v8::HandleScope scope(env->GetIsolate());
1184 :
1185 5 : DebugEventCounter delegate;
1186 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1187 :
1188 : i::Handle<i::BreakPoint> bp;
1189 :
1190 : v8::Local<v8::FunctionTemplate> function_template =
1191 5 : v8::FunctionTemplate::New(env->GetIsolate(), NoOpFunctionCallback);
1192 :
1193 : v8::Local<v8::Function> function =
1194 10 : function_template->GetFunction(env.local()).ToLocalChecked();
1195 :
1196 25 : env->Global()->Set(env.local(), v8_str("f"), function).ToChecked();
1197 : CompileRun("function g() { return 1 + f(); }");
1198 :
1199 : // === Test simple builtin ===
1200 5 : break_point_hit_count = 0;
1201 :
1202 : // Run with breakpoint.
1203 5 : bp = SetBreakPoint(function, 0);
1204 5 : ExpectInt32("g()", 3);
1205 5 : CHECK_EQ(1, break_point_hit_count);
1206 :
1207 5 : ExpectInt32("g()", 3);
1208 5 : CHECK_EQ(2, break_point_hit_count);
1209 :
1210 : CompileRun("%OptimizeFunctionOnNextCall(g)");
1211 5 : ExpectInt32("g()", 3);
1212 5 : CHECK_EQ(3, break_point_hit_count);
1213 :
1214 : // Run without breakpoints.
1215 5 : ClearBreakPoint(bp);
1216 5 : ExpectInt32("g()", 3);
1217 5 : CHECK_EQ(3, break_point_hit_count);
1218 :
1219 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1220 5 : CheckDebuggerUnloaded();
1221 5 : }
1222 :
1223 : // Test that a break point can be set at a return store location.
1224 25880 : TEST(BreakPointConditionBuiltin) {
1225 5 : i::FLAG_allow_natives_syntax = true;
1226 5 : i::FLAG_block_concurrent_recompilation = true;
1227 5 : LocalContext env;
1228 10 : v8::HandleScope scope(env->GetIsolate());
1229 :
1230 5 : DebugEventCounter delegate;
1231 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1232 : v8::Local<v8::Function> builtin;
1233 : i::Handle<i::BreakPoint> bp;
1234 :
1235 : // === Test global variable ===
1236 5 : break_point_hit_count = 0;
1237 5 : builtin = CompileRun("String.prototype.repeat").As<v8::Function>();
1238 : CompileRun("var condition = false");
1239 : CompileRun("'a'.repeat(10)");
1240 5 : CHECK_EQ(0, break_point_hit_count);
1241 :
1242 : // Run with breakpoint.
1243 5 : bp = SetBreakPoint(builtin, 0, "condition == true");
1244 : CompileRun("'b'.repeat(10)");
1245 5 : CHECK_EQ(0, break_point_hit_count);
1246 :
1247 : CompileRun("condition = true");
1248 : CompileRun("'b'.repeat(10)");
1249 5 : CHECK_EQ(1, break_point_hit_count);
1250 :
1251 : // Run without breakpoints.
1252 5 : ClearBreakPoint(bp);
1253 : CompileRun("'b'.repeat(10)");
1254 5 : CHECK_EQ(1, break_point_hit_count);
1255 :
1256 : // === Test arguments ===
1257 5 : break_point_hit_count = 0;
1258 5 : builtin = CompileRun("String.prototype.repeat").As<v8::Function>();
1259 : CompileRun("function f(x) { return 'a'.repeat(x * 2); }");
1260 5 : CHECK_EQ(0, break_point_hit_count);
1261 :
1262 : // Run with breakpoint.
1263 5 : bp = SetBreakPoint(builtin, 0, "arguments[0] == 20");
1264 5 : ExpectString("f(5)", "aaaaaaaaaa");
1265 5 : CHECK_EQ(0, break_point_hit_count);
1266 :
1267 5 : ExpectString("f(10)", "aaaaaaaaaaaaaaaaaaaa");
1268 5 : CHECK_EQ(1, break_point_hit_count);
1269 :
1270 : // Run without breakpoints.
1271 5 : ClearBreakPoint(bp);
1272 5 : ExpectString("f(10)", "aaaaaaaaaaaaaaaaaaaa");
1273 5 : CHECK_EQ(1, break_point_hit_count);
1274 :
1275 : // === Test adapted arguments ===
1276 5 : break_point_hit_count = 0;
1277 5 : builtin = CompileRun("String.prototype.repeat").As<v8::Function>();
1278 : CompileRun("function f(x) { return 'a'.repeat(x * 2, x); }");
1279 5 : CHECK_EQ(0, break_point_hit_count);
1280 :
1281 : // Run with breakpoint.
1282 : bp = SetBreakPoint(builtin, 0,
1283 5 : "arguments[1] == 10 && arguments[2] == undefined");
1284 5 : ExpectString("f(5)", "aaaaaaaaaa");
1285 5 : CHECK_EQ(0, break_point_hit_count);
1286 :
1287 5 : ExpectString("f(10)", "aaaaaaaaaaaaaaaaaaaa");
1288 5 : CHECK_EQ(1, break_point_hit_count);
1289 :
1290 : // Run without breakpoints.
1291 5 : ClearBreakPoint(bp);
1292 5 : ExpectString("f(10)", "aaaaaaaaaaaaaaaaaaaa");
1293 5 : CHECK_EQ(1, break_point_hit_count);
1294 :
1295 : // === Test var-arg builtins ===
1296 5 : break_point_hit_count = 0;
1297 5 : builtin = CompileRun("String.fromCharCode").As<v8::Function>();
1298 : CompileRun("function f() { return String.fromCharCode(1, 2, 3); }");
1299 5 : CHECK_EQ(0, break_point_hit_count);
1300 :
1301 : // Run with breakpoint.
1302 5 : bp = SetBreakPoint(builtin, 0, "arguments.length == 3 && arguments[1] == 2");
1303 : CompileRun("f(1, 2, 3)");
1304 5 : CHECK_EQ(1, break_point_hit_count);
1305 :
1306 : // Run without breakpoints.
1307 5 : ClearBreakPoint(bp);
1308 : CompileRun("f(1, 2, 3)");
1309 5 : CHECK_EQ(1, break_point_hit_count);
1310 :
1311 : // === Test rest arguments ===
1312 5 : break_point_hit_count = 0;
1313 5 : builtin = CompileRun("String.fromCharCode").As<v8::Function>();
1314 : CompileRun("function f(...args) { return String.fromCharCode(...args); }");
1315 5 : CHECK_EQ(0, break_point_hit_count);
1316 :
1317 : // Run with breakpoint.
1318 5 : bp = SetBreakPoint(builtin, 0, "arguments.length == 3 && arguments[1] == 2");
1319 : CompileRun("f(1, 2, 3)");
1320 5 : CHECK_EQ(1, break_point_hit_count);
1321 :
1322 5 : ClearBreakPoint(bp);
1323 : CompileRun("f(1, 3, 3)");
1324 5 : CHECK_EQ(1, break_point_hit_count);
1325 :
1326 : // Run without breakpoints.
1327 5 : ClearBreakPoint(bp);
1328 : CompileRun("f(1, 2, 3)");
1329 5 : CHECK_EQ(1, break_point_hit_count);
1330 :
1331 : // === Test receiver ===
1332 5 : break_point_hit_count = 0;
1333 5 : builtin = CompileRun("String.prototype.repeat").As<v8::Function>();
1334 : CompileRun("function f(x) { return x.repeat(10); }");
1335 5 : CHECK_EQ(0, break_point_hit_count);
1336 :
1337 : // Run with breakpoint.
1338 5 : bp = SetBreakPoint(builtin, 0, "this == 'a'");
1339 5 : ExpectString("f('b')", "bbbbbbbbbb");
1340 5 : CHECK_EQ(0, break_point_hit_count);
1341 :
1342 5 : ExpectString("f('a')", "aaaaaaaaaa");
1343 5 : CHECK_EQ(1, break_point_hit_count);
1344 :
1345 : // Run without breakpoints.
1346 5 : ClearBreakPoint(bp);
1347 5 : ExpectString("f('a')", "aaaaaaaaaa");
1348 5 : CHECK_EQ(1, break_point_hit_count);
1349 :
1350 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1351 5 : CheckDebuggerUnloaded();
1352 5 : }
1353 :
1354 25880 : TEST(BreakPointInlining) {
1355 5 : i::FLAG_allow_natives_syntax = true;
1356 5 : break_point_hit_count = 0;
1357 5 : LocalContext env;
1358 10 : v8::HandleScope scope(env->GetIsolate());
1359 :
1360 5 : DebugEventCounter delegate;
1361 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1362 :
1363 5 : break_point_hit_count = 0;
1364 : v8::Local<v8::Function> inlinee =
1365 5 : CompileRun("function f(x) { return x*2; } f").As<v8::Function>();
1366 : CompileRun("function test(x) { return 1 + f(x) }");
1367 : CompileRun(
1368 : "test(0.5); test(0.6);"
1369 : "%OptimizeFunctionOnNextCall(test); test(0.7);");
1370 5 : CHECK_EQ(0, break_point_hit_count);
1371 :
1372 : // Run with breakpoint.
1373 5 : i::Handle<i::BreakPoint> bp = SetBreakPoint(inlinee, 0);
1374 : CompileRun("f(0.1);");
1375 5 : CHECK_EQ(1, break_point_hit_count);
1376 : CompileRun("test(0.2);");
1377 5 : CHECK_EQ(2, break_point_hit_count);
1378 :
1379 : // Re-optimize.
1380 : CompileRun("%OptimizeFunctionOnNextCall(test);");
1381 : CompileRun("test(0.3);");
1382 5 : CHECK_EQ(3, break_point_hit_count);
1383 :
1384 : // Run without breakpoints.
1385 5 : ClearBreakPoint(bp);
1386 : CompileRun("test(0.3);");
1387 5 : CHECK_EQ(3, break_point_hit_count);
1388 :
1389 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1390 5 : CheckDebuggerUnloaded();
1391 5 : }
1392 :
1393 25 : static void CallWithBreakPoints(v8::Local<v8::Context> context,
1394 : v8::Local<v8::Object> recv,
1395 : v8::Local<v8::Function> f,
1396 : int break_point_count, int call_count) {
1397 25 : break_point_hit_count = 0;
1398 450 : for (int i = 0; i < call_count; i++) {
1399 800 : f->Call(context, recv, 0, nullptr).ToLocalChecked();
1400 400 : CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
1401 : }
1402 25 : }
1403 :
1404 :
1405 : // Test GC during break point processing.
1406 25880 : TEST(GCDuringBreakPointProcessing) {
1407 5 : break_point_hit_count = 0;
1408 5 : LocalContext env;
1409 10 : v8::HandleScope scope(env->GetIsolate());
1410 5 : v8::Local<v8::Context> context = env.local();
1411 :
1412 5 : DebugEventBreakPointCollectGarbage delegate;
1413 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1414 : v8::Local<v8::Function> foo;
1415 :
1416 : // Test IC store break point with garbage collection.
1417 5 : foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1418 5 : SetBreakPoint(foo, 0);
1419 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 10);
1420 :
1421 : // Test IC load break point with garbage collection.
1422 5 : foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1423 5 : SetBreakPoint(foo, 0);
1424 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 10);
1425 :
1426 : // Test IC call break point with garbage collection.
1427 5 : foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
1428 5 : SetBreakPoint(foo, 0);
1429 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 10);
1430 :
1431 : // Test return break point with garbage collection.
1432 5 : foo = CompileFunction(&env, "function foo(){}", "foo");
1433 5 : SetBreakPoint(foo, 0);
1434 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 25);
1435 :
1436 : // Test debug break slot break point with garbage collection.
1437 5 : foo = CompileFunction(&env, "function foo(){var a;}", "foo");
1438 5 : SetBreakPoint(foo, 0);
1439 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 25);
1440 :
1441 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1442 5 : CheckDebuggerUnloaded();
1443 5 : }
1444 :
1445 :
1446 : // Call the function three times with different garbage collections in between
1447 : // and make sure that the break point survives.
1448 25 : static void CallAndGC(v8::Local<v8::Context> context,
1449 : v8::Local<v8::Object> recv, v8::Local<v8::Function> f) {
1450 25 : break_point_hit_count = 0;
1451 :
1452 125 : for (int i = 0; i < 3; i++) {
1453 : // Call function.
1454 150 : f->Call(context, recv, 0, nullptr).ToLocalChecked();
1455 75 : CHECK_EQ(1 + i * 3, break_point_hit_count);
1456 :
1457 : // Scavenge and call function.
1458 75 : CcTest::CollectGarbage(v8::internal::NEW_SPACE);
1459 150 : f->Call(context, recv, 0, nullptr).ToLocalChecked();
1460 75 : CHECK_EQ(2 + i * 3, break_point_hit_count);
1461 :
1462 : // Mark sweep (and perhaps compact) and call function.
1463 75 : CcTest::CollectAllGarbage();
1464 150 : f->Call(context, recv, 0, nullptr).ToLocalChecked();
1465 75 : CHECK_EQ(3 + i * 3, break_point_hit_count);
1466 : }
1467 25 : }
1468 :
1469 :
1470 : // Test that a break point can be set at a return store location.
1471 25880 : TEST(BreakPointSurviveGC) {
1472 5 : break_point_hit_count = 0;
1473 5 : LocalContext env;
1474 10 : v8::HandleScope scope(env->GetIsolate());
1475 5 : v8::Local<v8::Context> context = env.local();
1476 :
1477 5 : DebugEventCounter delegate;
1478 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1479 : v8::Local<v8::Function> foo;
1480 :
1481 : // Test IC store break point with garbage collection.
1482 : {
1483 5 : CompileFunction(&env, "function foo(){}", "foo");
1484 5 : foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1485 5 : SetBreakPoint(foo, 0);
1486 : }
1487 5 : CallAndGC(context, env->Global(), foo);
1488 :
1489 : // Test IC load break point with garbage collection.
1490 : {
1491 5 : CompileFunction(&env, "function foo(){}", "foo");
1492 5 : foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1493 5 : SetBreakPoint(foo, 0);
1494 : }
1495 5 : CallAndGC(context, env->Global(), foo);
1496 :
1497 : // Test IC call break point with garbage collection.
1498 : {
1499 5 : CompileFunction(&env, "function foo(){}", "foo");
1500 : foo = CompileFunction(&env,
1501 : "function bar(){};function foo(){bar();}",
1502 5 : "foo");
1503 5 : SetBreakPoint(foo, 0);
1504 : }
1505 5 : CallAndGC(context, env->Global(), foo);
1506 :
1507 : // Test return break point with garbage collection.
1508 : {
1509 5 : CompileFunction(&env, "function foo(){}", "foo");
1510 5 : foo = CompileFunction(&env, "function foo(){}", "foo");
1511 5 : SetBreakPoint(foo, 0);
1512 : }
1513 5 : CallAndGC(context, env->Global(), foo);
1514 :
1515 : // Test non IC break point with garbage collection.
1516 : {
1517 5 : CompileFunction(&env, "function foo(){}", "foo");
1518 5 : foo = CompileFunction(&env, "function foo(){var bar=0;}", "foo");
1519 5 : SetBreakPoint(foo, 0);
1520 : }
1521 5 : CallAndGC(context, env->Global(), foo);
1522 :
1523 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1524 5 : CheckDebuggerUnloaded();
1525 5 : }
1526 :
1527 : // Test that the debugger statement causes a break.
1528 25880 : TEST(DebuggerStatement) {
1529 5 : break_point_hit_count = 0;
1530 5 : LocalContext env;
1531 10 : v8::HandleScope scope(env->GetIsolate());
1532 5 : DebugEventCounter delegate;
1533 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1534 5 : v8::Local<v8::Context> context = env.local();
1535 : v8::Script::Compile(context,
1536 5 : v8_str(env->GetIsolate(), "function bar(){debugger}"))
1537 5 : .ToLocalChecked()
1538 : ->Run(context)
1539 5 : .ToLocalChecked();
1540 : v8::Script::Compile(
1541 5 : context, v8_str(env->GetIsolate(), "function foo(){debugger;debugger;}"))
1542 5 : .ToLocalChecked()
1543 : ->Run(context)
1544 5 : .ToLocalChecked();
1545 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
1546 : env->Global()
1547 15 : ->Get(context, v8_str(env->GetIsolate(), "foo"))
1548 5 : .ToLocalChecked());
1549 : v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
1550 : env->Global()
1551 15 : ->Get(context, v8_str(env->GetIsolate(), "bar"))
1552 5 : .ToLocalChecked());
1553 :
1554 : // Run function with debugger statement
1555 15 : bar->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1556 5 : CHECK_EQ(1, break_point_hit_count);
1557 :
1558 : // Run function with two debugger statement
1559 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1560 5 : CHECK_EQ(3, break_point_hit_count);
1561 :
1562 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1563 5 : CheckDebuggerUnloaded();
1564 5 : }
1565 :
1566 :
1567 : // Test setting a breakpoint on the debugger statement.
1568 25880 : TEST(DebuggerStatementBreakpoint) {
1569 5 : break_point_hit_count = 0;
1570 5 : LocalContext env;
1571 10 : v8::HandleScope scope(env->GetIsolate());
1572 5 : v8::Local<v8::Context> context = env.local();
1573 5 : DebugEventCounter delegate;
1574 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1575 : v8::Script::Compile(context,
1576 5 : v8_str(env->GetIsolate(), "function foo(){debugger;}"))
1577 5 : .ToLocalChecked()
1578 : ->Run(context)
1579 5 : .ToLocalChecked();
1580 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
1581 : env->Global()
1582 15 : ->Get(context, v8_str(env->GetIsolate(), "foo"))
1583 5 : .ToLocalChecked());
1584 :
1585 : // The debugger statement triggers breakpoint hit
1586 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1587 5 : CHECK_EQ(1, break_point_hit_count);
1588 :
1589 5 : i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
1590 :
1591 : // Set breakpoint does not duplicate hits
1592 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1593 5 : CHECK_EQ(2, break_point_hit_count);
1594 :
1595 5 : ClearBreakPoint(bp);
1596 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1597 5 : CheckDebuggerUnloaded();
1598 5 : }
1599 :
1600 :
1601 : // Test that the conditional breakpoints work event if code generation from
1602 : // strings is prohibited in the debugee context.
1603 25880 : TEST(ConditionalBreakpointWithCodeGenerationDisallowed) {
1604 5 : LocalContext env;
1605 10 : v8::HandleScope scope(env->GetIsolate());
1606 :
1607 5 : DebugEventCounter delegate;
1608 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1609 :
1610 5 : v8::Local<v8::Context> context = env.local();
1611 : v8::Local<v8::Function> foo = CompileFunction(&env,
1612 : "function foo(x) {\n"
1613 : " var s = 'String value2';\n"
1614 : " return s + x;\n"
1615 : "}",
1616 5 : "foo");
1617 :
1618 : // Set conditional breakpoint with condition 'true'.
1619 5 : SetBreakPoint(foo, 4, "true");
1620 :
1621 5 : break_point_hit_count = 0;
1622 5 : env->AllowCodeGenerationFromStrings(false);
1623 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1624 5 : CHECK_EQ(1, break_point_hit_count);
1625 :
1626 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1627 5 : CheckDebuggerUnloaded();
1628 5 : }
1629 :
1630 :
1631 : // Simple test of the stepping mechanism using only store ICs.
1632 25880 : TEST(DebugStepLinear) {
1633 5 : LocalContext env;
1634 10 : v8::HandleScope scope(env->GetIsolate());
1635 :
1636 : // Create a function for testing stepping.
1637 : v8::Local<v8::Function> foo = CompileFunction(&env,
1638 : "function foo(){a=1;b=1;c=1;}",
1639 5 : "foo");
1640 :
1641 : // Run foo to allow it to get optimized.
1642 : CompileRun("a=0; b=0; c=0; foo();");
1643 :
1644 : // Register a debug event listener which steps and counts.
1645 5 : DebugEventCounter run_step;
1646 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1647 :
1648 5 : SetBreakPoint(foo, 3);
1649 :
1650 : run_step.set_step_action(StepIn);
1651 5 : break_point_hit_count = 0;
1652 5 : v8::Local<v8::Context> context = env.local();
1653 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1654 :
1655 : // With stepping all break locations are hit.
1656 5 : CHECK_EQ(4, break_point_hit_count);
1657 :
1658 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1659 : CheckDebuggerUnloaded();
1660 :
1661 : // Register a debug event listener which just counts.
1662 5 : DebugEventCounter delegate;
1663 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1664 :
1665 5 : SetBreakPoint(foo, 3);
1666 5 : break_point_hit_count = 0;
1667 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1668 :
1669 : // Without stepping only active break points are hit.
1670 5 : CHECK_EQ(1, break_point_hit_count);
1671 :
1672 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1673 5 : CheckDebuggerUnloaded();
1674 5 : }
1675 :
1676 :
1677 : // Test of the stepping mechanism for keyed load in a loop.
1678 25880 : TEST(DebugStepKeyedLoadLoop) {
1679 5 : LocalContext env;
1680 10 : v8::HandleScope scope(env->GetIsolate());
1681 :
1682 : // Register a debug event listener which steps and counts.
1683 5 : DebugEventCounter run_step;
1684 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1685 :
1686 : // Create a function for testing stepping of keyed load. The statement 'y=1'
1687 : // is there to have more than one breakable statement in the loop, TODO(315).
1688 : v8::Local<v8::Function> foo = CompileFunction(
1689 : &env,
1690 : "function foo(a) {\n"
1691 : " var x;\n"
1692 : " var len = a.length;\n"
1693 : " for (var i = 0; i < len; i++) {\n"
1694 : " y = 1;\n"
1695 : " x = a[i];\n"
1696 : " }\n"
1697 : "}\n"
1698 : "y=0\n",
1699 5 : "foo");
1700 :
1701 5 : v8::Local<v8::Context> context = env.local();
1702 : // Create array [0,1,2,3,4,5,6,7,8,9]
1703 5 : v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
1704 55 : for (int i = 0; i < 10; i++) {
1705 250 : CHECK(a->Set(context, v8::Number::New(env->GetIsolate(), i),
1706 : v8::Number::New(env->GetIsolate(), i))
1707 : .FromJust());
1708 : }
1709 :
1710 : // Call function without any break points to ensure inlining is in place.
1711 : const int kArgc = 1;
1712 : v8::Local<v8::Value> args[kArgc] = {a};
1713 15 : foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
1714 :
1715 : // Set up break point and step through the function.
1716 5 : SetBreakPoint(foo, 3);
1717 : run_step.set_step_action(StepNext);
1718 5 : break_point_hit_count = 0;
1719 15 : foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
1720 :
1721 : // With stepping all break locations are hit.
1722 5 : CHECK_EQ(44, break_point_hit_count);
1723 :
1724 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1725 5 : CheckDebuggerUnloaded();
1726 5 : }
1727 :
1728 :
1729 : // Test of the stepping mechanism for keyed store in a loop.
1730 25880 : TEST(DebugStepKeyedStoreLoop) {
1731 5 : LocalContext env;
1732 10 : v8::HandleScope scope(env->GetIsolate());
1733 :
1734 : // Register a debug event listener which steps and counts.
1735 5 : DebugEventCounter run_step;
1736 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1737 :
1738 : // Create a function for testing stepping of keyed store. The statement 'y=1'
1739 : // is there to have more than one breakable statement in the loop, TODO(315).
1740 : v8::Local<v8::Function> foo = CompileFunction(
1741 : &env,
1742 : "function foo(a) {\n"
1743 : " var len = a.length;\n"
1744 : " for (var i = 0; i < len; i++) {\n"
1745 : " y = 1;\n"
1746 : " a[i] = 42;\n"
1747 : " }\n"
1748 : "}\n"
1749 : "y=0\n",
1750 5 : "foo");
1751 :
1752 5 : v8::Local<v8::Context> context = env.local();
1753 : // Create array [0,1,2,3,4,5,6,7,8,9]
1754 5 : v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
1755 55 : for (int i = 0; i < 10; i++) {
1756 250 : CHECK(a->Set(context, v8::Number::New(env->GetIsolate(), i),
1757 : v8::Number::New(env->GetIsolate(), i))
1758 : .FromJust());
1759 : }
1760 :
1761 : // Call function without any break points to ensure inlining is in place.
1762 : const int kArgc = 1;
1763 : v8::Local<v8::Value> args[kArgc] = {a};
1764 15 : foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
1765 :
1766 : // Set up break point and step through the function.
1767 5 : SetBreakPoint(foo, 3);
1768 : run_step.set_step_action(StepNext);
1769 5 : break_point_hit_count = 0;
1770 15 : foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
1771 :
1772 : // With stepping all break locations are hit.
1773 5 : CHECK_EQ(44, break_point_hit_count);
1774 :
1775 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1776 5 : CheckDebuggerUnloaded();
1777 5 : }
1778 :
1779 :
1780 : // Test of the stepping mechanism for named load in a loop.
1781 25880 : TEST(DebugStepNamedLoadLoop) {
1782 5 : LocalContext env;
1783 10 : v8::HandleScope scope(env->GetIsolate());
1784 :
1785 : // Register a debug event listener which steps and counts.
1786 5 : DebugEventCounter run_step;
1787 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1788 :
1789 5 : v8::Local<v8::Context> context = env.local();
1790 : // Create a function for testing stepping of named load.
1791 : v8::Local<v8::Function> foo = CompileFunction(
1792 : &env,
1793 : "function foo() {\n"
1794 : " var a = [];\n"
1795 : " var s = \"\";\n"
1796 : " for (var i = 0; i < 10; i++) {\n"
1797 : " var v = new V(i, i + 1);\n"
1798 : " v.y;\n"
1799 : " a.length;\n" // Special case: array length.
1800 : " s.length;\n" // Special case: string length.
1801 : " }\n"
1802 : "}\n"
1803 : "function V(x, y) {\n"
1804 : " this.x = x;\n"
1805 : " this.y = y;\n"
1806 : "}\n",
1807 5 : "foo");
1808 :
1809 : // Call function without any break points to ensure inlining is in place.
1810 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1811 :
1812 : // Set up break point and step through the function.
1813 5 : SetBreakPoint(foo, 4);
1814 : run_step.set_step_action(StepNext);
1815 5 : break_point_hit_count = 0;
1816 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1817 :
1818 : // With stepping all break locations are hit.
1819 5 : CHECK_EQ(65, break_point_hit_count);
1820 :
1821 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1822 5 : CheckDebuggerUnloaded();
1823 5 : }
1824 :
1825 :
1826 5 : static void DoDebugStepNamedStoreLoop(int expected) {
1827 5 : LocalContext env;
1828 10 : v8::HandleScope scope(env->GetIsolate());
1829 :
1830 : // Register a debug event listener which steps and counts.
1831 5 : DebugEventCounter run_step;
1832 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1833 :
1834 : // Create a function for testing stepping of named store.
1835 5 : v8::Local<v8::Context> context = env.local();
1836 : v8::Local<v8::Function> foo = CompileFunction(
1837 : &env,
1838 : "function foo() {\n"
1839 : " var a = {a:1};\n"
1840 : " for (var i = 0; i < 10; i++) {\n"
1841 : " a.a = 2\n"
1842 : " }\n"
1843 : "}\n",
1844 5 : "foo");
1845 :
1846 : // Call function without any break points to ensure inlining is in place.
1847 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1848 :
1849 : // Set up break point and step through the function.
1850 5 : SetBreakPoint(foo, 3);
1851 : run_step.set_step_action(StepNext);
1852 5 : break_point_hit_count = 0;
1853 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1854 :
1855 : // With stepping all expected break locations are hit.
1856 5 : CHECK_EQ(expected, break_point_hit_count);
1857 :
1858 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1859 5 : CheckDebuggerUnloaded();
1860 5 : }
1861 :
1862 :
1863 : // Test of the stepping mechanism for named load in a loop.
1864 25880 : TEST(DebugStepNamedStoreLoop) { DoDebugStepNamedStoreLoop(34); }
1865 :
1866 : // Test the stepping mechanism with different ICs.
1867 25880 : TEST(DebugStepLinearMixedICs) {
1868 5 : LocalContext env;
1869 10 : v8::HandleScope scope(env->GetIsolate());
1870 :
1871 : // Register a debug event listener which steps and counts.
1872 5 : DebugEventCounter run_step;
1873 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1874 :
1875 5 : v8::Local<v8::Context> context = env.local();
1876 : // Create a function for testing stepping.
1877 : v8::Local<v8::Function> foo = CompileFunction(&env,
1878 : "function bar() {};"
1879 : "function foo() {"
1880 : " var x;"
1881 : " var index='name';"
1882 : " var y = {};"
1883 5 : " a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
1884 :
1885 : // Run functions to allow them to get optimized.
1886 : CompileRun("a=0; b=0; bar(); foo();");
1887 :
1888 5 : SetBreakPoint(foo, 0);
1889 :
1890 : run_step.set_step_action(StepIn);
1891 5 : break_point_hit_count = 0;
1892 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1893 :
1894 : // With stepping all break locations are hit.
1895 5 : CHECK_EQ(10, break_point_hit_count);
1896 :
1897 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1898 : CheckDebuggerUnloaded();
1899 :
1900 : // Register a debug event listener which just counts.
1901 5 : DebugEventCounter delegate;
1902 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1903 :
1904 5 : SetBreakPoint(foo, 0);
1905 5 : break_point_hit_count = 0;
1906 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1907 :
1908 : // Without stepping only active break points are hit.
1909 5 : CHECK_EQ(1, break_point_hit_count);
1910 :
1911 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1912 5 : CheckDebuggerUnloaded();
1913 5 : }
1914 :
1915 :
1916 25880 : TEST(DebugStepDeclarations) {
1917 5 : LocalContext env;
1918 10 : v8::HandleScope scope(env->GetIsolate());
1919 :
1920 : // Register a debug event listener which steps and counts.
1921 5 : DebugEventCounter run_step;
1922 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1923 :
1924 5 : v8::Local<v8::Context> context = env.local();
1925 : // Create a function for testing stepping. Run it to allow it to get
1926 : // optimized.
1927 : const char* src = "function foo() { "
1928 : " var a;"
1929 : " var b = 1;"
1930 : " var c = foo;"
1931 : " var d = Math.floor;"
1932 : " var e = b + d(1.2);"
1933 : "}"
1934 : "foo()";
1935 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
1936 :
1937 5 : SetBreakPoint(foo, 0);
1938 :
1939 : // Stepping through the declarations.
1940 : run_step.set_step_action(StepIn);
1941 5 : break_point_hit_count = 0;
1942 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1943 5 : CHECK_EQ(5, break_point_hit_count);
1944 :
1945 : // Get rid of the debug event listener.
1946 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1947 5 : CheckDebuggerUnloaded();
1948 5 : }
1949 :
1950 :
1951 25880 : TEST(DebugStepLocals) {
1952 5 : LocalContext env;
1953 10 : v8::HandleScope scope(env->GetIsolate());
1954 :
1955 : // Register a debug event listener which steps and counts.
1956 5 : DebugEventCounter run_step;
1957 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1958 :
1959 5 : v8::Local<v8::Context> context = env.local();
1960 : // Create a function for testing stepping. Run it to allow it to get
1961 : // optimized.
1962 : const char* src = "function foo() { "
1963 : " var a,b;"
1964 : " a = 1;"
1965 : " b = a + 2;"
1966 : " b = 1 + 2 + 3;"
1967 : " a = Math.floor(b);"
1968 : "}"
1969 : "foo()";
1970 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
1971 :
1972 5 : SetBreakPoint(foo, 0);
1973 :
1974 : // Stepping through the declarations.
1975 : run_step.set_step_action(StepIn);
1976 5 : break_point_hit_count = 0;
1977 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1978 5 : CHECK_EQ(5, break_point_hit_count);
1979 :
1980 : // Get rid of the debug event listener.
1981 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1982 5 : CheckDebuggerUnloaded();
1983 5 : }
1984 :
1985 :
1986 25880 : TEST(DebugStepIf) {
1987 5 : LocalContext env;
1988 5 : v8::Isolate* isolate = env->GetIsolate();
1989 10 : v8::HandleScope scope(isolate);
1990 :
1991 : // Register a debug event listener which steps and counts.
1992 5 : DebugEventCounter run_step;
1993 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1994 :
1995 5 : v8::Local<v8::Context> context = env.local();
1996 : // Create a function for testing stepping. Run it to allow it to get
1997 : // optimized.
1998 : const int argc = 1;
1999 : const char* src = "function foo(x) { "
2000 : " a = 1;"
2001 : " if (x) {"
2002 : " b = 1;"
2003 : " } else {"
2004 : " c = 1;"
2005 : " d = 1;"
2006 : " }"
2007 : "}"
2008 : "a=0; b=0; c=0; d=0; foo()";
2009 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2010 5 : SetBreakPoint(foo, 0);
2011 :
2012 : // Stepping through the true part.
2013 : run_step.set_step_action(StepIn);
2014 5 : break_point_hit_count = 0;
2015 : v8::Local<v8::Value> argv_true[argc] = {v8::True(isolate)};
2016 15 : foo->Call(context, env->Global(), argc, argv_true).ToLocalChecked();
2017 5 : CHECK_EQ(4, break_point_hit_count);
2018 :
2019 : // Stepping through the false part.
2020 : run_step.set_step_action(StepIn);
2021 5 : break_point_hit_count = 0;
2022 : v8::Local<v8::Value> argv_false[argc] = {v8::False(isolate)};
2023 15 : foo->Call(context, env->Global(), argc, argv_false).ToLocalChecked();
2024 5 : CHECK_EQ(5, break_point_hit_count);
2025 :
2026 : // Get rid of the debug event listener.
2027 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2028 5 : CheckDebuggerUnloaded();
2029 5 : }
2030 :
2031 :
2032 25880 : TEST(DebugStepSwitch) {
2033 5 : LocalContext env;
2034 5 : v8::Isolate* isolate = env->GetIsolate();
2035 10 : v8::HandleScope scope(isolate);
2036 :
2037 : // Register a debug event listener which steps and counts.
2038 5 : DebugEventCounter run_step;
2039 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2040 :
2041 5 : v8::Local<v8::Context> context = env.local();
2042 : // Create a function for testing stepping. Run it to allow it to get
2043 : // optimized.
2044 : const int argc = 1;
2045 : const char* src = "function foo(x) { "
2046 : " a = 1;"
2047 : " switch (x) {"
2048 : " case 1:"
2049 : " b = 1;"
2050 : " case 2:"
2051 : " c = 1;"
2052 : " break;"
2053 : " case 3:"
2054 : " d = 1;"
2055 : " e = 1;"
2056 : " f = 1;"
2057 : " break;"
2058 : " }"
2059 : "}"
2060 : "a=0; b=0; c=0; d=0; e=0; f=0; foo()";
2061 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2062 5 : SetBreakPoint(foo, 0);
2063 :
2064 : // One case with fall-through.
2065 : run_step.set_step_action(StepIn);
2066 5 : break_point_hit_count = 0;
2067 5 : v8::Local<v8::Value> argv_1[argc] = {v8::Number::New(isolate, 1)};
2068 15 : foo->Call(context, env->Global(), argc, argv_1).ToLocalChecked();
2069 5 : CHECK_EQ(6, break_point_hit_count);
2070 :
2071 : // Another case.
2072 : run_step.set_step_action(StepIn);
2073 5 : break_point_hit_count = 0;
2074 5 : v8::Local<v8::Value> argv_2[argc] = {v8::Number::New(isolate, 2)};
2075 15 : foo->Call(context, env->Global(), argc, argv_2).ToLocalChecked();
2076 5 : CHECK_EQ(5, break_point_hit_count);
2077 :
2078 : // Last case.
2079 : run_step.set_step_action(StepIn);
2080 5 : break_point_hit_count = 0;
2081 5 : v8::Local<v8::Value> argv_3[argc] = {v8::Number::New(isolate, 3)};
2082 15 : foo->Call(context, env->Global(), argc, argv_3).ToLocalChecked();
2083 5 : CHECK_EQ(7, break_point_hit_count);
2084 :
2085 : // Get rid of the debug event listener.
2086 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2087 5 : CheckDebuggerUnloaded();
2088 5 : }
2089 :
2090 :
2091 25880 : TEST(DebugStepWhile) {
2092 5 : LocalContext env;
2093 5 : v8::Isolate* isolate = env->GetIsolate();
2094 10 : v8::HandleScope scope(isolate);
2095 :
2096 : // Register a debug event listener which steps and counts.
2097 5 : DebugEventCounter run_step;
2098 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2099 :
2100 5 : v8::Local<v8::Context> context = env.local();
2101 : // Create a function for testing stepping. Run it to allow it to get
2102 : // optimized.
2103 : const int argc = 1;
2104 : const char* src = "function foo(x) { "
2105 : " var a = 0;"
2106 : " while (a < x) {"
2107 : " a++;"
2108 : " }"
2109 : "}"
2110 : "foo()";
2111 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2112 5 : SetBreakPoint(foo, 8); // "var a = 0;"
2113 :
2114 : // Looping 0 times. We still should break at the while-condition once.
2115 : run_step.set_step_action(StepIn);
2116 5 : break_point_hit_count = 0;
2117 5 : v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
2118 15 : foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
2119 5 : CHECK_EQ(3, break_point_hit_count);
2120 :
2121 : // Looping 10 times.
2122 : run_step.set_step_action(StepIn);
2123 5 : break_point_hit_count = 0;
2124 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2125 15 : foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2126 5 : CHECK_EQ(23, break_point_hit_count);
2127 :
2128 : // Looping 100 times.
2129 : run_step.set_step_action(StepIn);
2130 5 : break_point_hit_count = 0;
2131 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2132 15 : foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2133 5 : CHECK_EQ(203, break_point_hit_count);
2134 :
2135 : // Get rid of the debug event listener.
2136 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2137 5 : CheckDebuggerUnloaded();
2138 5 : }
2139 :
2140 :
2141 25880 : TEST(DebugStepDoWhile) {
2142 5 : LocalContext env;
2143 5 : v8::Isolate* isolate = env->GetIsolate();
2144 10 : v8::HandleScope scope(isolate);
2145 :
2146 : // Register a debug event listener which steps and counts.
2147 5 : DebugEventCounter run_step;
2148 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2149 :
2150 5 : v8::Local<v8::Context> context = env.local();
2151 : // Create a function for testing stepping. Run it to allow it to get
2152 : // optimized.
2153 : const int argc = 1;
2154 : const char* src = "function foo(x) { "
2155 : " var a = 0;"
2156 : " do {"
2157 : " a++;"
2158 : " } while (a < x)"
2159 : "}"
2160 : "foo()";
2161 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2162 5 : SetBreakPoint(foo, 8); // "var a = 0;"
2163 :
2164 : // Looping 0 times.
2165 : run_step.set_step_action(StepIn);
2166 5 : break_point_hit_count = 0;
2167 5 : v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
2168 15 : foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
2169 5 : CHECK_EQ(4, break_point_hit_count);
2170 :
2171 : // Looping 10 times.
2172 : run_step.set_step_action(StepIn);
2173 5 : break_point_hit_count = 0;
2174 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2175 15 : foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2176 5 : CHECK_EQ(22, break_point_hit_count);
2177 :
2178 : // Looping 100 times.
2179 : run_step.set_step_action(StepIn);
2180 5 : break_point_hit_count = 0;
2181 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2182 15 : foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2183 5 : CHECK_EQ(202, break_point_hit_count);
2184 :
2185 : // Get rid of the debug event listener.
2186 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2187 5 : CheckDebuggerUnloaded();
2188 5 : }
2189 :
2190 :
2191 25880 : TEST(DebugStepFor) {
2192 5 : LocalContext env;
2193 5 : v8::Isolate* isolate = env->GetIsolate();
2194 10 : v8::HandleScope scope(isolate);
2195 :
2196 : // Register a debug event listener which steps and counts.
2197 5 : DebugEventCounter run_step;
2198 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2199 :
2200 5 : v8::Local<v8::Context> context = env.local();
2201 : // Create a function for testing stepping. Run it to allow it to get
2202 : // optimized.
2203 : const int argc = 1;
2204 : const char* src = "function foo(x) { "
2205 : " a = 1;"
2206 : " for (i = 0; i < x; i++) {"
2207 : " b = 1;"
2208 : " }"
2209 : "}"
2210 : "a=0; b=0; i=0; foo()";
2211 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2212 :
2213 5 : SetBreakPoint(foo, 8); // "a = 1;"
2214 :
2215 : // Looping 0 times.
2216 : run_step.set_step_action(StepIn);
2217 5 : break_point_hit_count = 0;
2218 5 : v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
2219 15 : foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
2220 5 : CHECK_EQ(4, break_point_hit_count);
2221 :
2222 : // Looping 10 times.
2223 : run_step.set_step_action(StepIn);
2224 5 : break_point_hit_count = 0;
2225 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2226 15 : foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2227 5 : CHECK_EQ(34, break_point_hit_count);
2228 :
2229 : // Looping 100 times.
2230 : run_step.set_step_action(StepIn);
2231 5 : break_point_hit_count = 0;
2232 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2233 15 : foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2234 5 : CHECK_EQ(304, break_point_hit_count);
2235 :
2236 : // Get rid of the debug event listener.
2237 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2238 5 : CheckDebuggerUnloaded();
2239 5 : }
2240 :
2241 :
2242 25880 : TEST(DebugStepForContinue) {
2243 5 : LocalContext env;
2244 5 : v8::Isolate* isolate = env->GetIsolate();
2245 10 : v8::HandleScope scope(isolate);
2246 :
2247 : // Register a debug event listener which steps and counts.
2248 5 : DebugEventCounter run_step;
2249 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2250 :
2251 5 : v8::Local<v8::Context> context = env.local();
2252 : // Create a function for testing stepping. Run it to allow it to get
2253 : // optimized.
2254 : const int argc = 1;
2255 : const char* src = "function foo(x) { "
2256 : " var a = 0;"
2257 : " var b = 0;"
2258 : " var c = 0;"
2259 : " for (var i = 0; i < x; i++) {"
2260 : " a++;"
2261 : " if (a % 2 == 0) continue;"
2262 : " b++;"
2263 : " c++;"
2264 : " }"
2265 : " return b;"
2266 : "}"
2267 : "foo()";
2268 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2269 : v8::Local<v8::Value> result;
2270 5 : SetBreakPoint(foo, 8); // "var a = 0;"
2271 :
2272 : // Each loop generates 4 or 5 steps depending on whether a is equal.
2273 :
2274 : // Looping 10 times.
2275 : run_step.set_step_action(StepIn);
2276 5 : break_point_hit_count = 0;
2277 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2278 15 : result = foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2279 10 : CHECK_EQ(5, result->Int32Value(context).FromJust());
2280 5 : CHECK_EQ(62, break_point_hit_count);
2281 :
2282 : // Looping 100 times.
2283 : run_step.set_step_action(StepIn);
2284 5 : break_point_hit_count = 0;
2285 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2286 15 : result = foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2287 10 : CHECK_EQ(50, result->Int32Value(context).FromJust());
2288 5 : CHECK_EQ(557, break_point_hit_count);
2289 :
2290 : // Get rid of the debug event listener.
2291 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2292 5 : CheckDebuggerUnloaded();
2293 5 : }
2294 :
2295 :
2296 25880 : TEST(DebugStepForBreak) {
2297 5 : LocalContext env;
2298 5 : v8::Isolate* isolate = env->GetIsolate();
2299 10 : v8::HandleScope scope(isolate);
2300 :
2301 : // Register a debug event listener which steps and counts.
2302 5 : DebugEventCounter run_step;
2303 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2304 :
2305 5 : v8::Local<v8::Context> context = env.local();
2306 : // Create a function for testing stepping. Run it to allow it to get
2307 : // optimized.
2308 : const int argc = 1;
2309 : const char* src = "function foo(x) { "
2310 : " var a = 0;"
2311 : " var b = 0;"
2312 : " var c = 0;"
2313 : " for (var i = 0; i < 1000; i++) {"
2314 : " a++;"
2315 : " if (a == x) break;"
2316 : " b++;"
2317 : " c++;"
2318 : " }"
2319 : " return b;"
2320 : "}"
2321 : "foo()";
2322 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2323 : v8::Local<v8::Value> result;
2324 5 : SetBreakPoint(foo, 8); // "var a = 0;"
2325 :
2326 : // Each loop generates 5 steps except for the last (when break is executed)
2327 : // which only generates 4.
2328 :
2329 : // Looping 10 times.
2330 : run_step.set_step_action(StepIn);
2331 5 : break_point_hit_count = 0;
2332 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2333 15 : result = foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2334 10 : CHECK_EQ(9, result->Int32Value(context).FromJust());
2335 5 : CHECK_EQ(64, break_point_hit_count);
2336 :
2337 : // Looping 100 times.
2338 : run_step.set_step_action(StepIn);
2339 5 : break_point_hit_count = 0;
2340 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2341 15 : result = foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2342 10 : CHECK_EQ(99, result->Int32Value(context).FromJust());
2343 5 : CHECK_EQ(604, break_point_hit_count);
2344 :
2345 : // Get rid of the debug event listener.
2346 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2347 5 : CheckDebuggerUnloaded();
2348 5 : }
2349 :
2350 :
2351 25880 : TEST(DebugStepForIn) {
2352 5 : LocalContext env;
2353 10 : v8::HandleScope scope(env->GetIsolate());
2354 :
2355 : // Register a debug event listener which steps and counts.
2356 5 : DebugEventCounter run_step;
2357 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2358 :
2359 5 : v8::Local<v8::Context> context = env.local();
2360 : // Create a function for testing stepping. Run it to allow it to get
2361 : // optimized.
2362 : v8::Local<v8::Function> foo;
2363 : const char* src_1 = "function foo() { "
2364 : " var a = [1, 2];"
2365 : " for (x in a) {"
2366 : " b = 0;"
2367 : " }"
2368 : "}"
2369 : "foo()";
2370 5 : foo = CompileFunction(&env, src_1, "foo");
2371 5 : SetBreakPoint(foo, 0); // "var a = ..."
2372 :
2373 : run_step.set_step_action(StepIn);
2374 5 : break_point_hit_count = 0;
2375 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2376 5 : CHECK_EQ(8, break_point_hit_count);
2377 :
2378 : // Create a function for testing stepping. Run it to allow it to get
2379 : // optimized.
2380 : const char* src_2 = "function foo() { "
2381 : " var a = {a:[1, 2, 3]};"
2382 : " for (x in a.a) {"
2383 : " b = 0;"
2384 : " }"
2385 : "}"
2386 : "foo()";
2387 5 : foo = CompileFunction(&env, src_2, "foo");
2388 5 : SetBreakPoint(foo, 0); // "var a = ..."
2389 :
2390 : run_step.set_step_action(StepIn);
2391 5 : break_point_hit_count = 0;
2392 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2393 5 : CHECK_EQ(10, break_point_hit_count);
2394 :
2395 : // Get rid of the debug event listener.
2396 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2397 5 : CheckDebuggerUnloaded();
2398 5 : }
2399 :
2400 :
2401 25880 : TEST(DebugStepWith) {
2402 5 : LocalContext env;
2403 10 : v8::HandleScope scope(env->GetIsolate());
2404 :
2405 : // Register a debug event listener which steps and counts.
2406 5 : DebugEventCounter run_step;
2407 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2408 :
2409 5 : v8::Local<v8::Context> context = env.local();
2410 : // Create a function for testing stepping. Run it to allow it to get
2411 : // optimized.
2412 : const char* src = "function foo(x) { "
2413 : " var a = {};"
2414 : " with (a) {}"
2415 : " with (b) {}"
2416 : "}"
2417 : "foo()";
2418 25 : CHECK(env->Global()
2419 : ->Set(context, v8_str(env->GetIsolate(), "b"),
2420 : v8::Object::New(env->GetIsolate()))
2421 : .FromJust());
2422 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2423 : v8::Local<v8::Value> result;
2424 5 : SetBreakPoint(foo, 8); // "var a = {};"
2425 :
2426 : run_step.set_step_action(StepIn);
2427 5 : break_point_hit_count = 0;
2428 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2429 5 : CHECK_EQ(4, break_point_hit_count);
2430 :
2431 : // Get rid of the debug event listener.
2432 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2433 5 : CheckDebuggerUnloaded();
2434 5 : }
2435 :
2436 :
2437 25880 : TEST(DebugConditional) {
2438 5 : LocalContext env;
2439 5 : v8::Isolate* isolate = env->GetIsolate();
2440 10 : v8::HandleScope scope(isolate);
2441 :
2442 : // Register a debug event listener which steps and counts.
2443 5 : DebugEventCounter run_step;
2444 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2445 :
2446 5 : v8::Local<v8::Context> context = env.local();
2447 : // Create a function for testing stepping. Run it to allow it to get
2448 : // optimized.
2449 : const char* src =
2450 : "function foo(x) { "
2451 : " return x ? 1 : 2;"
2452 : "}"
2453 : "foo()";
2454 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2455 5 : SetBreakPoint(foo, 0); // "var a;"
2456 :
2457 : run_step.set_step_action(StepIn);
2458 5 : break_point_hit_count = 0;
2459 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2460 5 : CHECK_EQ(2, break_point_hit_count);
2461 :
2462 : run_step.set_step_action(StepIn);
2463 5 : break_point_hit_count = 0;
2464 : const int argc = 1;
2465 : v8::Local<v8::Value> argv_true[argc] = {v8::True(isolate)};
2466 15 : foo->Call(context, env->Global(), argc, argv_true).ToLocalChecked();
2467 5 : CHECK_EQ(2, break_point_hit_count);
2468 :
2469 : // Get rid of the debug event listener.
2470 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2471 5 : CheckDebuggerUnloaded();
2472 5 : }
2473 :
2474 : // Test that step in does not step into native functions.
2475 25880 : TEST(DebugStepNatives) {
2476 5 : LocalContext env;
2477 10 : v8::HandleScope scope(env->GetIsolate());
2478 :
2479 : // Create a function for testing stepping.
2480 : v8::Local<v8::Function> foo =
2481 5 : CompileFunction(&env, "function foo(){debugger;Math.sin(1);}", "foo");
2482 :
2483 : // Register a debug event listener which steps and counts.
2484 5 : DebugEventCounter run_step;
2485 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2486 :
2487 5 : v8::Local<v8::Context> context = env.local();
2488 : run_step.set_step_action(StepIn);
2489 5 : break_point_hit_count = 0;
2490 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2491 :
2492 : // With stepping all break locations are hit.
2493 5 : CHECK_EQ(3, break_point_hit_count);
2494 :
2495 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2496 : CheckDebuggerUnloaded();
2497 :
2498 : // Register a debug event listener which just counts.
2499 5 : DebugEventCounter delegate;
2500 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
2501 :
2502 5 : break_point_hit_count = 0;
2503 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2504 :
2505 : // Without stepping only active break points are hit.
2506 5 : CHECK_EQ(1, break_point_hit_count);
2507 :
2508 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2509 5 : CheckDebuggerUnloaded();
2510 5 : }
2511 :
2512 : // Test that step in works with function.apply.
2513 25880 : TEST(DebugStepFunctionApply) {
2514 5 : LocalContext env;
2515 10 : v8::HandleScope scope(env->GetIsolate());
2516 :
2517 : // Create a function for testing stepping.
2518 : v8::Local<v8::Function> foo =
2519 : CompileFunction(&env,
2520 : "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
2521 : "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
2522 5 : "foo");
2523 :
2524 : // Register a debug event listener which steps and counts.
2525 5 : DebugEventCounter run_step;
2526 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2527 :
2528 5 : v8::Local<v8::Context> context = env.local();
2529 : run_step.set_step_action(StepIn);
2530 5 : break_point_hit_count = 0;
2531 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2532 :
2533 : // With stepping all break locations are hit.
2534 5 : CHECK_EQ(7, break_point_hit_count);
2535 :
2536 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2537 : CheckDebuggerUnloaded();
2538 :
2539 : // Register a debug event listener which just counts.
2540 5 : DebugEventCounter delegate;
2541 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
2542 :
2543 5 : break_point_hit_count = 0;
2544 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2545 :
2546 : // Without stepping only the debugger statement is hit.
2547 5 : CHECK_EQ(1, break_point_hit_count);
2548 :
2549 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2550 5 : CheckDebuggerUnloaded();
2551 5 : }
2552 :
2553 :
2554 : // Test that step in works with function.call.
2555 25880 : TEST(DebugStepFunctionCall) {
2556 5 : LocalContext env;
2557 5 : v8::Isolate* isolate = env->GetIsolate();
2558 10 : v8::HandleScope scope(isolate);
2559 :
2560 5 : v8::Local<v8::Context> context = env.local();
2561 : // Create a function for testing stepping.
2562 : v8::Local<v8::Function> foo = CompileFunction(
2563 : &env,
2564 : "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
2565 : "function foo(a){ debugger;"
2566 : " if (a) {"
2567 : " bar.call(this, 1, 2, 3);"
2568 : " } else {"
2569 : " bar.call(this, 0);"
2570 : " }"
2571 : "}",
2572 5 : "foo");
2573 :
2574 : // Register a debug event listener which steps and counts.
2575 5 : DebugEventCounter run_step;
2576 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2577 : run_step.set_step_action(StepIn);
2578 :
2579 : // Check stepping where the if condition in bar is false.
2580 5 : break_point_hit_count = 0;
2581 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2582 5 : CHECK_EQ(6, break_point_hit_count);
2583 :
2584 : // Check stepping where the if condition in bar is true.
2585 5 : break_point_hit_count = 0;
2586 : const int argc = 1;
2587 : v8::Local<v8::Value> argv[argc] = {v8::True(isolate)};
2588 15 : foo->Call(context, env->Global(), argc, argv).ToLocalChecked();
2589 5 : CHECK_EQ(8, break_point_hit_count);
2590 :
2591 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2592 : CheckDebuggerUnloaded();
2593 :
2594 : // Register a debug event listener which just counts.
2595 5 : DebugEventCounter delegate;
2596 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
2597 :
2598 5 : break_point_hit_count = 0;
2599 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2600 :
2601 : // Without stepping only the debugger statement is hit.
2602 5 : CHECK_EQ(1, break_point_hit_count);
2603 :
2604 5 : v8::debug::SetDebugDelegate(isolate, nullptr);
2605 5 : CheckDebuggerUnloaded();
2606 5 : }
2607 :
2608 :
2609 : // Test that step in works with Function.call.apply.
2610 25880 : TEST(DebugStepFunctionCallApply) {
2611 5 : LocalContext env;
2612 5 : v8::Isolate* isolate = env->GetIsolate();
2613 10 : v8::HandleScope scope(isolate);
2614 :
2615 5 : v8::Local<v8::Context> context = env.local();
2616 : // Create a function for testing stepping.
2617 : v8::Local<v8::Function> foo =
2618 : CompileFunction(&env,
2619 : "function bar() { }"
2620 : "function foo(){ debugger;"
2621 : " Function.call.apply(bar);"
2622 : " Function.call.apply(Function.call, "
2623 : "[Function.call, bar]);"
2624 : "}",
2625 5 : "foo");
2626 :
2627 : // Register a debug event listener which steps and counts.
2628 5 : DebugEventCounter run_step;
2629 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2630 : run_step.set_step_action(StepIn);
2631 :
2632 5 : break_point_hit_count = 0;
2633 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2634 5 : CHECK_EQ(6, break_point_hit_count);
2635 :
2636 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2637 : CheckDebuggerUnloaded();
2638 :
2639 : // Register a debug event listener which just counts.
2640 5 : DebugEventCounter delegate;
2641 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
2642 :
2643 5 : break_point_hit_count = 0;
2644 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2645 :
2646 : // Without stepping only the debugger statement is hit.
2647 5 : CHECK_EQ(1, break_point_hit_count);
2648 :
2649 5 : v8::debug::SetDebugDelegate(isolate, nullptr);
2650 5 : CheckDebuggerUnloaded();
2651 5 : }
2652 :
2653 :
2654 : // Tests that breakpoint will be hit if it's set in script.
2655 25880 : TEST(PauseInScript) {
2656 5 : LocalContext env;
2657 10 : v8::HandleScope scope(env->GetIsolate());
2658 10 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
2659 :
2660 : // Register a debug event listener which counts.
2661 5 : DebugEventCounter event_counter;
2662 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &event_counter);
2663 :
2664 5 : v8::Local<v8::Context> context = env.local();
2665 : // Create a script that returns a function.
2666 : const char* src = "(function (evt) {})";
2667 : const char* script_name = "StepInHandlerTest";
2668 :
2669 : v8::ScriptOrigin origin(v8_str(env->GetIsolate(), script_name),
2670 10 : v8::Integer::New(env->GetIsolate(), 0));
2671 : v8::Local<v8::Script> script =
2672 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), src), &origin)
2673 5 : .ToLocalChecked();
2674 :
2675 : // Set breakpoint in the script.
2676 : i::Handle<i::Script> i_script(
2677 10 : i::Script::cast(v8::Utils::OpenHandle(*script)->shared()->script()),
2678 10 : isolate);
2679 5 : i::Handle<i::String> condition = isolate->factory()->empty_string();
2680 5 : int position = 0;
2681 : int id;
2682 5 : isolate->debug()->SetBreakPointForScript(i_script, condition, &position, &id);
2683 5 : break_point_hit_count = 0;
2684 :
2685 5 : v8::Local<v8::Value> r = script->Run(context).ToLocalChecked();
2686 :
2687 5 : CHECK(r->IsFunction());
2688 5 : CHECK_EQ(1, break_point_hit_count);
2689 :
2690 : // Get rid of the debug delegate.
2691 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2692 5 : CheckDebuggerUnloaded();
2693 5 : }
2694 :
2695 : int message_callback_count = 0;
2696 :
2697 25880 : TEST(DebugBreak) {
2698 5 : i::FLAG_stress_compaction = false;
2699 : #ifdef VERIFY_HEAP
2700 : i::FLAG_verify_heap = true;
2701 : #endif
2702 5 : LocalContext env;
2703 5 : v8::Isolate* isolate = env->GetIsolate();
2704 10 : v8::HandleScope scope(isolate);
2705 :
2706 : // Register a debug event listener which sets the break flag and counts.
2707 5 : DebugEventBreak delegate;
2708 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
2709 :
2710 5 : v8::Local<v8::Context> context = env.local();
2711 : // Create a function for testing stepping.
2712 : const char* src = "function f0() {}"
2713 : "function f1(x1) {}"
2714 : "function f2(x1,x2) {}"
2715 : "function f3(x1,x2,x3) {}";
2716 5 : v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
2717 5 : v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
2718 5 : v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
2719 5 : v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
2720 :
2721 : // Call the function to make sure it is compiled.
2722 : v8::Local<v8::Value> argv[] = {
2723 : v8::Number::New(isolate, 1), v8::Number::New(isolate, 1),
2724 20 : v8::Number::New(isolate, 1), v8::Number::New(isolate, 1)};
2725 :
2726 : // Call all functions to make sure that they are compiled.
2727 15 : f0->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2728 15 : f1->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2729 15 : f2->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2730 15 : f3->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2731 :
2732 : // Set the debug break flag.
2733 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
2734 :
2735 : // Call all functions with different argument count.
2736 5 : break_point_hit_count = 0;
2737 25 : for (unsigned int i = 0; i < arraysize(argv); i++) {
2738 80 : f0->Call(context, env->Global(), i, argv).ToLocalChecked();
2739 60 : f1->Call(context, env->Global(), i, argv).ToLocalChecked();
2740 60 : f2->Call(context, env->Global(), i, argv).ToLocalChecked();
2741 60 : f3->Call(context, env->Global(), i, argv).ToLocalChecked();
2742 : }
2743 :
2744 : // One break for each function called.
2745 10 : CHECK_EQ(4 * arraysize(argv), break_point_hit_count);
2746 :
2747 : // Get rid of the debug event listener.
2748 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2749 5 : CheckDebuggerUnloaded();
2750 5 : }
2751 :
2752 5 : class DebugScopingListener : public v8::debug::DebugDelegate {
2753 : public:
2754 0 : void BreakProgramRequested(
2755 : v8::Local<v8::Context>,
2756 : const std::vector<v8::debug::BreakpointId>&) override {
2757 : auto stack_traces =
2758 0 : v8::debug::StackTraceIterator::Create(CcTest::isolate());
2759 0 : v8::debug::Location location = stack_traces->GetSourceLocation();
2760 0 : CHECK_EQ(26, location.GetColumnNumber());
2761 0 : CHECK_EQ(0, location.GetLineNumber());
2762 :
2763 0 : auto scopes = stack_traces->GetScopeIterator();
2764 0 : CHECK_EQ(v8::debug::ScopeIterator::ScopeTypeWith, scopes->GetType());
2765 0 : CHECK_EQ(20, scopes->GetStartLocation().GetColumnNumber());
2766 0 : CHECK_EQ(31, scopes->GetEndLocation().GetColumnNumber());
2767 :
2768 0 : scopes->Advance();
2769 0 : CHECK_EQ(v8::debug::ScopeIterator::ScopeTypeLocal, scopes->GetType());
2770 0 : CHECK_EQ(0, scopes->GetStartLocation().GetColumnNumber());
2771 0 : CHECK_EQ(68, scopes->GetEndLocation().GetColumnNumber());
2772 :
2773 0 : scopes->Advance();
2774 0 : CHECK_EQ(v8::debug::ScopeIterator::ScopeTypeGlobal, scopes->GetType());
2775 :
2776 0 : scopes->Advance();
2777 0 : CHECK(scopes->Done());
2778 0 : }
2779 : };
2780 :
2781 25880 : TEST(DebugBreakInWrappedScript) {
2782 5 : i::FLAG_stress_compaction = false;
2783 : #ifdef VERIFY_HEAP
2784 : i::FLAG_verify_heap = true;
2785 : #endif
2786 5 : LocalContext env;
2787 5 : v8::Isolate* isolate = env->GetIsolate();
2788 10 : v8::HandleScope scope(isolate);
2789 :
2790 : // Register a debug event listener which sets the break flag and counts.
2791 5 : DebugScopingListener delegate;
2792 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
2793 :
2794 : static const char* source =
2795 : // 0 1 2 3 4 5 6 7
2796 : "try { with({o : []}){ o[0](); } } catch (e) { return e.toString(); }";
2797 : static const char* expect = "TypeError: o[0] is not a function";
2798 :
2799 : // For this test, we want to break on uncaught exceptions:
2800 5 : ChangeBreakOnException(true, true);
2801 :
2802 : {
2803 5 : v8::ScriptCompiler::Source script_source(v8_str(source));
2804 : v8::Local<v8::Function> fun =
2805 : v8::ScriptCompiler::CompileFunctionInContext(
2806 5 : env.local(), &script_source, 0, nullptr, 0, nullptr)
2807 5 : .ToLocalChecked();
2808 : v8::Local<v8::Value> result =
2809 15 : fun->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
2810 5 : CHECK(result->IsString());
2811 15 : CHECK(v8::Local<v8::String>::Cast(result)
2812 : ->Equals(env.local(), v8_str(expect))
2813 : .FromJust());
2814 : }
2815 :
2816 : // Get rid of the debug event listener.
2817 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2818 5 : CheckDebuggerUnloaded();
2819 5 : }
2820 :
2821 0 : static void EmptyHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {}
2822 :
2823 25880 : TEST(DebugScopeIteratorWithFunctionTemplate) {
2824 5 : LocalContext env;
2825 10 : v8::HandleScope handle_scope(env->GetIsolate());
2826 5 : v8::Isolate* isolate = env->GetIsolate();
2827 : EnableDebugger(isolate);
2828 : v8::Local<v8::Function> func =
2829 10 : v8::Function::New(env.local(), EmptyHandler).ToLocalChecked();
2830 : std::unique_ptr<v8::debug::ScopeIterator> iterator =
2831 5 : v8::debug::ScopeIterator::CreateForFunction(isolate, func);
2832 5 : CHECK(iterator->Done());
2833 5 : DisableDebugger(isolate);
2834 5 : }
2835 :
2836 25880 : TEST(DebugBreakWithoutJS) {
2837 5 : i::FLAG_stress_compaction = false;
2838 : #ifdef VERIFY_HEAP
2839 : i::FLAG_verify_heap = true;
2840 : #endif
2841 5 : LocalContext env;
2842 5 : v8::Isolate* isolate = env->GetIsolate();
2843 10 : v8::HandleScope scope(isolate);
2844 5 : v8::Local<v8::Context> context = env.local();
2845 :
2846 : // Register a debug event listener which sets the break flag and counts.
2847 5 : DebugEventBreak delegate;
2848 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
2849 :
2850 : // Set the debug break flag.
2851 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
2852 :
2853 5 : v8::Local<v8::String> json = v8_str("[1]");
2854 10 : v8::Local<v8::Value> parsed = v8::JSON::Parse(context, json).ToLocalChecked();
2855 15 : CHECK(v8::JSON::Stringify(context, parsed)
2856 : .ToLocalChecked()
2857 : ->Equals(context, json)
2858 : .FromJust());
2859 5 : CHECK_EQ(0, break_point_hit_count);
2860 : CompileRun("");
2861 5 : CHECK_EQ(1, break_point_hit_count);
2862 :
2863 : // Get rid of the debug event listener.
2864 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2865 5 : CheckDebuggerUnloaded();
2866 5 : }
2867 :
2868 : // Test to ensure that JavaScript code keeps running while the debug break
2869 : // through the stack limit flag is set but breaks are disabled.
2870 25880 : TEST(DisableBreak) {
2871 5 : LocalContext env;
2872 10 : v8::HandleScope scope(env->GetIsolate());
2873 :
2874 : // Register a debug event listener which sets the break flag and counts.
2875 5 : DebugEventCounter delegate;
2876 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
2877 :
2878 5 : v8::Local<v8::Context> context = env.local();
2879 : // Create a function for testing stepping.
2880 : const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
2881 5 : v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
2882 :
2883 : // Set, test and cancel debug break.
2884 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
2885 5 : v8::debug::ClearBreakOnNextFunctionCall(env->GetIsolate());
2886 :
2887 : // Set the debug break flag.
2888 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
2889 :
2890 : // Call all functions with different argument count.
2891 5 : break_point_hit_count = 0;
2892 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2893 5 : CHECK_EQ(1, break_point_hit_count);
2894 :
2895 : {
2896 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
2897 5 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
2898 : v8::internal::DisableBreak disable_break(isolate->debug());
2899 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2900 5 : CHECK_EQ(1, break_point_hit_count);
2901 : }
2902 :
2903 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2904 5 : CHECK_EQ(2, break_point_hit_count);
2905 :
2906 : // Get rid of the debug event listener.
2907 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2908 5 : CheckDebuggerUnloaded();
2909 5 : }
2910 :
2911 25880 : TEST(DisableDebuggerStatement) {
2912 5 : LocalContext env;
2913 10 : v8::HandleScope scope(env->GetIsolate());
2914 :
2915 : // Register a debug event listener which sets the break flag and counts.
2916 5 : DebugEventCounter delegate;
2917 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
2918 :
2919 : CompileRun("debugger;");
2920 5 : CHECK_EQ(1, break_point_hit_count);
2921 :
2922 : // Check that we ignore debugger statement when breakpoints aren't active.
2923 5 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
2924 : isolate->debug()->set_break_points_active(false);
2925 : CompileRun("debugger;");
2926 5 : CHECK_EQ(1, break_point_hit_count);
2927 :
2928 10 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2929 5 : }
2930 :
2931 : static const char* kSimpleExtensionSource =
2932 : "(function Foo() {"
2933 : " return 4;"
2934 : "})() ";
2935 :
2936 : // http://crbug.com/28933
2937 : // Test that debug break is disabled when bootstrapper is active.
2938 25880 : TEST(NoBreakWhenBootstrapping) {
2939 5 : v8::Isolate* isolate = CcTest::isolate();
2940 5 : v8::HandleScope scope(isolate);
2941 :
2942 : // Register a debug event listener which sets the break flag and counts.
2943 5 : DebugEventCounter delegate;
2944 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
2945 :
2946 : // Set the debug break flag.
2947 5 : v8::debug::SetBreakOnNextFunctionCall(isolate);
2948 5 : break_point_hit_count = 0;
2949 : {
2950 : // Create a context with an extension to make sure that some JavaScript
2951 : // code is executed during bootstrapping.
2952 : v8::RegisterExtension(v8::base::make_unique<v8::Extension>(
2953 10 : "simpletest", kSimpleExtensionSource));
2954 5 : const char* extension_names[] = { "simpletest" };
2955 : v8::ExtensionConfiguration extensions(1, extension_names);
2956 5 : v8::HandleScope handle_scope(isolate);
2957 5 : v8::Context::New(isolate, &extensions);
2958 : }
2959 : // Check that no DebugBreak events occurred during the context creation.
2960 5 : CHECK_EQ(0, break_point_hit_count);
2961 :
2962 : // Get rid of the debug event listener.
2963 5 : v8::debug::SetDebugDelegate(isolate, nullptr);
2964 5 : CheckDebuggerUnloaded();
2965 5 : }
2966 :
2967 25880 : TEST(SetDebugEventListenerOnUninitializedVM) {
2968 5 : v8::HandleScope scope(CcTest::isolate());
2969 10 : EnableDebugger(CcTest::isolate());
2970 5 : }
2971 :
2972 : // Test that clearing the debug event listener actually clears all break points
2973 : // and related information.
2974 25880 : TEST(DebuggerUnload) {
2975 5 : LocalContext env;
2976 10 : v8::HandleScope handle_scope(env->GetIsolate());
2977 : // Check debugger is unloaded before it is used.
2978 : CheckDebuggerUnloaded();
2979 :
2980 : // Set a debug event listener.
2981 5 : break_point_hit_count = 0;
2982 5 : DebugEventCounter delegate;
2983 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
2984 5 : v8::Local<v8::Context> context = env.local();
2985 : {
2986 5 : v8::HandleScope scope(env->GetIsolate());
2987 : // Create a couple of functions for the test.
2988 : v8::Local<v8::Function> foo =
2989 5 : CompileFunction(&env, "function foo(){x=1}", "foo");
2990 : v8::Local<v8::Function> bar =
2991 5 : CompileFunction(&env, "function bar(){y=2}", "bar");
2992 :
2993 : // Set some break points.
2994 5 : SetBreakPoint(foo, 0);
2995 5 : SetBreakPoint(foo, 4);
2996 5 : SetBreakPoint(bar, 0);
2997 5 : SetBreakPoint(bar, 4);
2998 :
2999 : // Make sure that the break points are there.
3000 5 : break_point_hit_count = 0;
3001 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3002 5 : CHECK_EQ(2, break_point_hit_count);
3003 15 : bar->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3004 5 : CHECK_EQ(4, break_point_hit_count);
3005 : }
3006 :
3007 : // Remove the debug event listener without clearing breakpoints. Do this
3008 : // outside a handle scope.
3009 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3010 5 : CheckDebuggerUnloaded();
3011 5 : }
3012 :
3013 : int event_listener_hit_count = 0;
3014 :
3015 : // Test for issue http://code.google.com/p/v8/issues/detail?id=289.
3016 : // Make sure that DebugGetLoadedScripts doesn't return scripts
3017 : // with disposed external source.
3018 : class EmptyExternalStringResource : public v8::String::ExternalStringResource {
3019 : public:
3020 : EmptyExternalStringResource() { empty_[0] = 0; }
3021 0 : ~EmptyExternalStringResource() override = default;
3022 0 : size_t length() const override { return empty_.length(); }
3023 0 : const uint16_t* data() const override { return empty_.start(); }
3024 :
3025 : private:
3026 : ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
3027 : };
3028 :
3029 25880 : TEST(DebugScriptLineEndsAreAscending) {
3030 5 : LocalContext env;
3031 5 : v8::Isolate* isolate = env->GetIsolate();
3032 10 : v8::HandleScope scope(isolate);
3033 :
3034 : // Compile a test script.
3035 : v8::Local<v8::String> script = v8_str(isolate,
3036 : "function f() {\n"
3037 : " debugger;\n"
3038 5 : "}\n");
3039 :
3040 5 : v8::ScriptOrigin origin1 = v8::ScriptOrigin(v8_str(isolate, "name"));
3041 : v8::Local<v8::Script> script1 =
3042 5 : v8::Script::Compile(env.local(), script, &origin1).ToLocalChecked();
3043 : USE(script1);
3044 :
3045 : Handle<v8::internal::FixedArray> instances;
3046 : {
3047 5 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
3048 5 : instances = debug->GetLoadedScripts();
3049 : }
3050 :
3051 5 : CHECK_GT(instances->length(), 0);
3052 45 : for (int i = 0; i < instances->length(); i++) {
3053 : Handle<v8::internal::Script> script = Handle<v8::internal::Script>(
3054 : v8::internal::Script::cast(instances->get(i)), CcTest::i_isolate());
3055 :
3056 20 : v8::internal::Script::InitLineEnds(script);
3057 : v8::internal::FixedArray ends =
3058 : v8::internal::FixedArray::cast(script->line_ends());
3059 20 : CHECK_GT(ends->length(), 0);
3060 :
3061 : int prev_end = -1;
3062 1030 : for (int j = 0; j < ends->length(); j++) {
3063 505 : const int curr_end = v8::internal::Smi::ToInt(ends->get(j));
3064 505 : CHECK_GT(curr_end, prev_end);
3065 : prev_end = curr_end;
3066 : }
3067 5 : }
3068 5 : }
3069 :
3070 : static v8::Local<v8::Context> expected_context;
3071 : static v8::Local<v8::Value> expected_context_data;
3072 :
3073 10 : class ContextCheckEventListener : public v8::debug::DebugDelegate {
3074 : public:
3075 15 : void BreakProgramRequested(v8::Local<v8::Context> paused_context,
3076 : const std::vector<v8::debug::BreakpointId>&
3077 : inspector_break_points_hit) override {
3078 15 : CheckContext();
3079 15 : }
3080 20 : void ScriptCompiled(v8::Local<v8::debug::Script> script, bool is_live_edited,
3081 : bool has_compile_error) override {
3082 20 : CheckContext();
3083 20 : }
3084 0 : void ExceptionThrown(v8::Local<v8::Context> paused_context,
3085 : v8::Local<v8::Value> exception,
3086 : v8::Local<v8::Value> promise, bool is_uncaught,
3087 : v8::debug::ExceptionType) override {
3088 0 : CheckContext();
3089 0 : }
3090 15 : bool IsFunctionBlackboxed(v8::Local<v8::debug::Script> script,
3091 : const v8::debug::Location& start,
3092 : const v8::debug::Location& end) override {
3093 15 : CheckContext();
3094 15 : return false;
3095 : }
3096 :
3097 : private:
3098 50 : void CheckContext() {
3099 50 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
3100 50 : CHECK(context == expected_context);
3101 50 : CHECK(context->GetEmbedderData(0)->StrictEquals(expected_context_data));
3102 50 : event_listener_hit_count++;
3103 50 : }
3104 : };
3105 :
3106 : // Test which creates two contexts and sets different embedder data on each.
3107 : // Checks that this data is set correctly and that when the debug event
3108 : // listener is called the expected context is the one active.
3109 25880 : TEST(ContextData) {
3110 5 : v8::Isolate* isolate = CcTest::isolate();
3111 5 : v8::HandleScope scope(isolate);
3112 :
3113 : // Create two contexts.
3114 : v8::Local<v8::Context> context_1;
3115 : v8::Local<v8::Context> context_2;
3116 : v8::Local<v8::ObjectTemplate> global_template =
3117 : v8::Local<v8::ObjectTemplate>();
3118 : v8::Local<v8::Value> global_object = v8::Local<v8::Value>();
3119 : context_1 =
3120 5 : v8::Context::New(isolate, nullptr, global_template, global_object);
3121 : context_2 =
3122 5 : v8::Context::New(isolate, nullptr, global_template, global_object);
3123 :
3124 5 : ContextCheckEventListener delegate;
3125 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
3126 :
3127 : // Default data value is undefined.
3128 5 : CHECK_EQ(0, context_1->GetNumberOfEmbedderDataFields());
3129 5 : CHECK_EQ(0, context_2->GetNumberOfEmbedderDataFields());
3130 :
3131 : // Set and check different data values.
3132 5 : v8::Local<v8::String> data_1 = v8_str(isolate, "1");
3133 5 : v8::Local<v8::String> data_2 = v8_str(isolate, "2");
3134 5 : context_1->SetEmbedderData(0, data_1);
3135 5 : context_2->SetEmbedderData(0, data_2);
3136 5 : CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
3137 5 : CHECK(context_2->GetEmbedderData(0)->StrictEquals(data_2));
3138 :
3139 : // Simple test function which causes a break.
3140 : const char* source = "function f() { debugger; }";
3141 :
3142 : // Enter and run function in the first context.
3143 : {
3144 : v8::Context::Scope context_scope(context_1);
3145 5 : expected_context = context_1;
3146 5 : expected_context_data = data_1;
3147 5 : v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
3148 15 : f->Call(context_1, context_1->Global(), 0, nullptr).ToLocalChecked();
3149 : }
3150 :
3151 : // Enter and run function in the second context.
3152 : {
3153 : v8::Context::Scope context_scope(context_2);
3154 5 : expected_context = context_2;
3155 5 : expected_context_data = data_2;
3156 5 : v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
3157 15 : f->Call(context_2, context_2->Global(), 0, nullptr).ToLocalChecked();
3158 : }
3159 :
3160 : // Two times compile event and two times break event.
3161 5 : CHECK_GT(event_listener_hit_count, 3);
3162 :
3163 5 : v8::debug::SetDebugDelegate(isolate, nullptr);
3164 5 : CheckDebuggerUnloaded();
3165 5 : }
3166 :
3167 : // Test which creates a context and sets embedder data on it. Checks that this
3168 : // data is set correctly and that when the debug event listener is called for
3169 : // break event in an eval statement the expected context is the one returned by
3170 : // Message.GetEventContext.
3171 25880 : TEST(EvalContextData) {
3172 5 : v8::HandleScope scope(CcTest::isolate());
3173 :
3174 : v8::Local<v8::Context> context_1;
3175 : v8::Local<v8::ObjectTemplate> global_template =
3176 : v8::Local<v8::ObjectTemplate>();
3177 5 : context_1 = v8::Context::New(CcTest::isolate(), nullptr, global_template);
3178 :
3179 5 : ContextCheckEventListener delegate;
3180 5 : v8::debug::SetDebugDelegate(CcTest::isolate(), &delegate);
3181 :
3182 : // Contexts initially do not have embedder data fields.
3183 5 : CHECK_EQ(0, context_1->GetNumberOfEmbedderDataFields());
3184 :
3185 : // Set and check a data value.
3186 5 : v8::Local<v8::String> data_1 = v8_str(CcTest::isolate(), "1");
3187 5 : context_1->SetEmbedderData(0, data_1);
3188 5 : CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
3189 :
3190 : // Simple test function with eval that causes a break.
3191 : const char* source = "function f() { eval('debugger;'); }";
3192 :
3193 : // Enter and run function in the context.
3194 : {
3195 : v8::Context::Scope context_scope(context_1);
3196 5 : expected_context = context_1;
3197 5 : expected_context_data = data_1;
3198 5 : v8::Local<v8::Function> f = CompileFunction(CcTest::isolate(), source, "f");
3199 15 : f->Call(context_1, context_1->Global(), 0, nullptr).ToLocalChecked();
3200 : }
3201 :
3202 5 : v8::debug::SetDebugDelegate(CcTest::isolate(), nullptr);
3203 :
3204 : // One time compile event and one time break event.
3205 5 : CHECK_GT(event_listener_hit_count, 2);
3206 5 : CheckDebuggerUnloaded();
3207 5 : }
3208 :
3209 : // Debug event listener which counts script compiled events.
3210 20 : class ScriptCompiledDelegate : public v8::debug::DebugDelegate {
3211 : public:
3212 50 : void ScriptCompiled(v8::Local<v8::debug::Script>, bool,
3213 : bool has_compile_error) override {
3214 50 : if (!has_compile_error) {
3215 35 : after_compile_event_count++;
3216 : } else {
3217 15 : compile_error_event_count++;
3218 : }
3219 50 : }
3220 :
3221 : int after_compile_event_count = 0;
3222 : int compile_error_event_count = 0;
3223 : };
3224 :
3225 : // Tests that after compile event is sent as many times as there are scripts
3226 : // compiled.
3227 25880 : TEST(AfterCompileEventWhenEventListenerIsReset) {
3228 5 : LocalContext env;
3229 10 : v8::HandleScope scope(env->GetIsolate());
3230 5 : v8::Local<v8::Context> context = env.local();
3231 : const char* script = "var a=1";
3232 :
3233 5 : ScriptCompiledDelegate delegate;
3234 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3235 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
3236 5 : .ToLocalChecked()
3237 : ->Run(context)
3238 5 : .ToLocalChecked();
3239 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3240 :
3241 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3242 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
3243 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
3244 5 : .ToLocalChecked()
3245 : ->Run(context)
3246 5 : .ToLocalChecked();
3247 :
3248 : // Setting listener to nullptr should cause debugger unload.
3249 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3250 : CheckDebuggerUnloaded();
3251 :
3252 : // Compilation cache should be disabled when debugger is active.
3253 10 : CHECK_EQ(2, delegate.after_compile_event_count);
3254 5 : }
3255 :
3256 : // Tests that syntax error event is sent as many times as there are scripts
3257 : // with syntax error compiled.
3258 25880 : TEST(SyntaxErrorEventOnSyntaxException) {
3259 5 : LocalContext env;
3260 10 : v8::HandleScope scope(env->GetIsolate());
3261 :
3262 : // For this test, we want to break on uncaught exceptions:
3263 5 : ChangeBreakOnException(false, true);
3264 :
3265 5 : ScriptCompiledDelegate delegate;
3266 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3267 5 : v8::Local<v8::Context> context = env.local();
3268 :
3269 : // Check initial state.
3270 5 : CHECK_EQ(0, delegate.compile_error_event_count);
3271 :
3272 : // Throws SyntaxError: Unexpected end of input
3273 10 : CHECK(
3274 : v8::Script::Compile(context, v8_str(env->GetIsolate(), "+++")).IsEmpty());
3275 5 : CHECK_EQ(1, delegate.compile_error_event_count);
3276 :
3277 10 : CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "/sel\\/: \\"))
3278 : .IsEmpty());
3279 5 : CHECK_EQ(2, delegate.compile_error_event_count);
3280 :
3281 : v8::Local<v8::Script> script =
3282 : v8::Script::Compile(context,
3283 5 : v8_str(env->GetIsolate(), "JSON.parse('1234:')"))
3284 5 : .ToLocalChecked();
3285 5 : CHECK_EQ(2, delegate.compile_error_event_count);
3286 10 : CHECK(script->Run(context).IsEmpty());
3287 5 : CHECK_EQ(3, delegate.compile_error_event_count);
3288 :
3289 : v8::Script::Compile(context,
3290 5 : v8_str(env->GetIsolate(), "new RegExp('/\\/\\\\');"))
3291 5 : .ToLocalChecked();
3292 5 : CHECK_EQ(3, delegate.compile_error_event_count);
3293 :
3294 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), "throw 1;"))
3295 5 : .ToLocalChecked();
3296 10 : CHECK_EQ(3, delegate.compile_error_event_count);
3297 5 : }
3298 :
3299 : // Tests that break event is sent when event listener is reset.
3300 25880 : TEST(BreakEventWhenEventListenerIsReset) {
3301 5 : LocalContext env;
3302 10 : v8::HandleScope scope(env->GetIsolate());
3303 5 : v8::Local<v8::Context> context = env.local();
3304 : const char* script = "function f() {};";
3305 :
3306 5 : ScriptCompiledDelegate delegate;
3307 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3308 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
3309 5 : .ToLocalChecked()
3310 : ->Run(context)
3311 5 : .ToLocalChecked();
3312 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3313 :
3314 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3315 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
3316 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
3317 : env->Global()
3318 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
3319 5 : .ToLocalChecked());
3320 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3321 :
3322 : // Setting event listener to nullptr should cause debugger unload.
3323 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3324 : CheckDebuggerUnloaded();
3325 :
3326 : // Compilation cache should be disabled when debugger is active.
3327 10 : CHECK_EQ(1, delegate.after_compile_event_count);
3328 5 : }
3329 :
3330 : // Tests that script is reported as compiled when bound to context.
3331 25880 : TEST(AfterCompileEventOnBindToContext) {
3332 5 : LocalContext env;
3333 5 : v8::Isolate* isolate = env->GetIsolate();
3334 10 : v8::HandleScope handle_scope(isolate);
3335 5 : ScriptCompiledDelegate delegate;
3336 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
3337 :
3338 : const char* source = "var a=1";
3339 : v8::ScriptCompiler::Source script_source(
3340 : v8::String::NewFromUtf8(isolate, source, v8::NewStringType::kNormal)
3341 5 : .ToLocalChecked());
3342 :
3343 : v8::Local<v8::UnboundScript> unbound =
3344 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source)
3345 5 : .ToLocalChecked();
3346 5 : CHECK_EQ(delegate.after_compile_event_count, 0);
3347 :
3348 5 : unbound->BindToCurrentContext();
3349 5 : CHECK_EQ(delegate.after_compile_event_count, 1);
3350 10 : v8::debug::SetDebugDelegate(isolate, nullptr);
3351 5 : }
3352 :
3353 :
3354 : // Test that if DebugBreak is forced it is ignored when code from
3355 : // debug-delay.js is executed.
3356 25880 : TEST(NoDebugBreakInAfterCompileEventListener) {
3357 5 : LocalContext env;
3358 10 : v8::HandleScope scope(env->GetIsolate());
3359 5 : v8::Local<v8::Context> context = env.local();
3360 :
3361 : // Register a debug event listener which sets the break flag and counts.
3362 5 : DebugEventCounter delegate;
3363 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3364 :
3365 : // Set the debug break flag.
3366 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
3367 :
3368 : // Create a function for testing stepping.
3369 : const char* src = "function f() { eval('var x = 10;'); } ";
3370 5 : v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
3371 :
3372 : // There should be only one break event.
3373 5 : CHECK_EQ(1, break_point_hit_count);
3374 :
3375 : // Set the debug break flag again.
3376 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
3377 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3378 : // There should be one more break event when the script is evaluated in 'f'.
3379 5 : CHECK_EQ(2, break_point_hit_count);
3380 :
3381 : // Get rid of the debug event listener.
3382 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3383 5 : CheckDebuggerUnloaded();
3384 5 : }
3385 :
3386 :
3387 : // Test that the debug break flag works with function.apply.
3388 25880 : TEST(DebugBreakFunctionApply) {
3389 5 : LocalContext env;
3390 10 : v8::HandleScope scope(env->GetIsolate());
3391 5 : v8::Local<v8::Context> context = env.local();
3392 :
3393 : // Create a function for testing breaking in apply.
3394 : v8::Local<v8::Function> foo = CompileFunction(
3395 : &env,
3396 : "function baz(x) { }"
3397 : "function bar(x) { baz(); }"
3398 : "function foo(){ bar.apply(this, [1]); }",
3399 5 : "foo");
3400 :
3401 : // Register a debug event listener which steps and counts.
3402 5 : DebugEventBreakMax delegate;
3403 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3404 :
3405 : // Set the debug break flag before calling the code using function.apply.
3406 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
3407 :
3408 : // Limit the number of debug breaks. This is a regression test for issue 493
3409 : // where this test would enter an infinite loop.
3410 5 : break_point_hit_count = 0;
3411 5 : max_break_point_hit_count = 10000; // 10000 => infinite loop.
3412 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3413 :
3414 : // When keeping the debug break several break will happen.
3415 5 : CHECK_GT(break_point_hit_count, 1);
3416 :
3417 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3418 5 : CheckDebuggerUnloaded();
3419 5 : }
3420 :
3421 : // Test that setting the terminate execution flag during debug break processing.
3422 60 : static void TestDebugBreakInLoop(const char* loop_head,
3423 : const char** loop_bodies,
3424 : const char* loop_tail) {
3425 : // Receive 10 breaks for each test and then terminate JavaScript execution.
3426 : static const int kBreaksPerTest = 10;
3427 :
3428 390 : for (int i = 0; loop_bodies[i] != nullptr; i++) {
3429 : // Perform a lazy deoptimization after various numbers of breaks
3430 : // have been hit.
3431 :
3432 : i::EmbeddedVector<char, 1024> buffer;
3433 : SNPrintF(buffer, "function f() {%s%s%s}", loop_head, loop_bodies[i],
3434 330 : loop_tail);
3435 :
3436 330 : i::PrintF("%s\n", buffer.start());
3437 :
3438 1320 : for (int j = 0; j < 3; j++) {
3439 990 : break_point_hit_count_deoptimize = j;
3440 990 : if (j == 2) {
3441 330 : break_point_hit_count_deoptimize = kBreaksPerTest;
3442 : }
3443 :
3444 990 : break_point_hit_count = 0;
3445 990 : max_break_point_hit_count = kBreaksPerTest;
3446 990 : terminate_after_max_break_point_hit = true;
3447 :
3448 : // Function with infinite loop.
3449 990 : CompileRun(buffer.start());
3450 :
3451 : // Set the debug break to enter the debugger as soon as possible.
3452 990 : v8::debug::SetBreakOnNextFunctionCall(CcTest::isolate());
3453 :
3454 : // Call function with infinite loop.
3455 : CompileRun("f();");
3456 990 : CHECK_EQ(kBreaksPerTest, break_point_hit_count);
3457 :
3458 990 : CHECK(!CcTest::isolate()->IsExecutionTerminating());
3459 : }
3460 : }
3461 60 : }
3462 :
3463 : static const char* loop_bodies_1[] = {"",
3464 : "g()",
3465 : "if (a == 0) { g() }",
3466 : "if (a == 1) { g() }",
3467 : "if (a == 0) { g() } else { h() }",
3468 : "if (a == 0) { continue }",
3469 : nullptr};
3470 :
3471 : static const char* loop_bodies_2[] = {
3472 : "if (a == 1) { continue }",
3473 : "switch (a) { case 1: g(); }",
3474 : "switch (a) { case 1: continue; }",
3475 : "switch (a) { case 1: g(); break; default: h() }",
3476 : "switch (a) { case 1: continue; break; default: h() }",
3477 : nullptr};
3478 :
3479 60 : void DebugBreakLoop(const char* loop_header, const char** loop_bodies,
3480 : const char* loop_footer) {
3481 60 : LocalContext env;
3482 120 : v8::HandleScope scope(env->GetIsolate());
3483 :
3484 : // Register a debug event listener which sets the break flag and counts.
3485 60 : DebugEventBreakMax delegate;
3486 60 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3487 :
3488 : CompileRun(
3489 : "var a = 1;\n"
3490 : "function g() { }\n"
3491 : "function h() { }");
3492 :
3493 60 : TestDebugBreakInLoop(loop_header, loop_bodies, loop_footer);
3494 :
3495 : // Get rid of the debug event listener.
3496 60 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3497 60 : CheckDebuggerUnloaded();
3498 60 : }
3499 :
3500 :
3501 25880 : TEST(DebugBreakInWhileTrue1) {
3502 5 : DebugBreakLoop("while (true) {", loop_bodies_1, "}");
3503 5 : }
3504 :
3505 :
3506 25880 : TEST(DebugBreakInWhileTrue2) {
3507 5 : DebugBreakLoop("while (true) {", loop_bodies_2, "}");
3508 5 : }
3509 :
3510 :
3511 25880 : TEST(DebugBreakInWhileCondition1) {
3512 5 : DebugBreakLoop("while (a == 1) {", loop_bodies_1, "}");
3513 5 : }
3514 :
3515 :
3516 25880 : TEST(DebugBreakInWhileCondition2) {
3517 5 : DebugBreakLoop("while (a == 1) {", loop_bodies_2, "}");
3518 5 : }
3519 :
3520 :
3521 25880 : TEST(DebugBreakInDoWhileTrue1) {
3522 5 : DebugBreakLoop("do {", loop_bodies_1, "} while (true)");
3523 5 : }
3524 :
3525 :
3526 25880 : TEST(DebugBreakInDoWhileTrue2) {
3527 5 : DebugBreakLoop("do {", loop_bodies_2, "} while (true)");
3528 5 : }
3529 :
3530 :
3531 25880 : TEST(DebugBreakInDoWhileCondition1) {
3532 5 : DebugBreakLoop("do {", loop_bodies_1, "} while (a == 1)");
3533 5 : }
3534 :
3535 :
3536 25880 : TEST(DebugBreakInDoWhileCondition2) {
3537 5 : DebugBreakLoop("do {", loop_bodies_2, "} while (a == 1)");
3538 5 : }
3539 :
3540 :
3541 25880 : TEST(DebugBreakInFor1) { DebugBreakLoop("for (;;) {", loop_bodies_1, "}"); }
3542 :
3543 :
3544 25880 : TEST(DebugBreakInFor2) { DebugBreakLoop("for (;;) {", loop_bodies_2, "}"); }
3545 :
3546 :
3547 25880 : TEST(DebugBreakInForCondition1) {
3548 5 : DebugBreakLoop("for (;a == 1;) {", loop_bodies_1, "}");
3549 5 : }
3550 :
3551 :
3552 25880 : TEST(DebugBreakInForCondition2) {
3553 5 : DebugBreakLoop("for (;a == 1;) {", loop_bodies_2, "}");
3554 5 : }
3555 :
3556 5 : class DebugBreakInlineListener : public v8::debug::DebugDelegate {
3557 : public:
3558 5 : void BreakProgramRequested(v8::Local<v8::Context> paused_context,
3559 : const std::vector<v8::debug::BreakpointId>&
3560 : inspector_break_points_hit) override {
3561 : int expected_frame_count = 4;
3562 5 : int expected_line_number[] = {1, 4, 7, 12};
3563 :
3564 : int frame_count = 0;
3565 5 : auto iterator = v8::debug::StackTraceIterator::Create(CcTest::isolate());
3566 50 : for (; !iterator->Done(); iterator->Advance(), ++frame_count) {
3567 20 : v8::debug::Location loc = iterator->GetSourceLocation();
3568 20 : CHECK_EQ(expected_line_number[frame_count], loc.GetLineNumber());
3569 : }
3570 5 : CHECK_EQ(frame_count, expected_frame_count);
3571 5 : }
3572 : };
3573 :
3574 25880 : TEST(DebugBreakInline) {
3575 5 : i::FLAG_allow_natives_syntax = true;
3576 5 : LocalContext env;
3577 10 : v8::HandleScope scope(env->GetIsolate());
3578 5 : v8::Local<v8::Context> context = env.local();
3579 : const char* source =
3580 : "function debug(b) { \n"
3581 : " if (b) debugger; \n"
3582 : "} \n"
3583 : "function f(b) { \n"
3584 : " debug(b) \n"
3585 : "}; \n"
3586 : "function g(b) { \n"
3587 : " f(b); \n"
3588 : "}; \n"
3589 : "g(false); \n"
3590 : "g(false); \n"
3591 : "%OptimizeFunctionOnNextCall(g); \n"
3592 : "g(true);";
3593 5 : DebugBreakInlineListener delegate;
3594 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3595 : v8::Local<v8::Script> inline_script =
3596 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), source))
3597 5 : .ToLocalChecked();
3598 5 : inline_script->Run(context).ToLocalChecked();
3599 10 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3600 5 : }
3601 :
3602 5 : static void RunScriptInANewCFrame(const char* source) {
3603 5 : v8::TryCatch try_catch(CcTest::isolate());
3604 : CompileRun(source);
3605 5 : CHECK(try_catch.HasCaught());
3606 5 : }
3607 :
3608 :
3609 25880 : TEST(Regress131642) {
3610 : // Bug description:
3611 : // When doing StepNext through the first script, the debugger is not reset
3612 : // after exiting through exception. A flawed implementation enabling the
3613 : // debugger to step into Array.prototype.forEach breaks inside the callback
3614 : // for forEach in the second script under the assumption that we are in a
3615 : // recursive call. In an attempt to step out, we crawl the stack using the
3616 : // recorded frame pointer from the first script and fail when not finding it
3617 : // on the stack.
3618 5 : LocalContext env;
3619 10 : v8::HandleScope scope(env->GetIsolate());
3620 5 : DebugEventCounter delegate;
3621 : delegate.set_step_action(StepNext);
3622 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3623 :
3624 : // We step through the first script. It exits through an exception. We run
3625 : // this inside a new frame to record a different FP than the second script
3626 : // would expect.
3627 : const char* script_1 = "debugger; throw new Error();";
3628 5 : RunScriptInANewCFrame(script_1);
3629 :
3630 : // The second script uses forEach.
3631 : const char* script_2 = "[0].forEach(function() { });";
3632 : CompileRun(script_2);
3633 :
3634 10 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3635 5 : }
3636 :
3637 5 : class DebugBreakStackTraceListener : public v8::debug::DebugDelegate {
3638 : public:
3639 0 : void BreakProgramRequested(v8::Local<v8::Context> paused_context,
3640 : const std::vector<v8::debug::BreakpointId>&
3641 : inspector_break_points_hit) override {
3642 0 : v8::StackTrace::CurrentStackTrace(CcTest::isolate(), 10);
3643 0 : }
3644 : };
3645 :
3646 5000 : static void AddDebugBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
3647 5000 : v8::debug::SetBreakOnNextFunctionCall(args.GetIsolate());
3648 5000 : }
3649 :
3650 25880 : TEST(DebugBreakStackTrace) {
3651 5 : LocalContext env;
3652 10 : v8::HandleScope scope(env->GetIsolate());
3653 5 : DebugBreakStackTraceListener delegate;
3654 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3655 5 : v8::Local<v8::Context> context = env.local();
3656 : v8::Local<v8::FunctionTemplate> add_debug_break_template =
3657 5 : v8::FunctionTemplate::New(env->GetIsolate(), AddDebugBreak);
3658 : v8::Local<v8::Function> add_debug_break =
3659 5 : add_debug_break_template->GetFunction(context).ToLocalChecked();
3660 20 : CHECK(env->Global()
3661 : ->Set(context, v8_str("add_debug_break"), add_debug_break)
3662 : .FromJust());
3663 :
3664 : CompileRun("(function loop() {"
3665 : " for (var j = 0; j < 1000; j++) {"
3666 : " for (var i = 0; i < 1000; i++) {"
3667 : " if (i == 999) add_debug_break();"
3668 : " }"
3669 : " }"
3670 5 : "})()");
3671 5 : }
3672 :
3673 :
3674 25875 : v8::base::Semaphore terminate_requested_semaphore(0);
3675 25875 : v8::base::Semaphore terminate_fired_semaphore(0);
3676 :
3677 5 : class DebugBreakTriggerTerminate : public v8::debug::DebugDelegate {
3678 : public:
3679 5 : void BreakProgramRequested(v8::Local<v8::Context> paused_context,
3680 : const std::vector<v8::debug::BreakpointId>&
3681 : inspector_break_points_hit) override {
3682 10 : if (terminate_already_fired_) return;
3683 5 : terminate_requested_semaphore.Signal();
3684 : // Wait for at most 2 seconds for the terminate request.
3685 5 : CHECK(
3686 : terminate_fired_semaphore.WaitFor(v8::base::TimeDelta::FromSeconds(2)));
3687 5 : terminate_already_fired_ = true;
3688 : }
3689 :
3690 : private:
3691 : bool terminate_already_fired_ = false;
3692 : };
3693 :
3694 5 : class TerminationThread : public v8::base::Thread {
3695 : public:
3696 : explicit TerminationThread(v8::Isolate* isolate)
3697 5 : : Thread(Options("terminator")), isolate_(isolate) {}
3698 :
3699 5 : void Run() override {
3700 5 : terminate_requested_semaphore.Wait();
3701 5 : isolate_->TerminateExecution();
3702 5 : terminate_fired_semaphore.Signal();
3703 5 : }
3704 :
3705 : private:
3706 : v8::Isolate* isolate_;
3707 : };
3708 :
3709 :
3710 25880 : TEST(DebugBreakOffThreadTerminate) {
3711 5 : LocalContext env;
3712 5 : v8::Isolate* isolate = env->GetIsolate();
3713 10 : v8::HandleScope scope(isolate);
3714 5 : DebugBreakTriggerTerminate delegate;
3715 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
3716 : TerminationThread terminator(isolate);
3717 5 : terminator.Start();
3718 10 : v8::TryCatch try_catch(env->GetIsolate());
3719 5 : env->GetIsolate()->RequestInterrupt(BreakRightNow, nullptr);
3720 : CompileRun("while (true);");
3721 10 : CHECK(try_catch.HasTerminated());
3722 5 : }
3723 :
3724 50 : class ArchiveRestoreThread : public v8::base::Thread,
3725 : public v8::debug::DebugDelegate {
3726 : public:
3727 : ArchiveRestoreThread(v8::Isolate* isolate, int spawn_count)
3728 : : Thread(Options("ArchiveRestoreThread")),
3729 : isolate_(isolate),
3730 25 : debug_(reinterpret_cast<i::Isolate*>(isolate_)->debug()),
3731 : spawn_count_(spawn_count),
3732 75 : break_count_(0) {}
3733 :
3734 25 : void Run() override {
3735 25 : v8::Locker locker(isolate_);
3736 25 : isolate_->Enter();
3737 :
3738 50 : v8::HandleScope scope(isolate_);
3739 25 : v8::Local<v8::Context> context = v8::Context::New(isolate_);
3740 : v8::Context::Scope context_scope(context);
3741 :
3742 : v8::Local<v8::Function> test = CompileFunction(isolate_,
3743 : "function test(n) {\n"
3744 : " debugger;\n"
3745 : " return n + 1;\n"
3746 : "}\n",
3747 25 : "test");
3748 :
3749 25 : debug_->SetDebugDelegate(this);
3750 25 : v8::internal::DisableBreak enable_break(debug_, false);
3751 :
3752 25 : v8::Local<v8::Value> args[1] = {v8::Integer::New(isolate_, spawn_count_)};
3753 :
3754 50 : int result = test->Call(context, context->Global(), 1, args)
3755 25 : .ToLocalChecked()
3756 : ->Int32Value(context)
3757 50 : .FromJust();
3758 :
3759 : // Verify that test(spawn_count_) returned spawn_count_ + 1.
3760 25 : CHECK_EQ(spawn_count_ + 1, result);
3761 :
3762 50 : isolate_->Exit();
3763 25 : }
3764 :
3765 50 : void BreakProgramRequested(
3766 : v8::Local<v8::Context> context,
3767 : const std::vector<v8::debug::BreakpointId>&) override {
3768 50 : auto stack_traces = v8::debug::StackTraceIterator::Create(isolate_);
3769 50 : if (!stack_traces->Done()) {
3770 50 : v8::debug::Location location = stack_traces->GetSourceLocation();
3771 :
3772 : i::PrintF("ArchiveRestoreThread #%d hit breakpoint at line %d\n",
3773 50 : spawn_count_, location.GetLineNumber());
3774 :
3775 50 : switch (location.GetLineNumber()) {
3776 : case 1: // debugger;
3777 25 : CHECK_EQ(break_count_, 0);
3778 :
3779 : // Attempt to stop on the next line after the first debugger
3780 : // statement. If debug->{Archive,Restore}Debug() improperly reset
3781 : // thread-local debug information, the debugger will fail to stop
3782 : // before the test function returns.
3783 25 : debug_->PrepareStep(StepNext);
3784 :
3785 : // Spawning threads while handling the current breakpoint verifies
3786 : // that the parent thread correctly archived and restored the
3787 : // state necessary to stop on the next line. If not, then control
3788 : // will simply continue past the `return n + 1` statement.
3789 25 : MaybeSpawnChildThread();
3790 :
3791 25 : break;
3792 :
3793 : case 2: // return n + 1;
3794 25 : CHECK_EQ(break_count_, 1);
3795 : break;
3796 :
3797 : default:
3798 0 : CHECK(false);
3799 : }
3800 : }
3801 :
3802 50 : ++break_count_;
3803 50 : }
3804 :
3805 25 : void MaybeSpawnChildThread() {
3806 25 : if (spawn_count_ > 1) {
3807 20 : v8::Unlocker unlocker(isolate_);
3808 :
3809 : // Spawn a thread that spawns a thread that spawns a thread (and so
3810 : // on) so that the ThreadManager is forced to archive and restore
3811 : // the current thread.
3812 20 : ArchiveRestoreThread child(isolate_, spawn_count_ - 1);
3813 20 : child.Start();
3814 20 : child.Join();
3815 :
3816 : // The child thread sets itself as the debug delegate, so we need to
3817 : // usurp it after the child finishes, or else future breakpoints
3818 : // will be delegated to a destroyed ArchiveRestoreThread object.
3819 20 : debug_->SetDebugDelegate(this);
3820 :
3821 : // This is the most important check in this test, since
3822 : // child.GetBreakCount() will return 1 if the debugger fails to stop
3823 : // on the `return n + 1` line after the grandchild thread returns.
3824 40 : CHECK_EQ(child.GetBreakCount(), 2);
3825 : }
3826 25 : }
3827 :
3828 : int GetBreakCount() { return break_count_; }
3829 :
3830 : private:
3831 : v8::Isolate* isolate_;
3832 : v8::internal::Debug* debug_;
3833 : const int spawn_count_;
3834 : int break_count_;
3835 : };
3836 :
3837 25880 : TEST(DebugArchiveRestore) {
3838 : v8::Isolate::CreateParams create_params;
3839 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
3840 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
3841 :
3842 : ArchiveRestoreThread thread(isolate, 5);
3843 : // Instead of calling thread.Start() and thread.Join() here, we call
3844 : // thread.Run() directly, to make sure we exercise archive/restore
3845 : // logic on the *current* thread as well as other threads.
3846 5 : thread.Run();
3847 5 : CHECK_EQ(thread.GetBreakCount(), 2);
3848 :
3849 5 : isolate->Dispose();
3850 5 : }
3851 :
3852 5 : class DebugEventExpectNoException : public v8::debug::DebugDelegate {
3853 : public:
3854 0 : void ExceptionThrown(v8::Local<v8::Context> paused_context,
3855 : v8::Local<v8::Value> exception,
3856 : v8::Local<v8::Value> promise, bool is_uncaught,
3857 : v8::debug::ExceptionType) override {
3858 0 : CHECK(false);
3859 : }
3860 : };
3861 :
3862 5 : static void TryCatchWrappedThrowCallback(
3863 5 : const v8::FunctionCallbackInfo<v8::Value>& args) {
3864 5 : v8::TryCatch try_catch(args.GetIsolate());
3865 : CompileRun("throw 'rejection';");
3866 5 : CHECK(try_catch.HasCaught());
3867 5 : }
3868 :
3869 25880 : TEST(DebugPromiseInterceptedByTryCatch) {
3870 5 : LocalContext env;
3871 5 : v8::Isolate* isolate = env->GetIsolate();
3872 10 : v8::HandleScope scope(isolate);
3873 5 : DebugEventExpectNoException delegate;
3874 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
3875 5 : v8::Local<v8::Context> context = env.local();
3876 5 : ChangeBreakOnException(false, true);
3877 :
3878 : v8::Local<v8::FunctionTemplate> fun =
3879 5 : v8::FunctionTemplate::New(isolate, TryCatchWrappedThrowCallback);
3880 25 : CHECK(env->Global()
3881 : ->Set(context, v8_str("fun"),
3882 : fun->GetFunction(context).ToLocalChecked())
3883 : .FromJust());
3884 :
3885 : CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
3886 : CompileRun(
3887 : "var r;"
3888 : "p.then(function() { r = 'resolved'; },"
3889 : " function() { r = 'rejected'; });");
3890 20 : CHECK(CompileRun("r")->Equals(context, v8_str("resolved")).FromJust());
3891 5 : }
3892 :
3893 5 : class NoInterruptsOnDebugEvent : public v8::debug::DebugDelegate {
3894 : public:
3895 5 : void ScriptCompiled(v8::Local<v8::debug::Script> script, bool is_live_edited,
3896 : bool has_compile_error) override {
3897 5 : ++after_compile_handler_depth_;
3898 : // Do not allow nested AfterCompile events.
3899 5 : CHECK_LE(after_compile_handler_depth_, 1);
3900 5 : v8::Isolate* isolate = CcTest::isolate();
3901 5 : v8::Isolate::AllowJavascriptExecutionScope allow_script(isolate);
3902 5 : isolate->RequestInterrupt(&HandleInterrupt, this);
3903 : CompileRun("function foo() {}; foo();");
3904 5 : --after_compile_handler_depth_;
3905 5 : }
3906 :
3907 : private:
3908 5 : static void HandleInterrupt(v8::Isolate* isolate, void* data) {
3909 : NoInterruptsOnDebugEvent* d = static_cast<NoInterruptsOnDebugEvent*>(data);
3910 5 : CHECK_EQ(0, d->after_compile_handler_depth_);
3911 5 : }
3912 :
3913 : int after_compile_handler_depth_ = 0;
3914 : };
3915 :
3916 25880 : TEST(NoInterruptsInDebugListener) {
3917 5 : LocalContext env;
3918 10 : v8::HandleScope handle_scope(env->GetIsolate());
3919 5 : NoInterruptsOnDebugEvent delegate;
3920 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3921 5 : CompileRun("void(0);");
3922 5 : }
3923 :
3924 25880 : TEST(BreakLocationIterator) {
3925 5 : LocalContext env;
3926 5 : v8::Isolate* isolate = env->GetIsolate();
3927 10 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
3928 10 : v8::HandleScope scope(isolate);
3929 :
3930 : v8::Local<v8::Value> result = CompileRun(
3931 : "function f() {\n"
3932 : " debugger; \n"
3933 : " f(); \n"
3934 : " debugger; \n"
3935 : "} \n"
3936 : "f");
3937 5 : Handle<i::Object> function_obj = v8::Utils::OpenHandle(*result);
3938 5 : Handle<i::JSFunction> function = Handle<i::JSFunction>::cast(function_obj);
3939 10 : Handle<i::SharedFunctionInfo> shared(function->shared(), i_isolate);
3940 :
3941 : EnableDebugger(isolate);
3942 5 : CHECK(i_isolate->debug()->EnsureBreakInfo(shared));
3943 5 : i_isolate->debug()->PrepareFunctionForDebugExecution(shared);
3944 :
3945 10 : Handle<i::DebugInfo> debug_info(shared->GetDebugInfo(), i_isolate);
3946 :
3947 : {
3948 5 : i::BreakIterator iterator(debug_info);
3949 5 : CHECK(iterator.GetBreakLocation().IsDebuggerStatement());
3950 5 : CHECK_EQ(17, iterator.GetBreakLocation().position());
3951 5 : iterator.Next();
3952 10 : CHECK(iterator.GetBreakLocation().IsDebugBreakSlot());
3953 5 : CHECK_EQ(32, iterator.GetBreakLocation().position());
3954 5 : iterator.Next();
3955 5 : CHECK(iterator.GetBreakLocation().IsCall());
3956 5 : CHECK_EQ(32, iterator.GetBreakLocation().position());
3957 5 : iterator.Next();
3958 5 : CHECK(iterator.GetBreakLocation().IsDebuggerStatement());
3959 5 : CHECK_EQ(47, iterator.GetBreakLocation().position());
3960 5 : iterator.Next();
3961 5 : CHECK(iterator.GetBreakLocation().IsReturn());
3962 5 : CHECK_EQ(60, iterator.GetBreakLocation().position());
3963 5 : iterator.Next();
3964 5 : CHECK(iterator.Done());
3965 : }
3966 :
3967 5 : DisableDebugger(isolate);
3968 5 : }
3969 :
3970 5 : class DebugStepOverFunctionWithCaughtExceptionListener
3971 : : public v8::debug::DebugDelegate {
3972 : public:
3973 15 : void BreakProgramRequested(v8::Local<v8::Context> paused_context,
3974 : const std::vector<v8::debug::BreakpointId>&
3975 : inspector_break_points_hit) override {
3976 15 : ++break_point_hit_count;
3977 30 : if (break_point_hit_count >= 3) return;
3978 10 : PrepareStep(StepNext);
3979 : }
3980 : int break_point_hit_count = 0;
3981 : };
3982 :
3983 25880 : TEST(DebugStepOverFunctionWithCaughtException) {
3984 5 : i::FLAG_allow_natives_syntax = true;
3985 :
3986 5 : LocalContext env;
3987 5 : v8::Isolate* isolate = env->GetIsolate();
3988 10 : v8::HandleScope scope(isolate);
3989 5 : DebugStepOverFunctionWithCaughtExceptionListener delegate;
3990 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
3991 :
3992 : CompileRun(
3993 : "function foo() {\n"
3994 : " try { throw new Error(); } catch (e) {}\n"
3995 : "}\n"
3996 : "debugger;\n"
3997 : "foo();\n"
3998 : "foo();\n");
3999 :
4000 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
4001 10 : CHECK_EQ(3, delegate.break_point_hit_count);
4002 5 : }
4003 :
4004 : bool near_heap_limit_callback_called = false;
4005 5 : size_t NearHeapLimitCallback(void* data, size_t current_heap_limit,
4006 : size_t initial_heap_limit) {
4007 5 : near_heap_limit_callback_called = true;
4008 5 : return initial_heap_limit + 10u * i::MB;
4009 : }
4010 :
4011 25880 : UNINITIALIZED_TEST(DebugSetOutOfMemoryListener) {
4012 : v8::Isolate::CreateParams create_params;
4013 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
4014 : create_params.constraints.set_max_old_space_size(10);
4015 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
4016 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
4017 : {
4018 : v8::Isolate::Scope i_scope(isolate);
4019 10 : v8::HandleScope scope(isolate);
4020 5 : LocalContext context(isolate);
4021 5 : isolate->AddNearHeapLimitCallback(NearHeapLimitCallback, nullptr);
4022 5 : CHECK(!near_heap_limit_callback_called);
4023 : // The following allocation fails unless the out-of-memory callback
4024 : // increases the heap limit.
4025 : int length = 10 * i::MB / i::kTaggedSize;
4026 5 : i_isolate->factory()->NewFixedArray(length, i::TENURED);
4027 5 : CHECK(near_heap_limit_callback_called);
4028 5 : isolate->RemoveNearHeapLimitCallback(NearHeapLimitCallback, 0);
4029 : }
4030 5 : isolate->Dispose();
4031 5 : }
4032 :
4033 25880 : TEST(DebugCoverage) {
4034 : // Coverage needs feedback vectors.
4035 5 : if (i::FLAG_lite_mode) return;
4036 5 : i::FLAG_always_opt = false;
4037 5 : LocalContext env;
4038 5 : v8::Isolate* isolate = env->GetIsolate();
4039 10 : v8::HandleScope scope(isolate);
4040 5 : v8::debug::Coverage::SelectMode(isolate, v8::debug::Coverage::kPreciseCount);
4041 : v8::Local<v8::String> source = v8_str(
4042 : "function f() {\n"
4043 : "}\n"
4044 : "f();\n"
4045 5 : "f();");
4046 5 : CompileRun(source);
4047 5 : v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(isolate);
4048 5 : CHECK_EQ(1u, coverage.ScriptCount());
4049 5 : v8::debug::Coverage::ScriptData script_data = coverage.GetScriptData(0);
4050 5 : v8::Local<v8::debug::Script> script = script_data.GetScript();
4051 15 : CHECK(script->Source()
4052 : .ToLocalChecked()
4053 : ->Equals(env.local(), source)
4054 : .FromMaybe(false));
4055 :
4056 5 : CHECK_EQ(2u, script_data.FunctionCount());
4057 : v8::debug::Coverage::FunctionData function_data =
4058 5 : script_data.GetFunctionData(0);
4059 : v8::debug::Location start =
4060 5 : script->GetSourceLocation(function_data.StartOffset());
4061 : v8::debug::Location end =
4062 5 : script->GetSourceLocation(function_data.EndOffset());
4063 5 : CHECK_EQ(0, start.GetLineNumber());
4064 5 : CHECK_EQ(0, start.GetColumnNumber());
4065 5 : CHECK_EQ(3, end.GetLineNumber());
4066 5 : CHECK_EQ(4, end.GetColumnNumber());
4067 5 : CHECK_EQ(1, function_data.Count());
4068 :
4069 10 : function_data = script_data.GetFunctionData(1);
4070 5 : start = script->GetSourceLocation(function_data.StartOffset());
4071 5 : end = script->GetSourceLocation(function_data.EndOffset());
4072 5 : CHECK_EQ(0, start.GetLineNumber());
4073 5 : CHECK_EQ(0, start.GetColumnNumber());
4074 5 : CHECK_EQ(1, end.GetLineNumber());
4075 5 : CHECK_EQ(1, end.GetColumnNumber());
4076 10 : CHECK_EQ(2, function_data.Count());
4077 : }
4078 :
4079 : namespace {
4080 5 : v8::debug::Coverage::ScriptData GetScriptDataAndDeleteCoverage(
4081 : v8::Isolate* isolate) {
4082 5 : v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(isolate);
4083 5 : CHECK_EQ(1u, coverage.ScriptCount());
4084 10 : return coverage.GetScriptData(0);
4085 : }
4086 : } // namespace
4087 :
4088 25880 : TEST(DebugCoverageWithCoverageOutOfScope) {
4089 : // Coverage needs feedback vectors.
4090 5 : if (i::FLAG_lite_mode) return;
4091 5 : i::FLAG_always_opt = false;
4092 5 : LocalContext env;
4093 5 : v8::Isolate* isolate = env->GetIsolate();
4094 10 : v8::HandleScope scope(isolate);
4095 5 : v8::debug::Coverage::SelectMode(isolate, v8::debug::Coverage::kPreciseCount);
4096 : v8::Local<v8::String> source = v8_str(
4097 : "function f() {\n"
4098 : "}\n"
4099 : "f();\n"
4100 5 : "f();");
4101 5 : CompileRun(source);
4102 : v8::debug::Coverage::ScriptData script_data =
4103 5 : GetScriptDataAndDeleteCoverage(isolate);
4104 5 : v8::Local<v8::debug::Script> script = script_data.GetScript();
4105 15 : CHECK(script->Source()
4106 : .ToLocalChecked()
4107 : ->Equals(env.local(), source)
4108 : .FromMaybe(false));
4109 :
4110 5 : CHECK_EQ(2u, script_data.FunctionCount());
4111 : v8::debug::Coverage::FunctionData function_data =
4112 5 : script_data.GetFunctionData(0);
4113 :
4114 5 : CHECK_EQ(0, function_data.StartOffset());
4115 5 : CHECK_EQ(26, function_data.EndOffset());
4116 :
4117 : v8::debug::Location start =
4118 5 : script->GetSourceLocation(function_data.StartOffset());
4119 : v8::debug::Location end =
4120 5 : script->GetSourceLocation(function_data.EndOffset());
4121 5 : CHECK_EQ(0, start.GetLineNumber());
4122 5 : CHECK_EQ(0, start.GetColumnNumber());
4123 5 : CHECK_EQ(3, end.GetLineNumber());
4124 5 : CHECK_EQ(4, end.GetColumnNumber());
4125 5 : CHECK_EQ(1, function_data.Count());
4126 :
4127 10 : function_data = script_data.GetFunctionData(1);
4128 5 : start = script->GetSourceLocation(function_data.StartOffset());
4129 5 : end = script->GetSourceLocation(function_data.EndOffset());
4130 :
4131 5 : CHECK_EQ(0, function_data.StartOffset());
4132 5 : CHECK_EQ(16, function_data.EndOffset());
4133 :
4134 5 : CHECK_EQ(0, start.GetLineNumber());
4135 5 : CHECK_EQ(0, start.GetColumnNumber());
4136 5 : CHECK_EQ(1, end.GetLineNumber());
4137 5 : CHECK_EQ(1, end.GetColumnNumber());
4138 10 : CHECK_EQ(2, function_data.Count());
4139 : }
4140 :
4141 : namespace {
4142 5 : v8::debug::Coverage::FunctionData GetFunctionDataAndDeleteCoverage(
4143 : v8::Isolate* isolate) {
4144 5 : v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(isolate);
4145 5 : CHECK_EQ(1u, coverage.ScriptCount());
4146 :
4147 5 : v8::debug::Coverage::ScriptData script_data = coverage.GetScriptData(0);
4148 :
4149 5 : CHECK_EQ(2u, script_data.FunctionCount());
4150 : v8::debug::Coverage::FunctionData function_data =
4151 5 : script_data.GetFunctionData(0);
4152 5 : CHECK_EQ(1, function_data.Count());
4153 5 : CHECK_EQ(0, function_data.StartOffset());
4154 5 : CHECK_EQ(26, function_data.EndOffset());
4155 5 : return function_data;
4156 : }
4157 : } // namespace
4158 :
4159 25880 : TEST(DebugCoverageWithScriptDataOutOfScope) {
4160 : // Coverage needs feedback vectors.
4161 5 : if (i::FLAG_lite_mode) return;
4162 5 : i::FLAG_always_opt = false;
4163 5 : LocalContext env;
4164 5 : v8::Isolate* isolate = env->GetIsolate();
4165 10 : v8::HandleScope scope(isolate);
4166 5 : v8::debug::Coverage::SelectMode(isolate, v8::debug::Coverage::kPreciseCount);
4167 : v8::Local<v8::String> source = v8_str(
4168 : "function f() {\n"
4169 : "}\n"
4170 : "f();\n"
4171 5 : "f();");
4172 5 : CompileRun(source);
4173 :
4174 : v8::debug::Coverage::FunctionData function_data =
4175 5 : GetFunctionDataAndDeleteCoverage(isolate);
4176 5 : CHECK_EQ(1, function_data.Count());
4177 5 : CHECK_EQ(0, function_data.StartOffset());
4178 10 : CHECK_EQ(26, function_data.EndOffset());
4179 : }
4180 :
4181 25880 : TEST(BuiltinsExceptionPrediction) {
4182 5 : v8::Isolate* isolate = CcTest::isolate();
4183 : i::Isolate* iisolate = CcTest::i_isolate();
4184 5 : v8::HandleScope handle_scope(isolate);
4185 5 : v8::Context::New(isolate);
4186 :
4187 5 : i::Builtins* builtins = iisolate->builtins();
4188 : bool fail = false;
4189 7530 : for (int i = 0; i < i::Builtins::builtin_count; i++) {
4190 7525 : i::Code builtin = builtins->builtin(i);
4191 9895 : if (builtin->kind() != i::Code::BUILTIN) continue;
4192 5155 : auto prediction = builtin->GetBuiltinCatchPrediction();
4193 : USE(prediction);
4194 : }
4195 5 : CHECK(!fail);
4196 5 : }
4197 :
4198 25880 : TEST(DebugGetPossibleBreakpointsReturnLocations) {
4199 5 : LocalContext env;
4200 5 : v8::Isolate* isolate = env->GetIsolate();
4201 10 : v8::HandleScope scope(isolate);
4202 : v8::Local<v8::String> source = v8_str(
4203 : "function fib(x) {\n"
4204 : " if (x < 0) return;\n"
4205 : " if (x === 0) return 1;\n"
4206 : " if (x === 1) return fib(0);\n"
4207 : " return x > 2 ? fib(x - 1) + fib(x - 2) : fib(1) + fib(0);\n"
4208 5 : "}");
4209 5 : CompileRun(source);
4210 5 : v8::PersistentValueVector<v8::debug::Script> scripts(isolate);
4211 5 : v8::debug::GetLoadedScripts(isolate, scripts);
4212 5 : CHECK_EQ(scripts.Size(), 1);
4213 : std::vector<v8::debug::BreakLocation> locations;
4214 10 : CHECK(scripts.Get(0)->GetPossibleBreakpoints(
4215 : v8::debug::Location(0, 17), v8::debug::Location(), true, &locations));
4216 : int returns_count = 0;
4217 165 : for (size_t i = 0; i < locations.size(); ++i) {
4218 80 : if (locations[i].type() == v8::debug::kReturnBreakLocation) {
4219 20 : ++returns_count;
4220 : }
4221 : }
4222 : // With Ignition we generate one return location per return statement,
4223 : // each has line = 5, column = 0 as statement position.
4224 10 : CHECK_EQ(returns_count, 4);
4225 5 : }
4226 :
4227 25880 : TEST(DebugEvaluateNoSideEffect) {
4228 5 : LocalContext env;
4229 10 : v8::HandleScope scope(env->GetIsolate());
4230 5 : EnableDebugger(env->GetIsolate());
4231 5 : i::Isolate* isolate = CcTest::i_isolate();
4232 : std::vector<i::Handle<i::JSFunction>> all_functions;
4233 : {
4234 9419 : i::HeapIterator iterator(isolate->heap());
4235 68744 : for (i::HeapObject obj = iterator.next(); !obj.is_null();
4236 : obj = iterator.next()) {
4237 65596 : if (!obj->IsJSFunction()) continue;
4238 3138 : i::JSFunction fun = i::JSFunction::cast(obj);
4239 3138 : all_functions.emplace_back(fun, isolate);
4240 5 : }
4241 : }
4242 :
4243 : // Perform side effect check on all built-in functions. The side effect check
4244 : // itself contains additional sanity checks.
4245 3148 : for (i::Handle<i::JSFunction> fun : all_functions) {
4246 : bool failed = false;
4247 6276 : isolate->debug()->StartSideEffectCheckMode();
4248 : failed = !isolate->debug()->PerformSideEffectCheck(
4249 9414 : fun, v8::Utils::OpenHandle(*env->Global()));
4250 6276 : isolate->debug()->StopSideEffectCheckMode();
4251 3138 : if (failed) isolate->clear_pending_exception();
4252 : }
4253 10 : DisableDebugger(env->GetIsolate());
4254 5 : }
4255 :
4256 : namespace {
4257 10 : i::MaybeHandle<i::Script> FindScript(
4258 : i::Isolate* isolate, const std::vector<i::Handle<i::Script>>& scripts,
4259 : const char* name) {
4260 : Handle<i::String> i_name =
4261 10 : isolate->factory()->NewStringFromAsciiChecked(name);
4262 35 : for (const auto& script : scripts) {
4263 50 : if (!script->name()->IsString()) continue;
4264 25 : if (i_name->Equals(i::String::cast(script->name()))) return script;
4265 : }
4266 0 : return i::MaybeHandle<i::Script>();
4267 : }
4268 : } // anonymous namespace
4269 :
4270 25880 : UNINITIALIZED_TEST(LoadedAtStartupScripts) {
4271 5 : i::FLAG_expose_gc = true;
4272 :
4273 : v8::Isolate::CreateParams create_params;
4274 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
4275 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
4276 5 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
4277 : {
4278 : v8::Isolate::Scope i_scope(isolate);
4279 10 : v8::HandleScope scope(isolate);
4280 5 : LocalContext context(isolate);
4281 :
4282 : std::vector<i::Handle<i::Script>> scripts;
4283 5 : CompileWithOrigin(v8_str("function foo(){}"), v8_str("normal.js"));
4284 5 : std::unordered_map<int, int> count_by_type;
4285 : {
4286 : i::DisallowHeapAllocation no_gc;
4287 5 : i::Script::Iterator iterator(i_isolate);
4288 60 : for (i::Script script = iterator.Next(); !script.is_null();
4289 : script = iterator.Next()) {
4290 75 : if (script->type() == i::Script::TYPE_NATIVE &&
4291 55 : script->name()->IsUndefined(i_isolate)) {
4292 : continue;
4293 : }
4294 30 : ++count_by_type[script->type()];
4295 15 : scripts.emplace_back(script, i_isolate);
4296 : }
4297 : }
4298 10 : CHECK_EQ(count_by_type[i::Script::TYPE_NATIVE], 0);
4299 10 : CHECK_EQ(count_by_type[i::Script::TYPE_EXTENSION], 2);
4300 10 : CHECK_EQ(count_by_type[i::Script::TYPE_NORMAL], 1);
4301 10 : CHECK_EQ(count_by_type[i::Script::TYPE_WASM], 0);
4302 10 : CHECK_EQ(count_by_type[i::Script::TYPE_INSPECTOR], 0);
4303 :
4304 : i::Handle<i::Script> gc_script =
4305 10 : FindScript(i_isolate, scripts, "v8/gc").ToHandleChecked();
4306 5 : CHECK_EQ(gc_script->type(), i::Script::TYPE_EXTENSION);
4307 :
4308 : i::Handle<i::Script> normal_script =
4309 10 : FindScript(i_isolate, scripts, "normal.js").ToHandleChecked();
4310 5 : CHECK_EQ(normal_script->type(), i::Script::TYPE_NORMAL);
4311 : }
4312 5 : isolate->Dispose();
4313 5 : }
4314 :
4315 25880 : TEST(SourceInfo) {
4316 5 : LocalContext env;
4317 10 : v8::HandleScope scope(env->GetIsolate());
4318 : const char* source =
4319 : "//\n"
4320 : "function a() { b(); };\n"
4321 : "function b() {\n"
4322 : " c(true);\n"
4323 : "};\n"
4324 : " function c(x) {\n"
4325 : " if (x) {\n"
4326 : " return 1;\n"
4327 : " } else {\n"
4328 : " return 1;\n"
4329 : " }\n"
4330 : " };\n"
4331 : "function d(x) {\n"
4332 : " x = 1 ;\n"
4333 : " x = 2 ;\n"
4334 : " x = 3 ;\n"
4335 : " x = 4 ;\n"
4336 : " x = 5 ;\n"
4337 : " x = 6 ;\n"
4338 : " x = 7 ;\n"
4339 : " x = 8 ;\n"
4340 : " x = 9 ;\n"
4341 : " x = 10;\n"
4342 : " x = 11;\n"
4343 : " x = 12;\n"
4344 : " x = 13;\n"
4345 : " x = 14;\n"
4346 : " x = 15;\n"
4347 : "}\n";
4348 : v8::Local<v8::Script> v8_script =
4349 5 : v8::Script::Compile(env.local(), v8_str(source)).ToLocalChecked();
4350 : i::Handle<i::Script> i_script(
4351 10 : i::Script::cast(v8::Utils::OpenHandle(*v8_script)->shared()->script()),
4352 10 : CcTest::i_isolate());
4353 : v8::Local<v8::debug::Script> script =
4354 : v8::ToApiHandle<v8::debug::Script>(i_script);
4355 :
4356 : // Test that when running through source positions the position, line and
4357 : // column progresses as expected.
4358 5 : v8::debug::Location prev_location = script->GetSourceLocation(0);
4359 5 : CHECK_EQ(prev_location.GetLineNumber(), 0);
4360 5 : CHECK_EQ(prev_location.GetColumnNumber(), 0);
4361 495 : for (int offset = 1; offset < 100; ++offset) {
4362 495 : v8::debug::Location location = script->GetSourceLocation(offset);
4363 495 : if (prev_location.GetLineNumber() == location.GetLineNumber()) {
4364 460 : CHECK_EQ(location.GetColumnNumber(), prev_location.GetColumnNumber() + 1);
4365 : } else {
4366 35 : CHECK_EQ(location.GetLineNumber(), prev_location.GetLineNumber() + 1);
4367 35 : CHECK_EQ(location.GetColumnNumber(), 0);
4368 : }
4369 495 : prev_location = location;
4370 : }
4371 :
4372 : // Every line of d() is the same length. Verify we can loop through all
4373 : // positions and find the right line # for each.
4374 : // The position of the first line of d(), i.e. "x = 1 ;".
4375 : const int start_line_d = 13;
4376 : const int start_code_d =
4377 : static_cast<int>(strstr(source, " x = 1 ;") - source);
4378 : const int num_lines_d = 15;
4379 : const int line_length_d = 10;
4380 : int p = start_code_d;
4381 75 : for (int line = 0; line < num_lines_d; ++line) {
4382 750 : for (int column = 0; column < line_length_d; ++column) {
4383 750 : v8::debug::Location location = script->GetSourceLocation(p);
4384 750 : CHECK_EQ(location.GetLineNumber(), start_line_d + line);
4385 750 : CHECK_EQ(location.GetColumnNumber(), column);
4386 750 : ++p;
4387 : }
4388 : }
4389 :
4390 : // Test first positon.
4391 5 : CHECK_EQ(script->GetSourceLocation(0).GetLineNumber(), 0);
4392 5 : CHECK_EQ(script->GetSourceLocation(0).GetColumnNumber(), 0);
4393 :
4394 : // Test second positon.
4395 5 : CHECK_EQ(script->GetSourceLocation(1).GetLineNumber(), 0);
4396 5 : CHECK_EQ(script->GetSourceLocation(1).GetColumnNumber(), 1);
4397 :
4398 : // Test first positin in function a().
4399 : const int start_a =
4400 : static_cast<int>(strstr(source, "function a") - source) + 10;
4401 5 : CHECK_EQ(script->GetSourceLocation(start_a).GetLineNumber(), 1);
4402 5 : CHECK_EQ(script->GetSourceLocation(start_a).GetColumnNumber(), 10);
4403 :
4404 : // Test first positin in function b().
4405 : const int start_b =
4406 : static_cast<int>(strstr(source, "function b") - source) + 13;
4407 5 : CHECK_EQ(script->GetSourceLocation(start_b).GetLineNumber(), 2);
4408 5 : CHECK_EQ(script->GetSourceLocation(start_b).GetColumnNumber(), 13);
4409 :
4410 : // Test first positin in function c().
4411 : const int start_c =
4412 : static_cast<int>(strstr(source, "function c") - source) + 10;
4413 5 : CHECK_EQ(script->GetSourceLocation(start_c).GetLineNumber(), 5);
4414 5 : CHECK_EQ(script->GetSourceLocation(start_c).GetColumnNumber(), 12);
4415 :
4416 : // Test first positin in function d().
4417 : const int start_d =
4418 : static_cast<int>(strstr(source, "function d") - source) + 10;
4419 5 : CHECK_EQ(script->GetSourceLocation(start_d).GetLineNumber(), 12);
4420 5 : CHECK_EQ(script->GetSourceLocation(start_d).GetColumnNumber(), 10);
4421 :
4422 : // Test offsets.
4423 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(1, 10)), start_a);
4424 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(2, 13)), start_b);
4425 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(3, 0)), start_b + 5);
4426 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(3, 2)), start_b + 7);
4427 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(4, 0)), start_b + 16);
4428 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(5, 12)), start_c);
4429 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(6, 0)), start_c + 6);
4430 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(7, 0)), start_c + 19);
4431 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(8, 0)), start_c + 35);
4432 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(9, 0)), start_c + 48);
4433 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(10, 0)), start_c + 64);
4434 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(11, 0)), start_c + 70);
4435 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(12, 10)), start_d);
4436 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(13, 0)), start_d + 6);
4437 75 : for (int i = 1; i <= num_lines_d; ++i) {
4438 75 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(start_line_d + i, 0)),
4439 : 6 + (i * line_length_d) + start_d);
4440 : }
4441 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(start_line_d + 17, 0)),
4442 : start_d + 158);
4443 :
4444 : // Make sure invalid inputs work properly.
4445 : const int last_position = static_cast<int>(strlen(source)) - 1;
4446 5 : CHECK_EQ(script->GetSourceLocation(-1).GetLineNumber(), 0);
4447 5 : CHECK_EQ(script->GetSourceLocation(last_position + 2).GetLineNumber(),
4448 : i::kNoSourcePosition);
4449 :
4450 : // Test last position.
4451 5 : CHECK_EQ(script->GetSourceLocation(last_position).GetLineNumber(), 28);
4452 5 : CHECK_EQ(script->GetSourceLocation(last_position).GetColumnNumber(), 1);
4453 5 : CHECK_EQ(script->GetSourceLocation(last_position + 1).GetLineNumber(), 29);
4454 10 : CHECK_EQ(script->GetSourceLocation(last_position + 1).GetColumnNumber(), 0);
4455 5 : }
4456 :
4457 : namespace {
4458 10 : class SetBreakpointOnScriptCompiled : public v8::debug::DebugDelegate {
4459 : public:
4460 15 : void ScriptCompiled(v8::Local<v8::debug::Script> script, bool is_live_edited,
4461 : bool has_compile_error) override {
4462 : v8::Local<v8::String> name;
4463 40 : if (!script->SourceURL().ToLocal(&name)) return;
4464 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
4465 15 : if (!name->Equals(context, v8_str("test")).FromJust()) return;
4466 5 : CHECK(!has_compile_error);
4467 5 : v8::debug::Location loc(1, 2);
4468 5 : CHECK(script->SetBreakpoint(v8_str(""), &loc, &id_));
4469 5 : CHECK_EQ(loc.GetLineNumber(), 1);
4470 5 : CHECK_EQ(loc.GetColumnNumber(), 10);
4471 : }
4472 :
4473 5 : void BreakProgramRequested(v8::Local<v8::Context> paused_context,
4474 : const std::vector<v8::debug::BreakpointId>&
4475 5 : inspector_break_points_hit) override {
4476 5 : ++break_count_;
4477 10 : CHECK_EQ(inspector_break_points_hit[0], id_);
4478 5 : }
4479 :
4480 : int break_count() const { return break_count_; }
4481 :
4482 : private:
4483 : int break_count_ = 0;
4484 : v8::debug::BreakpointId id_;
4485 : };
4486 : } // anonymous namespace
4487 :
4488 25880 : TEST(Regress517592) {
4489 5 : LocalContext env;
4490 10 : v8::HandleScope handle_scope(env->GetIsolate());
4491 : SetBreakpointOnScriptCompiled delegate;
4492 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
4493 : CompileRun(
4494 : v8_str("eval('var foo = function foo() {\\n' +\n"
4495 : "' var a = 1;\\n' +\n"
4496 : "'}\\n' +\n"
4497 5 : "'//@ sourceURL=test')"));
4498 5 : CHECK_EQ(delegate.break_count(), 0);
4499 5 : CompileRun(v8_str("foo()"));
4500 5 : CHECK_EQ(delegate.break_count(), 1);
4501 10 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
4502 77630 : }
|