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 : 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 : Handle<v8::internal::JSFunction>::cast(v8::Utils::OpenHandle(*fun));
76 : 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 : i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*fun));
87 350 : position += function->shared()->StartPosition();
88 : static int break_point_index = 0;
89 : 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 : static void ClearBreakPoint(i::Handle<i::BreakPoint> break_point) {
103 : v8::internal::Isolate* isolate = CcTest::i_isolate();
104 : v8::internal::Debug* debug = isolate->debug();
105 175 : debug->ClearBreakPoint(break_point);
106 : }
107 :
108 :
109 : // Change break on exception.
110 15 : static void ChangeBreakOnException(bool caught, bool uncaught) {
111 : 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 : static void PrepareStep(i::StepAction step_action) {
119 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
120 11980 : debug->PrepareStep(step_action);
121 : }
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 : Debug* debug = CcTest::i_isolate()->debug();
131 :
132 25 : v8::internal::DebugInfoListNode* node = debug->debug_info_list_;
133 :
134 : // Find the number of debugged functions.
135 : int count = 0;
136 65 : 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 25 : 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 820 : HeapIterator iterator(CcTest::heap());
168 5633160 : for (HeapObject obj = iterator.next(); !obj.is_null();
169 : obj = iterator.next()) {
170 2816170 : CHECK(!obj->IsDebugInfo());
171 : }
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 570 : class DebugEventCounter : public v8::debug::DebugDelegate {
191 : public:
192 12775 : void BreakProgramRequested(
193 : v8::Local<v8::Context>,
194 : const std::vector<v8::debug::BreakpointId>&) override {
195 12775 : break_point_hit_count++;
196 : // Perform a full deoptimization when the specified number of
197 : // breaks have been hit.
198 12775 : if (break_point_hit_count == break_point_hit_count_deoptimize) {
199 0 : i::Deoptimizer::DeoptimizeAll(CcTest::i_isolate());
200 : }
201 12775 : if (step_action_ != StepNone) PrepareStep(step_action_);
202 12775 : }
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 30 : 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 20 : 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 130 : 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 26661 : 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 : 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 : ClearBreakPoint(bp2);
320 5 : DisableDebugger(env->GetIsolate());
321 10 : CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
322 5 : CHECK(!HasBreakInfo(foo));
323 5 : CHECK(!HasBreakInfo(bar));
324 5 : }
325 :
326 :
327 : // Test that a break point can be set at an IC store location.
328 26661 : 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 : 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 : 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 : CheckDebuggerUnloaded();
356 5 : }
357 :
358 : // Test that a break point can be set at an IC store location.
359 26661 : 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 : ClearBreakPoint(bp);
384 : CompileRun("foo()");
385 5 : CHECK_EQ(1, break_point_hit_count);
386 :
387 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
388 : CheckDebuggerUnloaded();
389 5 : }
390 :
391 : // Test that a break point can be set at an IC load location.
392 26661 : 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 : 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 : 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 : CheckDebuggerUnloaded();
421 5 : }
422 :
423 :
424 : // Test that a break point can be set at an IC call location.
425 26661 : 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 : 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 : 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 : CheckDebuggerUnloaded();
453 5 : }
454 :
455 :
456 : // Test that a break point can be set at an IC call location and survive a GC.
457 26661 : 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 : 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 : 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 : CheckDebuggerUnloaded();
495 5 : }
496 :
497 :
498 : // Test that a break point can be set at an IC call location and survive a GC.
499 26661 : 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 : 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 : 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 : CheckDebuggerUnloaded();
537 5 : }
538 :
539 :
540 26661 : 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 : 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 : CheckDebuggerUnloaded();
569 5 : }
570 :
571 26661 : 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 : 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 : CheckDebuggerUnloaded();
600 5 : }
601 :
602 26661 : 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 : 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 : CheckDebuggerUnloaded();
633 5 : }
634 :
635 26661 : 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 : 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 : 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 : 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 : CheckDebuggerUnloaded();
695 5 : }
696 :
697 26661 : 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 : 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 : CheckDebuggerUnloaded();
736 5 : }
737 :
738 26661 : 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 : 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 : CheckDebuggerUnloaded();
781 5 : }
782 :
783 26661 : 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 : 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 : CheckDebuggerUnloaded();
823 5 : }
824 :
825 26661 : 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 : 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 : CheckDebuggerUnloaded();
863 5 : }
864 :
865 26661 : 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 : 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 : CheckDebuggerUnloaded();
904 5 : }
905 :
906 26661 : 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 10 : 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 : ClearBreakPoint(bp);
941 : CompileRun("'b'.repeat(10)");
942 5 : CHECK_EQ(2, break_point_hit_count);
943 : }
944 : #endif
945 :
946 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
947 : CheckDebuggerUnloaded();
948 5 : }
949 :
950 415 : void NoOpFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
951 415 : args.GetReturnValue().Set(v8_num(2));
952 415 : }
953 :
954 26661 : 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 5 : function_template->GetFunction(env.local()).ToLocalChecked();
968 :
969 20 : 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 : 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 : CheckDebuggerUnloaded();
989 5 : }
990 :
991 10 : void GetWrapperCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
992 : args.GetReturnValue().Set(
993 : args[0]
994 : .As<v8::Object>()
995 20 : ->Get(args.GetIsolate()->GetCurrentContext(), args[1])
996 : .ToLocalChecked());
997 10 : }
998 :
999 26661 : 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 5 : function_template->GetFunction(env.local()).ToLocalChecked();
1015 : v8::Local<v8::Function> get =
1016 5 : get_template->GetFunction(env.local()).ToLocalChecked();
1017 :
1018 20 : env->Global()->Set(env.local(), v8_str("f"), function).ToChecked();
1019 20 : 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 : 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 : CheckDebuggerUnloaded();
1042 5 : }
1043 :
1044 20 : 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 26661 : 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 5 : function_template->GetFunction(env.local()).ToLocalChecked();
1067 : v8::Local<v8::Function> set =
1068 5 : set_template->GetFunction(env.local()).ToLocalChecked();
1069 :
1070 20 : env->Global()->Set(env.local(), v8_str("f"), function).ToChecked();
1071 20 : 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 : 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 : 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 : CheckDebuggerUnloaded();
1115 5 : }
1116 :
1117 26661 : 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 10 : obj_template->SetAccessorProperty(v8_str("f"), accessor_template,
1132 5 : accessor_template);
1133 : v8::Local<v8::Object> obj =
1134 5 : obj_template->NewInstance(env.local()).ToLocalChecked();
1135 20 : 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 : // Test that the break point also works when we install the function
1171 : // template on a new property (with a fresh AccessorPair instance).
1172 : v8::Local<v8::ObjectTemplate> baz_template =
1173 5 : v8::ObjectTemplate::New(env->GetIsolate());
1174 10 : baz_template->SetAccessorProperty(v8_str("g"), accessor_template,
1175 5 : accessor_template);
1176 : v8::Local<v8::Object> baz =
1177 5 : baz_template->NewInstance(env.local()).ToLocalChecked();
1178 20 : env->Global()->Set(env.local(), v8_str("b"), baz).ToChecked();
1179 :
1180 : CompileRun("b.g = 4");
1181 5 : CHECK_EQ(43, break_point_hit_count);
1182 :
1183 : CompileRun("b.g");
1184 5 : CHECK_EQ(44, break_point_hit_count);
1185 :
1186 : // Run without breakpoints.
1187 : ClearBreakPoint(bp);
1188 : CompileRun("o.f = 3");
1189 : CompileRun("o.f");
1190 5 : CHECK_EQ(44, break_point_hit_count);
1191 :
1192 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1193 : CheckDebuggerUnloaded();
1194 5 : }
1195 :
1196 26661 : TEST(BreakPointInlineApiFunction) {
1197 5 : i::FLAG_allow_natives_syntax = true;
1198 5 : LocalContext env;
1199 10 : v8::HandleScope scope(env->GetIsolate());
1200 :
1201 5 : DebugEventCounter delegate;
1202 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1203 :
1204 : i::Handle<i::BreakPoint> bp;
1205 :
1206 : v8::Local<v8::FunctionTemplate> function_template =
1207 5 : v8::FunctionTemplate::New(env->GetIsolate(), NoOpFunctionCallback);
1208 :
1209 : v8::Local<v8::Function> function =
1210 5 : function_template->GetFunction(env.local()).ToLocalChecked();
1211 :
1212 20 : env->Global()->Set(env.local(), v8_str("f"), function).ToChecked();
1213 : CompileRun("function g() { return 1 + f(); }");
1214 :
1215 : // === Test simple builtin ===
1216 5 : break_point_hit_count = 0;
1217 :
1218 : // Run with breakpoint.
1219 5 : bp = SetBreakPoint(function, 0);
1220 5 : ExpectInt32("g()", 3);
1221 5 : CHECK_EQ(1, break_point_hit_count);
1222 :
1223 5 : ExpectInt32("g()", 3);
1224 5 : CHECK_EQ(2, break_point_hit_count);
1225 :
1226 : CompileRun("%OptimizeFunctionOnNextCall(g)");
1227 5 : ExpectInt32("g()", 3);
1228 5 : CHECK_EQ(3, break_point_hit_count);
1229 :
1230 : // Run without breakpoints.
1231 : ClearBreakPoint(bp);
1232 5 : ExpectInt32("g()", 3);
1233 5 : CHECK_EQ(3, break_point_hit_count);
1234 :
1235 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1236 : CheckDebuggerUnloaded();
1237 5 : }
1238 :
1239 : // Test that a break point can be set at a return store location.
1240 26661 : TEST(BreakPointConditionBuiltin) {
1241 5 : i::FLAG_allow_natives_syntax = true;
1242 5 : i::FLAG_block_concurrent_recompilation = true;
1243 5 : LocalContext env;
1244 10 : v8::HandleScope scope(env->GetIsolate());
1245 :
1246 5 : DebugEventCounter delegate;
1247 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1248 : v8::Local<v8::Function> builtin;
1249 : i::Handle<i::BreakPoint> bp;
1250 :
1251 : // === Test global variable ===
1252 5 : break_point_hit_count = 0;
1253 5 : builtin = CompileRun("String.prototype.repeat").As<v8::Function>();
1254 : CompileRun("var condition = false");
1255 : CompileRun("'a'.repeat(10)");
1256 5 : CHECK_EQ(0, break_point_hit_count);
1257 :
1258 : // Run with breakpoint.
1259 5 : bp = SetBreakPoint(builtin, 0, "condition == true");
1260 : CompileRun("'b'.repeat(10)");
1261 5 : CHECK_EQ(0, break_point_hit_count);
1262 :
1263 : CompileRun("condition = true");
1264 : CompileRun("'b'.repeat(10)");
1265 5 : CHECK_EQ(1, break_point_hit_count);
1266 :
1267 : // Run without breakpoints.
1268 : ClearBreakPoint(bp);
1269 : CompileRun("'b'.repeat(10)");
1270 5 : CHECK_EQ(1, break_point_hit_count);
1271 :
1272 : // === Test arguments ===
1273 5 : break_point_hit_count = 0;
1274 5 : builtin = CompileRun("String.prototype.repeat").As<v8::Function>();
1275 : CompileRun("function f(x) { return 'a'.repeat(x * 2); }");
1276 5 : CHECK_EQ(0, break_point_hit_count);
1277 :
1278 : // Run with breakpoint.
1279 5 : bp = SetBreakPoint(builtin, 0, "arguments[0] == 20");
1280 5 : ExpectString("f(5)", "aaaaaaaaaa");
1281 5 : CHECK_EQ(0, break_point_hit_count);
1282 :
1283 5 : ExpectString("f(10)", "aaaaaaaaaaaaaaaaaaaa");
1284 5 : CHECK_EQ(1, break_point_hit_count);
1285 :
1286 : // Run without breakpoints.
1287 : ClearBreakPoint(bp);
1288 5 : ExpectString("f(10)", "aaaaaaaaaaaaaaaaaaaa");
1289 5 : CHECK_EQ(1, break_point_hit_count);
1290 :
1291 : // === Test adapted arguments ===
1292 5 : break_point_hit_count = 0;
1293 5 : builtin = CompileRun("String.prototype.repeat").As<v8::Function>();
1294 : CompileRun("function f(x) { return 'a'.repeat(x * 2, x); }");
1295 5 : CHECK_EQ(0, break_point_hit_count);
1296 :
1297 : // Run with breakpoint.
1298 : bp = SetBreakPoint(builtin, 0,
1299 5 : "arguments[1] == 10 && arguments[2] == undefined");
1300 5 : ExpectString("f(5)", "aaaaaaaaaa");
1301 5 : CHECK_EQ(0, break_point_hit_count);
1302 :
1303 5 : ExpectString("f(10)", "aaaaaaaaaaaaaaaaaaaa");
1304 5 : CHECK_EQ(1, break_point_hit_count);
1305 :
1306 : // Run without breakpoints.
1307 : ClearBreakPoint(bp);
1308 5 : ExpectString("f(10)", "aaaaaaaaaaaaaaaaaaaa");
1309 5 : CHECK_EQ(1, break_point_hit_count);
1310 :
1311 : // === Test var-arg builtins ===
1312 5 : break_point_hit_count = 0;
1313 5 : builtin = CompileRun("String.fromCharCode").As<v8::Function>();
1314 : CompileRun("function f() { return String.fromCharCode(1, 2, 3); }");
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 : // Run without breakpoints.
1323 : ClearBreakPoint(bp);
1324 : CompileRun("f(1, 2, 3)");
1325 5 : CHECK_EQ(1, break_point_hit_count);
1326 :
1327 : // === Test rest arguments ===
1328 5 : break_point_hit_count = 0;
1329 5 : builtin = CompileRun("String.fromCharCode").As<v8::Function>();
1330 : CompileRun("function f(...args) { return String.fromCharCode(...args); }");
1331 5 : CHECK_EQ(0, break_point_hit_count);
1332 :
1333 : // Run with breakpoint.
1334 5 : bp = SetBreakPoint(builtin, 0, "arguments.length == 3 && arguments[1] == 2");
1335 : CompileRun("f(1, 2, 3)");
1336 5 : CHECK_EQ(1, break_point_hit_count);
1337 :
1338 : ClearBreakPoint(bp);
1339 : CompileRun("f(1, 3, 3)");
1340 5 : CHECK_EQ(1, break_point_hit_count);
1341 :
1342 : // Run without breakpoints.
1343 : ClearBreakPoint(bp);
1344 : CompileRun("f(1, 2, 3)");
1345 5 : CHECK_EQ(1, break_point_hit_count);
1346 :
1347 : // === Test receiver ===
1348 5 : break_point_hit_count = 0;
1349 5 : builtin = CompileRun("String.prototype.repeat").As<v8::Function>();
1350 : CompileRun("function f(x) { return x.repeat(10); }");
1351 5 : CHECK_EQ(0, break_point_hit_count);
1352 :
1353 : // Run with breakpoint.
1354 5 : bp = SetBreakPoint(builtin, 0, "this == 'a'");
1355 5 : ExpectString("f('b')", "bbbbbbbbbb");
1356 5 : CHECK_EQ(0, break_point_hit_count);
1357 :
1358 5 : ExpectString("f('a')", "aaaaaaaaaa");
1359 5 : CHECK_EQ(1, break_point_hit_count);
1360 :
1361 : // Run without breakpoints.
1362 : ClearBreakPoint(bp);
1363 5 : ExpectString("f('a')", "aaaaaaaaaa");
1364 5 : CHECK_EQ(1, break_point_hit_count);
1365 :
1366 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1367 : CheckDebuggerUnloaded();
1368 5 : }
1369 :
1370 26661 : TEST(BreakPointInlining) {
1371 5 : i::FLAG_allow_natives_syntax = true;
1372 5 : break_point_hit_count = 0;
1373 5 : LocalContext env;
1374 10 : v8::HandleScope scope(env->GetIsolate());
1375 :
1376 5 : DebugEventCounter delegate;
1377 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1378 :
1379 5 : break_point_hit_count = 0;
1380 : v8::Local<v8::Function> inlinee =
1381 5 : CompileRun("function f(x) { return x*2; } f").As<v8::Function>();
1382 : CompileRun("function test(x) { return 1 + f(x) }");
1383 : CompileRun(
1384 : "test(0.5); test(0.6);"
1385 : "%OptimizeFunctionOnNextCall(test); test(0.7);");
1386 5 : CHECK_EQ(0, break_point_hit_count);
1387 :
1388 : // Run with breakpoint.
1389 5 : i::Handle<i::BreakPoint> bp = SetBreakPoint(inlinee, 0);
1390 : CompileRun("f(0.1);");
1391 5 : CHECK_EQ(1, break_point_hit_count);
1392 : CompileRun("test(0.2);");
1393 5 : CHECK_EQ(2, break_point_hit_count);
1394 :
1395 : // Re-optimize.
1396 : CompileRun("%OptimizeFunctionOnNextCall(test);");
1397 : CompileRun("test(0.3);");
1398 5 : CHECK_EQ(3, break_point_hit_count);
1399 :
1400 : // Run without breakpoints.
1401 : ClearBreakPoint(bp);
1402 : CompileRun("test(0.3);");
1403 5 : CHECK_EQ(3, break_point_hit_count);
1404 :
1405 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1406 : CheckDebuggerUnloaded();
1407 5 : }
1408 :
1409 25 : static void CallWithBreakPoints(v8::Local<v8::Context> context,
1410 : v8::Local<v8::Object> recv,
1411 : v8::Local<v8::Function> f,
1412 : int break_point_count, int call_count) {
1413 25 : break_point_hit_count = 0;
1414 425 : for (int i = 0; i < call_count; i++) {
1415 800 : f->Call(context, recv, 0, nullptr).ToLocalChecked();
1416 400 : CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
1417 : }
1418 25 : }
1419 :
1420 :
1421 : // Test GC during break point processing.
1422 26661 : TEST(GCDuringBreakPointProcessing) {
1423 5 : break_point_hit_count = 0;
1424 5 : LocalContext env;
1425 10 : v8::HandleScope scope(env->GetIsolate());
1426 5 : v8::Local<v8::Context> context = env.local();
1427 :
1428 5 : DebugEventBreakPointCollectGarbage delegate;
1429 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1430 : v8::Local<v8::Function> foo;
1431 :
1432 : // Test IC store break point with garbage collection.
1433 5 : foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1434 5 : SetBreakPoint(foo, 0);
1435 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 10);
1436 :
1437 : // Test IC load break point with garbage collection.
1438 5 : foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1439 5 : SetBreakPoint(foo, 0);
1440 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 10);
1441 :
1442 : // Test IC call break point with garbage collection.
1443 5 : foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
1444 5 : SetBreakPoint(foo, 0);
1445 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 10);
1446 :
1447 : // Test return break point with garbage collection.
1448 5 : foo = CompileFunction(&env, "function foo(){}", "foo");
1449 5 : SetBreakPoint(foo, 0);
1450 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 25);
1451 :
1452 : // Test debug break slot break point with garbage collection.
1453 5 : foo = CompileFunction(&env, "function foo(){var a;}", "foo");
1454 5 : SetBreakPoint(foo, 0);
1455 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 25);
1456 :
1457 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1458 : CheckDebuggerUnloaded();
1459 5 : }
1460 :
1461 :
1462 : // Call the function three times with different garbage collections in between
1463 : // and make sure that the break point survives.
1464 25 : static void CallAndGC(v8::Local<v8::Context> context,
1465 : v8::Local<v8::Object> recv, v8::Local<v8::Function> f) {
1466 25 : break_point_hit_count = 0;
1467 :
1468 100 : for (int i = 0; i < 3; i++) {
1469 : // Call function.
1470 150 : f->Call(context, recv, 0, nullptr).ToLocalChecked();
1471 75 : CHECK_EQ(1 + i * 3, break_point_hit_count);
1472 :
1473 : // Scavenge and call function.
1474 75 : CcTest::CollectGarbage(v8::internal::NEW_SPACE);
1475 150 : f->Call(context, recv, 0, nullptr).ToLocalChecked();
1476 75 : CHECK_EQ(2 + i * 3, break_point_hit_count);
1477 :
1478 : // Mark sweep (and perhaps compact) and call function.
1479 75 : CcTest::CollectAllGarbage();
1480 150 : f->Call(context, recv, 0, nullptr).ToLocalChecked();
1481 75 : CHECK_EQ(3 + i * 3, break_point_hit_count);
1482 : }
1483 25 : }
1484 :
1485 :
1486 : // Test that a break point can be set at a return store location.
1487 26661 : TEST(BreakPointSurviveGC) {
1488 5 : break_point_hit_count = 0;
1489 5 : LocalContext env;
1490 10 : v8::HandleScope scope(env->GetIsolate());
1491 5 : v8::Local<v8::Context> context = env.local();
1492 :
1493 5 : DebugEventCounter delegate;
1494 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1495 : v8::Local<v8::Function> foo;
1496 :
1497 : // Test IC store break point with garbage collection.
1498 : {
1499 : CompileFunction(&env, "function foo(){}", "foo");
1500 5 : foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1501 5 : SetBreakPoint(foo, 0);
1502 : }
1503 5 : CallAndGC(context, env->Global(), foo);
1504 :
1505 : // Test IC load break point with garbage collection.
1506 : {
1507 : CompileFunction(&env, "function foo(){}", "foo");
1508 5 : foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1509 5 : SetBreakPoint(foo, 0);
1510 : }
1511 5 : CallAndGC(context, env->Global(), foo);
1512 :
1513 : // Test IC call break point with garbage collection.
1514 : {
1515 : CompileFunction(&env, "function foo(){}", "foo");
1516 : foo = CompileFunction(&env,
1517 : "function bar(){};function foo(){bar();}",
1518 5 : "foo");
1519 5 : SetBreakPoint(foo, 0);
1520 : }
1521 5 : CallAndGC(context, env->Global(), foo);
1522 :
1523 : // Test return break point with garbage collection.
1524 : {
1525 : CompileFunction(&env, "function foo(){}", "foo");
1526 5 : foo = CompileFunction(&env, "function foo(){}", "foo");
1527 5 : SetBreakPoint(foo, 0);
1528 : }
1529 5 : CallAndGC(context, env->Global(), foo);
1530 :
1531 : // Test non IC break point with garbage collection.
1532 : {
1533 : CompileFunction(&env, "function foo(){}", "foo");
1534 5 : foo = CompileFunction(&env, "function foo(){var bar=0;}", "foo");
1535 5 : SetBreakPoint(foo, 0);
1536 : }
1537 5 : CallAndGC(context, env->Global(), foo);
1538 :
1539 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1540 : CheckDebuggerUnloaded();
1541 5 : }
1542 :
1543 : // Test that the debugger statement causes a break.
1544 26661 : TEST(DebuggerStatement) {
1545 5 : break_point_hit_count = 0;
1546 5 : LocalContext env;
1547 10 : v8::HandleScope scope(env->GetIsolate());
1548 5 : DebugEventCounter delegate;
1549 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1550 5 : v8::Local<v8::Context> context = env.local();
1551 5 : v8::Script::Compile(context,
1552 5 : v8_str(env->GetIsolate(), "function bar(){debugger}"))
1553 : .ToLocalChecked()
1554 5 : ->Run(context)
1555 : .ToLocalChecked();
1556 5 : v8::Script::Compile(
1557 5 : context, v8_str(env->GetIsolate(), "function foo(){debugger;debugger;}"))
1558 : .ToLocalChecked()
1559 5 : ->Run(context)
1560 : .ToLocalChecked();
1561 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
1562 10 : env->Global()
1563 15 : ->Get(context, v8_str(env->GetIsolate(), "foo"))
1564 : .ToLocalChecked());
1565 : v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
1566 10 : env->Global()
1567 15 : ->Get(context, v8_str(env->GetIsolate(), "bar"))
1568 : .ToLocalChecked());
1569 :
1570 : // Run function with debugger statement
1571 15 : bar->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1572 5 : CHECK_EQ(1, break_point_hit_count);
1573 :
1574 : // Run function with two debugger statement
1575 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1576 5 : CHECK_EQ(3, break_point_hit_count);
1577 :
1578 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1579 : CheckDebuggerUnloaded();
1580 5 : }
1581 :
1582 :
1583 : // Test setting a breakpoint on the debugger statement.
1584 26661 : TEST(DebuggerStatementBreakpoint) {
1585 5 : break_point_hit_count = 0;
1586 5 : LocalContext env;
1587 10 : v8::HandleScope scope(env->GetIsolate());
1588 5 : v8::Local<v8::Context> context = env.local();
1589 5 : DebugEventCounter delegate;
1590 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1591 5 : v8::Script::Compile(context,
1592 5 : v8_str(env->GetIsolate(), "function foo(){debugger;}"))
1593 : .ToLocalChecked()
1594 5 : ->Run(context)
1595 : .ToLocalChecked();
1596 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
1597 10 : env->Global()
1598 15 : ->Get(context, v8_str(env->GetIsolate(), "foo"))
1599 : .ToLocalChecked());
1600 :
1601 : // The debugger statement triggers breakpoint hit
1602 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1603 5 : CHECK_EQ(1, break_point_hit_count);
1604 :
1605 5 : i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
1606 :
1607 : // Set breakpoint does not duplicate hits
1608 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1609 5 : CHECK_EQ(2, break_point_hit_count);
1610 :
1611 : ClearBreakPoint(bp);
1612 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1613 : CheckDebuggerUnloaded();
1614 5 : }
1615 :
1616 :
1617 : // Test that the conditional breakpoints work event if code generation from
1618 : // strings is prohibited in the debugee context.
1619 26661 : TEST(ConditionalBreakpointWithCodeGenerationDisallowed) {
1620 5 : LocalContext env;
1621 10 : v8::HandleScope scope(env->GetIsolate());
1622 :
1623 5 : DebugEventCounter delegate;
1624 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1625 :
1626 5 : v8::Local<v8::Context> context = env.local();
1627 : v8::Local<v8::Function> foo = CompileFunction(&env,
1628 : "function foo(x) {\n"
1629 : " var s = 'String value2';\n"
1630 : " return s + x;\n"
1631 : "}",
1632 : "foo");
1633 :
1634 : // Set conditional breakpoint with condition 'true'.
1635 5 : SetBreakPoint(foo, 4, "true");
1636 :
1637 5 : break_point_hit_count = 0;
1638 5 : env->AllowCodeGenerationFromStrings(false);
1639 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1640 5 : CHECK_EQ(1, break_point_hit_count);
1641 :
1642 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1643 : CheckDebuggerUnloaded();
1644 5 : }
1645 :
1646 :
1647 : // Simple test of the stepping mechanism using only store ICs.
1648 26661 : TEST(DebugStepLinear) {
1649 5 : LocalContext env;
1650 10 : v8::HandleScope scope(env->GetIsolate());
1651 :
1652 : // Create a function for testing stepping.
1653 : v8::Local<v8::Function> foo = CompileFunction(&env,
1654 : "function foo(){a=1;b=1;c=1;}",
1655 : "foo");
1656 :
1657 : // Run foo to allow it to get optimized.
1658 : CompileRun("a=0; b=0; c=0; foo();");
1659 :
1660 : // Register a debug event listener which steps and counts.
1661 5 : DebugEventCounter run_step;
1662 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1663 :
1664 5 : SetBreakPoint(foo, 3);
1665 :
1666 : run_step.set_step_action(StepIn);
1667 5 : break_point_hit_count = 0;
1668 5 : v8::Local<v8::Context> context = env.local();
1669 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1670 :
1671 : // With stepping all break locations are hit.
1672 5 : CHECK_EQ(4, break_point_hit_count);
1673 :
1674 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1675 : CheckDebuggerUnloaded();
1676 :
1677 : // Register a debug event listener which just counts.
1678 5 : DebugEventCounter delegate;
1679 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1680 :
1681 5 : SetBreakPoint(foo, 3);
1682 5 : break_point_hit_count = 0;
1683 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1684 :
1685 : // Without stepping only active break points are hit.
1686 5 : CHECK_EQ(1, break_point_hit_count);
1687 :
1688 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1689 : CheckDebuggerUnloaded();
1690 5 : }
1691 :
1692 :
1693 : // Test of the stepping mechanism for keyed load in a loop.
1694 26661 : TEST(DebugStepKeyedLoadLoop) {
1695 5 : LocalContext env;
1696 10 : v8::HandleScope scope(env->GetIsolate());
1697 :
1698 : // Register a debug event listener which steps and counts.
1699 5 : DebugEventCounter run_step;
1700 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1701 :
1702 : // Create a function for testing stepping of keyed load. The statement 'y=1'
1703 : // is there to have more than one breakable statement in the loop, TODO(315).
1704 : v8::Local<v8::Function> foo = CompileFunction(
1705 : &env,
1706 : "function foo(a) {\n"
1707 : " var x;\n"
1708 : " var len = a.length;\n"
1709 : " for (var i = 0; i < len; i++) {\n"
1710 : " y = 1;\n"
1711 : " x = a[i];\n"
1712 : " }\n"
1713 : "}\n"
1714 : "y=0\n",
1715 : "foo");
1716 :
1717 5 : v8::Local<v8::Context> context = env.local();
1718 : // Create array [0,1,2,3,4,5,6,7,8,9]
1719 5 : v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
1720 105 : for (int i = 0; i < 10; i++) {
1721 250 : CHECK(a->Set(context, v8::Number::New(env->GetIsolate(), i),
1722 : v8::Number::New(env->GetIsolate(), i))
1723 : .FromJust());
1724 : }
1725 :
1726 : // Call function without any break points to ensure inlining is in place.
1727 : const int kArgc = 1;
1728 : v8::Local<v8::Value> args[kArgc] = {a};
1729 15 : foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
1730 :
1731 : // Set up break point and step through the function.
1732 5 : SetBreakPoint(foo, 3);
1733 : run_step.set_step_action(StepNext);
1734 5 : break_point_hit_count = 0;
1735 15 : foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
1736 :
1737 : // With stepping all break locations are hit.
1738 5 : CHECK_EQ(44, break_point_hit_count);
1739 :
1740 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1741 : CheckDebuggerUnloaded();
1742 5 : }
1743 :
1744 :
1745 : // Test of the stepping mechanism for keyed store in a loop.
1746 26661 : TEST(DebugStepKeyedStoreLoop) {
1747 5 : LocalContext env;
1748 10 : v8::HandleScope scope(env->GetIsolate());
1749 :
1750 : // Register a debug event listener which steps and counts.
1751 5 : DebugEventCounter run_step;
1752 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1753 :
1754 : // Create a function for testing stepping of keyed store. The statement 'y=1'
1755 : // is there to have more than one breakable statement in the loop, TODO(315).
1756 : v8::Local<v8::Function> foo = CompileFunction(
1757 : &env,
1758 : "function foo(a) {\n"
1759 : " var len = a.length;\n"
1760 : " for (var i = 0; i < len; i++) {\n"
1761 : " y = 1;\n"
1762 : " a[i] = 42;\n"
1763 : " }\n"
1764 : "}\n"
1765 : "y=0\n",
1766 : "foo");
1767 :
1768 5 : v8::Local<v8::Context> context = env.local();
1769 : // Create array [0,1,2,3,4,5,6,7,8,9]
1770 5 : v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
1771 105 : for (int i = 0; i < 10; i++) {
1772 250 : CHECK(a->Set(context, v8::Number::New(env->GetIsolate(), i),
1773 : v8::Number::New(env->GetIsolate(), i))
1774 : .FromJust());
1775 : }
1776 :
1777 : // Call function without any break points to ensure inlining is in place.
1778 : const int kArgc = 1;
1779 : v8::Local<v8::Value> args[kArgc] = {a};
1780 15 : foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
1781 :
1782 : // Set up break point and step through the function.
1783 5 : SetBreakPoint(foo, 3);
1784 : run_step.set_step_action(StepNext);
1785 5 : break_point_hit_count = 0;
1786 15 : foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
1787 :
1788 : // With stepping all break locations are hit.
1789 5 : CHECK_EQ(44, break_point_hit_count);
1790 :
1791 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1792 : CheckDebuggerUnloaded();
1793 5 : }
1794 :
1795 :
1796 : // Test of the stepping mechanism for named load in a loop.
1797 26661 : TEST(DebugStepNamedLoadLoop) {
1798 5 : LocalContext env;
1799 10 : v8::HandleScope scope(env->GetIsolate());
1800 :
1801 : // Register a debug event listener which steps and counts.
1802 5 : DebugEventCounter run_step;
1803 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1804 :
1805 5 : v8::Local<v8::Context> context = env.local();
1806 : // Create a function for testing stepping of named load.
1807 : v8::Local<v8::Function> foo = CompileFunction(
1808 : &env,
1809 : "function foo() {\n"
1810 : " var a = [];\n"
1811 : " var s = \"\";\n"
1812 : " for (var i = 0; i < 10; i++) {\n"
1813 : " var v = new V(i, i + 1);\n"
1814 : " v.y;\n"
1815 : " a.length;\n" // Special case: array length.
1816 : " s.length;\n" // Special case: string length.
1817 : " }\n"
1818 : "}\n"
1819 : "function V(x, y) {\n"
1820 : " this.x = x;\n"
1821 : " this.y = y;\n"
1822 : "}\n",
1823 : "foo");
1824 :
1825 : // Call function without any break points to ensure inlining is in place.
1826 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1827 :
1828 : // Set up break point and step through the function.
1829 5 : SetBreakPoint(foo, 4);
1830 : run_step.set_step_action(StepNext);
1831 5 : break_point_hit_count = 0;
1832 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1833 :
1834 : // With stepping all break locations are hit.
1835 5 : CHECK_EQ(65, break_point_hit_count);
1836 :
1837 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1838 : CheckDebuggerUnloaded();
1839 5 : }
1840 :
1841 :
1842 5 : static void DoDebugStepNamedStoreLoop(int expected) {
1843 5 : LocalContext env;
1844 10 : v8::HandleScope scope(env->GetIsolate());
1845 :
1846 : // Register a debug event listener which steps and counts.
1847 5 : DebugEventCounter run_step;
1848 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1849 :
1850 : // Create a function for testing stepping of named store.
1851 5 : v8::Local<v8::Context> context = env.local();
1852 : v8::Local<v8::Function> foo = CompileFunction(
1853 : &env,
1854 : "function foo() {\n"
1855 : " var a = {a:1};\n"
1856 : " for (var i = 0; i < 10; i++) {\n"
1857 : " a.a = 2\n"
1858 : " }\n"
1859 : "}\n",
1860 : "foo");
1861 :
1862 : // Call function without any break points to ensure inlining is in place.
1863 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1864 :
1865 : // Set up break point and step through the function.
1866 5 : SetBreakPoint(foo, 3);
1867 : run_step.set_step_action(StepNext);
1868 5 : break_point_hit_count = 0;
1869 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1870 :
1871 : // With stepping all expected break locations are hit.
1872 5 : CHECK_EQ(expected, break_point_hit_count);
1873 :
1874 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1875 : CheckDebuggerUnloaded();
1876 5 : }
1877 :
1878 :
1879 : // Test of the stepping mechanism for named load in a loop.
1880 26661 : TEST(DebugStepNamedStoreLoop) { DoDebugStepNamedStoreLoop(34); }
1881 :
1882 : // Test the stepping mechanism with different ICs.
1883 26661 : TEST(DebugStepLinearMixedICs) {
1884 5 : LocalContext env;
1885 10 : v8::HandleScope scope(env->GetIsolate());
1886 :
1887 : // Register a debug event listener which steps and counts.
1888 5 : DebugEventCounter run_step;
1889 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1890 :
1891 5 : v8::Local<v8::Context> context = env.local();
1892 : // Create a function for testing stepping.
1893 : v8::Local<v8::Function> foo = CompileFunction(&env,
1894 : "function bar() {};"
1895 : "function foo() {"
1896 : " var x;"
1897 : " var index='name';"
1898 : " var y = {};"
1899 : " a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
1900 :
1901 : // Run functions to allow them to get optimized.
1902 : CompileRun("a=0; b=0; bar(); foo();");
1903 :
1904 5 : SetBreakPoint(foo, 0);
1905 :
1906 : run_step.set_step_action(StepIn);
1907 5 : break_point_hit_count = 0;
1908 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1909 :
1910 : // With stepping all break locations are hit.
1911 5 : CHECK_EQ(10, break_point_hit_count);
1912 :
1913 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1914 : CheckDebuggerUnloaded();
1915 :
1916 : // Register a debug event listener which just counts.
1917 5 : DebugEventCounter delegate;
1918 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
1919 :
1920 5 : SetBreakPoint(foo, 0);
1921 5 : break_point_hit_count = 0;
1922 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1923 :
1924 : // Without stepping only active break points are hit.
1925 5 : CHECK_EQ(1, break_point_hit_count);
1926 :
1927 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1928 : CheckDebuggerUnloaded();
1929 5 : }
1930 :
1931 :
1932 26661 : TEST(DebugStepDeclarations) {
1933 5 : LocalContext env;
1934 10 : v8::HandleScope scope(env->GetIsolate());
1935 :
1936 : // Register a debug event listener which steps and counts.
1937 5 : DebugEventCounter run_step;
1938 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1939 :
1940 5 : v8::Local<v8::Context> context = env.local();
1941 : // Create a function for testing stepping. Run it to allow it to get
1942 : // optimized.
1943 : const char* src = "function foo() { "
1944 : " var a;"
1945 : " var b = 1;"
1946 : " var c = foo;"
1947 : " var d = Math.floor;"
1948 : " var e = b + d(1.2);"
1949 : "}"
1950 : "foo()";
1951 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
1952 :
1953 5 : SetBreakPoint(foo, 0);
1954 :
1955 : // Stepping through the declarations.
1956 : run_step.set_step_action(StepIn);
1957 5 : break_point_hit_count = 0;
1958 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1959 5 : CHECK_EQ(5, break_point_hit_count);
1960 :
1961 : // Get rid of the debug event listener.
1962 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1963 : CheckDebuggerUnloaded();
1964 5 : }
1965 :
1966 :
1967 26661 : TEST(DebugStepLocals) {
1968 5 : LocalContext env;
1969 10 : v8::HandleScope scope(env->GetIsolate());
1970 :
1971 : // Register a debug event listener which steps and counts.
1972 5 : DebugEventCounter run_step;
1973 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
1974 :
1975 5 : v8::Local<v8::Context> context = env.local();
1976 : // Create a function for testing stepping. Run it to allow it to get
1977 : // optimized.
1978 : const char* src = "function foo() { "
1979 : " var a,b;"
1980 : " a = 1;"
1981 : " b = a + 2;"
1982 : " b = 1 + 2 + 3;"
1983 : " a = Math.floor(b);"
1984 : "}"
1985 : "foo()";
1986 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
1987 :
1988 5 : SetBreakPoint(foo, 0);
1989 :
1990 : // Stepping through the declarations.
1991 : run_step.set_step_action(StepIn);
1992 5 : break_point_hit_count = 0;
1993 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1994 5 : CHECK_EQ(5, break_point_hit_count);
1995 :
1996 : // Get rid of the debug event listener.
1997 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
1998 : CheckDebuggerUnloaded();
1999 5 : }
2000 :
2001 :
2002 26661 : TEST(DebugStepIf) {
2003 5 : LocalContext env;
2004 5 : v8::Isolate* isolate = env->GetIsolate();
2005 10 : v8::HandleScope scope(isolate);
2006 :
2007 : // Register a debug event listener which steps and counts.
2008 5 : DebugEventCounter run_step;
2009 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2010 :
2011 5 : v8::Local<v8::Context> context = env.local();
2012 : // Create a function for testing stepping. Run it to allow it to get
2013 : // optimized.
2014 : const int argc = 1;
2015 : const char* src = "function foo(x) { "
2016 : " a = 1;"
2017 : " if (x) {"
2018 : " b = 1;"
2019 : " } else {"
2020 : " c = 1;"
2021 : " d = 1;"
2022 : " }"
2023 : "}"
2024 : "a=0; b=0; c=0; d=0; foo()";
2025 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2026 5 : SetBreakPoint(foo, 0);
2027 :
2028 : // Stepping through the true part.
2029 : run_step.set_step_action(StepIn);
2030 5 : break_point_hit_count = 0;
2031 : v8::Local<v8::Value> argv_true[argc] = {v8::True(isolate)};
2032 15 : foo->Call(context, env->Global(), argc, argv_true).ToLocalChecked();
2033 5 : CHECK_EQ(4, break_point_hit_count);
2034 :
2035 : // Stepping through the false part.
2036 : run_step.set_step_action(StepIn);
2037 5 : break_point_hit_count = 0;
2038 : v8::Local<v8::Value> argv_false[argc] = {v8::False(isolate)};
2039 15 : foo->Call(context, env->Global(), argc, argv_false).ToLocalChecked();
2040 5 : CHECK_EQ(5, break_point_hit_count);
2041 :
2042 : // Get rid of the debug event listener.
2043 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2044 : CheckDebuggerUnloaded();
2045 5 : }
2046 :
2047 :
2048 26661 : TEST(DebugStepSwitch) {
2049 5 : LocalContext env;
2050 5 : v8::Isolate* isolate = env->GetIsolate();
2051 10 : v8::HandleScope scope(isolate);
2052 :
2053 : // Register a debug event listener which steps and counts.
2054 5 : DebugEventCounter run_step;
2055 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2056 :
2057 5 : v8::Local<v8::Context> context = env.local();
2058 : // Create a function for testing stepping. Run it to allow it to get
2059 : // optimized.
2060 : const int argc = 1;
2061 : const char* src = "function foo(x) { "
2062 : " a = 1;"
2063 : " switch (x) {"
2064 : " case 1:"
2065 : " b = 1;"
2066 : " case 2:"
2067 : " c = 1;"
2068 : " break;"
2069 : " case 3:"
2070 : " d = 1;"
2071 : " e = 1;"
2072 : " f = 1;"
2073 : " break;"
2074 : " }"
2075 : "}"
2076 : "a=0; b=0; c=0; d=0; e=0; f=0; foo()";
2077 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2078 5 : SetBreakPoint(foo, 0);
2079 :
2080 : // One case with fall-through.
2081 : run_step.set_step_action(StepIn);
2082 5 : break_point_hit_count = 0;
2083 5 : v8::Local<v8::Value> argv_1[argc] = {v8::Number::New(isolate, 1)};
2084 15 : foo->Call(context, env->Global(), argc, argv_1).ToLocalChecked();
2085 5 : CHECK_EQ(6, break_point_hit_count);
2086 :
2087 : // Another case.
2088 : run_step.set_step_action(StepIn);
2089 5 : break_point_hit_count = 0;
2090 5 : v8::Local<v8::Value> argv_2[argc] = {v8::Number::New(isolate, 2)};
2091 15 : foo->Call(context, env->Global(), argc, argv_2).ToLocalChecked();
2092 5 : CHECK_EQ(5, break_point_hit_count);
2093 :
2094 : // Last case.
2095 : run_step.set_step_action(StepIn);
2096 5 : break_point_hit_count = 0;
2097 5 : v8::Local<v8::Value> argv_3[argc] = {v8::Number::New(isolate, 3)};
2098 15 : foo->Call(context, env->Global(), argc, argv_3).ToLocalChecked();
2099 5 : CHECK_EQ(7, break_point_hit_count);
2100 :
2101 : // Get rid of the debug event listener.
2102 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2103 : CheckDebuggerUnloaded();
2104 5 : }
2105 :
2106 :
2107 26661 : TEST(DebugStepWhile) {
2108 5 : LocalContext env;
2109 5 : v8::Isolate* isolate = env->GetIsolate();
2110 10 : v8::HandleScope scope(isolate);
2111 :
2112 : // Register a debug event listener which steps and counts.
2113 5 : DebugEventCounter run_step;
2114 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2115 :
2116 5 : v8::Local<v8::Context> context = env.local();
2117 : // Create a function for testing stepping. Run it to allow it to get
2118 : // optimized.
2119 : const int argc = 1;
2120 : const char* src = "function foo(x) { "
2121 : " var a = 0;"
2122 : " while (a < x) {"
2123 : " a++;"
2124 : " }"
2125 : "}"
2126 : "foo()";
2127 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2128 5 : SetBreakPoint(foo, 8); // "var a = 0;"
2129 :
2130 : // Looping 0 times. We still should break at the while-condition once.
2131 : run_step.set_step_action(StepIn);
2132 5 : break_point_hit_count = 0;
2133 5 : v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
2134 15 : foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
2135 5 : CHECK_EQ(3, break_point_hit_count);
2136 :
2137 : // Looping 10 times.
2138 : run_step.set_step_action(StepIn);
2139 5 : break_point_hit_count = 0;
2140 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2141 15 : foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2142 5 : CHECK_EQ(23, break_point_hit_count);
2143 :
2144 : // Looping 100 times.
2145 : run_step.set_step_action(StepIn);
2146 5 : break_point_hit_count = 0;
2147 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2148 15 : foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2149 5 : CHECK_EQ(203, break_point_hit_count);
2150 :
2151 : // Get rid of the debug event listener.
2152 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2153 : CheckDebuggerUnloaded();
2154 5 : }
2155 :
2156 :
2157 26661 : TEST(DebugStepDoWhile) {
2158 5 : LocalContext env;
2159 5 : v8::Isolate* isolate = env->GetIsolate();
2160 10 : v8::HandleScope scope(isolate);
2161 :
2162 : // Register a debug event listener which steps and counts.
2163 5 : DebugEventCounter run_step;
2164 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2165 :
2166 5 : v8::Local<v8::Context> context = env.local();
2167 : // Create a function for testing stepping. Run it to allow it to get
2168 : // optimized.
2169 : const int argc = 1;
2170 : const char* src = "function foo(x) { "
2171 : " var a = 0;"
2172 : " do {"
2173 : " a++;"
2174 : " } while (a < x)"
2175 : "}"
2176 : "foo()";
2177 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2178 5 : SetBreakPoint(foo, 8); // "var a = 0;"
2179 :
2180 : // Looping 0 times.
2181 : run_step.set_step_action(StepIn);
2182 5 : break_point_hit_count = 0;
2183 5 : v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
2184 15 : foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
2185 5 : CHECK_EQ(4, break_point_hit_count);
2186 :
2187 : // Looping 10 times.
2188 : run_step.set_step_action(StepIn);
2189 5 : break_point_hit_count = 0;
2190 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2191 15 : foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2192 5 : CHECK_EQ(22, break_point_hit_count);
2193 :
2194 : // Looping 100 times.
2195 : run_step.set_step_action(StepIn);
2196 5 : break_point_hit_count = 0;
2197 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2198 15 : foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2199 5 : CHECK_EQ(202, break_point_hit_count);
2200 :
2201 : // Get rid of the debug event listener.
2202 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2203 : CheckDebuggerUnloaded();
2204 5 : }
2205 :
2206 :
2207 26661 : TEST(DebugStepFor) {
2208 5 : LocalContext env;
2209 5 : v8::Isolate* isolate = env->GetIsolate();
2210 10 : v8::HandleScope scope(isolate);
2211 :
2212 : // Register a debug event listener which steps and counts.
2213 5 : DebugEventCounter run_step;
2214 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2215 :
2216 5 : v8::Local<v8::Context> context = env.local();
2217 : // Create a function for testing stepping. Run it to allow it to get
2218 : // optimized.
2219 : const int argc = 1;
2220 : const char* src = "function foo(x) { "
2221 : " a = 1;"
2222 : " for (i = 0; i < x; i++) {"
2223 : " b = 1;"
2224 : " }"
2225 : "}"
2226 : "a=0; b=0; i=0; foo()";
2227 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2228 :
2229 5 : SetBreakPoint(foo, 8); // "a = 1;"
2230 :
2231 : // Looping 0 times.
2232 : run_step.set_step_action(StepIn);
2233 5 : break_point_hit_count = 0;
2234 5 : v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
2235 15 : foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
2236 5 : CHECK_EQ(4, break_point_hit_count);
2237 :
2238 : // Looping 10 times.
2239 : run_step.set_step_action(StepIn);
2240 5 : break_point_hit_count = 0;
2241 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2242 15 : foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2243 5 : CHECK_EQ(34, break_point_hit_count);
2244 :
2245 : // Looping 100 times.
2246 : run_step.set_step_action(StepIn);
2247 5 : break_point_hit_count = 0;
2248 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2249 15 : foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2250 5 : CHECK_EQ(304, break_point_hit_count);
2251 :
2252 : // Get rid of the debug event listener.
2253 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2254 : CheckDebuggerUnloaded();
2255 5 : }
2256 :
2257 :
2258 26661 : TEST(DebugStepForContinue) {
2259 5 : LocalContext env;
2260 5 : v8::Isolate* isolate = env->GetIsolate();
2261 10 : v8::HandleScope scope(isolate);
2262 :
2263 : // Register a debug event listener which steps and counts.
2264 5 : DebugEventCounter run_step;
2265 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2266 :
2267 5 : v8::Local<v8::Context> context = env.local();
2268 : // Create a function for testing stepping. Run it to allow it to get
2269 : // optimized.
2270 : const int argc = 1;
2271 : const char* src = "function foo(x) { "
2272 : " var a = 0;"
2273 : " var b = 0;"
2274 : " var c = 0;"
2275 : " for (var i = 0; i < x; i++) {"
2276 : " a++;"
2277 : " if (a % 2 == 0) continue;"
2278 : " b++;"
2279 : " c++;"
2280 : " }"
2281 : " return b;"
2282 : "}"
2283 : "foo()";
2284 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2285 : v8::Local<v8::Value> result;
2286 5 : SetBreakPoint(foo, 8); // "var a = 0;"
2287 :
2288 : // Each loop generates 4 or 5 steps depending on whether a is equal.
2289 :
2290 : // Looping 10 times.
2291 : run_step.set_step_action(StepIn);
2292 5 : break_point_hit_count = 0;
2293 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2294 15 : result = foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2295 10 : CHECK_EQ(5, result->Int32Value(context).FromJust());
2296 5 : CHECK_EQ(62, break_point_hit_count);
2297 :
2298 : // Looping 100 times.
2299 : run_step.set_step_action(StepIn);
2300 5 : break_point_hit_count = 0;
2301 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2302 15 : result = foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2303 10 : CHECK_EQ(50, result->Int32Value(context).FromJust());
2304 5 : CHECK_EQ(557, break_point_hit_count);
2305 :
2306 : // Get rid of the debug event listener.
2307 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2308 : CheckDebuggerUnloaded();
2309 5 : }
2310 :
2311 :
2312 26661 : TEST(DebugStepForBreak) {
2313 5 : LocalContext env;
2314 5 : v8::Isolate* isolate = env->GetIsolate();
2315 10 : v8::HandleScope scope(isolate);
2316 :
2317 : // Register a debug event listener which steps and counts.
2318 5 : DebugEventCounter run_step;
2319 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2320 :
2321 5 : v8::Local<v8::Context> context = env.local();
2322 : // Create a function for testing stepping. Run it to allow it to get
2323 : // optimized.
2324 : const int argc = 1;
2325 : const char* src = "function foo(x) { "
2326 : " var a = 0;"
2327 : " var b = 0;"
2328 : " var c = 0;"
2329 : " for (var i = 0; i < 1000; i++) {"
2330 : " a++;"
2331 : " if (a == x) break;"
2332 : " b++;"
2333 : " c++;"
2334 : " }"
2335 : " return b;"
2336 : "}"
2337 : "foo()";
2338 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2339 : v8::Local<v8::Value> result;
2340 5 : SetBreakPoint(foo, 8); // "var a = 0;"
2341 :
2342 : // Each loop generates 5 steps except for the last (when break is executed)
2343 : // which only generates 4.
2344 :
2345 : // Looping 10 times.
2346 : run_step.set_step_action(StepIn);
2347 5 : break_point_hit_count = 0;
2348 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2349 15 : result = foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2350 10 : CHECK_EQ(9, result->Int32Value(context).FromJust());
2351 5 : CHECK_EQ(64, break_point_hit_count);
2352 :
2353 : // Looping 100 times.
2354 : run_step.set_step_action(StepIn);
2355 5 : break_point_hit_count = 0;
2356 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2357 15 : result = foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2358 10 : CHECK_EQ(99, result->Int32Value(context).FromJust());
2359 5 : CHECK_EQ(604, break_point_hit_count);
2360 :
2361 : // Get rid of the debug event listener.
2362 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2363 : CheckDebuggerUnloaded();
2364 5 : }
2365 :
2366 :
2367 26661 : TEST(DebugStepForIn) {
2368 5 : LocalContext env;
2369 10 : v8::HandleScope scope(env->GetIsolate());
2370 :
2371 : // Register a debug event listener which steps and counts.
2372 5 : DebugEventCounter run_step;
2373 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2374 :
2375 5 : v8::Local<v8::Context> context = env.local();
2376 : // Create a function for testing stepping. Run it to allow it to get
2377 : // optimized.
2378 : v8::Local<v8::Function> foo;
2379 : const char* src_1 = "function foo() { "
2380 : " var a = [1, 2];"
2381 : " for (x in a) {"
2382 : " b = 0;"
2383 : " }"
2384 : "}"
2385 : "foo()";
2386 : foo = CompileFunction(&env, src_1, "foo");
2387 5 : SetBreakPoint(foo, 0); // "var a = ..."
2388 :
2389 : run_step.set_step_action(StepIn);
2390 5 : break_point_hit_count = 0;
2391 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2392 5 : CHECK_EQ(8, break_point_hit_count);
2393 :
2394 : // Create a function for testing stepping. Run it to allow it to get
2395 : // optimized.
2396 : const char* src_2 = "function foo() { "
2397 : " var a = {a:[1, 2, 3]};"
2398 : " for (x in a.a) {"
2399 : " b = 0;"
2400 : " }"
2401 : "}"
2402 : "foo()";
2403 : foo = CompileFunction(&env, src_2, "foo");
2404 5 : SetBreakPoint(foo, 0); // "var a = ..."
2405 :
2406 : run_step.set_step_action(StepIn);
2407 5 : break_point_hit_count = 0;
2408 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2409 5 : CHECK_EQ(10, break_point_hit_count);
2410 :
2411 : // Get rid of the debug event listener.
2412 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2413 : CheckDebuggerUnloaded();
2414 5 : }
2415 :
2416 :
2417 26661 : TEST(DebugStepWith) {
2418 5 : LocalContext env;
2419 10 : v8::HandleScope scope(env->GetIsolate());
2420 :
2421 : // Register a debug event listener which steps and counts.
2422 5 : DebugEventCounter run_step;
2423 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2424 :
2425 5 : v8::Local<v8::Context> context = env.local();
2426 : // Create a function for testing stepping. Run it to allow it to get
2427 : // optimized.
2428 : const char* src = "function foo(x) { "
2429 : " var a = {};"
2430 : " with (a) {}"
2431 : " with (b) {}"
2432 : "}"
2433 : "foo()";
2434 25 : CHECK(env->Global()
2435 : ->Set(context, v8_str(env->GetIsolate(), "b"),
2436 : v8::Object::New(env->GetIsolate()))
2437 : .FromJust());
2438 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2439 : v8::Local<v8::Value> result;
2440 5 : SetBreakPoint(foo, 8); // "var a = {};"
2441 :
2442 : run_step.set_step_action(StepIn);
2443 5 : break_point_hit_count = 0;
2444 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2445 5 : CHECK_EQ(4, break_point_hit_count);
2446 :
2447 : // Get rid of the debug event listener.
2448 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2449 : CheckDebuggerUnloaded();
2450 5 : }
2451 :
2452 :
2453 26661 : TEST(DebugConditional) {
2454 5 : LocalContext env;
2455 5 : v8::Isolate* isolate = env->GetIsolate();
2456 10 : v8::HandleScope scope(isolate);
2457 :
2458 : // Register a debug event listener which steps and counts.
2459 5 : DebugEventCounter run_step;
2460 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2461 :
2462 5 : v8::Local<v8::Context> context = env.local();
2463 : // Create a function for testing stepping. Run it to allow it to get
2464 : // optimized.
2465 : const char* src =
2466 : "function foo(x) { "
2467 : " return x ? 1 : 2;"
2468 : "}"
2469 : "foo()";
2470 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2471 5 : SetBreakPoint(foo, 0); // "var a;"
2472 :
2473 : run_step.set_step_action(StepIn);
2474 5 : break_point_hit_count = 0;
2475 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2476 5 : CHECK_EQ(2, break_point_hit_count);
2477 :
2478 : run_step.set_step_action(StepIn);
2479 5 : break_point_hit_count = 0;
2480 : const int argc = 1;
2481 : v8::Local<v8::Value> argv_true[argc] = {v8::True(isolate)};
2482 15 : foo->Call(context, env->Global(), argc, argv_true).ToLocalChecked();
2483 5 : CHECK_EQ(2, break_point_hit_count);
2484 :
2485 : // Get rid of the debug event listener.
2486 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2487 : CheckDebuggerUnloaded();
2488 5 : }
2489 :
2490 : // Test that step in does not step into native functions.
2491 26661 : TEST(DebugStepNatives) {
2492 5 : LocalContext env;
2493 10 : v8::HandleScope scope(env->GetIsolate());
2494 :
2495 : // Create a function for testing stepping.
2496 : v8::Local<v8::Function> foo =
2497 : CompileFunction(&env, "function foo(){debugger;Math.sin(1);}", "foo");
2498 :
2499 : // Register a debug event listener which steps and counts.
2500 5 : DebugEventCounter run_step;
2501 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2502 :
2503 5 : v8::Local<v8::Context> context = env.local();
2504 : run_step.set_step_action(StepIn);
2505 5 : break_point_hit_count = 0;
2506 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2507 :
2508 : // With stepping all break locations are hit.
2509 5 : CHECK_EQ(3, break_point_hit_count);
2510 :
2511 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2512 : CheckDebuggerUnloaded();
2513 :
2514 : // Register a debug event listener which just counts.
2515 5 : DebugEventCounter delegate;
2516 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
2517 :
2518 5 : break_point_hit_count = 0;
2519 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2520 :
2521 : // Without stepping only active break points are hit.
2522 5 : CHECK_EQ(1, break_point_hit_count);
2523 :
2524 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2525 : CheckDebuggerUnloaded();
2526 5 : }
2527 :
2528 : // Test that step in works with function.apply.
2529 26661 : TEST(DebugStepFunctionApply) {
2530 5 : LocalContext env;
2531 10 : v8::HandleScope scope(env->GetIsolate());
2532 :
2533 : // Create a function for testing stepping.
2534 : v8::Local<v8::Function> foo =
2535 : CompileFunction(&env,
2536 : "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
2537 : "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
2538 : "foo");
2539 :
2540 : // Register a debug event listener which steps and counts.
2541 5 : DebugEventCounter run_step;
2542 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2543 :
2544 5 : v8::Local<v8::Context> context = env.local();
2545 : run_step.set_step_action(StepIn);
2546 5 : break_point_hit_count = 0;
2547 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2548 :
2549 : // With stepping all break locations are hit.
2550 5 : CHECK_EQ(7, break_point_hit_count);
2551 :
2552 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2553 : CheckDebuggerUnloaded();
2554 :
2555 : // Register a debug event listener which just counts.
2556 5 : DebugEventCounter delegate;
2557 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
2558 :
2559 5 : break_point_hit_count = 0;
2560 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2561 :
2562 : // Without stepping only the debugger statement is hit.
2563 5 : CHECK_EQ(1, break_point_hit_count);
2564 :
2565 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2566 : CheckDebuggerUnloaded();
2567 5 : }
2568 :
2569 :
2570 : // Test that step in works with function.call.
2571 26661 : TEST(DebugStepFunctionCall) {
2572 5 : LocalContext env;
2573 5 : v8::Isolate* isolate = env->GetIsolate();
2574 10 : v8::HandleScope scope(isolate);
2575 :
2576 5 : v8::Local<v8::Context> context = env.local();
2577 : // Create a function for testing stepping.
2578 : v8::Local<v8::Function> foo = CompileFunction(
2579 : &env,
2580 : "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
2581 : "function foo(a){ debugger;"
2582 : " if (a) {"
2583 : " bar.call(this, 1, 2, 3);"
2584 : " } else {"
2585 : " bar.call(this, 0);"
2586 : " }"
2587 : "}",
2588 : "foo");
2589 :
2590 : // Register a debug event listener which steps and counts.
2591 5 : DebugEventCounter run_step;
2592 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2593 : run_step.set_step_action(StepIn);
2594 :
2595 : // Check stepping where the if condition in bar is false.
2596 5 : break_point_hit_count = 0;
2597 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2598 5 : CHECK_EQ(6, break_point_hit_count);
2599 :
2600 : // Check stepping where the if condition in bar is true.
2601 5 : break_point_hit_count = 0;
2602 : const int argc = 1;
2603 : v8::Local<v8::Value> argv[argc] = {v8::True(isolate)};
2604 15 : foo->Call(context, env->Global(), argc, argv).ToLocalChecked();
2605 5 : CHECK_EQ(8, break_point_hit_count);
2606 :
2607 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2608 : CheckDebuggerUnloaded();
2609 :
2610 : // Register a debug event listener which just counts.
2611 5 : DebugEventCounter delegate;
2612 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
2613 :
2614 5 : break_point_hit_count = 0;
2615 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2616 :
2617 : // Without stepping only the debugger statement is hit.
2618 5 : CHECK_EQ(1, break_point_hit_count);
2619 :
2620 5 : v8::debug::SetDebugDelegate(isolate, nullptr);
2621 : CheckDebuggerUnloaded();
2622 5 : }
2623 :
2624 :
2625 : // Test that step in works with Function.call.apply.
2626 26661 : TEST(DebugStepFunctionCallApply) {
2627 5 : LocalContext env;
2628 5 : v8::Isolate* isolate = env->GetIsolate();
2629 10 : v8::HandleScope scope(isolate);
2630 :
2631 5 : v8::Local<v8::Context> context = env.local();
2632 : // Create a function for testing stepping.
2633 : v8::Local<v8::Function> foo =
2634 : CompileFunction(&env,
2635 : "function bar() { }"
2636 : "function foo(){ debugger;"
2637 : " Function.call.apply(bar);"
2638 : " Function.call.apply(Function.call, "
2639 : "[Function.call, bar]);"
2640 : "}",
2641 : "foo");
2642 :
2643 : // Register a debug event listener which steps and counts.
2644 5 : DebugEventCounter run_step;
2645 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &run_step);
2646 : run_step.set_step_action(StepIn);
2647 :
2648 5 : break_point_hit_count = 0;
2649 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2650 5 : CHECK_EQ(6, break_point_hit_count);
2651 :
2652 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2653 : CheckDebuggerUnloaded();
2654 :
2655 : // Register a debug event listener which just counts.
2656 5 : DebugEventCounter delegate;
2657 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
2658 :
2659 5 : break_point_hit_count = 0;
2660 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2661 :
2662 : // Without stepping only the debugger statement is hit.
2663 5 : CHECK_EQ(1, break_point_hit_count);
2664 :
2665 5 : v8::debug::SetDebugDelegate(isolate, nullptr);
2666 : CheckDebuggerUnloaded();
2667 5 : }
2668 :
2669 :
2670 : // Tests that breakpoint will be hit if it's set in script.
2671 26661 : TEST(PauseInScript) {
2672 5 : LocalContext env;
2673 10 : v8::HandleScope scope(env->GetIsolate());
2674 5 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
2675 :
2676 : // Register a debug event listener which counts.
2677 5 : DebugEventCounter event_counter;
2678 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &event_counter);
2679 :
2680 5 : v8::Local<v8::Context> context = env.local();
2681 : // Create a script that returns a function.
2682 : const char* src = "(function (evt) {})";
2683 : const char* script_name = "StepInHandlerTest";
2684 :
2685 : v8::ScriptOrigin origin(v8_str(env->GetIsolate(), script_name),
2686 10 : v8::Integer::New(env->GetIsolate(), 0));
2687 : v8::Local<v8::Script> script =
2688 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), src), &origin)
2689 : .ToLocalChecked();
2690 :
2691 : // Set breakpoint in the script.
2692 : i::Handle<i::Script> i_script(
2693 10 : i::Script::cast(v8::Utils::OpenHandle(*script)->shared()->script()),
2694 5 : isolate);
2695 5 : i::Handle<i::String> condition = isolate->factory()->empty_string();
2696 5 : int position = 0;
2697 : int id;
2698 5 : isolate->debug()->SetBreakPointForScript(i_script, condition, &position, &id);
2699 5 : break_point_hit_count = 0;
2700 :
2701 5 : v8::Local<v8::Value> r = script->Run(context).ToLocalChecked();
2702 :
2703 5 : CHECK(r->IsFunction());
2704 5 : CHECK_EQ(1, break_point_hit_count);
2705 :
2706 : // Get rid of the debug delegate.
2707 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2708 : CheckDebuggerUnloaded();
2709 5 : }
2710 :
2711 : int message_callback_count = 0;
2712 :
2713 26661 : TEST(DebugBreak) {
2714 5 : i::FLAG_stress_compaction = false;
2715 : #ifdef VERIFY_HEAP
2716 : i::FLAG_verify_heap = true;
2717 : #endif
2718 5 : LocalContext env;
2719 5 : v8::Isolate* isolate = env->GetIsolate();
2720 10 : v8::HandleScope scope(isolate);
2721 :
2722 : // Register a debug event listener which sets the break flag and counts.
2723 5 : DebugEventBreak delegate;
2724 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
2725 :
2726 5 : v8::Local<v8::Context> context = env.local();
2727 : // Create a function for testing stepping.
2728 : const char* src = "function f0() {}"
2729 : "function f1(x1) {}"
2730 : "function f2(x1,x2) {}"
2731 : "function f3(x1,x2,x3) {}";
2732 : v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
2733 : v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
2734 : v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
2735 : v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
2736 :
2737 : // Call the function to make sure it is compiled.
2738 : v8::Local<v8::Value> argv[] = {
2739 : v8::Number::New(isolate, 1), v8::Number::New(isolate, 1),
2740 20 : v8::Number::New(isolate, 1), v8::Number::New(isolate, 1)};
2741 :
2742 : // Call all functions to make sure that they are compiled.
2743 15 : f0->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2744 15 : f1->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2745 15 : f2->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2746 15 : f3->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2747 :
2748 : // Set the debug break flag.
2749 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
2750 :
2751 : // Call all functions with different argument count.
2752 5 : break_point_hit_count = 0;
2753 45 : for (unsigned int i = 0; i < arraysize(argv); i++) {
2754 80 : f0->Call(context, env->Global(), i, argv).ToLocalChecked();
2755 60 : f1->Call(context, env->Global(), i, argv).ToLocalChecked();
2756 60 : f2->Call(context, env->Global(), i, argv).ToLocalChecked();
2757 60 : f3->Call(context, env->Global(), i, argv).ToLocalChecked();
2758 : }
2759 :
2760 : // One break for each function called.
2761 10 : CHECK_EQ(4 * arraysize(argv), break_point_hit_count);
2762 :
2763 : // Get rid of the debug event listener.
2764 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2765 : CheckDebuggerUnloaded();
2766 5 : }
2767 :
2768 10 : class DebugScopingListener : public v8::debug::DebugDelegate {
2769 : public:
2770 0 : void BreakProgramRequested(
2771 : v8::Local<v8::Context>,
2772 : const std::vector<v8::debug::BreakpointId>&) override {
2773 : auto stack_traces =
2774 0 : v8::debug::StackTraceIterator::Create(CcTest::isolate());
2775 0 : v8::debug::Location location = stack_traces->GetSourceLocation();
2776 0 : CHECK_EQ(26, location.GetColumnNumber());
2777 0 : CHECK_EQ(0, location.GetLineNumber());
2778 :
2779 0 : auto scopes = stack_traces->GetScopeIterator();
2780 0 : CHECK_EQ(v8::debug::ScopeIterator::ScopeTypeWith, scopes->GetType());
2781 0 : CHECK_EQ(20, scopes->GetStartLocation().GetColumnNumber());
2782 0 : CHECK_EQ(31, scopes->GetEndLocation().GetColumnNumber());
2783 :
2784 0 : scopes->Advance();
2785 0 : CHECK_EQ(v8::debug::ScopeIterator::ScopeTypeLocal, scopes->GetType());
2786 0 : CHECK_EQ(0, scopes->GetStartLocation().GetColumnNumber());
2787 0 : CHECK_EQ(68, scopes->GetEndLocation().GetColumnNumber());
2788 :
2789 0 : scopes->Advance();
2790 0 : CHECK_EQ(v8::debug::ScopeIterator::ScopeTypeGlobal, scopes->GetType());
2791 :
2792 0 : scopes->Advance();
2793 0 : CHECK(scopes->Done());
2794 0 : }
2795 : };
2796 :
2797 26661 : TEST(DebugBreakInWrappedScript) {
2798 5 : i::FLAG_stress_compaction = false;
2799 : #ifdef VERIFY_HEAP
2800 : i::FLAG_verify_heap = true;
2801 : #endif
2802 5 : LocalContext env;
2803 5 : v8::Isolate* isolate = env->GetIsolate();
2804 10 : v8::HandleScope scope(isolate);
2805 :
2806 : // Register a debug event listener which sets the break flag and counts.
2807 5 : DebugScopingListener delegate;
2808 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
2809 :
2810 : static const char* source =
2811 : // 0 1 2 3 4 5 6 7
2812 : "try { with({o : []}){ o[0](); } } catch (e) { return e.toString(); }";
2813 : static const char* expect = "TypeError: o[0] is not a function";
2814 :
2815 : // For this test, we want to break on uncaught exceptions:
2816 5 : ChangeBreakOnException(true, true);
2817 :
2818 : {
2819 5 : v8::ScriptCompiler::Source script_source(v8_str(source));
2820 : v8::Local<v8::Function> fun =
2821 5 : v8::ScriptCompiler::CompileFunctionInContext(
2822 : env.local(), &script_source, 0, nullptr, 0, nullptr)
2823 : .ToLocalChecked();
2824 : v8::Local<v8::Value> result =
2825 15 : fun->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
2826 5 : CHECK(result->IsString());
2827 15 : CHECK(v8::Local<v8::String>::Cast(result)
2828 : ->Equals(env.local(), v8_str(expect))
2829 : .FromJust());
2830 : }
2831 :
2832 : // Get rid of the debug event listener.
2833 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2834 : CheckDebuggerUnloaded();
2835 5 : }
2836 :
2837 0 : static void EmptyHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {}
2838 :
2839 26661 : TEST(DebugScopeIteratorWithFunctionTemplate) {
2840 5 : LocalContext env;
2841 10 : v8::HandleScope handle_scope(env->GetIsolate());
2842 5 : v8::Isolate* isolate = env->GetIsolate();
2843 : EnableDebugger(isolate);
2844 : v8::Local<v8::Function> func =
2845 10 : v8::Function::New(env.local(), EmptyHandler).ToLocalChecked();
2846 : std::unique_ptr<v8::debug::ScopeIterator> iterator =
2847 5 : v8::debug::ScopeIterator::CreateForFunction(isolate, func);
2848 5 : CHECK(iterator->Done());
2849 : DisableDebugger(isolate);
2850 5 : }
2851 :
2852 26661 : TEST(DebugBreakWithoutJS) {
2853 5 : i::FLAG_stress_compaction = false;
2854 : #ifdef VERIFY_HEAP
2855 : i::FLAG_verify_heap = true;
2856 : #endif
2857 5 : LocalContext env;
2858 5 : v8::Isolate* isolate = env->GetIsolate();
2859 10 : v8::HandleScope scope(isolate);
2860 5 : v8::Local<v8::Context> context = env.local();
2861 :
2862 : // Register a debug event listener which sets the break flag and counts.
2863 5 : DebugEventBreak delegate;
2864 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
2865 :
2866 : // Set the debug break flag.
2867 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
2868 :
2869 5 : v8::Local<v8::String> json = v8_str("[1]");
2870 10 : v8::Local<v8::Value> parsed = v8::JSON::Parse(context, json).ToLocalChecked();
2871 15 : CHECK(v8::JSON::Stringify(context, parsed)
2872 : .ToLocalChecked()
2873 : ->Equals(context, json)
2874 : .FromJust());
2875 5 : CHECK_EQ(0, break_point_hit_count);
2876 : CompileRun("");
2877 5 : CHECK_EQ(1, break_point_hit_count);
2878 :
2879 : // Get rid of the debug event listener.
2880 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2881 : CheckDebuggerUnloaded();
2882 5 : }
2883 :
2884 : // Test to ensure that JavaScript code keeps running while the debug break
2885 : // through the stack limit flag is set but breaks are disabled.
2886 26661 : TEST(DisableBreak) {
2887 5 : LocalContext env;
2888 10 : v8::HandleScope scope(env->GetIsolate());
2889 :
2890 : // Register a debug event listener which sets the break flag and counts.
2891 5 : DebugEventCounter delegate;
2892 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
2893 :
2894 5 : v8::Local<v8::Context> context = env.local();
2895 : // Create a function for testing stepping.
2896 : const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
2897 : v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
2898 :
2899 : // Set, test and cancel debug break.
2900 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
2901 5 : v8::debug::ClearBreakOnNextFunctionCall(env->GetIsolate());
2902 :
2903 : // Set the debug break flag.
2904 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
2905 :
2906 : // Call all functions with different argument count.
2907 5 : break_point_hit_count = 0;
2908 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2909 5 : CHECK_EQ(1, break_point_hit_count);
2910 :
2911 : {
2912 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
2913 5 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
2914 : v8::internal::DisableBreak disable_break(isolate->debug());
2915 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2916 5 : CHECK_EQ(1, break_point_hit_count);
2917 : }
2918 :
2919 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2920 5 : CHECK_EQ(2, break_point_hit_count);
2921 :
2922 : // Get rid of the debug event listener.
2923 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2924 : CheckDebuggerUnloaded();
2925 5 : }
2926 :
2927 26661 : TEST(DisableDebuggerStatement) {
2928 5 : LocalContext env;
2929 10 : v8::HandleScope scope(env->GetIsolate());
2930 :
2931 : // Register a debug event listener which sets the break flag and counts.
2932 5 : DebugEventCounter delegate;
2933 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
2934 :
2935 : CompileRun("debugger;");
2936 5 : CHECK_EQ(1, break_point_hit_count);
2937 :
2938 : // Check that we ignore debugger statement when breakpoints aren't active.
2939 5 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
2940 : isolate->debug()->set_break_points_active(false);
2941 : CompileRun("debugger;");
2942 5 : CHECK_EQ(1, break_point_hit_count);
2943 :
2944 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
2945 5 : }
2946 :
2947 : static const char* kSimpleExtensionSource =
2948 : "(function Foo() {"
2949 : " return 4;"
2950 : "})() ";
2951 :
2952 : // http://crbug.com/28933
2953 : // Test that debug break is disabled when bootstrapper is active.
2954 26661 : TEST(NoBreakWhenBootstrapping) {
2955 5 : v8::Isolate* isolate = CcTest::isolate();
2956 10 : v8::HandleScope scope(isolate);
2957 :
2958 : // Register a debug event listener which sets the break flag and counts.
2959 5 : DebugEventCounter delegate;
2960 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
2961 :
2962 : // Set the debug break flag.
2963 5 : v8::debug::SetBreakOnNextFunctionCall(isolate);
2964 5 : break_point_hit_count = 0;
2965 : {
2966 : // Create a context with an extension to make sure that some JavaScript
2967 : // code is executed during bootstrapping.
2968 10 : v8::RegisterExtension(v8::base::make_unique<v8::Extension>(
2969 5 : "simpletest", kSimpleExtensionSource));
2970 5 : const char* extension_names[] = { "simpletest" };
2971 : v8::ExtensionConfiguration extensions(1, extension_names);
2972 10 : v8::HandleScope handle_scope(isolate);
2973 5 : v8::Context::New(isolate, &extensions);
2974 : }
2975 : // Check that no DebugBreak events occurred during the context creation.
2976 5 : CHECK_EQ(0, break_point_hit_count);
2977 :
2978 : // Get rid of the debug event listener.
2979 5 : v8::debug::SetDebugDelegate(isolate, nullptr);
2980 : CheckDebuggerUnloaded();
2981 5 : }
2982 :
2983 26661 : TEST(SetDebugEventListenerOnUninitializedVM) {
2984 10 : v8::HandleScope scope(CcTest::isolate());
2985 5 : EnableDebugger(CcTest::isolate());
2986 5 : }
2987 :
2988 : // Test that clearing the debug event listener actually clears all break points
2989 : // and related information.
2990 26661 : TEST(DebuggerUnload) {
2991 5 : LocalContext env;
2992 10 : v8::HandleScope handle_scope(env->GetIsolate());
2993 : // Check debugger is unloaded before it is used.
2994 : CheckDebuggerUnloaded();
2995 :
2996 : // Set a debug event listener.
2997 5 : break_point_hit_count = 0;
2998 5 : DebugEventCounter delegate;
2999 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3000 5 : v8::Local<v8::Context> context = env.local();
3001 : {
3002 10 : v8::HandleScope scope(env->GetIsolate());
3003 : // Create a couple of functions for the test.
3004 : v8::Local<v8::Function> foo =
3005 : CompileFunction(&env, "function foo(){x=1}", "foo");
3006 : v8::Local<v8::Function> bar =
3007 : CompileFunction(&env, "function bar(){y=2}", "bar");
3008 :
3009 : // Set some break points.
3010 5 : SetBreakPoint(foo, 0);
3011 5 : SetBreakPoint(foo, 4);
3012 5 : SetBreakPoint(bar, 0);
3013 5 : SetBreakPoint(bar, 4);
3014 :
3015 : // Make sure that the break points are there.
3016 5 : break_point_hit_count = 0;
3017 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3018 5 : CHECK_EQ(2, break_point_hit_count);
3019 15 : bar->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3020 5 : CHECK_EQ(4, break_point_hit_count);
3021 : }
3022 :
3023 : // Remove the debug event listener without clearing breakpoints. Do this
3024 : // outside a handle scope.
3025 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3026 : CheckDebuggerUnloaded();
3027 5 : }
3028 :
3029 : int event_listener_hit_count = 0;
3030 :
3031 : // Test for issue http://code.google.com/p/v8/issues/detail?id=289.
3032 : // Make sure that DebugGetLoadedScripts doesn't return scripts
3033 : // with disposed external source.
3034 : class EmptyExternalStringResource : public v8::String::ExternalStringResource {
3035 : public:
3036 : EmptyExternalStringResource() { empty_[0] = 0; }
3037 0 : ~EmptyExternalStringResource() override = default;
3038 0 : size_t length() const override { return empty_.length(); }
3039 0 : const uint16_t* data() const override { return empty_.start(); }
3040 :
3041 : private:
3042 : ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
3043 : };
3044 :
3045 26661 : TEST(DebugScriptLineEndsAreAscending) {
3046 5 : LocalContext env;
3047 5 : v8::Isolate* isolate = env->GetIsolate();
3048 10 : v8::HandleScope scope(isolate);
3049 :
3050 : // Compile a test script.
3051 : v8::Local<v8::String> script = v8_str(isolate,
3052 : "function f() {\n"
3053 : " debugger;\n"
3054 5 : "}\n");
3055 :
3056 5 : v8::ScriptOrigin origin1 = v8::ScriptOrigin(v8_str(isolate, "name"));
3057 : v8::Local<v8::Script> script1 =
3058 5 : v8::Script::Compile(env.local(), script, &origin1).ToLocalChecked();
3059 : USE(script1);
3060 :
3061 : Handle<v8::internal::FixedArray> instances;
3062 : {
3063 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
3064 5 : instances = debug->GetLoadedScripts();
3065 : }
3066 :
3067 5 : CHECK_GT(instances->length(), 0);
3068 45 : for (int i = 0; i < instances->length(); i++) {
3069 : Handle<v8::internal::Script> script = Handle<v8::internal::Script>(
3070 : v8::internal::Script::cast(instances->get(i)), CcTest::i_isolate());
3071 :
3072 20 : v8::internal::Script::InitLineEnds(script);
3073 : v8::internal::FixedArray ends =
3074 : v8::internal::FixedArray::cast(script->line_ends());
3075 20 : CHECK_GT(ends->length(), 0);
3076 :
3077 : int prev_end = -1;
3078 1030 : for (int j = 0; j < ends->length(); j++) {
3079 : const int curr_end = v8::internal::Smi::ToInt(ends->get(j));
3080 505 : CHECK_GT(curr_end, prev_end);
3081 : prev_end = curr_end;
3082 : }
3083 : }
3084 5 : }
3085 :
3086 : static v8::Local<v8::Context> expected_context;
3087 : static v8::Local<v8::Value> expected_context_data;
3088 :
3089 20 : class ContextCheckEventListener : public v8::debug::DebugDelegate {
3090 : public:
3091 15 : void BreakProgramRequested(v8::Local<v8::Context> paused_context,
3092 : const std::vector<v8::debug::BreakpointId>&
3093 : inspector_break_points_hit) override {
3094 15 : CheckContext();
3095 15 : }
3096 20 : void ScriptCompiled(v8::Local<v8::debug::Script> script, bool is_live_edited,
3097 : bool has_compile_error) override {
3098 20 : CheckContext();
3099 20 : }
3100 0 : void ExceptionThrown(v8::Local<v8::Context> paused_context,
3101 : v8::Local<v8::Value> exception,
3102 : v8::Local<v8::Value> promise, bool is_uncaught,
3103 : v8::debug::ExceptionType) override {
3104 0 : CheckContext();
3105 0 : }
3106 15 : bool IsFunctionBlackboxed(v8::Local<v8::debug::Script> script,
3107 : const v8::debug::Location& start,
3108 : const v8::debug::Location& end) override {
3109 15 : CheckContext();
3110 15 : return false;
3111 : }
3112 :
3113 : private:
3114 50 : void CheckContext() {
3115 50 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
3116 50 : CHECK(context == expected_context);
3117 50 : CHECK(context->GetEmbedderData(0)->StrictEquals(expected_context_data));
3118 50 : event_listener_hit_count++;
3119 50 : }
3120 : };
3121 :
3122 : // Test which creates two contexts and sets different embedder data on each.
3123 : // Checks that this data is set correctly and that when the debug event
3124 : // listener is called the expected context is the one active.
3125 26661 : TEST(ContextData) {
3126 5 : v8::Isolate* isolate = CcTest::isolate();
3127 10 : v8::HandleScope scope(isolate);
3128 :
3129 : // Create two contexts.
3130 : v8::Local<v8::Context> context_1;
3131 : v8::Local<v8::Context> context_2;
3132 : v8::Local<v8::ObjectTemplate> global_template =
3133 : v8::Local<v8::ObjectTemplate>();
3134 : v8::Local<v8::Value> global_object = v8::Local<v8::Value>();
3135 : context_1 =
3136 5 : v8::Context::New(isolate, nullptr, global_template, global_object);
3137 : context_2 =
3138 5 : v8::Context::New(isolate, nullptr, global_template, global_object);
3139 :
3140 5 : ContextCheckEventListener delegate;
3141 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
3142 :
3143 : // Default data value is undefined.
3144 5 : CHECK_EQ(0, context_1->GetNumberOfEmbedderDataFields());
3145 5 : CHECK_EQ(0, context_2->GetNumberOfEmbedderDataFields());
3146 :
3147 : // Set and check different data values.
3148 5 : v8::Local<v8::String> data_1 = v8_str(isolate, "1");
3149 5 : v8::Local<v8::String> data_2 = v8_str(isolate, "2");
3150 5 : context_1->SetEmbedderData(0, data_1);
3151 5 : context_2->SetEmbedderData(0, data_2);
3152 5 : CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
3153 5 : CHECK(context_2->GetEmbedderData(0)->StrictEquals(data_2));
3154 :
3155 : // Simple test function which causes a break.
3156 : const char* source = "function f() { debugger; }";
3157 :
3158 : // Enter and run function in the first context.
3159 : {
3160 : v8::Context::Scope context_scope(context_1);
3161 5 : expected_context = context_1;
3162 5 : expected_context_data = data_1;
3163 5 : v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
3164 15 : f->Call(context_1, context_1->Global(), 0, nullptr).ToLocalChecked();
3165 : }
3166 :
3167 : // Enter and run function in the second context.
3168 : {
3169 : v8::Context::Scope context_scope(context_2);
3170 5 : expected_context = context_2;
3171 5 : expected_context_data = data_2;
3172 5 : v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
3173 15 : f->Call(context_2, context_2->Global(), 0, nullptr).ToLocalChecked();
3174 : }
3175 :
3176 : // Two times compile event and two times break event.
3177 5 : CHECK_GT(event_listener_hit_count, 3);
3178 :
3179 5 : v8::debug::SetDebugDelegate(isolate, nullptr);
3180 : CheckDebuggerUnloaded();
3181 5 : }
3182 :
3183 : // Test which creates a context and sets embedder data on it. Checks that this
3184 : // data is set correctly and that when the debug event listener is called for
3185 : // break event in an eval statement the expected context is the one returned by
3186 : // Message.GetEventContext.
3187 26661 : TEST(EvalContextData) {
3188 10 : v8::HandleScope scope(CcTest::isolate());
3189 :
3190 : v8::Local<v8::Context> context_1;
3191 : v8::Local<v8::ObjectTemplate> global_template =
3192 : v8::Local<v8::ObjectTemplate>();
3193 5 : context_1 = v8::Context::New(CcTest::isolate(), nullptr, global_template);
3194 :
3195 5 : ContextCheckEventListener delegate;
3196 5 : v8::debug::SetDebugDelegate(CcTest::isolate(), &delegate);
3197 :
3198 : // Contexts initially do not have embedder data fields.
3199 5 : CHECK_EQ(0, context_1->GetNumberOfEmbedderDataFields());
3200 :
3201 : // Set and check a data value.
3202 5 : v8::Local<v8::String> data_1 = v8_str(CcTest::isolate(), "1");
3203 5 : context_1->SetEmbedderData(0, data_1);
3204 5 : CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
3205 :
3206 : // Simple test function with eval that causes a break.
3207 : const char* source = "function f() { eval('debugger;'); }";
3208 :
3209 : // Enter and run function in the context.
3210 : {
3211 : v8::Context::Scope context_scope(context_1);
3212 5 : expected_context = context_1;
3213 5 : expected_context_data = data_1;
3214 5 : v8::Local<v8::Function> f = CompileFunction(CcTest::isolate(), source, "f");
3215 15 : f->Call(context_1, context_1->Global(), 0, nullptr).ToLocalChecked();
3216 : }
3217 :
3218 5 : v8::debug::SetDebugDelegate(CcTest::isolate(), nullptr);
3219 :
3220 : // One time compile event and one time break event.
3221 5 : CHECK_GT(event_listener_hit_count, 2);
3222 : CheckDebuggerUnloaded();
3223 5 : }
3224 :
3225 : // Debug event listener which counts script compiled events.
3226 40 : class ScriptCompiledDelegate : public v8::debug::DebugDelegate {
3227 : public:
3228 50 : void ScriptCompiled(v8::Local<v8::debug::Script>, bool,
3229 : bool has_compile_error) override {
3230 50 : if (!has_compile_error) {
3231 35 : after_compile_event_count++;
3232 : } else {
3233 15 : compile_error_event_count++;
3234 : }
3235 50 : }
3236 :
3237 : int after_compile_event_count = 0;
3238 : int compile_error_event_count = 0;
3239 : };
3240 :
3241 : // Tests that after compile event is sent as many times as there are scripts
3242 : // compiled.
3243 26661 : TEST(AfterCompileEventWhenEventListenerIsReset) {
3244 5 : LocalContext env;
3245 10 : v8::HandleScope scope(env->GetIsolate());
3246 5 : v8::Local<v8::Context> context = env.local();
3247 : const char* script = "var a=1";
3248 :
3249 5 : ScriptCompiledDelegate delegate;
3250 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3251 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
3252 : .ToLocalChecked()
3253 5 : ->Run(context)
3254 : .ToLocalChecked();
3255 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3256 :
3257 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3258 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
3259 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
3260 : .ToLocalChecked()
3261 5 : ->Run(context)
3262 : .ToLocalChecked();
3263 :
3264 : // Setting listener to nullptr should cause debugger unload.
3265 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3266 : CheckDebuggerUnloaded();
3267 :
3268 : // Compilation cache should be disabled when debugger is active.
3269 5 : CHECK_EQ(2, delegate.after_compile_event_count);
3270 5 : }
3271 :
3272 : // Tests that syntax error event is sent as many times as there are scripts
3273 : // with syntax error compiled.
3274 26661 : TEST(SyntaxErrorEventOnSyntaxException) {
3275 5 : LocalContext env;
3276 10 : v8::HandleScope scope(env->GetIsolate());
3277 :
3278 : // For this test, we want to break on uncaught exceptions:
3279 5 : ChangeBreakOnException(false, true);
3280 :
3281 5 : ScriptCompiledDelegate delegate;
3282 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3283 5 : v8::Local<v8::Context> context = env.local();
3284 :
3285 : // Check initial state.
3286 5 : CHECK_EQ(0, delegate.compile_error_event_count);
3287 :
3288 : // Throws SyntaxError: Unexpected end of input
3289 10 : CHECK(
3290 : v8::Script::Compile(context, v8_str(env->GetIsolate(), "+++")).IsEmpty());
3291 5 : CHECK_EQ(1, delegate.compile_error_event_count);
3292 :
3293 10 : CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "/sel\\/: \\"))
3294 : .IsEmpty());
3295 5 : CHECK_EQ(2, delegate.compile_error_event_count);
3296 :
3297 : v8::Local<v8::Script> script =
3298 5 : v8::Script::Compile(context,
3299 5 : v8_str(env->GetIsolate(), "JSON.parse('1234:')"))
3300 : .ToLocalChecked();
3301 5 : CHECK_EQ(2, delegate.compile_error_event_count);
3302 10 : CHECK(script->Run(context).IsEmpty());
3303 5 : CHECK_EQ(3, delegate.compile_error_event_count);
3304 :
3305 5 : v8::Script::Compile(context,
3306 5 : v8_str(env->GetIsolate(), "new RegExp('/\\/\\\\');"))
3307 : .ToLocalChecked();
3308 5 : CHECK_EQ(3, delegate.compile_error_event_count);
3309 :
3310 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), "throw 1;"))
3311 : .ToLocalChecked();
3312 5 : CHECK_EQ(3, delegate.compile_error_event_count);
3313 5 : }
3314 :
3315 : // Tests that break event is sent when event listener is reset.
3316 26661 : TEST(BreakEventWhenEventListenerIsReset) {
3317 5 : LocalContext env;
3318 10 : v8::HandleScope scope(env->GetIsolate());
3319 5 : v8::Local<v8::Context> context = env.local();
3320 : const char* script = "function f() {};";
3321 :
3322 5 : ScriptCompiledDelegate delegate;
3323 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3324 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
3325 : .ToLocalChecked()
3326 5 : ->Run(context)
3327 : .ToLocalChecked();
3328 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3329 :
3330 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3331 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
3332 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
3333 10 : env->Global()
3334 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
3335 : .ToLocalChecked());
3336 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3337 :
3338 : // Setting event listener to nullptr should cause debugger unload.
3339 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3340 : CheckDebuggerUnloaded();
3341 :
3342 : // Compilation cache should be disabled when debugger is active.
3343 5 : CHECK_EQ(1, delegate.after_compile_event_count);
3344 5 : }
3345 :
3346 : // Tests that script is reported as compiled when bound to context.
3347 26661 : TEST(AfterCompileEventOnBindToContext) {
3348 5 : LocalContext env;
3349 5 : v8::Isolate* isolate = env->GetIsolate();
3350 10 : v8::HandleScope handle_scope(isolate);
3351 5 : ScriptCompiledDelegate delegate;
3352 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
3353 :
3354 : const char* source = "var a=1";
3355 : v8::ScriptCompiler::Source script_source(
3356 5 : v8::String::NewFromUtf8(isolate, source, v8::NewStringType::kNormal)
3357 : .ToLocalChecked());
3358 :
3359 : v8::Local<v8::UnboundScript> unbound =
3360 5 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source)
3361 : .ToLocalChecked();
3362 5 : CHECK_EQ(delegate.after_compile_event_count, 0);
3363 :
3364 5 : unbound->BindToCurrentContext();
3365 5 : CHECK_EQ(delegate.after_compile_event_count, 1);
3366 5 : v8::debug::SetDebugDelegate(isolate, nullptr);
3367 5 : }
3368 :
3369 :
3370 : // Test that if DebugBreak is forced it is ignored when code from
3371 : // debug-delay.js is executed.
3372 26661 : TEST(NoDebugBreakInAfterCompileEventListener) {
3373 5 : LocalContext env;
3374 10 : v8::HandleScope scope(env->GetIsolate());
3375 5 : v8::Local<v8::Context> context = env.local();
3376 :
3377 : // Register a debug event listener which sets the break flag and counts.
3378 5 : DebugEventCounter delegate;
3379 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3380 :
3381 : // Set the debug break flag.
3382 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
3383 :
3384 : // Create a function for testing stepping.
3385 : const char* src = "function f() { eval('var x = 10;'); } ";
3386 : v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
3387 :
3388 : // There should be only one break event.
3389 5 : CHECK_EQ(1, break_point_hit_count);
3390 :
3391 : // Set the debug break flag again.
3392 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
3393 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3394 : // There should be one more break event when the script is evaluated in 'f'.
3395 5 : CHECK_EQ(2, break_point_hit_count);
3396 :
3397 : // Get rid of the debug event listener.
3398 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3399 : CheckDebuggerUnloaded();
3400 5 : }
3401 :
3402 :
3403 : // Test that the debug break flag works with function.apply.
3404 26661 : TEST(DebugBreakFunctionApply) {
3405 5 : LocalContext env;
3406 10 : v8::HandleScope scope(env->GetIsolate());
3407 5 : v8::Local<v8::Context> context = env.local();
3408 :
3409 : // Create a function for testing breaking in apply.
3410 : v8::Local<v8::Function> foo = CompileFunction(
3411 : &env,
3412 : "function baz(x) { }"
3413 : "function bar(x) { baz(); }"
3414 : "function foo(){ bar.apply(this, [1]); }",
3415 : "foo");
3416 :
3417 : // Register a debug event listener which steps and counts.
3418 5 : DebugEventBreakMax delegate;
3419 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3420 :
3421 : // Set the debug break flag before calling the code using function.apply.
3422 5 : v8::debug::SetBreakOnNextFunctionCall(env->GetIsolate());
3423 :
3424 : // Limit the number of debug breaks. This is a regression test for issue 493
3425 : // where this test would enter an infinite loop.
3426 5 : break_point_hit_count = 0;
3427 5 : max_break_point_hit_count = 10000; // 10000 => infinite loop.
3428 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3429 :
3430 : // When keeping the debug break several break will happen.
3431 5 : CHECK_GT(break_point_hit_count, 1);
3432 :
3433 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3434 : CheckDebuggerUnloaded();
3435 5 : }
3436 :
3437 : // Test that setting the terminate execution flag during debug break processing.
3438 60 : static void TestDebugBreakInLoop(const char* loop_head,
3439 : const char** loop_bodies,
3440 : const char* loop_tail) {
3441 : // Receive 10 breaks for each test and then terminate JavaScript execution.
3442 : static const int kBreaksPerTest = 10;
3443 :
3444 720 : for (int i = 0; loop_bodies[i] != nullptr; i++) {
3445 : // Perform a lazy deoptimization after various numbers of breaks
3446 : // have been hit.
3447 :
3448 : i::EmbeddedVector<char, 1024> buffer;
3449 : SNPrintF(buffer, "function f() {%s%s%s}", loop_head, loop_bodies[i],
3450 330 : loop_tail);
3451 :
3452 330 : i::PrintF("%s\n", buffer.start());
3453 :
3454 2310 : for (int j = 0; j < 3; j++) {
3455 990 : break_point_hit_count_deoptimize = j;
3456 990 : if (j == 2) {
3457 330 : break_point_hit_count_deoptimize = kBreaksPerTest;
3458 : }
3459 :
3460 990 : break_point_hit_count = 0;
3461 990 : max_break_point_hit_count = kBreaksPerTest;
3462 990 : terminate_after_max_break_point_hit = true;
3463 :
3464 : // Function with infinite loop.
3465 : CompileRun(buffer.start());
3466 :
3467 : // Set the debug break to enter the debugger as soon as possible.
3468 990 : v8::debug::SetBreakOnNextFunctionCall(CcTest::isolate());
3469 :
3470 : // Call function with infinite loop.
3471 : CompileRun("f();");
3472 990 : CHECK_EQ(kBreaksPerTest, break_point_hit_count);
3473 :
3474 990 : CHECK(!CcTest::isolate()->IsExecutionTerminating());
3475 : }
3476 : }
3477 60 : }
3478 :
3479 : static const char* loop_bodies_1[] = {"",
3480 : "g()",
3481 : "if (a == 0) { g() }",
3482 : "if (a == 1) { g() }",
3483 : "if (a == 0) { g() } else { h() }",
3484 : "if (a == 0) { continue }",
3485 : nullptr};
3486 :
3487 : static const char* loop_bodies_2[] = {
3488 : "if (a == 1) { continue }",
3489 : "switch (a) { case 1: g(); }",
3490 : "switch (a) { case 1: continue; }",
3491 : "switch (a) { case 1: g(); break; default: h() }",
3492 : "switch (a) { case 1: continue; break; default: h() }",
3493 : nullptr};
3494 :
3495 60 : void DebugBreakLoop(const char* loop_header, const char** loop_bodies,
3496 : const char* loop_footer) {
3497 60 : LocalContext env;
3498 120 : v8::HandleScope scope(env->GetIsolate());
3499 :
3500 : // Register a debug event listener which sets the break flag and counts.
3501 60 : DebugEventBreakMax delegate;
3502 60 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3503 :
3504 : CompileRun(
3505 : "var a = 1;\n"
3506 : "function g() { }\n"
3507 : "function h() { }");
3508 :
3509 60 : TestDebugBreakInLoop(loop_header, loop_bodies, loop_footer);
3510 :
3511 : // Get rid of the debug event listener.
3512 60 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3513 : CheckDebuggerUnloaded();
3514 60 : }
3515 :
3516 :
3517 26661 : TEST(DebugBreakInWhileTrue1) {
3518 5 : DebugBreakLoop("while (true) {", loop_bodies_1, "}");
3519 5 : }
3520 :
3521 :
3522 26661 : TEST(DebugBreakInWhileTrue2) {
3523 5 : DebugBreakLoop("while (true) {", loop_bodies_2, "}");
3524 5 : }
3525 :
3526 :
3527 26661 : TEST(DebugBreakInWhileCondition1) {
3528 5 : DebugBreakLoop("while (a == 1) {", loop_bodies_1, "}");
3529 5 : }
3530 :
3531 :
3532 26661 : TEST(DebugBreakInWhileCondition2) {
3533 5 : DebugBreakLoop("while (a == 1) {", loop_bodies_2, "}");
3534 5 : }
3535 :
3536 :
3537 26661 : TEST(DebugBreakInDoWhileTrue1) {
3538 5 : DebugBreakLoop("do {", loop_bodies_1, "} while (true)");
3539 5 : }
3540 :
3541 :
3542 26661 : TEST(DebugBreakInDoWhileTrue2) {
3543 5 : DebugBreakLoop("do {", loop_bodies_2, "} while (true)");
3544 5 : }
3545 :
3546 :
3547 26661 : TEST(DebugBreakInDoWhileCondition1) {
3548 5 : DebugBreakLoop("do {", loop_bodies_1, "} while (a == 1)");
3549 5 : }
3550 :
3551 :
3552 26661 : TEST(DebugBreakInDoWhileCondition2) {
3553 5 : DebugBreakLoop("do {", loop_bodies_2, "} while (a == 1)");
3554 5 : }
3555 :
3556 :
3557 26661 : TEST(DebugBreakInFor1) { DebugBreakLoop("for (;;) {", loop_bodies_1, "}"); }
3558 :
3559 :
3560 26661 : TEST(DebugBreakInFor2) { DebugBreakLoop("for (;;) {", loop_bodies_2, "}"); }
3561 :
3562 :
3563 26661 : TEST(DebugBreakInForCondition1) {
3564 5 : DebugBreakLoop("for (;a == 1;) {", loop_bodies_1, "}");
3565 5 : }
3566 :
3567 :
3568 26661 : TEST(DebugBreakInForCondition2) {
3569 5 : DebugBreakLoop("for (;a == 1;) {", loop_bodies_2, "}");
3570 5 : }
3571 :
3572 10 : class DebugBreakInlineListener : public v8::debug::DebugDelegate {
3573 : public:
3574 5 : void BreakProgramRequested(v8::Local<v8::Context> paused_context,
3575 : const std::vector<v8::debug::BreakpointId>&
3576 : inspector_break_points_hit) override {
3577 : int expected_frame_count = 4;
3578 5 : int expected_line_number[] = {1, 4, 7, 12};
3579 :
3580 : int frame_count = 0;
3581 5 : auto iterator = v8::debug::StackTraceIterator::Create(CcTest::isolate());
3582 45 : for (; !iterator->Done(); iterator->Advance(), ++frame_count) {
3583 20 : v8::debug::Location loc = iterator->GetSourceLocation();
3584 20 : CHECK_EQ(expected_line_number[frame_count], loc.GetLineNumber());
3585 : }
3586 5 : CHECK_EQ(frame_count, expected_frame_count);
3587 5 : }
3588 : };
3589 :
3590 26661 : TEST(DebugBreakInline) {
3591 5 : i::FLAG_allow_natives_syntax = true;
3592 5 : LocalContext env;
3593 10 : v8::HandleScope scope(env->GetIsolate());
3594 5 : v8::Local<v8::Context> context = env.local();
3595 : const char* source =
3596 : "function debug(b) { \n"
3597 : " if (b) debugger; \n"
3598 : "} \n"
3599 : "function f(b) { \n"
3600 : " debug(b) \n"
3601 : "}; \n"
3602 : "function g(b) { \n"
3603 : " f(b); \n"
3604 : "}; \n"
3605 : "g(false); \n"
3606 : "g(false); \n"
3607 : "%OptimizeFunctionOnNextCall(g); \n"
3608 : "g(true);";
3609 5 : DebugBreakInlineListener delegate;
3610 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3611 : v8::Local<v8::Script> inline_script =
3612 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), source))
3613 : .ToLocalChecked();
3614 5 : inline_script->Run(context).ToLocalChecked();
3615 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3616 5 : }
3617 :
3618 5 : static void RunScriptInANewCFrame(const char* source) {
3619 10 : v8::TryCatch try_catch(CcTest::isolate());
3620 : CompileRun(source);
3621 5 : CHECK(try_catch.HasCaught());
3622 5 : }
3623 :
3624 :
3625 26661 : TEST(Regress131642) {
3626 : // Bug description:
3627 : // When doing StepNext through the first script, the debugger is not reset
3628 : // after exiting through exception. A flawed implementation enabling the
3629 : // debugger to step into Array.prototype.forEach breaks inside the callback
3630 : // for forEach in the second script under the assumption that we are in a
3631 : // recursive call. In an attempt to step out, we crawl the stack using the
3632 : // recorded frame pointer from the first script and fail when not finding it
3633 : // on the stack.
3634 5 : LocalContext env;
3635 10 : v8::HandleScope scope(env->GetIsolate());
3636 5 : DebugEventCounter delegate;
3637 : delegate.set_step_action(StepNext);
3638 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3639 :
3640 : // We step through the first script. It exits through an exception. We run
3641 : // this inside a new frame to record a different FP than the second script
3642 : // would expect.
3643 : const char* script_1 = "debugger; throw new Error();";
3644 5 : RunScriptInANewCFrame(script_1);
3645 :
3646 : // The second script uses forEach.
3647 : const char* script_2 = "[0].forEach(function() { });";
3648 : CompileRun(script_2);
3649 :
3650 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
3651 5 : }
3652 :
3653 10 : class DebugBreakStackTraceListener : public v8::debug::DebugDelegate {
3654 : public:
3655 0 : void BreakProgramRequested(v8::Local<v8::Context> paused_context,
3656 : const std::vector<v8::debug::BreakpointId>&
3657 : inspector_break_points_hit) override {
3658 0 : v8::StackTrace::CurrentStackTrace(CcTest::isolate(), 10);
3659 0 : }
3660 : };
3661 :
3662 5000 : static void AddDebugBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
3663 5000 : v8::debug::SetBreakOnNextFunctionCall(args.GetIsolate());
3664 5000 : }
3665 :
3666 26661 : TEST(DebugBreakStackTrace) {
3667 5 : LocalContext env;
3668 10 : v8::HandleScope scope(env->GetIsolate());
3669 5 : DebugBreakStackTraceListener delegate;
3670 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3671 5 : v8::Local<v8::Context> context = env.local();
3672 : v8::Local<v8::FunctionTemplate> add_debug_break_template =
3673 5 : v8::FunctionTemplate::New(env->GetIsolate(), AddDebugBreak);
3674 : v8::Local<v8::Function> add_debug_break =
3675 5 : add_debug_break_template->GetFunction(context).ToLocalChecked();
3676 20 : CHECK(env->Global()
3677 : ->Set(context, v8_str("add_debug_break"), add_debug_break)
3678 : .FromJust());
3679 :
3680 : CompileRun("(function loop() {"
3681 : " for (var j = 0; j < 1000; j++) {"
3682 : " for (var i = 0; i < 1000; i++) {"
3683 : " if (i == 999) add_debug_break();"
3684 : " }"
3685 : " }"
3686 : "})()");
3687 5 : }
3688 :
3689 :
3690 26656 : v8::base::Semaphore terminate_requested_semaphore(0);
3691 26656 : v8::base::Semaphore terminate_fired_semaphore(0);
3692 :
3693 10 : class DebugBreakTriggerTerminate : public v8::debug::DebugDelegate {
3694 : public:
3695 5 : void BreakProgramRequested(v8::Local<v8::Context> paused_context,
3696 : const std::vector<v8::debug::BreakpointId>&
3697 : inspector_break_points_hit) override {
3698 5 : if (terminate_already_fired_) return;
3699 5 : terminate_requested_semaphore.Signal();
3700 : // Wait for at most 2 seconds for the terminate request.
3701 5 : CHECK(
3702 : terminate_fired_semaphore.WaitFor(v8::base::TimeDelta::FromSeconds(2)));
3703 5 : terminate_already_fired_ = true;
3704 : }
3705 :
3706 : private:
3707 : bool terminate_already_fired_ = false;
3708 : };
3709 :
3710 5 : class TerminationThread : public v8::base::Thread {
3711 : public:
3712 : explicit TerminationThread(v8::Isolate* isolate)
3713 5 : : Thread(Options("terminator")), isolate_(isolate) {}
3714 :
3715 5 : void Run() override {
3716 5 : terminate_requested_semaphore.Wait();
3717 5 : isolate_->TerminateExecution();
3718 5 : terminate_fired_semaphore.Signal();
3719 5 : }
3720 :
3721 : private:
3722 : v8::Isolate* isolate_;
3723 : };
3724 :
3725 :
3726 26661 : TEST(DebugBreakOffThreadTerminate) {
3727 5 : LocalContext env;
3728 5 : v8::Isolate* isolate = env->GetIsolate();
3729 10 : v8::HandleScope scope(isolate);
3730 5 : DebugBreakTriggerTerminate delegate;
3731 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
3732 : TerminationThread terminator(isolate);
3733 5 : terminator.Start();
3734 10 : v8::TryCatch try_catch(env->GetIsolate());
3735 5 : env->GetIsolate()->RequestInterrupt(BreakRightNow, nullptr);
3736 : CompileRun("while (true);");
3737 5 : CHECK(try_catch.HasTerminated());
3738 5 : }
3739 :
3740 50 : class ArchiveRestoreThread : public v8::base::Thread,
3741 : public v8::debug::DebugDelegate {
3742 : public:
3743 : ArchiveRestoreThread(v8::Isolate* isolate, int spawn_count)
3744 : : Thread(Options("ArchiveRestoreThread")),
3745 : isolate_(isolate),
3746 : debug_(reinterpret_cast<i::Isolate*>(isolate_)->debug()),
3747 : spawn_count_(spawn_count),
3748 50 : break_count_(0) {}
3749 :
3750 25 : void Run() override {
3751 50 : v8::Locker locker(isolate_);
3752 25 : isolate_->Enter();
3753 :
3754 50 : v8::HandleScope scope(isolate_);
3755 25 : v8::Local<v8::Context> context = v8::Context::New(isolate_);
3756 : v8::Context::Scope context_scope(context);
3757 :
3758 : v8::Local<v8::Function> test = CompileFunction(isolate_,
3759 : "function test(n) {\n"
3760 : " debugger;\n"
3761 : " return n + 1;\n"
3762 : "}\n",
3763 25 : "test");
3764 :
3765 25 : debug_->SetDebugDelegate(this);
3766 25 : v8::internal::DisableBreak enable_break(debug_, false);
3767 :
3768 25 : v8::Local<v8::Value> args[1] = {v8::Integer::New(isolate_, spawn_count_)};
3769 :
3770 75 : int result = test->Call(context, context->Global(), 1, args)
3771 : .ToLocalChecked()
3772 50 : ->Int32Value(context)
3773 : .FromJust();
3774 :
3775 : // Verify that test(spawn_count_) returned spawn_count_ + 1.
3776 25 : CHECK_EQ(spawn_count_ + 1, result);
3777 :
3778 25 : isolate_->Exit();
3779 25 : }
3780 :
3781 50 : void BreakProgramRequested(
3782 : v8::Local<v8::Context> context,
3783 : const std::vector<v8::debug::BreakpointId>&) override {
3784 50 : auto stack_traces = v8::debug::StackTraceIterator::Create(isolate_);
3785 50 : if (!stack_traces->Done()) {
3786 50 : v8::debug::Location location = stack_traces->GetSourceLocation();
3787 :
3788 50 : i::PrintF("ArchiveRestoreThread #%d hit breakpoint at line %d\n",
3789 50 : spawn_count_, location.GetLineNumber());
3790 :
3791 50 : switch (location.GetLineNumber()) {
3792 : case 1: // debugger;
3793 25 : CHECK_EQ(break_count_, 0);
3794 :
3795 : // Attempt to stop on the next line after the first debugger
3796 : // statement. If debug->{Archive,Restore}Debug() improperly reset
3797 : // thread-local debug information, the debugger will fail to stop
3798 : // before the test function returns.
3799 25 : debug_->PrepareStep(StepNext);
3800 :
3801 : // Spawning threads while handling the current breakpoint verifies
3802 : // that the parent thread correctly archived and restored the
3803 : // state necessary to stop on the next line. If not, then control
3804 : // will simply continue past the `return n + 1` statement.
3805 25 : MaybeSpawnChildThread();
3806 :
3807 25 : break;
3808 :
3809 : case 2: // return n + 1;
3810 25 : CHECK_EQ(break_count_, 1);
3811 : break;
3812 :
3813 : default:
3814 0 : CHECK(false);
3815 : }
3816 : }
3817 :
3818 50 : ++break_count_;
3819 50 : }
3820 :
3821 25 : void MaybeSpawnChildThread() {
3822 25 : if (spawn_count_ > 1) {
3823 40 : v8::Unlocker unlocker(isolate_);
3824 :
3825 : // Spawn a thread that spawns a thread that spawns a thread (and so
3826 : // on) so that the ThreadManager is forced to archive and restore
3827 : // the current thread.
3828 20 : ArchiveRestoreThread child(isolate_, spawn_count_ - 1);
3829 20 : child.Start();
3830 20 : child.Join();
3831 :
3832 : // The child thread sets itself as the debug delegate, so we need to
3833 : // usurp it after the child finishes, or else future breakpoints
3834 : // will be delegated to a destroyed ArchiveRestoreThread object.
3835 20 : debug_->SetDebugDelegate(this);
3836 :
3837 : // This is the most important check in this test, since
3838 : // child.GetBreakCount() will return 1 if the debugger fails to stop
3839 : // on the `return n + 1` line after the grandchild thread returns.
3840 20 : CHECK_EQ(child.GetBreakCount(), 2);
3841 : }
3842 25 : }
3843 :
3844 : int GetBreakCount() { return break_count_; }
3845 :
3846 : private:
3847 : v8::Isolate* isolate_;
3848 : v8::internal::Debug* debug_;
3849 : const int spawn_count_;
3850 : int break_count_;
3851 : };
3852 :
3853 26661 : TEST(DebugArchiveRestore) {
3854 : v8::Isolate::CreateParams create_params;
3855 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
3856 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
3857 :
3858 : ArchiveRestoreThread thread(isolate, 5);
3859 : // Instead of calling thread.Start() and thread.Join() here, we call
3860 : // thread.Run() directly, to make sure we exercise archive/restore
3861 : // logic on the *current* thread as well as other threads.
3862 5 : thread.Run();
3863 5 : CHECK_EQ(thread.GetBreakCount(), 2);
3864 :
3865 5 : isolate->Dispose();
3866 5 : }
3867 :
3868 10 : class DebugEventExpectNoException : public v8::debug::DebugDelegate {
3869 : public:
3870 0 : void ExceptionThrown(v8::Local<v8::Context> paused_context,
3871 : v8::Local<v8::Value> exception,
3872 : v8::Local<v8::Value> promise, bool is_uncaught,
3873 : v8::debug::ExceptionType) override {
3874 0 : CHECK(false);
3875 : }
3876 : };
3877 :
3878 5 : static void TryCatchWrappedThrowCallback(
3879 : const v8::FunctionCallbackInfo<v8::Value>& args) {
3880 10 : v8::TryCatch try_catch(args.GetIsolate());
3881 : CompileRun("throw 'rejection';");
3882 5 : CHECK(try_catch.HasCaught());
3883 5 : }
3884 :
3885 26661 : TEST(DebugPromiseInterceptedByTryCatch) {
3886 5 : LocalContext env;
3887 5 : v8::Isolate* isolate = env->GetIsolate();
3888 10 : v8::HandleScope scope(isolate);
3889 5 : DebugEventExpectNoException delegate;
3890 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
3891 5 : v8::Local<v8::Context> context = env.local();
3892 5 : ChangeBreakOnException(false, true);
3893 :
3894 : v8::Local<v8::FunctionTemplate> fun =
3895 5 : v8::FunctionTemplate::New(isolate, TryCatchWrappedThrowCallback);
3896 25 : CHECK(env->Global()
3897 : ->Set(context, v8_str("fun"),
3898 : fun->GetFunction(context).ToLocalChecked())
3899 : .FromJust());
3900 :
3901 : CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
3902 : CompileRun(
3903 : "var r;"
3904 : "p.then(function() { r = 'resolved'; },"
3905 : " function() { r = 'rejected'; });");
3906 15 : CHECK(CompileRun("r")->Equals(context, v8_str("resolved")).FromJust());
3907 5 : }
3908 :
3909 10 : class NoInterruptsOnDebugEvent : public v8::debug::DebugDelegate {
3910 : public:
3911 5 : void ScriptCompiled(v8::Local<v8::debug::Script> script, bool is_live_edited,
3912 : bool has_compile_error) override {
3913 5 : ++after_compile_handler_depth_;
3914 : // Do not allow nested AfterCompile events.
3915 5 : CHECK_LE(after_compile_handler_depth_, 1);
3916 5 : v8::Isolate* isolate = CcTest::isolate();
3917 10 : v8::Isolate::AllowJavascriptExecutionScope allow_script(isolate);
3918 5 : isolate->RequestInterrupt(&HandleInterrupt, this);
3919 : CompileRun("function foo() {}; foo();");
3920 5 : --after_compile_handler_depth_;
3921 5 : }
3922 :
3923 : private:
3924 5 : static void HandleInterrupt(v8::Isolate* isolate, void* data) {
3925 : NoInterruptsOnDebugEvent* d = static_cast<NoInterruptsOnDebugEvent*>(data);
3926 5 : CHECK_EQ(0, d->after_compile_handler_depth_);
3927 5 : }
3928 :
3929 : int after_compile_handler_depth_ = 0;
3930 : };
3931 :
3932 26661 : TEST(NoInterruptsInDebugListener) {
3933 5 : LocalContext env;
3934 10 : v8::HandleScope handle_scope(env->GetIsolate());
3935 5 : NoInterruptsOnDebugEvent delegate;
3936 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
3937 : CompileRun("void(0);");
3938 5 : }
3939 :
3940 26661 : TEST(BreakLocationIterator) {
3941 5 : LocalContext env;
3942 5 : v8::Isolate* isolate = env->GetIsolate();
3943 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
3944 10 : v8::HandleScope scope(isolate);
3945 :
3946 : v8::Local<v8::Value> result = CompileRun(
3947 : "function f() {\n"
3948 : " debugger; \n"
3949 : " f(); \n"
3950 : " debugger; \n"
3951 : "} \n"
3952 : "f");
3953 : Handle<i::Object> function_obj = v8::Utils::OpenHandle(*result);
3954 : Handle<i::JSFunction> function = Handle<i::JSFunction>::cast(function_obj);
3955 : Handle<i::SharedFunctionInfo> shared(function->shared(), i_isolate);
3956 :
3957 : EnableDebugger(isolate);
3958 5 : CHECK(i_isolate->debug()->EnsureBreakInfo(shared));
3959 5 : i_isolate->debug()->PrepareFunctionForDebugExecution(shared);
3960 :
3961 : Handle<i::DebugInfo> debug_info(shared->GetDebugInfo(), i_isolate);
3962 :
3963 : {
3964 5 : i::BreakIterator iterator(debug_info);
3965 5 : CHECK(iterator.GetBreakLocation().IsDebuggerStatement());
3966 5 : CHECK_EQ(17, iterator.GetBreakLocation().position());
3967 5 : iterator.Next();
3968 10 : CHECK(iterator.GetBreakLocation().IsDebugBreakSlot());
3969 5 : CHECK_EQ(32, iterator.GetBreakLocation().position());
3970 5 : iterator.Next();
3971 5 : CHECK(iterator.GetBreakLocation().IsCall());
3972 5 : CHECK_EQ(32, iterator.GetBreakLocation().position());
3973 5 : iterator.Next();
3974 5 : CHECK(iterator.GetBreakLocation().IsDebuggerStatement());
3975 5 : CHECK_EQ(47, iterator.GetBreakLocation().position());
3976 5 : iterator.Next();
3977 5 : CHECK(iterator.GetBreakLocation().IsReturn());
3978 5 : CHECK_EQ(60, iterator.GetBreakLocation().position());
3979 5 : iterator.Next();
3980 5 : CHECK(iterator.Done());
3981 : }
3982 :
3983 : DisableDebugger(isolate);
3984 5 : }
3985 :
3986 10 : class DebugStepOverFunctionWithCaughtExceptionListener
3987 : : public v8::debug::DebugDelegate {
3988 : public:
3989 15 : void BreakProgramRequested(v8::Local<v8::Context> paused_context,
3990 : const std::vector<v8::debug::BreakpointId>&
3991 : inspector_break_points_hit) override {
3992 15 : ++break_point_hit_count;
3993 15 : if (break_point_hit_count >= 3) return;
3994 : PrepareStep(StepNext);
3995 : }
3996 : int break_point_hit_count = 0;
3997 : };
3998 :
3999 26661 : TEST(DebugStepOverFunctionWithCaughtException) {
4000 5 : i::FLAG_allow_natives_syntax = true;
4001 :
4002 5 : LocalContext env;
4003 5 : v8::Isolate* isolate = env->GetIsolate();
4004 10 : v8::HandleScope scope(isolate);
4005 5 : DebugStepOverFunctionWithCaughtExceptionListener delegate;
4006 5 : v8::debug::SetDebugDelegate(isolate, &delegate);
4007 :
4008 : CompileRun(
4009 : "function foo() {\n"
4010 : " try { throw new Error(); } catch (e) {}\n"
4011 : "}\n"
4012 : "debugger;\n"
4013 : "foo();\n"
4014 : "foo();\n");
4015 :
4016 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
4017 5 : CHECK_EQ(3, delegate.break_point_hit_count);
4018 5 : }
4019 :
4020 : bool near_heap_limit_callback_called = false;
4021 5 : size_t NearHeapLimitCallback(void* data, size_t current_heap_limit,
4022 : size_t initial_heap_limit) {
4023 5 : near_heap_limit_callback_called = true;
4024 5 : return initial_heap_limit + 10u * i::MB;
4025 : }
4026 :
4027 26661 : UNINITIALIZED_TEST(DebugSetOutOfMemoryListener) {
4028 : v8::Isolate::CreateParams create_params;
4029 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
4030 : create_params.constraints.set_max_old_space_size(10);
4031 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
4032 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
4033 : {
4034 : v8::Isolate::Scope i_scope(isolate);
4035 10 : v8::HandleScope scope(isolate);
4036 5 : LocalContext context(isolate);
4037 5 : isolate->AddNearHeapLimitCallback(NearHeapLimitCallback, nullptr);
4038 5 : CHECK(!near_heap_limit_callback_called);
4039 : // The following allocation fails unless the out-of-memory callback
4040 : // increases the heap limit.
4041 : int length = 10 * i::MB / i::kTaggedSize;
4042 5 : i_isolate->factory()->NewFixedArray(length, i::AllocationType::kOld);
4043 5 : CHECK(near_heap_limit_callback_called);
4044 5 : isolate->RemoveNearHeapLimitCallback(NearHeapLimitCallback, 0);
4045 : }
4046 5 : isolate->Dispose();
4047 5 : }
4048 :
4049 26661 : TEST(DebugCoverage) {
4050 : // Coverage needs feedback vectors.
4051 : if (i::FLAG_lite_mode) return;
4052 5 : i::FLAG_always_opt = false;
4053 5 : LocalContext env;
4054 5 : v8::Isolate* isolate = env->GetIsolate();
4055 10 : v8::HandleScope scope(isolate);
4056 : v8::debug::Coverage::SelectMode(isolate,
4057 5 : v8::debug::CoverageMode::kPreciseCount);
4058 : v8::Local<v8::String> source = v8_str(
4059 : "function f() {\n"
4060 : "}\n"
4061 : "f();\n"
4062 5 : "f();");
4063 5 : CompileRun(source);
4064 5 : v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(isolate);
4065 5 : CHECK_EQ(1u, coverage.ScriptCount());
4066 5 : v8::debug::Coverage::ScriptData script_data = coverage.GetScriptData(0);
4067 5 : v8::Local<v8::debug::Script> script = script_data.GetScript();
4068 15 : CHECK(script->Source()
4069 : .ToLocalChecked()
4070 : ->Equals(env.local(), source)
4071 : .FromMaybe(false));
4072 :
4073 5 : CHECK_EQ(2u, script_data.FunctionCount());
4074 : v8::debug::Coverage::FunctionData function_data =
4075 5 : script_data.GetFunctionData(0);
4076 : v8::debug::Location start =
4077 5 : script->GetSourceLocation(function_data.StartOffset());
4078 : v8::debug::Location end =
4079 5 : script->GetSourceLocation(function_data.EndOffset());
4080 5 : CHECK_EQ(0, start.GetLineNumber());
4081 5 : CHECK_EQ(0, start.GetColumnNumber());
4082 5 : CHECK_EQ(3, end.GetLineNumber());
4083 5 : CHECK_EQ(4, end.GetColumnNumber());
4084 5 : CHECK_EQ(1, function_data.Count());
4085 :
4086 10 : function_data = script_data.GetFunctionData(1);
4087 5 : start = script->GetSourceLocation(function_data.StartOffset());
4088 5 : end = script->GetSourceLocation(function_data.EndOffset());
4089 5 : CHECK_EQ(0, start.GetLineNumber());
4090 5 : CHECK_EQ(0, start.GetColumnNumber());
4091 5 : CHECK_EQ(1, end.GetLineNumber());
4092 5 : CHECK_EQ(1, end.GetColumnNumber());
4093 5 : CHECK_EQ(2, function_data.Count());
4094 : }
4095 :
4096 : namespace {
4097 5 : v8::debug::Coverage::ScriptData GetScriptDataAndDeleteCoverage(
4098 : v8::Isolate* isolate) {
4099 5 : v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(isolate);
4100 5 : CHECK_EQ(1u, coverage.ScriptCount());
4101 10 : return coverage.GetScriptData(0);
4102 : }
4103 : } // namespace
4104 :
4105 26661 : TEST(DebugCoverageWithCoverageOutOfScope) {
4106 : // Coverage needs feedback vectors.
4107 : if (i::FLAG_lite_mode) return;
4108 5 : i::FLAG_always_opt = false;
4109 5 : LocalContext env;
4110 5 : v8::Isolate* isolate = env->GetIsolate();
4111 10 : v8::HandleScope scope(isolate);
4112 : v8::debug::Coverage::SelectMode(isolate,
4113 5 : v8::debug::CoverageMode::kPreciseCount);
4114 : v8::Local<v8::String> source = v8_str(
4115 : "function f() {\n"
4116 : "}\n"
4117 : "f();\n"
4118 5 : "f();");
4119 5 : CompileRun(source);
4120 : v8::debug::Coverage::ScriptData script_data =
4121 5 : GetScriptDataAndDeleteCoverage(isolate);
4122 5 : v8::Local<v8::debug::Script> script = script_data.GetScript();
4123 15 : CHECK(script->Source()
4124 : .ToLocalChecked()
4125 : ->Equals(env.local(), source)
4126 : .FromMaybe(false));
4127 :
4128 5 : CHECK_EQ(2u, script_data.FunctionCount());
4129 : v8::debug::Coverage::FunctionData function_data =
4130 5 : script_data.GetFunctionData(0);
4131 :
4132 5 : CHECK_EQ(0, function_data.StartOffset());
4133 5 : CHECK_EQ(26, function_data.EndOffset());
4134 :
4135 : v8::debug::Location start =
4136 5 : script->GetSourceLocation(function_data.StartOffset());
4137 : v8::debug::Location end =
4138 5 : script->GetSourceLocation(function_data.EndOffset());
4139 5 : CHECK_EQ(0, start.GetLineNumber());
4140 5 : CHECK_EQ(0, start.GetColumnNumber());
4141 5 : CHECK_EQ(3, end.GetLineNumber());
4142 5 : CHECK_EQ(4, end.GetColumnNumber());
4143 5 : CHECK_EQ(1, function_data.Count());
4144 :
4145 10 : function_data = script_data.GetFunctionData(1);
4146 5 : start = script->GetSourceLocation(function_data.StartOffset());
4147 5 : end = script->GetSourceLocation(function_data.EndOffset());
4148 :
4149 5 : CHECK_EQ(0, function_data.StartOffset());
4150 5 : CHECK_EQ(16, function_data.EndOffset());
4151 :
4152 5 : CHECK_EQ(0, start.GetLineNumber());
4153 5 : CHECK_EQ(0, start.GetColumnNumber());
4154 5 : CHECK_EQ(1, end.GetLineNumber());
4155 5 : CHECK_EQ(1, end.GetColumnNumber());
4156 5 : CHECK_EQ(2, function_data.Count());
4157 : }
4158 :
4159 : namespace {
4160 5 : v8::debug::Coverage::FunctionData GetFunctionDataAndDeleteCoverage(
4161 : v8::Isolate* isolate) {
4162 5 : v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(isolate);
4163 5 : CHECK_EQ(1u, coverage.ScriptCount());
4164 :
4165 5 : v8::debug::Coverage::ScriptData script_data = coverage.GetScriptData(0);
4166 :
4167 5 : CHECK_EQ(2u, script_data.FunctionCount());
4168 : v8::debug::Coverage::FunctionData function_data =
4169 5 : script_data.GetFunctionData(0);
4170 5 : CHECK_EQ(1, function_data.Count());
4171 5 : CHECK_EQ(0, function_data.StartOffset());
4172 5 : CHECK_EQ(26, function_data.EndOffset());
4173 5 : return function_data;
4174 : }
4175 : } // namespace
4176 :
4177 26661 : TEST(DebugCoverageWithScriptDataOutOfScope) {
4178 : // Coverage needs feedback vectors.
4179 : if (i::FLAG_lite_mode) return;
4180 5 : i::FLAG_always_opt = false;
4181 5 : LocalContext env;
4182 5 : v8::Isolate* isolate = env->GetIsolate();
4183 10 : v8::HandleScope scope(isolate);
4184 : v8::debug::Coverage::SelectMode(isolate,
4185 5 : v8::debug::CoverageMode::kPreciseCount);
4186 : v8::Local<v8::String> source = v8_str(
4187 : "function f() {\n"
4188 : "}\n"
4189 : "f();\n"
4190 5 : "f();");
4191 5 : CompileRun(source);
4192 :
4193 : v8::debug::Coverage::FunctionData function_data =
4194 5 : GetFunctionDataAndDeleteCoverage(isolate);
4195 5 : CHECK_EQ(1, function_data.Count());
4196 5 : CHECK_EQ(0, function_data.StartOffset());
4197 5 : CHECK_EQ(26, function_data.EndOffset());
4198 : }
4199 :
4200 26661 : TEST(BuiltinsExceptionPrediction) {
4201 5 : v8::Isolate* isolate = CcTest::isolate();
4202 : i::Isolate* iisolate = CcTest::i_isolate();
4203 10 : v8::HandleScope handle_scope(isolate);
4204 5 : v8::Context::New(isolate);
4205 :
4206 : i::Builtins* builtins = iisolate->builtins();
4207 : bool fail = false;
4208 15225 : for (int i = 0; i < i::Builtins::builtin_count; i++) {
4209 7610 : i::Code builtin = builtins->builtin(i);
4210 9980 : if (builtin->kind() != i::Code::BUILTIN) continue;
4211 5240 : auto prediction = builtin->GetBuiltinCatchPrediction();
4212 : USE(prediction);
4213 : }
4214 : CHECK(!fail);
4215 5 : }
4216 :
4217 26661 : TEST(DebugGetPossibleBreakpointsReturnLocations) {
4218 5 : LocalContext env;
4219 5 : v8::Isolate* isolate = env->GetIsolate();
4220 10 : v8::HandleScope scope(isolate);
4221 : v8::Local<v8::String> source = v8_str(
4222 : "function fib(x) {\n"
4223 : " if (x < 0) return;\n"
4224 : " if (x === 0) return 1;\n"
4225 : " if (x === 1) return fib(0);\n"
4226 : " return x > 2 ? fib(x - 1) + fib(x - 2) : fib(1) + fib(0);\n"
4227 5 : "}");
4228 5 : CompileRun(source);
4229 5 : v8::PersistentValueVector<v8::debug::Script> scripts(isolate);
4230 5 : v8::debug::GetLoadedScripts(isolate, scripts);
4231 5 : CHECK_EQ(scripts.Size(), 1);
4232 : std::vector<v8::debug::BreakLocation> locations;
4233 10 : CHECK(scripts.Get(0)->GetPossibleBreakpoints(
4234 : v8::debug::Location(0, 17), v8::debug::Location(), true, &locations));
4235 : int returns_count = 0;
4236 165 : for (size_t i = 0; i < locations.size(); ++i) {
4237 80 : if (locations[i].type() == v8::debug::kReturnBreakLocation) {
4238 20 : ++returns_count;
4239 : }
4240 : }
4241 : // With Ignition we generate one return location per return statement,
4242 : // each has line = 5, column = 0 as statement position.
4243 5 : CHECK_EQ(returns_count, 4);
4244 5 : }
4245 :
4246 26661 : TEST(DebugEvaluateNoSideEffect) {
4247 5 : LocalContext env;
4248 10 : v8::HandleScope scope(env->GetIsolate());
4249 5 : EnableDebugger(env->GetIsolate());
4250 5 : i::Isolate* isolate = CcTest::i_isolate();
4251 : std::vector<i::Handle<i::JSFunction>> all_functions;
4252 : {
4253 10 : i::HeapIterator iterator(isolate->heap());
4254 35222 : for (i::HeapObject obj = iterator.next(); !obj.is_null();
4255 : obj = iterator.next()) {
4256 67226 : if (!obj->IsJSFunction()) continue;
4257 3208 : i::JSFunction fun = i::JSFunction::cast(obj);
4258 3208 : all_functions.emplace_back(fun, isolate);
4259 : }
4260 : }
4261 :
4262 : // Perform side effect check on all built-in functions. The side effect check
4263 : // itself contains additional sanity checks.
4264 3213 : for (i::Handle<i::JSFunction> fun : all_functions) {
4265 : bool failed = false;
4266 3208 : isolate->debug()->StartSideEffectCheckMode();
4267 3208 : failed = !isolate->debug()->PerformSideEffectCheck(
4268 6416 : fun, v8::Utils::OpenHandle(*env->Global()));
4269 3208 : isolate->debug()->StopSideEffectCheckMode();
4270 3208 : if (failed) isolate->clear_pending_exception();
4271 : }
4272 5 : DisableDebugger(env->GetIsolate());
4273 5 : }
4274 :
4275 : namespace {
4276 10 : i::MaybeHandle<i::Script> FindScript(
4277 : i::Isolate* isolate, const std::vector<i::Handle<i::Script>>& scripts,
4278 : const char* name) {
4279 : Handle<i::String> i_name =
4280 10 : isolate->factory()->NewStringFromAsciiChecked(name);
4281 25 : for (const auto& script : scripts) {
4282 25 : if (!script->name()->IsString()) continue;
4283 25 : if (i_name->Equals(i::String::cast(script->name()))) return script;
4284 : }
4285 0 : return i::MaybeHandle<i::Script>();
4286 : }
4287 : } // anonymous namespace
4288 :
4289 26661 : UNINITIALIZED_TEST(LoadedAtStartupScripts) {
4290 5 : i::FLAG_expose_gc = true;
4291 :
4292 : v8::Isolate::CreateParams create_params;
4293 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
4294 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
4295 5 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
4296 : {
4297 : v8::Isolate::Scope i_scope(isolate);
4298 10 : v8::HandleScope scope(isolate);
4299 5 : LocalContext context(isolate);
4300 :
4301 : std::vector<i::Handle<i::Script>> scripts;
4302 : CompileWithOrigin(v8_str("function foo(){}"), v8_str("normal.js"),
4303 5 : v8_bool(false));
4304 : std::unordered_map<int, int> count_by_type;
4305 : {
4306 : i::DisallowHeapAllocation no_gc;
4307 5 : i::Script::Iterator iterator(i_isolate);
4308 60 : for (i::Script script = iterator.Next(); !script.is_null();
4309 : script = iterator.Next()) {
4310 35 : if (script->type() == i::Script::TYPE_NATIVE &&
4311 10 : script->name()->IsUndefined(i_isolate)) {
4312 : continue;
4313 : }
4314 30 : ++count_by_type[script->type()];
4315 15 : scripts.emplace_back(script, i_isolate);
4316 : }
4317 : }
4318 10 : CHECK_EQ(count_by_type[i::Script::TYPE_NATIVE], 0);
4319 10 : CHECK_EQ(count_by_type[i::Script::TYPE_EXTENSION], 2);
4320 10 : CHECK_EQ(count_by_type[i::Script::TYPE_NORMAL], 1);
4321 10 : CHECK_EQ(count_by_type[i::Script::TYPE_WASM], 0);
4322 10 : CHECK_EQ(count_by_type[i::Script::TYPE_INSPECTOR], 0);
4323 :
4324 : i::Handle<i::Script> gc_script =
4325 10 : FindScript(i_isolate, scripts, "v8/gc").ToHandleChecked();
4326 5 : CHECK_EQ(gc_script->type(), i::Script::TYPE_EXTENSION);
4327 :
4328 : i::Handle<i::Script> normal_script =
4329 10 : FindScript(i_isolate, scripts, "normal.js").ToHandleChecked();
4330 5 : CHECK_EQ(normal_script->type(), i::Script::TYPE_NORMAL);
4331 : }
4332 5 : isolate->Dispose();
4333 5 : }
4334 :
4335 26661 : TEST(SourceInfo) {
4336 5 : LocalContext env;
4337 10 : v8::HandleScope scope(env->GetIsolate());
4338 : const char* source =
4339 : "//\n"
4340 : "function a() { b(); };\n"
4341 : "function b() {\n"
4342 : " c(true);\n"
4343 : "};\n"
4344 : " function c(x) {\n"
4345 : " if (x) {\n"
4346 : " return 1;\n"
4347 : " } else {\n"
4348 : " return 1;\n"
4349 : " }\n"
4350 : " };\n"
4351 : "function d(x) {\n"
4352 : " x = 1 ;\n"
4353 : " x = 2 ;\n"
4354 : " x = 3 ;\n"
4355 : " x = 4 ;\n"
4356 : " x = 5 ;\n"
4357 : " x = 6 ;\n"
4358 : " x = 7 ;\n"
4359 : " x = 8 ;\n"
4360 : " x = 9 ;\n"
4361 : " x = 10;\n"
4362 : " x = 11;\n"
4363 : " x = 12;\n"
4364 : " x = 13;\n"
4365 : " x = 14;\n"
4366 : " x = 15;\n"
4367 : "}\n";
4368 : v8::Local<v8::Script> v8_script =
4369 10 : v8::Script::Compile(env.local(), v8_str(source)).ToLocalChecked();
4370 : i::Handle<i::Script> i_script(
4371 10 : i::Script::cast(v8::Utils::OpenHandle(*v8_script)->shared()->script()),
4372 5 : CcTest::i_isolate());
4373 : v8::Local<v8::debug::Script> script =
4374 : v8::ToApiHandle<v8::debug::Script>(i_script);
4375 :
4376 : // Test that when running through source positions the position, line and
4377 : // column progresses as expected.
4378 5 : v8::debug::Location prev_location = script->GetSourceLocation(0);
4379 5 : CHECK_EQ(prev_location.GetLineNumber(), 0);
4380 5 : CHECK_EQ(prev_location.GetColumnNumber(), 0);
4381 995 : for (int offset = 1; offset < 100; ++offset) {
4382 495 : v8::debug::Location location = script->GetSourceLocation(offset);
4383 495 : if (prev_location.GetLineNumber() == location.GetLineNumber()) {
4384 460 : CHECK_EQ(location.GetColumnNumber(), prev_location.GetColumnNumber() + 1);
4385 : } else {
4386 35 : CHECK_EQ(location.GetLineNumber(), prev_location.GetLineNumber() + 1);
4387 35 : CHECK_EQ(location.GetColumnNumber(), 0);
4388 : }
4389 495 : prev_location = location;
4390 : }
4391 :
4392 : // Every line of d() is the same length. Verify we can loop through all
4393 : // positions and find the right line # for each.
4394 : // The position of the first line of d(), i.e. "x = 1 ;".
4395 : const int start_line_d = 13;
4396 : const int start_code_d =
4397 : static_cast<int>(strstr(source, " x = 1 ;") - source);
4398 : const int num_lines_d = 15;
4399 : const int line_length_d = 10;
4400 : int p = start_code_d;
4401 155 : for (int line = 0; line < num_lines_d; ++line) {
4402 1575 : for (int column = 0; column < line_length_d; ++column) {
4403 750 : v8::debug::Location location = script->GetSourceLocation(p);
4404 750 : CHECK_EQ(location.GetLineNumber(), start_line_d + line);
4405 750 : CHECK_EQ(location.GetColumnNumber(), column);
4406 750 : ++p;
4407 : }
4408 : }
4409 :
4410 : // Test first positon.
4411 5 : CHECK_EQ(script->GetSourceLocation(0).GetLineNumber(), 0);
4412 5 : CHECK_EQ(script->GetSourceLocation(0).GetColumnNumber(), 0);
4413 :
4414 : // Test second positon.
4415 5 : CHECK_EQ(script->GetSourceLocation(1).GetLineNumber(), 0);
4416 5 : CHECK_EQ(script->GetSourceLocation(1).GetColumnNumber(), 1);
4417 :
4418 : // Test first positin in function a().
4419 : const int start_a =
4420 : static_cast<int>(strstr(source, "function a") - source) + 10;
4421 5 : CHECK_EQ(script->GetSourceLocation(start_a).GetLineNumber(), 1);
4422 5 : CHECK_EQ(script->GetSourceLocation(start_a).GetColumnNumber(), 10);
4423 :
4424 : // Test first positin in function b().
4425 : const int start_b =
4426 : static_cast<int>(strstr(source, "function b") - source) + 13;
4427 5 : CHECK_EQ(script->GetSourceLocation(start_b).GetLineNumber(), 2);
4428 5 : CHECK_EQ(script->GetSourceLocation(start_b).GetColumnNumber(), 13);
4429 :
4430 : // Test first positin in function c().
4431 : const int start_c =
4432 : static_cast<int>(strstr(source, "function c") - source) + 10;
4433 5 : CHECK_EQ(script->GetSourceLocation(start_c).GetLineNumber(), 5);
4434 5 : CHECK_EQ(script->GetSourceLocation(start_c).GetColumnNumber(), 12);
4435 :
4436 : // Test first positin in function d().
4437 : const int start_d =
4438 : static_cast<int>(strstr(source, "function d") - source) + 10;
4439 5 : CHECK_EQ(script->GetSourceLocation(start_d).GetLineNumber(), 12);
4440 5 : CHECK_EQ(script->GetSourceLocation(start_d).GetColumnNumber(), 10);
4441 :
4442 : // Test offsets.
4443 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(1, 10)), start_a);
4444 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(2, 13)), start_b);
4445 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(3, 0)), start_b + 5);
4446 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(3, 2)), start_b + 7);
4447 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(4, 0)), start_b + 16);
4448 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(5, 12)), start_c);
4449 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(6, 0)), start_c + 6);
4450 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(7, 0)), start_c + 19);
4451 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(8, 0)), start_c + 35);
4452 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(9, 0)), start_c + 48);
4453 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(10, 0)), start_c + 64);
4454 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(11, 0)), start_c + 70);
4455 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(12, 10)), start_d);
4456 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(13, 0)), start_d + 6);
4457 155 : for (int i = 1; i <= num_lines_d; ++i) {
4458 75 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(start_line_d + i, 0)),
4459 : 6 + (i * line_length_d) + start_d);
4460 : }
4461 5 : CHECK_EQ(script->GetSourceOffset(v8::debug::Location(start_line_d + 17, 0)),
4462 : start_d + 158);
4463 :
4464 : // Make sure invalid inputs work properly.
4465 : const int last_position = static_cast<int>(strlen(source)) - 1;
4466 5 : CHECK_EQ(script->GetSourceLocation(-1).GetLineNumber(), 0);
4467 5 : CHECK_EQ(script->GetSourceLocation(last_position + 2).GetLineNumber(),
4468 : i::kNoSourcePosition);
4469 :
4470 : // Test last position.
4471 5 : CHECK_EQ(script->GetSourceLocation(last_position).GetLineNumber(), 28);
4472 5 : CHECK_EQ(script->GetSourceLocation(last_position).GetColumnNumber(), 1);
4473 5 : CHECK_EQ(script->GetSourceLocation(last_position + 1).GetLineNumber(), 29);
4474 5 : CHECK_EQ(script->GetSourceLocation(last_position + 1).GetColumnNumber(), 0);
4475 5 : }
4476 :
4477 : namespace {
4478 15 : class SetBreakpointOnScriptCompiled : public v8::debug::DebugDelegate {
4479 : public:
4480 15 : void ScriptCompiled(v8::Local<v8::debug::Script> script, bool is_live_edited,
4481 : bool has_compile_error) override {
4482 : v8::Local<v8::String> name;
4483 40 : if (!script->SourceURL().ToLocal(&name)) return;
4484 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
4485 15 : if (!name->Equals(context, v8_str("test")).FromJust()) return;
4486 5 : CHECK(!has_compile_error);
4487 5 : v8::debug::Location loc(1, 2);
4488 5 : CHECK(script->SetBreakpoint(v8_str(""), &loc, &id_));
4489 5 : CHECK_EQ(loc.GetLineNumber(), 1);
4490 5 : CHECK_EQ(loc.GetColumnNumber(), 10);
4491 : }
4492 :
4493 5 : void BreakProgramRequested(v8::Local<v8::Context> paused_context,
4494 : const std::vector<v8::debug::BreakpointId>&
4495 : inspector_break_points_hit) override {
4496 5 : ++break_count_;
4497 5 : CHECK_EQ(inspector_break_points_hit[0], id_);
4498 5 : }
4499 :
4500 : int break_count() const { return break_count_; }
4501 :
4502 : private:
4503 : int break_count_ = 0;
4504 : v8::debug::BreakpointId id_;
4505 : };
4506 : } // anonymous namespace
4507 :
4508 26661 : TEST(Regress517592) {
4509 5 : LocalContext env;
4510 10 : v8::HandleScope handle_scope(env->GetIsolate());
4511 : SetBreakpointOnScriptCompiled delegate;
4512 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
4513 : CompileRun(
4514 : v8_str("eval('var foo = function foo() {\\n' +\n"
4515 : "' var a = 1;\\n' +\n"
4516 : "'}\\n' +\n"
4517 5 : "'//@ sourceURL=test')"));
4518 5 : CHECK_EQ(delegate.break_count(), 0);
4519 5 : CompileRun(v8_str("foo()"));
4520 5 : CHECK_EQ(delegate.break_count(), 1);
4521 5 : v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
4522 5 : }
4523 :
4524 26661 : TEST(GetPrivateFields) {
4525 5 : LocalContext env;
4526 5 : v8::Isolate* v8_isolate = CcTest::isolate();
4527 : v8::internal::Isolate* isolate = CcTest::i_isolate();
4528 10 : v8::HandleScope scope(v8_isolate);
4529 5 : v8::Local<v8::Context> context = env.local();
4530 5 : v8::internal::FLAG_harmony_class_fields = true;
4531 5 : v8::internal::FLAG_harmony_private_fields = true;
4532 : v8::Local<v8::String> source = v8_str(
4533 : "var X = class {\n"
4534 : " #foo = 1;\n"
4535 : " #bar = function() {};\n"
4536 : "}\n"
4537 5 : "var x = new X()");
4538 5 : CompileRun(source);
4539 : v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(
4540 10 : env->Global()
4541 15 : ->Get(context, v8_str(env->GetIsolate(), "x"))
4542 5 : .ToLocalChecked());
4543 : v8::Local<v8::Array> private_names =
4544 5 : v8::debug::GetPrivateFields(context, object).ToLocalChecked();
4545 :
4546 25 : for (int i = 0; i < 4; i = i + 2) {
4547 : Handle<v8::internal::JSReceiver> private_name =
4548 10 : v8::Utils::OpenHandle(*private_names->Get(context, i)
4549 : .ToLocalChecked()
4550 10 : ->ToObject(context)
4551 : .ToLocalChecked());
4552 : Handle<v8::internal::JSValue> private_value =
4553 : Handle<v8::internal::JSValue>::cast(private_name);
4554 : Handle<v8::internal::Symbol> priv_symbol(
4555 : v8::internal::Symbol::cast(private_value->value()), isolate);
4556 10 : CHECK(priv_symbol->is_private_name());
4557 : }
4558 :
4559 : source = v8_str(
4560 : "var Y = class {\n"
4561 : " #baz = 2;\n"
4562 : "}\n"
4563 : "var X = class extends Y{\n"
4564 : " #foo = 1;\n"
4565 : " #bar = function() {};\n"
4566 : "}\n"
4567 5 : "var x = new X()");
4568 5 : CompileRun(source);
4569 : object = v8::Local<v8::Object>::Cast(
4570 10 : env->Global()
4571 15 : ->Get(context, v8_str(env->GetIsolate(), "x"))
4572 5 : .ToLocalChecked());
4573 5 : private_names = v8::debug::GetPrivateFields(context, object).ToLocalChecked();
4574 :
4575 35 : for (int i = 0; i < 6; i = i + 2) {
4576 : Handle<v8::internal::JSReceiver> private_name =
4577 15 : v8::Utils::OpenHandle(*private_names->Get(context, i)
4578 : .ToLocalChecked()
4579 15 : ->ToObject(context)
4580 : .ToLocalChecked());
4581 : Handle<v8::internal::JSValue> private_value =
4582 : Handle<v8::internal::JSValue>::cast(private_name);
4583 : Handle<v8::internal::Symbol> priv_symbol(
4584 : v8::internal::Symbol::cast(private_value->value()), isolate);
4585 15 : CHECK(priv_symbol->is_private_name());
4586 : }
4587 :
4588 : source = v8_str(
4589 : "var Y = class {\n"
4590 : " constructor() {"
4591 : " return new Proxy({}, {});"
4592 : " }"
4593 : "}\n"
4594 : "var X = class extends Y{\n"
4595 : " #foo = 1;\n"
4596 : " #bar = function() {};\n"
4597 : "}\n"
4598 5 : "var x = new X()");
4599 5 : CompileRun(source);
4600 : object = v8::Local<v8::Object>::Cast(
4601 10 : env->Global()
4602 15 : ->Get(context, v8_str(env->GetIsolate(), "x"))
4603 5 : .ToLocalChecked());
4604 5 : private_names = v8::debug::GetPrivateFields(context, object).ToLocalChecked();
4605 :
4606 25 : for (int i = 0; i < 4; i = i + 2) {
4607 : Handle<v8::internal::JSReceiver> private_name =
4608 10 : v8::Utils::OpenHandle(*private_names->Get(context, i)
4609 : .ToLocalChecked()
4610 10 : ->ToObject(context)
4611 : .ToLocalChecked());
4612 : Handle<v8::internal::JSValue> private_value =
4613 : Handle<v8::internal::JSValue>::cast(private_name);
4614 : Handle<v8::internal::Symbol> priv_symbol(
4615 : v8::internal::Symbol::cast(private_value->value()), isolate);
4616 10 : CHECK(priv_symbol->is_private_name());
4617 : }
4618 79973 : }
|