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.h"
33 #include "src/base/platform/condition-variable.h"
34 #include "src/base/platform/platform.h"
35 #include "src/compilation-cache.h"
36 #include "src/debug/debug.h"
37 #include "src/deoptimizer.h"
38 #include "src/frames.h"
39 #include "src/utils.h"
40 #include "test/cctest/cctest.h"
41
42
43 using ::v8::base::Mutex;
44 using ::v8::base::LockGuard;
45 using ::v8::base::ConditionVariable;
46 using ::v8::base::OS;
47 using ::v8::base::Semaphore;
48 using ::v8::internal::EmbeddedVector;
49 using ::v8::internal::Object;
50 using ::v8::internal::Handle;
51 using ::v8::internal::Heap;
52 using ::v8::internal::JSGlobalProxy;
53 using ::v8::internal::Code;
54 using ::v8::internal::Debug;
55 using ::v8::internal::CommandMessage;
56 using ::v8::internal::CommandMessageQueue;
57 using ::v8::internal::StackFrame;
58 using ::v8::internal::StepAction;
59 using ::v8::internal::StepIn; // From StepAction enum
60 using ::v8::internal::StepNext; // From StepAction enum
61 using ::v8::internal::StepOut; // From StepAction enum
62 using ::v8::internal::Vector;
63 using ::v8::internal::StrLength;
64
65 // Size of temp buffer for formatting small strings.
66 #define SMALL_STRING_BUFFER_SIZE 80
67
68 // --- H e l p e r C l a s s e s
69
70
71 // Helper class for creating a V8 enviromnent for running tests
72 class DebugLocalContext {
73 public:
DebugLocalContext(v8::Isolate * isolate,v8::ExtensionConfiguration * extensions=0,v8::Local<v8::ObjectTemplate> global_template=v8::Local<v8::ObjectTemplate> (),v8::Local<v8::Value> global_object=v8::Local<v8::Value> ())74 inline DebugLocalContext(
75 v8::Isolate* isolate, v8::ExtensionConfiguration* extensions = 0,
76 v8::Local<v8::ObjectTemplate> global_template =
77 v8::Local<v8::ObjectTemplate>(),
78 v8::Local<v8::Value> global_object = v8::Local<v8::Value>())
79 : scope_(isolate),
80 context_(v8::Context::New(isolate, extensions, global_template,
81 global_object)) {
82 context_->Enter();
83 }
DebugLocalContext(v8::ExtensionConfiguration * extensions=0,v8::Local<v8::ObjectTemplate> global_template=v8::Local<v8::ObjectTemplate> (),v8::Local<v8::Value> global_object=v8::Local<v8::Value> ())84 inline DebugLocalContext(
85 v8::ExtensionConfiguration* extensions = 0,
86 v8::Local<v8::ObjectTemplate> global_template =
87 v8::Local<v8::ObjectTemplate>(),
88 v8::Local<v8::Value> global_object = v8::Local<v8::Value>())
89 : scope_(CcTest::isolate()),
90 context_(v8::Context::New(CcTest::isolate(), extensions,
91 global_template, global_object)) {
92 context_->Enter();
93 }
~DebugLocalContext()94 inline ~DebugLocalContext() {
95 context_->Exit();
96 }
context()97 inline v8::Local<v8::Context> context() { return context_; }
operator ->()98 inline v8::Context* operator->() { return *context_; }
operator *()99 inline v8::Context* operator*() { return *context_; }
GetIsolate()100 inline v8::Isolate* GetIsolate() { return context_->GetIsolate(); }
IsReady()101 inline bool IsReady() { return !context_.IsEmpty(); }
ExposeDebug()102 void ExposeDebug() {
103 v8::internal::Isolate* isolate =
104 reinterpret_cast<v8::internal::Isolate*>(context_->GetIsolate());
105 v8::internal::Factory* factory = isolate->factory();
106 // Expose the debug context global object in the global object for testing.
107 CHECK(isolate->debug()->Load());
108 Handle<v8::internal::Context> debug_context =
109 isolate->debug()->debug_context();
110 debug_context->set_security_token(
111 v8::Utils::OpenHandle(*context_)->security_token());
112
113 Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
114 v8::Utils::OpenHandle(*context_->Global())));
115 Handle<v8::internal::String> debug_string =
116 factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("debug"));
117 v8::internal::JSObject::SetOwnPropertyIgnoreAttributes(
118 global, debug_string, handle(debug_context->global_proxy()),
119 v8::internal::DONT_ENUM)
120 .Check();
121 }
122
123 private:
124 v8::HandleScope scope_;
125 v8::Local<v8::Context> context_;
126 };
127
128
129 // --- H e l p e r F u n c t i o n s
130
131 // Compile and run the supplied source and return the requested function.
CompileFunction(v8::Isolate * isolate,const char * source,const char * function_name)132 static v8::Local<v8::Function> CompileFunction(v8::Isolate* isolate,
133 const char* source,
134 const char* function_name) {
135 CompileRunChecked(isolate, source);
136 v8::Local<v8::String> name = v8_str(isolate, function_name);
137 v8::Local<v8::Context> context = isolate->GetCurrentContext();
138 v8::MaybeLocal<v8::Value> maybe_function =
139 context->Global()->Get(context, name);
140 return v8::Local<v8::Function>::Cast(maybe_function.ToLocalChecked());
141 }
142
143
144 // Compile and run the supplied source and return the requested function.
CompileFunction(DebugLocalContext * env,const char * source,const char * function_name)145 static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env,
146 const char* source,
147 const char* function_name) {
148 return CompileFunction(env->GetIsolate(), source, function_name);
149 }
150
151
152 // Is there any debug info for the function?
HasDebugInfo(v8::Local<v8::Function> fun)153 static bool HasDebugInfo(v8::Local<v8::Function> fun) {
154 Handle<v8::internal::JSFunction> f =
155 Handle<v8::internal::JSFunction>::cast(v8::Utils::OpenHandle(*fun));
156 Handle<v8::internal::SharedFunctionInfo> shared(f->shared());
157 return shared->HasDebugInfo();
158 }
159
160
161 // Set a break point in a function and return the associated break point
162 // number.
SetBreakPoint(Handle<v8::internal::JSFunction> fun,int position)163 static int SetBreakPoint(Handle<v8::internal::JSFunction> fun, int position) {
164 static int break_point = 0;
165 v8::internal::Isolate* isolate = fun->GetIsolate();
166 v8::internal::Debug* debug = isolate->debug();
167 debug->SetBreakPoint(
168 fun,
169 Handle<Object>(v8::internal::Smi::FromInt(++break_point), isolate),
170 &position);
171 return break_point;
172 }
173
174
175 // Set a break point in a function and return the associated break point
176 // number.
SetBreakPoint(v8::Local<v8::Function> fun,int position)177 static int SetBreakPoint(v8::Local<v8::Function> fun, int position) {
178 return SetBreakPoint(
179 i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*fun)), position);
180 }
181
182
183 // Set a break point in a function using the Debug object and return the
184 // associated break point number.
SetBreakPointFromJS(v8::Isolate * isolate,const char * function_name,int line,int position)185 static int SetBreakPointFromJS(v8::Isolate* isolate,
186 const char* function_name,
187 int line, int position) {
188 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
189 SNPrintF(buffer,
190 "debug.Debug.setBreakPoint(%s,%d,%d)",
191 function_name, line, position);
192 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
193 v8::Local<v8::Value> value = CompileRunChecked(isolate, buffer.start());
194 return value->Int32Value(isolate->GetCurrentContext()).FromJust();
195 }
196
197
198 // Set a break point in a script identified by id using the global Debug object.
SetScriptBreakPointByIdFromJS(v8::Isolate * isolate,int script_id,int line,int column)199 static int SetScriptBreakPointByIdFromJS(v8::Isolate* isolate, int script_id,
200 int line, int column) {
201 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
202 if (column >= 0) {
203 // Column specified set script break point on precise location.
204 SNPrintF(buffer,
205 "debug.Debug.setScriptBreakPointById(%d,%d,%d)",
206 script_id, line, column);
207 } else {
208 // Column not specified set script break point on line.
209 SNPrintF(buffer,
210 "debug.Debug.setScriptBreakPointById(%d,%d)",
211 script_id, line);
212 }
213 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
214 {
215 v8::TryCatch try_catch(isolate);
216 v8::Local<v8::Value> value = CompileRunChecked(isolate, buffer.start());
217 CHECK(!try_catch.HasCaught());
218 return value->Int32Value(isolate->GetCurrentContext()).FromJust();
219 }
220 }
221
222
223 // Set a break point in a script identified by name using the global Debug
224 // object.
SetScriptBreakPointByNameFromJS(v8::Isolate * isolate,const char * script_name,int line,int column)225 static int SetScriptBreakPointByNameFromJS(v8::Isolate* isolate,
226 const char* script_name, int line,
227 int column) {
228 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
229 if (column >= 0) {
230 // Column specified set script break point on precise location.
231 SNPrintF(buffer,
232 "debug.Debug.setScriptBreakPointByName(\"%s\",%d,%d)",
233 script_name, line, column);
234 } else {
235 // Column not specified set script break point on line.
236 SNPrintF(buffer,
237 "debug.Debug.setScriptBreakPointByName(\"%s\",%d)",
238 script_name, line);
239 }
240 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
241 {
242 v8::TryCatch try_catch(isolate);
243 v8::Local<v8::Value> value = CompileRunChecked(isolate, buffer.start());
244 CHECK(!try_catch.HasCaught());
245 return value->Int32Value(isolate->GetCurrentContext()).FromJust();
246 }
247 }
248
249
250 // Clear a break point.
ClearBreakPoint(int break_point)251 static void ClearBreakPoint(int break_point) {
252 v8::internal::Isolate* isolate = CcTest::i_isolate();
253 v8::internal::Debug* debug = isolate->debug();
254 debug->ClearBreakPoint(
255 Handle<Object>(v8::internal::Smi::FromInt(break_point), isolate));
256 }
257
258
259 // Clear a break point using the global Debug object.
ClearBreakPointFromJS(v8::Isolate * isolate,int break_point_number)260 static void ClearBreakPointFromJS(v8::Isolate* isolate,
261 int break_point_number) {
262 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
263 SNPrintF(buffer,
264 "debug.Debug.clearBreakPoint(%d)",
265 break_point_number);
266 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
267 CompileRunChecked(isolate, buffer.start());
268 }
269
270
EnableScriptBreakPointFromJS(v8::Isolate * isolate,int break_point_number)271 static void EnableScriptBreakPointFromJS(v8::Isolate* isolate,
272 int break_point_number) {
273 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
274 SNPrintF(buffer,
275 "debug.Debug.enableScriptBreakPoint(%d)",
276 break_point_number);
277 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
278 CompileRunChecked(isolate, buffer.start());
279 }
280
281
DisableScriptBreakPointFromJS(v8::Isolate * isolate,int break_point_number)282 static void DisableScriptBreakPointFromJS(v8::Isolate* isolate,
283 int break_point_number) {
284 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
285 SNPrintF(buffer,
286 "debug.Debug.disableScriptBreakPoint(%d)",
287 break_point_number);
288 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
289 CompileRunChecked(isolate, buffer.start());
290 }
291
292
ChangeScriptBreakPointConditionFromJS(v8::Isolate * isolate,int break_point_number,const char * condition)293 static void ChangeScriptBreakPointConditionFromJS(v8::Isolate* isolate,
294 int break_point_number,
295 const char* condition) {
296 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
297 SNPrintF(buffer,
298 "debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")",
299 break_point_number, condition);
300 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
301 CompileRunChecked(isolate, buffer.start());
302 }
303
304
ChangeScriptBreakPointIgnoreCountFromJS(v8::Isolate * isolate,int break_point_number,int ignoreCount)305 static void ChangeScriptBreakPointIgnoreCountFromJS(v8::Isolate* isolate,
306 int break_point_number,
307 int ignoreCount) {
308 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
309 SNPrintF(buffer,
310 "debug.Debug.changeScriptBreakPointIgnoreCount(%d, %d)",
311 break_point_number, ignoreCount);
312 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
313 CompileRunChecked(isolate, buffer.start());
314 }
315
316
317 // Change break on exception.
ChangeBreakOnException(bool caught,bool uncaught)318 static void ChangeBreakOnException(bool caught, bool uncaught) {
319 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
320 debug->ChangeBreakOnException(v8::internal::BreakException, caught);
321 debug->ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
322 }
323
324
325 // Change break on exception using the global Debug object.
ChangeBreakOnExceptionFromJS(v8::Isolate * isolate,bool caught,bool uncaught)326 static void ChangeBreakOnExceptionFromJS(v8::Isolate* isolate, bool caught,
327 bool uncaught) {
328 if (caught) {
329 CompileRunChecked(isolate, "debug.Debug.setBreakOnException()");
330 } else {
331 CompileRunChecked(isolate, "debug.Debug.clearBreakOnException()");
332 }
333 if (uncaught) {
334 CompileRunChecked(isolate, "debug.Debug.setBreakOnUncaughtException()");
335 } else {
336 CompileRunChecked(isolate, "debug.Debug.clearBreakOnUncaughtException()");
337 }
338 }
339
340
341 // Prepare to step to next break location.
PrepareStep(StepAction step_action)342 static void PrepareStep(StepAction step_action) {
343 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
344 debug->PrepareStep(step_action);
345 }
346
347
ClearStepping()348 static void ClearStepping() { CcTest::i_isolate()->debug()->ClearStepping(); }
349
350
351 // This function is in namespace v8::internal to be friend with class
352 // v8::internal::Debug.
353 namespace v8 {
354 namespace internal {
355
356 // Collect the currently debugged functions.
GetDebuggedFunctions()357 Handle<FixedArray> GetDebuggedFunctions() {
358 Debug* debug = CcTest::i_isolate()->debug();
359
360 v8::internal::DebugInfoListNode* node = debug->debug_info_list_;
361
362 // Find the number of debugged functions.
363 int count = 0;
364 while (node) {
365 count++;
366 node = node->next();
367 }
368
369 // Allocate array for the debugged functions
370 Handle<FixedArray> debugged_functions =
371 CcTest::i_isolate()->factory()->NewFixedArray(count);
372
373 // Run through the debug info objects and collect all functions.
374 count = 0;
375 while (node) {
376 debugged_functions->set(count++, *node->debug_info());
377 node = node->next();
378 }
379
380 return debugged_functions;
381 }
382
383
384 // Check that the debugger has been fully unloaded.
CheckDebuggerUnloaded(bool check_functions)385 void CheckDebuggerUnloaded(bool check_functions) {
386 // Check that the debugger context is cleared and that there is no debug
387 // information stored for the debugger.
388 CHECK(CcTest::i_isolate()->debug()->debug_context().is_null());
389 CHECK(!CcTest::i_isolate()->debug()->debug_info_list_);
390
391 // Collect garbage to ensure weak handles are cleared.
392 CcTest::heap()->CollectAllGarbage();
393 CcTest::heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
394
395 // Iterate the head and check that there are no debugger related objects left.
396 HeapIterator iterator(CcTest::heap());
397 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
398 CHECK(!obj->IsDebugInfo());
399 CHECK(!obj->IsBreakPointInfo());
400
401 // If deep check of functions is requested check that no debug break code
402 // is left in all functions.
403 if (check_functions) {
404 if (obj->IsJSFunction()) {
405 JSFunction* fun = JSFunction::cast(obj);
406 for (RelocIterator it(fun->shared()->code(),
407 RelocInfo::kDebugBreakSlotMask);
408 !it.done(); it.next()) {
409 CHECK(!it.rinfo()->IsPatchedDebugBreakSlotSequence());
410 }
411 }
412 }
413 }
414 }
415
416
417 } // namespace internal
418 } // namespace v8
419
420
421 // Check that the debugger has been fully unloaded.
CheckDebuggerUnloaded(v8::Isolate * isolate,bool check_functions=false)422 static void CheckDebuggerUnloaded(v8::Isolate* isolate,
423 bool check_functions = false) {
424 // Let debugger to unload itself synchronously
425 v8::Debug::ProcessDebugMessages(isolate);
426
427 v8::internal::CheckDebuggerUnloaded(check_functions);
428 }
429
430
431 // --- D e b u g E v e n t H a n d l e r s
432 // ---
433 // --- The different tests uses a number of debug event handlers.
434 // ---
435
436
437 // Source for the JavaScript function which picks out the function
438 // name of a frame.
439 const char* frame_function_name_source =
440 "function frame_function_name(exec_state, frame_number) {"
441 " return exec_state.frame(frame_number).func().name();"
442 "}";
443 v8::Local<v8::Function> frame_function_name;
444
445
446 // Source for the JavaScript function which pick out the name of the
447 // first argument of a frame.
448 const char* frame_argument_name_source =
449 "function frame_argument_name(exec_state, frame_number) {"
450 " return exec_state.frame(frame_number).argumentName(0);"
451 "}";
452 v8::Local<v8::Function> frame_argument_name;
453
454
455 // Source for the JavaScript function which pick out the value of the
456 // first argument of a frame.
457 const char* frame_argument_value_source =
458 "function frame_argument_value(exec_state, frame_number) {"
459 " return exec_state.frame(frame_number).argumentValue(0).value_;"
460 "}";
461 v8::Local<v8::Function> frame_argument_value;
462
463
464 // Source for the JavaScript function which pick out the name of the
465 // first argument of a frame.
466 const char* frame_local_name_source =
467 "function frame_local_name(exec_state, frame_number) {"
468 " return exec_state.frame(frame_number).localName(0);"
469 "}";
470 v8::Local<v8::Function> frame_local_name;
471
472
473 // Source for the JavaScript function which pick out the value of the
474 // first argument of a frame.
475 const char* frame_local_value_source =
476 "function frame_local_value(exec_state, frame_number) {"
477 " return exec_state.frame(frame_number).localValue(0).value_;"
478 "}";
479 v8::Local<v8::Function> frame_local_value;
480
481
482 // Source for the JavaScript function which picks out the source line for the
483 // top frame.
484 const char* frame_source_line_source =
485 "function frame_source_line(exec_state) {"
486 " return exec_state.frame(0).sourceLine();"
487 "}";
488 v8::Local<v8::Function> frame_source_line;
489
490
491 // Source for the JavaScript function which picks out the source column for the
492 // top frame.
493 const char* frame_source_column_source =
494 "function frame_source_column(exec_state) {"
495 " return exec_state.frame(0).sourceColumn();"
496 "}";
497 v8::Local<v8::Function> frame_source_column;
498
499
500 // Source for the JavaScript function which picks out the script name for the
501 // top frame.
502 const char* frame_script_name_source =
503 "function frame_script_name(exec_state) {"
504 " return exec_state.frame(0).func().script().name();"
505 "}";
506 v8::Local<v8::Function> frame_script_name;
507
508
509 // Source for the JavaScript function which returns the number of frames.
510 static const char* frame_count_source =
511 "function frame_count(exec_state) {"
512 " return exec_state.frameCount();"
513 "}";
514 v8::Local<v8::Function> frame_count;
515
516
517 // Global variable to store the last function hit - used by some tests.
518 char last_function_hit[80];
519
520 // Global variable to store the name for last script hit - used by some tests.
521 char last_script_name_hit[80];
522
523 // Global variables to store the last source position - used by some tests.
524 int last_source_line = -1;
525 int last_source_column = -1;
526
527 // Debug event handler which counts the break points which have been hit.
528 int break_point_hit_count = 0;
529 int break_point_hit_count_deoptimize = 0;
DebugEventBreakPointHitCount(const v8::Debug::EventDetails & event_details)530 static void DebugEventBreakPointHitCount(
531 const v8::Debug::EventDetails& event_details) {
532 v8::DebugEvent event = event_details.GetEvent();
533 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
534 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
535 v8::internal::Isolate* isolate = CcTest::i_isolate();
536 Debug* debug = isolate->debug();
537 // When hitting a debug event listener there must be a break set.
538 CHECK_NE(debug->break_id(), 0);
539
540 // Count the number of breaks.
541 if (event == v8::Break) {
542 break_point_hit_count++;
543 if (!frame_function_name.IsEmpty()) {
544 // Get the name of the function.
545 const int argc = 2;
546 v8::Local<v8::Value> argv[argc] = {
547 exec_state, v8::Integer::New(CcTest::isolate(), 0)};
548 v8::Local<v8::Value> result =
549 frame_function_name->Call(context, exec_state, argc, argv)
550 .ToLocalChecked();
551 if (result->IsUndefined()) {
552 last_function_hit[0] = '\0';
553 } else {
554 CHECK(result->IsString());
555 v8::Local<v8::String> function_name(result.As<v8::String>());
556 function_name->WriteUtf8(last_function_hit);
557 }
558 }
559
560 if (!frame_source_line.IsEmpty()) {
561 // Get the source line.
562 const int argc = 1;
563 v8::Local<v8::Value> argv[argc] = {exec_state};
564 v8::Local<v8::Value> result =
565 frame_source_line->Call(context, exec_state, argc, argv)
566 .ToLocalChecked();
567 CHECK(result->IsNumber());
568 last_source_line = result->Int32Value(context).FromJust();
569 }
570
571 if (!frame_source_column.IsEmpty()) {
572 // Get the source column.
573 const int argc = 1;
574 v8::Local<v8::Value> argv[argc] = {exec_state};
575 v8::Local<v8::Value> result =
576 frame_source_column->Call(context, exec_state, argc, argv)
577 .ToLocalChecked();
578 CHECK(result->IsNumber());
579 last_source_column = result->Int32Value(context).FromJust();
580 }
581
582 if (!frame_script_name.IsEmpty()) {
583 // Get the script name of the function script.
584 const int argc = 1;
585 v8::Local<v8::Value> argv[argc] = {exec_state};
586 v8::Local<v8::Value> result =
587 frame_script_name->Call(context, exec_state, argc, argv)
588 .ToLocalChecked();
589 if (result->IsUndefined()) {
590 last_script_name_hit[0] = '\0';
591 } else {
592 CHECK(result->IsString());
593 v8::Local<v8::String> script_name(result.As<v8::String>());
594 script_name->WriteUtf8(last_script_name_hit);
595 }
596 }
597
598 // Perform a full deoptimization when the specified number of
599 // breaks have been hit.
600 if (break_point_hit_count == break_point_hit_count_deoptimize) {
601 i::Deoptimizer::DeoptimizeAll(isolate);
602 }
603 }
604 }
605
606
607 // Debug event handler which counts a number of events and collects the stack
608 // height if there is a function compiled for that.
609 int exception_hit_count = 0;
610 int uncaught_exception_hit_count = 0;
611 int last_js_stack_height = -1;
612 v8::Local<v8::Function> debug_event_listener_callback;
613 int debug_event_listener_callback_result;
614
DebugEventCounterClear()615 static void DebugEventCounterClear() {
616 break_point_hit_count = 0;
617 exception_hit_count = 0;
618 uncaught_exception_hit_count = 0;
619 }
620
DebugEventCounter(const v8::Debug::EventDetails & event_details)621 static void DebugEventCounter(
622 const v8::Debug::EventDetails& event_details) {
623 v8::DebugEvent event = event_details.GetEvent();
624 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
625 v8::Local<v8::Object> event_data = event_details.GetEventData();
626 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
627 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
628
629 // When hitting a debug event listener there must be a break set.
630 CHECK_NE(debug->break_id(), 0);
631
632 // Count the number of breaks.
633 if (event == v8::Break) {
634 break_point_hit_count++;
635 } else if (event == v8::Exception) {
636 exception_hit_count++;
637
638 // Check whether the exception was uncaught.
639 v8::Local<v8::String> fun_name = v8_str(CcTest::isolate(), "uncaught");
640 v8::Local<v8::Function> fun = v8::Local<v8::Function>::Cast(
641 event_data->Get(context, fun_name).ToLocalChecked());
642 v8::Local<v8::Value> result =
643 fun->Call(context, event_data, 0, NULL).ToLocalChecked();
644 if (result->IsTrue()) {
645 uncaught_exception_hit_count++;
646 }
647 }
648
649 // Collect the JavsScript stack height if the function frame_count is
650 // compiled.
651 if (!frame_count.IsEmpty()) {
652 static const int kArgc = 1;
653 v8::Local<v8::Value> argv[kArgc] = {exec_state};
654 // Using exec_state as receiver is just to have a receiver.
655 v8::Local<v8::Value> result =
656 frame_count->Call(context, exec_state, kArgc, argv).ToLocalChecked();
657 last_js_stack_height = result->Int32Value(context).FromJust();
658 }
659
660 // Run callback from DebugEventListener and check the result.
661 if (!debug_event_listener_callback.IsEmpty()) {
662 v8::Local<v8::Value> result =
663 debug_event_listener_callback->Call(context, event_data, 0, NULL)
664 .ToLocalChecked();
665 CHECK(!result.IsEmpty());
666 CHECK_EQ(debug_event_listener_callback_result,
667 result->Int32Value(context).FromJust());
668 }
669 }
670
671
672 // Debug event handler which evaluates a number of expressions when a break
673 // point is hit. Each evaluated expression is compared with an expected value.
674 // For this debug event handler to work the following two global varaibles
675 // must be initialized.
676 // checks: An array of expressions and expected results
677 // evaluate_check_function: A JavaScript function (see below)
678
679 // Structure for holding checks to do.
680 struct EvaluateCheck {
681 const char* expr; // An expression to evaluate when a break point is hit.
682 v8::Local<v8::Value> expected; // The expected result.
683 };
684
685
686 // Array of checks to do.
687 struct EvaluateCheck* checks = NULL;
688 // Source for The JavaScript function which can do the evaluation when a break
689 // point is hit.
690 const char* evaluate_check_source =
691 "function evaluate_check(exec_state, expr, expected) {"
692 " return exec_state.frame(0).evaluate(expr).value() === expected;"
693 "}";
694 v8::Local<v8::Function> evaluate_check_function;
695
696 // The actual debug event described by the longer comment above.
DebugEventEvaluate(const v8::Debug::EventDetails & event_details)697 static void DebugEventEvaluate(
698 const v8::Debug::EventDetails& event_details) {
699 v8::DebugEvent event = event_details.GetEvent();
700 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
701 v8::Isolate* isolate = CcTest::isolate();
702 v8::Local<v8::Context> context = isolate->GetCurrentContext();
703 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
704 // When hitting a debug event listener there must be a break set.
705 CHECK_NE(debug->break_id(), 0);
706
707 if (event == v8::Break) {
708 break_point_hit_count++;
709 for (int i = 0; checks[i].expr != NULL; i++) {
710 const int argc = 3;
711 v8::Local<v8::String> string = v8_str(isolate, checks[i].expr);
712 v8::Local<v8::Value> argv[argc] = {exec_state, string,
713 checks[i].expected};
714 v8::Local<v8::Value> result =
715 evaluate_check_function->Call(context, exec_state, argc, argv)
716 .ToLocalChecked();
717 if (!result->IsTrue()) {
718 v8::String::Utf8Value utf8(checks[i].expected);
719 V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *utf8);
720 }
721 }
722 }
723 }
724
725
726 // This debug event listener removes a breakpoint in a function
727 int debug_event_remove_break_point = 0;
DebugEventRemoveBreakPoint(const v8::Debug::EventDetails & event_details)728 static void DebugEventRemoveBreakPoint(
729 const v8::Debug::EventDetails& event_details) {
730 v8::DebugEvent event = event_details.GetEvent();
731 v8::Local<v8::Value> data = event_details.GetCallbackData();
732 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
733 // When hitting a debug event listener there must be a break set.
734 CHECK_NE(debug->break_id(), 0);
735
736 if (event == v8::Break) {
737 break_point_hit_count++;
738 CHECK(data->IsFunction());
739 ClearBreakPoint(debug_event_remove_break_point);
740 }
741 }
742
743
744 // Debug event handler which counts break points hit and performs a step
745 // afterwards.
746 StepAction step_action = StepIn; // Step action to perform when stepping.
DebugEventStep(const v8::Debug::EventDetails & event_details)747 static void DebugEventStep(
748 const v8::Debug::EventDetails& event_details) {
749 v8::DebugEvent event = event_details.GetEvent();
750 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
751 // When hitting a debug event listener there must be a break set.
752 CHECK_NE(debug->break_id(), 0);
753
754 if (event == v8::Break) {
755 break_point_hit_count++;
756 PrepareStep(step_action);
757 }
758 }
759
760
761 // Debug event handler which counts break points hit and performs a step
762 // afterwards. For each call the expected function is checked.
763 // For this debug event handler to work the following two global varaibles
764 // must be initialized.
765 // expected_step_sequence: An array of the expected function call sequence.
766 // frame_function_name: A JavaScript function (see below).
767
768 // String containing the expected function call sequence. Note: this only works
769 // if functions have name length of one.
770 const char* expected_step_sequence = NULL;
771
772 // The actual debug event described by the longer comment above.
DebugEventStepSequence(const v8::Debug::EventDetails & event_details)773 static void DebugEventStepSequence(
774 const v8::Debug::EventDetails& event_details) {
775 v8::DebugEvent event = event_details.GetEvent();
776 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
777 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
778 // When hitting a debug event listener there must be a break set.
779 CHECK_NE(debug->break_id(), 0);
780
781 if (event == v8::Break || event == v8::Exception) {
782 // Check that the current function is the expected.
783 CHECK(break_point_hit_count <
784 StrLength(expected_step_sequence));
785 const int argc = 2;
786 v8::Local<v8::Value> argv[argc] = {exec_state,
787 v8::Integer::New(CcTest::isolate(), 0)};
788 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
789 v8::Local<v8::Value> result =
790 frame_function_name->Call(context, exec_state, argc, argv)
791 .ToLocalChecked();
792 CHECK(result->IsString());
793 v8::String::Utf8Value function_name(
794 result->ToString(context).ToLocalChecked());
795 CHECK_EQ(1, StrLength(*function_name));
796 CHECK_EQ((*function_name)[0],
797 expected_step_sequence[break_point_hit_count]);
798
799 // Perform step.
800 break_point_hit_count++;
801 PrepareStep(step_action);
802 }
803 }
804
805
806 // Debug event handler which performs a garbage collection.
DebugEventBreakPointCollectGarbage(const v8::Debug::EventDetails & event_details)807 static void DebugEventBreakPointCollectGarbage(
808 const v8::Debug::EventDetails& event_details) {
809 v8::DebugEvent event = event_details.GetEvent();
810 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
811 // When hitting a debug event listener there must be a break set.
812 CHECK_NE(debug->break_id(), 0);
813
814 // Perform a garbage collection when break point is hit and continue. Based
815 // on the number of break points hit either scavenge or mark compact
816 // collector is used.
817 if (event == v8::Break) {
818 break_point_hit_count++;
819 if (break_point_hit_count % 2 == 0) {
820 // Scavenge.
821 CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE);
822 } else {
823 // Mark sweep compact.
824 CcTest::heap()->CollectAllGarbage();
825 }
826 }
827 }
828
829
830 // Debug event handler which re-issues a debug break and calls the garbage
831 // collector to have the heap verified.
DebugEventBreak(const v8::Debug::EventDetails & event_details)832 static void DebugEventBreak(
833 const v8::Debug::EventDetails& event_details) {
834 v8::DebugEvent event = event_details.GetEvent();
835 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
836 // When hitting a debug event listener there must be a break set.
837 CHECK_NE(debug->break_id(), 0);
838
839 if (event == v8::Break) {
840 // Count the number of breaks.
841 break_point_hit_count++;
842
843 // Run the garbage collector to enforce heap verification if option
844 // --verify-heap is set.
845 CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE);
846
847 // Set the break flag again to come back here as soon as possible.
848 v8::Debug::DebugBreak(CcTest::isolate());
849 }
850 }
851
852
853 // Debug event handler which re-issues a debug break until a limit has been
854 // reached.
855 int max_break_point_hit_count = 0;
856 bool terminate_after_max_break_point_hit = false;
DebugEventBreakMax(const v8::Debug::EventDetails & event_details)857 static void DebugEventBreakMax(
858 const v8::Debug::EventDetails& event_details) {
859 v8::DebugEvent event = event_details.GetEvent();
860 v8::Isolate* v8_isolate = CcTest::isolate();
861 v8::internal::Isolate* isolate = CcTest::i_isolate();
862 v8::internal::Debug* debug = isolate->debug();
863 // When hitting a debug event listener there must be a break set.
864 CHECK_NE(debug->break_id(), 0);
865
866 if (event == v8::Break) {
867 if (break_point_hit_count < max_break_point_hit_count) {
868 // Count the number of breaks.
869 break_point_hit_count++;
870
871 // Set the break flag again to come back here as soon as possible.
872 v8::Debug::DebugBreak(v8_isolate);
873
874 } else if (terminate_after_max_break_point_hit) {
875 // Terminate execution after the last break if requested.
876 v8_isolate->TerminateExecution();
877 }
878
879 // Perform a full deoptimization when the specified number of
880 // breaks have been hit.
881 if (break_point_hit_count == break_point_hit_count_deoptimize) {
882 i::Deoptimizer::DeoptimizeAll(isolate);
883 }
884 }
885 }
886
887
888 // --- M e s s a g e C a l l b a c k
889
890
891 // Message callback which counts the number of messages.
892 int message_callback_count = 0;
893
MessageCallbackCountClear()894 static void MessageCallbackCountClear() {
895 message_callback_count = 0;
896 }
897
MessageCallbackCount(v8::Local<v8::Message> message,v8::Local<v8::Value> data)898 static void MessageCallbackCount(v8::Local<v8::Message> message,
899 v8::Local<v8::Value> data) {
900 message_callback_count++;
901 }
902
903
904 // --- T h e A c t u a l T e s t s
905
906 // Test that the debug info in the VM is in sync with the functions being
907 // debugged.
TEST(DebugInfo)908 TEST(DebugInfo) {
909 DebugLocalContext env;
910 v8::HandleScope scope(env->GetIsolate());
911 // Create a couple of functions for the test.
912 v8::Local<v8::Function> foo =
913 CompileFunction(&env, "function foo(){}", "foo");
914 v8::Local<v8::Function> bar =
915 CompileFunction(&env, "function bar(){}", "bar");
916 // Initially no functions are debugged.
917 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
918 CHECK(!HasDebugInfo(foo));
919 CHECK(!HasDebugInfo(bar));
920 EnableDebugger(env->GetIsolate());
921 // One function (foo) is debugged.
922 int bp1 = SetBreakPoint(foo, 0);
923 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
924 CHECK(HasDebugInfo(foo));
925 CHECK(!HasDebugInfo(bar));
926 // Two functions are debugged.
927 int bp2 = SetBreakPoint(bar, 0);
928 CHECK_EQ(2, v8::internal::GetDebuggedFunctions()->length());
929 CHECK(HasDebugInfo(foo));
930 CHECK(HasDebugInfo(bar));
931 // One function (bar) is debugged.
932 ClearBreakPoint(bp1);
933 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
934 CHECK(!HasDebugInfo(foo));
935 CHECK(HasDebugInfo(bar));
936 // No functions are debugged.
937 ClearBreakPoint(bp2);
938 DisableDebugger(env->GetIsolate());
939 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
940 CHECK(!HasDebugInfo(foo));
941 CHECK(!HasDebugInfo(bar));
942 }
943
944
945 // Test that a break point can be set at an IC store location.
TEST(BreakPointICStore)946 TEST(BreakPointICStore) {
947 break_point_hit_count = 0;
948 DebugLocalContext env;
949 v8::HandleScope scope(env->GetIsolate());
950
951 v8::Debug::SetDebugEventListener(env->GetIsolate(),
952 DebugEventBreakPointHitCount);
953 v8::Local<v8::Function> foo =
954 CompileFunction(&env, "function foo(){bar=0;}", "foo");
955
956 // Run without breakpoints.
957 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
958 CHECK_EQ(0, break_point_hit_count);
959
960 // Run with breakpoint
961 int bp = SetBreakPoint(foo, 0);
962 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
963 CHECK_EQ(1, break_point_hit_count);
964 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
965 CHECK_EQ(2, break_point_hit_count);
966
967 // Run without breakpoints.
968 ClearBreakPoint(bp);
969 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
970 CHECK_EQ(2, break_point_hit_count);
971
972 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
973 CheckDebuggerUnloaded(env->GetIsolate());
974 }
975
976
977 // Test that a break point can be set at an IC load location.
TEST(BreakPointICLoad)978 TEST(BreakPointICLoad) {
979 break_point_hit_count = 0;
980 DebugLocalContext env;
981 v8::HandleScope scope(env->GetIsolate());
982 v8::Debug::SetDebugEventListener(env->GetIsolate(),
983 DebugEventBreakPointHitCount);
984
985 CompileRunChecked(env->GetIsolate(), "bar=1");
986 v8::Local<v8::Function> foo =
987 CompileFunction(&env, "function foo(){var x=bar;}", "foo");
988
989 // Run without breakpoints.
990 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
991 CHECK_EQ(0, break_point_hit_count);
992
993 // Run with breakpoint.
994 int bp = SetBreakPoint(foo, 0);
995 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
996 CHECK_EQ(1, break_point_hit_count);
997 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
998 CHECK_EQ(2, break_point_hit_count);
999
1000 // Run without breakpoints.
1001 ClearBreakPoint(bp);
1002 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
1003 CHECK_EQ(2, break_point_hit_count);
1004
1005 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1006 CheckDebuggerUnloaded(env->GetIsolate());
1007 }
1008
1009
1010 // Test that a break point can be set at an IC call location.
TEST(BreakPointICCall)1011 TEST(BreakPointICCall) {
1012 break_point_hit_count = 0;
1013 DebugLocalContext env;
1014 v8::HandleScope scope(env->GetIsolate());
1015 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1016 DebugEventBreakPointHitCount);
1017 CompileRunChecked(env->GetIsolate(), "function bar(){}");
1018 v8::Local<v8::Function> foo =
1019 CompileFunction(&env, "function foo(){bar();}", "foo");
1020
1021 // Run without breakpoints.
1022 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
1023 CHECK_EQ(0, break_point_hit_count);
1024
1025 // Run with breakpoint
1026 int bp = SetBreakPoint(foo, 0);
1027 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
1028 CHECK_EQ(1, break_point_hit_count);
1029 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
1030 CHECK_EQ(2, break_point_hit_count);
1031
1032 // Run without breakpoints.
1033 ClearBreakPoint(bp);
1034 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
1035 CHECK_EQ(2, break_point_hit_count);
1036
1037 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1038 CheckDebuggerUnloaded(env->GetIsolate());
1039 }
1040
1041
1042 // Test that a break point can be set at an IC call location and survive a GC.
TEST(BreakPointICCallWithGC)1043 TEST(BreakPointICCallWithGC) {
1044 break_point_hit_count = 0;
1045 DebugLocalContext env;
1046 v8::HandleScope scope(env->GetIsolate());
1047 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1048 DebugEventBreakPointCollectGarbage);
1049 CompileRunChecked(env->GetIsolate(), "function bar(){return 1;}");
1050 v8::Local<v8::Function> foo =
1051 CompileFunction(&env, "function foo(){return bar();}", "foo");
1052 v8::Local<v8::Context> context = env.context();
1053
1054 // Run without breakpoints.
1055 CHECK_EQ(1, foo->Call(context, env->Global(), 0, NULL)
1056 .ToLocalChecked()
1057 ->Int32Value(context)
1058 .FromJust());
1059 CHECK_EQ(0, break_point_hit_count);
1060
1061 // Run with breakpoint.
1062 int bp = SetBreakPoint(foo, 0);
1063 CHECK_EQ(1, foo->Call(context, env->Global(), 0, NULL)
1064 .ToLocalChecked()
1065 ->Int32Value(context)
1066 .FromJust());
1067 CHECK_EQ(1, break_point_hit_count);
1068 CHECK_EQ(1, foo->Call(context, env->Global(), 0, NULL)
1069 .ToLocalChecked()
1070 ->Int32Value(context)
1071 .FromJust());
1072 CHECK_EQ(2, break_point_hit_count);
1073
1074 // Run without breakpoints.
1075 ClearBreakPoint(bp);
1076 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1077 CHECK_EQ(2, break_point_hit_count);
1078
1079 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1080 CheckDebuggerUnloaded(env->GetIsolate());
1081 }
1082
1083
1084 // Test that a break point can be set at an IC call location and survive a GC.
TEST(BreakPointConstructCallWithGC)1085 TEST(BreakPointConstructCallWithGC) {
1086 break_point_hit_count = 0;
1087 DebugLocalContext env;
1088 v8::HandleScope scope(env->GetIsolate());
1089 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1090 DebugEventBreakPointCollectGarbage);
1091 CompileRunChecked(env->GetIsolate(), "function bar(){ this.x = 1;}");
1092 v8::Local<v8::Function> foo =
1093 CompileFunction(&env, "function foo(){return new bar(1).x;}", "foo");
1094 v8::Local<v8::Context> context = env.context();
1095
1096 // Run without breakpoints.
1097 CHECK_EQ(1, foo->Call(context, env->Global(), 0, NULL)
1098 .ToLocalChecked()
1099 ->Int32Value(context)
1100 .FromJust());
1101 CHECK_EQ(0, break_point_hit_count);
1102
1103 // Run with breakpoint.
1104 int bp = SetBreakPoint(foo, 0);
1105 CHECK_EQ(1, foo->Call(context, env->Global(), 0, NULL)
1106 .ToLocalChecked()
1107 ->Int32Value(context)
1108 .FromJust());
1109 CHECK_EQ(1, break_point_hit_count);
1110 CHECK_EQ(1, foo->Call(context, env->Global(), 0, NULL)
1111 .ToLocalChecked()
1112 ->Int32Value(context)
1113 .FromJust());
1114 CHECK_EQ(2, break_point_hit_count);
1115
1116 // Run without breakpoints.
1117 ClearBreakPoint(bp);
1118 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1119 CHECK_EQ(2, break_point_hit_count);
1120
1121 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1122 CheckDebuggerUnloaded(env->GetIsolate());
1123 }
1124
1125
1126 // Test that a break point can be set at a return store location.
TEST(BreakPointReturn)1127 TEST(BreakPointReturn) {
1128 break_point_hit_count = 0;
1129 DebugLocalContext env;
1130 v8::HandleScope scope(env->GetIsolate());
1131
1132 // Create a functions for checking the source line and column when hitting
1133 // a break point.
1134 frame_source_line = CompileFunction(&env,
1135 frame_source_line_source,
1136 "frame_source_line");
1137 frame_source_column = CompileFunction(&env,
1138 frame_source_column_source,
1139 "frame_source_column");
1140
1141
1142 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1143 DebugEventBreakPointHitCount);
1144 v8::Local<v8::Function> foo =
1145 CompileFunction(&env, "function foo(){}", "foo");
1146 v8::Local<v8::Context> context = env.context();
1147
1148 // Run without breakpoints.
1149 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1150 CHECK_EQ(0, break_point_hit_count);
1151
1152 // Run with breakpoint
1153 int bp = SetBreakPoint(foo, 0);
1154 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1155 CHECK_EQ(1, break_point_hit_count);
1156 CHECK_EQ(0, last_source_line);
1157 CHECK_EQ(15, last_source_column);
1158 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1159 CHECK_EQ(2, break_point_hit_count);
1160 CHECK_EQ(0, last_source_line);
1161 CHECK_EQ(15, last_source_column);
1162
1163 // Run without breakpoints.
1164 ClearBreakPoint(bp);
1165 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1166 CHECK_EQ(2, break_point_hit_count);
1167
1168 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1169 CheckDebuggerUnloaded(env->GetIsolate());
1170 }
1171
1172
CallWithBreakPoints(v8::Local<v8::Context> context,v8::Local<v8::Object> recv,v8::Local<v8::Function> f,int break_point_count,int call_count)1173 static void CallWithBreakPoints(v8::Local<v8::Context> context,
1174 v8::Local<v8::Object> recv,
1175 v8::Local<v8::Function> f,
1176 int break_point_count, int call_count) {
1177 break_point_hit_count = 0;
1178 for (int i = 0; i < call_count; i++) {
1179 f->Call(context, recv, 0, NULL).ToLocalChecked();
1180 CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
1181 }
1182 }
1183
1184
1185 // Test GC during break point processing.
TEST(GCDuringBreakPointProcessing)1186 TEST(GCDuringBreakPointProcessing) {
1187 break_point_hit_count = 0;
1188 DebugLocalContext env;
1189 v8::HandleScope scope(env->GetIsolate());
1190 v8::Local<v8::Context> context = env.context();
1191
1192 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1193 DebugEventBreakPointCollectGarbage);
1194 v8::Local<v8::Function> foo;
1195
1196 // Test IC store break point with garbage collection.
1197 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1198 SetBreakPoint(foo, 0);
1199 CallWithBreakPoints(context, env->Global(), foo, 1, 10);
1200
1201 // Test IC load break point with garbage collection.
1202 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1203 SetBreakPoint(foo, 0);
1204 CallWithBreakPoints(context, env->Global(), foo, 1, 10);
1205
1206 // Test IC call break point with garbage collection.
1207 foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
1208 SetBreakPoint(foo, 0);
1209 CallWithBreakPoints(context, env->Global(), foo, 1, 10);
1210
1211 // Test return break point with garbage collection.
1212 foo = CompileFunction(&env, "function foo(){}", "foo");
1213 SetBreakPoint(foo, 0);
1214 CallWithBreakPoints(context, env->Global(), foo, 1, 25);
1215
1216 // Test debug break slot break point with garbage collection.
1217 foo = CompileFunction(&env, "function foo(){var a;}", "foo");
1218 SetBreakPoint(foo, 0);
1219 CallWithBreakPoints(context, env->Global(), foo, 1, 25);
1220
1221 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1222 CheckDebuggerUnloaded(env->GetIsolate());
1223 }
1224
1225
1226 // Call the function three times with different garbage collections in between
1227 // and make sure that the break point survives.
CallAndGC(v8::Local<v8::Context> context,v8::Local<v8::Object> recv,v8::Local<v8::Function> f)1228 static void CallAndGC(v8::Local<v8::Context> context,
1229 v8::Local<v8::Object> recv, v8::Local<v8::Function> f) {
1230 break_point_hit_count = 0;
1231
1232 for (int i = 0; i < 3; i++) {
1233 // Call function.
1234 f->Call(context, recv, 0, NULL).ToLocalChecked();
1235 CHECK_EQ(1 + i * 3, break_point_hit_count);
1236
1237 // Scavenge and call function.
1238 CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE);
1239 f->Call(context, recv, 0, NULL).ToLocalChecked();
1240 CHECK_EQ(2 + i * 3, break_point_hit_count);
1241
1242 // Mark sweep (and perhaps compact) and call function.
1243 CcTest::heap()->CollectAllGarbage();
1244 f->Call(context, recv, 0, NULL).ToLocalChecked();
1245 CHECK_EQ(3 + i * 3, break_point_hit_count);
1246 }
1247 }
1248
1249
1250 // Test that a break point can be set at a return store location.
TEST(BreakPointSurviveGC)1251 TEST(BreakPointSurviveGC) {
1252 break_point_hit_count = 0;
1253 DebugLocalContext env;
1254 v8::HandleScope scope(env->GetIsolate());
1255 v8::Local<v8::Context> context = env.context();
1256
1257 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1258 DebugEventBreakPointHitCount);
1259 v8::Local<v8::Function> foo;
1260
1261 // Test IC store break point with garbage collection.
1262 {
1263 CompileFunction(&env, "function foo(){}", "foo");
1264 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1265 SetBreakPoint(foo, 0);
1266 }
1267 CallAndGC(context, env->Global(), foo);
1268
1269 // Test IC load break point with garbage collection.
1270 {
1271 CompileFunction(&env, "function foo(){}", "foo");
1272 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1273 SetBreakPoint(foo, 0);
1274 }
1275 CallAndGC(context, env->Global(), foo);
1276
1277 // Test IC call break point with garbage collection.
1278 {
1279 CompileFunction(&env, "function foo(){}", "foo");
1280 foo = CompileFunction(&env,
1281 "function bar(){};function foo(){bar();}",
1282 "foo");
1283 SetBreakPoint(foo, 0);
1284 }
1285 CallAndGC(context, env->Global(), foo);
1286
1287 // Test return break point with garbage collection.
1288 {
1289 CompileFunction(&env, "function foo(){}", "foo");
1290 foo = CompileFunction(&env, "function foo(){}", "foo");
1291 SetBreakPoint(foo, 0);
1292 }
1293 CallAndGC(context, env->Global(), foo);
1294
1295 // Test non IC break point with garbage collection.
1296 {
1297 CompileFunction(&env, "function foo(){}", "foo");
1298 foo = CompileFunction(&env, "function foo(){var bar=0;}", "foo");
1299 SetBreakPoint(foo, 0);
1300 }
1301 CallAndGC(context, env->Global(), foo);
1302
1303
1304 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1305 CheckDebuggerUnloaded(env->GetIsolate());
1306 }
1307
1308
1309 // Test that break points can be set using the global Debug object.
TEST(BreakPointThroughJavaScript)1310 TEST(BreakPointThroughJavaScript) {
1311 break_point_hit_count = 0;
1312 DebugLocalContext env;
1313 v8::Isolate* isolate = env->GetIsolate();
1314 v8::HandleScope scope(isolate);
1315 v8::Local<v8::Context> context = env.context();
1316 env.ExposeDebug();
1317
1318 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
1319 CompileRunChecked(isolate, "function bar(){}");
1320 CompileFunction(isolate, "function foo(){bar();bar();}", "foo");
1321 // 012345678901234567890
1322 // 1 2
1323 // Break points are set at position 3 and 9
1324 v8::Local<v8::String> source = v8_str(env->GetIsolate(), "foo()");
1325 v8::Local<v8::Script> foo =
1326 v8::Script::Compile(context, source).ToLocalChecked();
1327
1328 CHECK_EQ(0, break_point_hit_count);
1329
1330 // Run with one breakpoint
1331 int bp1 = SetBreakPointFromJS(env->GetIsolate(), "foo", 0, 3);
1332 foo->Run(context).ToLocalChecked();
1333 CHECK_EQ(1, break_point_hit_count);
1334 foo->Run(context).ToLocalChecked();
1335 CHECK_EQ(2, break_point_hit_count);
1336
1337 // Run with two breakpoints
1338 int bp2 = SetBreakPointFromJS(env->GetIsolate(), "foo", 0, 9);
1339 foo->Run(context).ToLocalChecked();
1340 CHECK_EQ(4, break_point_hit_count);
1341 foo->Run(context).ToLocalChecked();
1342 CHECK_EQ(6, break_point_hit_count);
1343
1344 // Run with one breakpoint
1345 ClearBreakPointFromJS(env->GetIsolate(), bp2);
1346 foo->Run(context).ToLocalChecked();
1347 CHECK_EQ(7, break_point_hit_count);
1348 foo->Run(context).ToLocalChecked();
1349 CHECK_EQ(8, break_point_hit_count);
1350
1351 // Run without breakpoints.
1352 ClearBreakPointFromJS(env->GetIsolate(), bp1);
1353 foo->Run(context).ToLocalChecked();
1354 CHECK_EQ(8, break_point_hit_count);
1355
1356 v8::Debug::SetDebugEventListener(isolate, nullptr);
1357 CheckDebuggerUnloaded(isolate);
1358
1359 // Make sure that the break point numbers are consecutive.
1360 CHECK_EQ(1, bp1);
1361 CHECK_EQ(2, bp2);
1362 }
1363
1364
1365 // Test that break points on scripts identified by name can be set using the
1366 // global Debug object.
TEST(ScriptBreakPointByNameThroughJavaScript)1367 TEST(ScriptBreakPointByNameThroughJavaScript) {
1368 break_point_hit_count = 0;
1369 DebugLocalContext env;
1370 v8::Isolate* isolate = env->GetIsolate();
1371 v8::HandleScope scope(isolate);
1372 v8::Local<v8::Context> context = env.context();
1373 env.ExposeDebug();
1374
1375 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
1376
1377 v8::Local<v8::String> script = v8_str(isolate,
1378 "function f() {\n"
1379 " function h() {\n"
1380 " a = 0; // line 2\n"
1381 " }\n"
1382 " b = 1; // line 4\n"
1383 " return h();\n"
1384 "}\n"
1385 "\n"
1386 "function g() {\n"
1387 " function h() {\n"
1388 " a = 0;\n"
1389 " }\n"
1390 " b = 2; // line 12\n"
1391 " h();\n"
1392 " b = 3; // line 14\n"
1393 " f(); // line 15\n"
1394 "}");
1395
1396 // Compile the script and get the two functions.
1397 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(isolate, "test"));
1398 v8::Script::Compile(context, script, &origin)
1399 .ToLocalChecked()
1400 ->Run(context)
1401 .ToLocalChecked();
1402 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1403 env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
1404 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
1405 env->Global()->Get(context, v8_str(isolate, "g")).ToLocalChecked());
1406
1407 // Call f and g without break points.
1408 break_point_hit_count = 0;
1409 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1410 CHECK_EQ(0, break_point_hit_count);
1411 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1412 CHECK_EQ(0, break_point_hit_count);
1413
1414 // Call f and g with break point on line 12.
1415 int sbp1 = SetScriptBreakPointByNameFromJS(isolate, "test", 12, 0);
1416 break_point_hit_count = 0;
1417 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1418 CHECK_EQ(0, break_point_hit_count);
1419 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1420 CHECK_EQ(1, break_point_hit_count);
1421
1422 // Remove the break point again.
1423 break_point_hit_count = 0;
1424 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
1425 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1426 CHECK_EQ(0, break_point_hit_count);
1427 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1428 CHECK_EQ(0, break_point_hit_count);
1429
1430 // Call f and g with break point on line 2.
1431 int sbp2 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 2, 0);
1432 break_point_hit_count = 0;
1433 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1434 CHECK_EQ(1, break_point_hit_count);
1435 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1436 CHECK_EQ(2, break_point_hit_count);
1437
1438 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1439 int sbp3 = SetScriptBreakPointByNameFromJS(isolate, "test", 4, 0);
1440 int sbp4 = SetScriptBreakPointByNameFromJS(isolate, "test", 12, 0);
1441 int sbp5 = SetScriptBreakPointByNameFromJS(isolate, "test", 14, 0);
1442 int sbp6 = SetScriptBreakPointByNameFromJS(isolate, "test", 15, 0);
1443 break_point_hit_count = 0;
1444 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1445 CHECK_EQ(2, break_point_hit_count);
1446 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1447 CHECK_EQ(7, break_point_hit_count);
1448
1449 // Remove all the break points again.
1450 break_point_hit_count = 0;
1451 ClearBreakPointFromJS(isolate, sbp2);
1452 ClearBreakPointFromJS(isolate, sbp3);
1453 ClearBreakPointFromJS(isolate, sbp4);
1454 ClearBreakPointFromJS(isolate, sbp5);
1455 ClearBreakPointFromJS(isolate, sbp6);
1456 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1457 CHECK_EQ(0, break_point_hit_count);
1458 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1459 CHECK_EQ(0, break_point_hit_count);
1460
1461 v8::Debug::SetDebugEventListener(isolate, nullptr);
1462 CheckDebuggerUnloaded(isolate);
1463
1464 // Make sure that the break point numbers are consecutive.
1465 CHECK_EQ(1, sbp1);
1466 CHECK_EQ(2, sbp2);
1467 CHECK_EQ(3, sbp3);
1468 CHECK_EQ(4, sbp4);
1469 CHECK_EQ(5, sbp5);
1470 CHECK_EQ(6, sbp6);
1471 }
1472
1473
TEST(ScriptBreakPointByIdThroughJavaScript)1474 TEST(ScriptBreakPointByIdThroughJavaScript) {
1475 break_point_hit_count = 0;
1476 DebugLocalContext env;
1477 v8::Isolate* isolate = env->GetIsolate();
1478 v8::HandleScope scope(isolate);
1479 v8::Local<v8::Context> context = env.context();
1480 env.ExposeDebug();
1481
1482 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
1483
1484 v8::Local<v8::String> source = v8_str(isolate,
1485 "function f() {\n"
1486 " function h() {\n"
1487 " a = 0; // line 2\n"
1488 " }\n"
1489 " b = 1; // line 4\n"
1490 " return h();\n"
1491 "}\n"
1492 "\n"
1493 "function g() {\n"
1494 " function h() {\n"
1495 " a = 0;\n"
1496 " }\n"
1497 " b = 2; // line 12\n"
1498 " h();\n"
1499 " b = 3; // line 14\n"
1500 " f(); // line 15\n"
1501 "}");
1502
1503 // Compile the script and get the two functions.
1504 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(isolate, "test"));
1505 v8::Local<v8::Script> script =
1506 v8::Script::Compile(context, source, &origin).ToLocalChecked();
1507 script->Run(context).ToLocalChecked();
1508 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1509 env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
1510 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
1511 env->Global()->Get(context, v8_str(isolate, "g")).ToLocalChecked());
1512
1513 // Get the script id knowing that internally it is a 32 integer.
1514 int script_id = script->GetUnboundScript()->GetId();
1515
1516 // Call f and g without break points.
1517 break_point_hit_count = 0;
1518 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1519 CHECK_EQ(0, break_point_hit_count);
1520 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1521 CHECK_EQ(0, break_point_hit_count);
1522
1523 // Call f and g with break point on line 12.
1524 int sbp1 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 12, 0);
1525 break_point_hit_count = 0;
1526 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1527 CHECK_EQ(0, break_point_hit_count);
1528 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1529 CHECK_EQ(1, break_point_hit_count);
1530
1531 // Remove the break point again.
1532 break_point_hit_count = 0;
1533 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
1534 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1535 CHECK_EQ(0, break_point_hit_count);
1536 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1537 CHECK_EQ(0, break_point_hit_count);
1538
1539 // Call f and g with break point on line 2.
1540 int sbp2 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 2, 0);
1541 break_point_hit_count = 0;
1542 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1543 CHECK_EQ(1, break_point_hit_count);
1544 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1545 CHECK_EQ(2, break_point_hit_count);
1546
1547 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1548 int sbp3 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 4, 0);
1549 int sbp4 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 12, 0);
1550 int sbp5 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 14, 0);
1551 int sbp6 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 15, 0);
1552 break_point_hit_count = 0;
1553 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1554 CHECK_EQ(2, break_point_hit_count);
1555 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1556 CHECK_EQ(7, break_point_hit_count);
1557
1558 // Remove all the break points again.
1559 break_point_hit_count = 0;
1560 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
1561 ClearBreakPointFromJS(env->GetIsolate(), sbp3);
1562 ClearBreakPointFromJS(env->GetIsolate(), sbp4);
1563 ClearBreakPointFromJS(env->GetIsolate(), sbp5);
1564 ClearBreakPointFromJS(env->GetIsolate(), sbp6);
1565 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1566 CHECK_EQ(0, break_point_hit_count);
1567 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1568 CHECK_EQ(0, break_point_hit_count);
1569
1570 v8::Debug::SetDebugEventListener(isolate, nullptr);
1571 CheckDebuggerUnloaded(isolate);
1572
1573 // Make sure that the break point numbers are consecutive.
1574 CHECK_EQ(1, sbp1);
1575 CHECK_EQ(2, sbp2);
1576 CHECK_EQ(3, sbp3);
1577 CHECK_EQ(4, sbp4);
1578 CHECK_EQ(5, sbp5);
1579 CHECK_EQ(6, sbp6);
1580 }
1581
1582
1583 // Test conditional script break points.
TEST(EnableDisableScriptBreakPoint)1584 TEST(EnableDisableScriptBreakPoint) {
1585 break_point_hit_count = 0;
1586 DebugLocalContext env;
1587 v8::Isolate* isolate = env->GetIsolate();
1588 v8::HandleScope scope(isolate);
1589 v8::Local<v8::Context> context = env.context();
1590 env.ExposeDebug();
1591
1592 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
1593
1594 v8::Local<v8::String> script = v8_str(isolate,
1595 "function f() {\n"
1596 " a = 0; // line 1\n"
1597 "};");
1598
1599 // Compile the script and get function f.
1600 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(isolate, "test"));
1601 v8::Script::Compile(context, script, &origin)
1602 .ToLocalChecked()
1603 ->Run(context)
1604 .ToLocalChecked();
1605 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1606 env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
1607
1608 // Set script break point on line 1 (in function f).
1609 int sbp = SetScriptBreakPointByNameFromJS(isolate, "test", 1, 0);
1610
1611 // Call f while enabeling and disabling the script break point.
1612 break_point_hit_count = 0;
1613 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1614 CHECK_EQ(1, break_point_hit_count);
1615
1616 DisableScriptBreakPointFromJS(isolate, sbp);
1617 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1618 CHECK_EQ(1, break_point_hit_count);
1619
1620 EnableScriptBreakPointFromJS(isolate, sbp);
1621 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1622 CHECK_EQ(2, break_point_hit_count);
1623
1624 DisableScriptBreakPointFromJS(isolate, sbp);
1625 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1626 CHECK_EQ(2, break_point_hit_count);
1627
1628 // Reload the script and get f again checking that the disabling survives.
1629 v8::Script::Compile(context, script, &origin)
1630 .ToLocalChecked()
1631 ->Run(context)
1632 .ToLocalChecked();
1633 f = v8::Local<v8::Function>::Cast(
1634 env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
1635 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1636 CHECK_EQ(2, break_point_hit_count);
1637
1638 EnableScriptBreakPointFromJS(isolate, sbp);
1639 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1640 CHECK_EQ(3, break_point_hit_count);
1641
1642 v8::Debug::SetDebugEventListener(isolate, nullptr);
1643 CheckDebuggerUnloaded(isolate);
1644 }
1645
1646
1647 // Test conditional script break points.
TEST(ConditionalScriptBreakPoint)1648 TEST(ConditionalScriptBreakPoint) {
1649 break_point_hit_count = 0;
1650 DebugLocalContext env;
1651 v8::HandleScope scope(env->GetIsolate());
1652 env.ExposeDebug();
1653
1654 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1655 DebugEventBreakPointHitCount);
1656
1657 v8::Local<v8::String> script = v8_str(env->GetIsolate(),
1658 "count = 0;\n"
1659 "function f() {\n"
1660 " g(count++); // line 2\n"
1661 "};\n"
1662 "function g(x) {\n"
1663 " var a=x; // line 5\n"
1664 "};");
1665
1666 // Compile the script and get function f.
1667 v8::Local<v8::Context> context = env.context();
1668 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(env->GetIsolate(), "test"));
1669 v8::Script::Compile(context, script, &origin)
1670 .ToLocalChecked()
1671 ->Run(context)
1672 .ToLocalChecked();
1673 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1674 env->Global()
1675 ->Get(context, v8_str(env->GetIsolate(), "f"))
1676 .ToLocalChecked());
1677
1678 // Set script break point on line 5 (in function g).
1679 int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 5, 0);
1680
1681 // Call f with different conditions on the script break point.
1682 break_point_hit_count = 0;
1683 ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "false");
1684 f->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
1685 CHECK_EQ(0, break_point_hit_count);
1686
1687 ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "true");
1688 break_point_hit_count = 0;
1689 f->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
1690 CHECK_EQ(1, break_point_hit_count);
1691
1692 ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "x % 2 == 0");
1693 break_point_hit_count = 0;
1694 for (int i = 0; i < 10; i++) {
1695 f->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
1696 }
1697 CHECK_EQ(5, break_point_hit_count);
1698
1699 // Reload the script and get f again checking that the condition survives.
1700 v8::Script::Compile(context, script, &origin)
1701 .ToLocalChecked()
1702 ->Run(context)
1703 .ToLocalChecked();
1704 f = v8::Local<v8::Function>::Cast(
1705 env->Global()
1706 ->Get(context, v8_str(env->GetIsolate(), "f"))
1707 .ToLocalChecked());
1708
1709 break_point_hit_count = 0;
1710 for (int i = 0; i < 10; i++) {
1711 f->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
1712 }
1713 CHECK_EQ(5, break_point_hit_count);
1714
1715 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1716 CheckDebuggerUnloaded(env->GetIsolate());
1717 }
1718
1719
1720 // Test ignore count on script break points.
TEST(ScriptBreakPointIgnoreCount)1721 TEST(ScriptBreakPointIgnoreCount) {
1722 break_point_hit_count = 0;
1723 DebugLocalContext env;
1724 v8::HandleScope scope(env->GetIsolate());
1725 env.ExposeDebug();
1726
1727 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1728 DebugEventBreakPointHitCount);
1729
1730 v8::Local<v8::String> script = v8_str(env->GetIsolate(),
1731 "function f() {\n"
1732 " a = 0; // line 1\n"
1733 "};");
1734
1735 // Compile the script and get function f.
1736 v8::Local<v8::Context> context = env.context();
1737 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(env->GetIsolate(), "test"));
1738 v8::Script::Compile(context, script, &origin)
1739 .ToLocalChecked()
1740 ->Run(context)
1741 .ToLocalChecked();
1742 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1743 env->Global()
1744 ->Get(context, v8_str(env->GetIsolate(), "f"))
1745 .ToLocalChecked());
1746
1747 // Set script break point on line 1 (in function f).
1748 int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
1749
1750 // Call f with different ignores on the script break point.
1751 break_point_hit_count = 0;
1752 ChangeScriptBreakPointIgnoreCountFromJS(env->GetIsolate(), sbp, 1);
1753 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1754 CHECK_EQ(0, break_point_hit_count);
1755 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1756 CHECK_EQ(1, break_point_hit_count);
1757
1758 ChangeScriptBreakPointIgnoreCountFromJS(env->GetIsolate(), sbp, 5);
1759 break_point_hit_count = 0;
1760 for (int i = 0; i < 10; i++) {
1761 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1762 }
1763 CHECK_EQ(5, break_point_hit_count);
1764
1765 // Reload the script and get f again checking that the ignore survives.
1766 v8::Script::Compile(context, script, &origin)
1767 .ToLocalChecked()
1768 ->Run(context)
1769 .ToLocalChecked();
1770 f = v8::Local<v8::Function>::Cast(
1771 env->Global()
1772 ->Get(context, v8_str(env->GetIsolate(), "f"))
1773 .ToLocalChecked());
1774
1775 break_point_hit_count = 0;
1776 for (int i = 0; i < 10; i++) {
1777 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1778 }
1779 CHECK_EQ(5, break_point_hit_count);
1780
1781 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1782 CheckDebuggerUnloaded(env->GetIsolate());
1783 }
1784
1785
1786 // Test that script break points survive when a script is reloaded.
TEST(ScriptBreakPointReload)1787 TEST(ScriptBreakPointReload) {
1788 break_point_hit_count = 0;
1789 DebugLocalContext env;
1790 v8::HandleScope scope(env->GetIsolate());
1791 env.ExposeDebug();
1792
1793 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1794 DebugEventBreakPointHitCount);
1795
1796 v8::Local<v8::Context> context = env.context();
1797 v8::Local<v8::Function> f;
1798 v8::Local<v8::String> script = v8_str(env->GetIsolate(),
1799 "function f() {\n"
1800 " function h() {\n"
1801 " a = 0; // line 2\n"
1802 " }\n"
1803 " b = 1; // line 4\n"
1804 " return h();\n"
1805 "}");
1806
1807 v8::ScriptOrigin origin_1 = v8::ScriptOrigin(v8_str(env->GetIsolate(), "1"));
1808 v8::ScriptOrigin origin_2 = v8::ScriptOrigin(v8_str(env->GetIsolate(), "2"));
1809
1810 // Set a script break point before the script is loaded.
1811 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "1", 2, 0);
1812
1813 // Compile the script and get the function.
1814 v8::Script::Compile(context, script, &origin_1)
1815 .ToLocalChecked()
1816 ->Run(context)
1817 .ToLocalChecked();
1818 f = v8::Local<v8::Function>::Cast(
1819 env->Global()
1820 ->Get(context, v8_str(env->GetIsolate(), "f"))
1821 .ToLocalChecked());
1822
1823 // Call f and check that the script break point is active.
1824 break_point_hit_count = 0;
1825 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1826 CHECK_EQ(1, break_point_hit_count);
1827
1828 // Compile the script again with a different script data and get the
1829 // function.
1830 v8::Script::Compile(context, script, &origin_2)
1831 .ToLocalChecked()
1832 ->Run(context)
1833 .ToLocalChecked();
1834 f = v8::Local<v8::Function>::Cast(
1835 env->Global()
1836 ->Get(context, v8_str(env->GetIsolate(), "f"))
1837 .ToLocalChecked());
1838
1839 // Call f and check that no break points are set.
1840 break_point_hit_count = 0;
1841 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1842 CHECK_EQ(0, break_point_hit_count);
1843
1844 // Compile the script again and get the function.
1845 v8::Script::Compile(context, script, &origin_1)
1846 .ToLocalChecked()
1847 ->Run(context)
1848 .ToLocalChecked();
1849 f = v8::Local<v8::Function>::Cast(
1850 env->Global()
1851 ->Get(context, v8_str(env->GetIsolate(), "f"))
1852 .ToLocalChecked());
1853
1854 // Call f and check that the script break point is active.
1855 break_point_hit_count = 0;
1856 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1857 CHECK_EQ(1, break_point_hit_count);
1858
1859 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1860 CheckDebuggerUnloaded(env->GetIsolate());
1861 }
1862
1863
1864 // Test when several scripts has the same script data
TEST(ScriptBreakPointMultiple)1865 TEST(ScriptBreakPointMultiple) {
1866 break_point_hit_count = 0;
1867 DebugLocalContext env;
1868 v8::HandleScope scope(env->GetIsolate());
1869 env.ExposeDebug();
1870
1871 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1872 DebugEventBreakPointHitCount);
1873
1874 v8::Local<v8::Context> context = env.context();
1875 v8::Local<v8::Function> f;
1876 v8::Local<v8::String> script_f = v8_str(env->GetIsolate(),
1877 "function f() {\n"
1878 " a = 0; // line 1\n"
1879 "}");
1880
1881 v8::Local<v8::Function> g;
1882 v8::Local<v8::String> script_g = v8_str(env->GetIsolate(),
1883 "function g() {\n"
1884 " b = 0; // line 1\n"
1885 "}");
1886
1887 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(env->GetIsolate(), "test"));
1888
1889 // Set a script break point before the scripts are loaded.
1890 int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
1891
1892 // Compile the scripts with same script data and get the functions.
1893 v8::Script::Compile(context, script_f, &origin)
1894 .ToLocalChecked()
1895 ->Run(context)
1896 .ToLocalChecked();
1897 f = v8::Local<v8::Function>::Cast(
1898 env->Global()
1899 ->Get(context, v8_str(env->GetIsolate(), "f"))
1900 .ToLocalChecked());
1901 v8::Script::Compile(context, script_g, &origin)
1902 .ToLocalChecked()
1903 ->Run(context)
1904 .ToLocalChecked();
1905 g = v8::Local<v8::Function>::Cast(
1906 env->Global()
1907 ->Get(context, v8_str(env->GetIsolate(), "g"))
1908 .ToLocalChecked());
1909
1910 // Call f and g and check that the script break point is active.
1911 break_point_hit_count = 0;
1912 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1913 CHECK_EQ(1, break_point_hit_count);
1914 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1915 CHECK_EQ(2, break_point_hit_count);
1916
1917 // Clear the script break point.
1918 ClearBreakPointFromJS(env->GetIsolate(), sbp);
1919
1920 // Call f and g and check that the script break point is no longer active.
1921 break_point_hit_count = 0;
1922 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1923 CHECK_EQ(0, break_point_hit_count);
1924 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1925 CHECK_EQ(0, break_point_hit_count);
1926
1927 // Set script break point with the scripts loaded.
1928 sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
1929
1930 // Call f and g and check that the script break point is active.
1931 break_point_hit_count = 0;
1932 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1933 CHECK_EQ(1, break_point_hit_count);
1934 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1935 CHECK_EQ(2, break_point_hit_count);
1936
1937 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1938 CheckDebuggerUnloaded(env->GetIsolate());
1939 }
1940
1941
1942 // Test the script origin which has both name and line offset.
TEST(ScriptBreakPointLineOffset)1943 TEST(ScriptBreakPointLineOffset) {
1944 break_point_hit_count = 0;
1945 DebugLocalContext env;
1946 v8::HandleScope scope(env->GetIsolate());
1947 env.ExposeDebug();
1948
1949 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1950 DebugEventBreakPointHitCount);
1951
1952 v8::Local<v8::Context> context = env.context();
1953 v8::Local<v8::Function> f;
1954 v8::Local<v8::String> script =
1955 v8_str(env->GetIsolate(),
1956 "function f() {\n"
1957 " a = 0; // line 8 as this script has line offset 7\n"
1958 " b = 0; // line 9 as this script has line offset 7\n"
1959 "}");
1960
1961 // Create script origin both name and line offset.
1962 v8::ScriptOrigin origin(v8_str(env->GetIsolate(), "test.html"),
1963 v8::Integer::New(env->GetIsolate(), 7));
1964
1965 // Set two script break points before the script is loaded.
1966 int sbp1 =
1967 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 8, 0);
1968 int sbp2 =
1969 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0);
1970
1971 // Compile the script and get the function.
1972 v8::Script::Compile(context, script, &origin)
1973 .ToLocalChecked()
1974 ->Run(context)
1975 .ToLocalChecked();
1976 f = v8::Local<v8::Function>::Cast(
1977 env->Global()
1978 ->Get(context, v8_str(env->GetIsolate(), "f"))
1979 .ToLocalChecked());
1980
1981 // Call f and check that the script break point is active.
1982 break_point_hit_count = 0;
1983 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1984 CHECK_EQ(2, break_point_hit_count);
1985
1986 // Clear the script break points.
1987 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
1988 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
1989
1990 // Call f and check that no script break points are active.
1991 break_point_hit_count = 0;
1992 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
1993 CHECK_EQ(0, break_point_hit_count);
1994
1995 // Set a script break point with the script loaded.
1996 sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0);
1997
1998 // Call f and check that the script break point is active.
1999 break_point_hit_count = 0;
2000 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2001 CHECK_EQ(1, break_point_hit_count);
2002
2003 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2004 CheckDebuggerUnloaded(env->GetIsolate());
2005 }
2006
2007
2008 // Test script break points set on lines.
TEST(ScriptBreakPointLine)2009 TEST(ScriptBreakPointLine) {
2010 DebugLocalContext env;
2011 v8::HandleScope scope(env->GetIsolate());
2012 env.ExposeDebug();
2013
2014 // Create a function for checking the function when hitting a break point.
2015 frame_function_name = CompileFunction(&env,
2016 frame_function_name_source,
2017 "frame_function_name");
2018
2019 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2020 DebugEventBreakPointHitCount);
2021
2022 v8::Local<v8::Context> context = env.context();
2023 v8::Local<v8::Function> f;
2024 v8::Local<v8::Function> g;
2025 v8::Local<v8::String> script =
2026 v8_str(env->GetIsolate(),
2027 "a = 0 // line 0\n"
2028 "function f() {\n"
2029 " a = 1; // line 2\n"
2030 "}\n"
2031 " a = 2; // line 4\n"
2032 " /* xx */ function g() { // line 5\n"
2033 " function h() { // line 6\n"
2034 " a = 3; // line 7\n"
2035 " }\n"
2036 " h(); // line 9\n"
2037 " a = 4; // line 10\n"
2038 " }\n"
2039 " a=5; // line 12");
2040
2041 // Set a couple script break point before the script is loaded.
2042 int sbp1 =
2043 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 0, -1);
2044 int sbp2 =
2045 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 1, -1);
2046 int sbp3 =
2047 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 5, -1);
2048
2049 // Compile the script and get the function.
2050 break_point_hit_count = 0;
2051 v8::ScriptOrigin origin(v8_str(env->GetIsolate(), "test.html"),
2052 v8::Integer::New(env->GetIsolate(), 0));
2053 v8::Script::Compile(context, script, &origin)
2054 .ToLocalChecked()
2055 ->Run(context)
2056 .ToLocalChecked();
2057 f = v8::Local<v8::Function>::Cast(
2058 env->Global()
2059 ->Get(context, v8_str(env->GetIsolate(), "f"))
2060 .ToLocalChecked());
2061 g = v8::Local<v8::Function>::Cast(
2062 env->Global()
2063 ->Get(context, v8_str(env->GetIsolate(), "g"))
2064 .ToLocalChecked());
2065
2066 // Check that a break point was hit when the script was run.
2067 CHECK_EQ(1, break_point_hit_count);
2068 CHECK_EQ(0, StrLength(last_function_hit));
2069
2070 // Call f and check that the script break point.
2071 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2072 CHECK_EQ(2, break_point_hit_count);
2073 CHECK_EQ(0, strcmp("f", last_function_hit));
2074
2075 // Call g and check that the script break point.
2076 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2077 CHECK_EQ(3, break_point_hit_count);
2078 CHECK_EQ(0, strcmp("g", last_function_hit));
2079
2080 // Clear the script break point on g and set one on h.
2081 ClearBreakPointFromJS(env->GetIsolate(), sbp3);
2082 int sbp4 =
2083 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 6, -1);
2084
2085 // Call g and check that the script break point in h is hit.
2086 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2087 CHECK_EQ(4, break_point_hit_count);
2088 CHECK_EQ(0, strcmp("h", last_function_hit));
2089
2090 // Clear break points in f and h. Set a new one in the script between
2091 // functions f and g and test that there is no break points in f and g any
2092 // more.
2093 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
2094 ClearBreakPointFromJS(env->GetIsolate(), sbp4);
2095 int sbp5 =
2096 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 4, -1);
2097 break_point_hit_count = 0;
2098 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2099 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2100 CHECK_EQ(0, break_point_hit_count);
2101
2102 // Reload the script which should hit two break points.
2103 break_point_hit_count = 0;
2104 v8::Script::Compile(context, script, &origin)
2105 .ToLocalChecked()
2106 ->Run(context)
2107 .ToLocalChecked();
2108 CHECK_EQ(2, break_point_hit_count);
2109 CHECK_EQ(0, StrLength(last_function_hit));
2110
2111 // Set a break point in the code after the last function decleration.
2112 int sbp6 =
2113 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 12, -1);
2114
2115 // Reload the script which should hit three break points.
2116 break_point_hit_count = 0;
2117 v8::Script::Compile(context, script, &origin)
2118 .ToLocalChecked()
2119 ->Run(context)
2120 .ToLocalChecked();
2121 CHECK_EQ(3, break_point_hit_count);
2122 CHECK_EQ(0, StrLength(last_function_hit));
2123
2124 // Clear the last break points, and reload the script which should not hit any
2125 // break points.
2126 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
2127 ClearBreakPointFromJS(env->GetIsolate(), sbp5);
2128 ClearBreakPointFromJS(env->GetIsolate(), sbp6);
2129 break_point_hit_count = 0;
2130 v8::Script::Compile(context, script, &origin)
2131 .ToLocalChecked()
2132 ->Run(context)
2133 .ToLocalChecked();
2134 CHECK_EQ(0, break_point_hit_count);
2135
2136 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2137 CheckDebuggerUnloaded(env->GetIsolate());
2138 }
2139
2140
2141 // Test top level script break points set on lines.
TEST(ScriptBreakPointLineTopLevel)2142 TEST(ScriptBreakPointLineTopLevel) {
2143 DebugLocalContext env;
2144 v8::HandleScope scope(env->GetIsolate());
2145 env.ExposeDebug();
2146
2147 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2148 DebugEventBreakPointHitCount);
2149
2150 v8::Local<v8::Context> context = env.context();
2151 v8::Local<v8::String> script =
2152 v8_str(env->GetIsolate(),
2153 "function f() {\n"
2154 " a = 1; // line 1\n"
2155 "}\n"
2156 "a = 2; // line 3\n");
2157 v8::Local<v8::Function> f;
2158 {
2159 v8::HandleScope scope(env->GetIsolate());
2160 CompileRunWithOrigin(script, "test.html");
2161 }
2162 f = v8::Local<v8::Function>::Cast(
2163 env->Global()
2164 ->Get(context, v8_str(env->GetIsolate(), "f"))
2165 .ToLocalChecked());
2166
2167 CcTest::heap()->CollectAllGarbage();
2168
2169 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
2170
2171 // Call f and check that there was no break points.
2172 break_point_hit_count = 0;
2173 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2174 CHECK_EQ(0, break_point_hit_count);
2175
2176 // Recompile and run script and check that break point was hit.
2177 break_point_hit_count = 0;
2178 CompileRunWithOrigin(script, "test.html");
2179 CHECK_EQ(1, break_point_hit_count);
2180
2181 // Call f and check that there are still no break points.
2182 break_point_hit_count = 0;
2183 f = v8::Local<v8::Function>::Cast(
2184 env->Global()
2185 ->Get(context, v8_str(env->GetIsolate(), "f"))
2186 .ToLocalChecked());
2187 CHECK_EQ(0, break_point_hit_count);
2188
2189 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2190 CheckDebuggerUnloaded(env->GetIsolate());
2191 }
2192
2193
2194 // Test that it is possible to add and remove break points in a top level
2195 // function which has no references but has not been collected yet.
TEST(ScriptBreakPointTopLevelCrash)2196 TEST(ScriptBreakPointTopLevelCrash) {
2197 DebugLocalContext env;
2198 v8::HandleScope scope(env->GetIsolate());
2199 env.ExposeDebug();
2200
2201 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2202 DebugEventBreakPointHitCount);
2203
2204 v8::Local<v8::String> script_source = v8_str(env->GetIsolate(),
2205 "function f() {\n"
2206 " return 0;\n"
2207 "}\n"
2208 "f()");
2209
2210 int sbp1 =
2211 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
2212 {
2213 v8::HandleScope scope(env->GetIsolate());
2214 break_point_hit_count = 0;
2215 CompileRunWithOrigin(script_source, "test.html");
2216 CHECK_EQ(1, break_point_hit_count);
2217 }
2218
2219 int sbp2 =
2220 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
2221 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
2222 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
2223
2224 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2225 CheckDebuggerUnloaded(env->GetIsolate());
2226 }
2227
2228
2229 // Test that it is possible to remove the last break point for a function
2230 // inside the break handling of that break point.
TEST(RemoveBreakPointInBreak)2231 TEST(RemoveBreakPointInBreak) {
2232 DebugLocalContext env;
2233 v8::HandleScope scope(env->GetIsolate());
2234
2235 v8::Local<v8::Context> context = env.context();
2236 v8::Local<v8::Function> foo =
2237 CompileFunction(&env, "function foo(){a=1;}", "foo");
2238
2239 // Register the debug event listener pasing the function
2240 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2241 DebugEventRemoveBreakPoint, foo);
2242
2243 debug_event_remove_break_point = SetBreakPoint(foo, 0);
2244
2245 break_point_hit_count = 0;
2246 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2247 CHECK_EQ(1, break_point_hit_count);
2248
2249 break_point_hit_count = 0;
2250 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2251 CHECK_EQ(0, break_point_hit_count);
2252
2253 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2254 CheckDebuggerUnloaded(env->GetIsolate());
2255 }
2256
2257
2258 // Test that the debugger statement causes a break.
TEST(DebuggerStatement)2259 TEST(DebuggerStatement) {
2260 break_point_hit_count = 0;
2261 DebugLocalContext env;
2262 v8::HandleScope scope(env->GetIsolate());
2263 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2264 DebugEventBreakPointHitCount);
2265 v8::Local<v8::Context> context = env.context();
2266 v8::Script::Compile(context,
2267 v8_str(env->GetIsolate(), "function bar(){debugger}"))
2268 .ToLocalChecked()
2269 ->Run(context)
2270 .ToLocalChecked();
2271 v8::Script::Compile(
2272 context, v8_str(env->GetIsolate(), "function foo(){debugger;debugger;}"))
2273 .ToLocalChecked()
2274 ->Run(context)
2275 .ToLocalChecked();
2276 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
2277 env->Global()
2278 ->Get(context, v8_str(env->GetIsolate(), "foo"))
2279 .ToLocalChecked());
2280 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
2281 env->Global()
2282 ->Get(context, v8_str(env->GetIsolate(), "bar"))
2283 .ToLocalChecked());
2284
2285 // Run function with debugger statement
2286 bar->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2287 CHECK_EQ(1, break_point_hit_count);
2288
2289 // Run function with two debugger statement
2290 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2291 CHECK_EQ(3, break_point_hit_count);
2292
2293 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2294 CheckDebuggerUnloaded(env->GetIsolate());
2295 }
2296
2297
2298 // Test setting a breakpoint on the debugger statement.
TEST(DebuggerStatementBreakpoint)2299 TEST(DebuggerStatementBreakpoint) {
2300 break_point_hit_count = 0;
2301 DebugLocalContext env;
2302 v8::HandleScope scope(env->GetIsolate());
2303 v8::Local<v8::Context> context = env.context();
2304 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2305 DebugEventBreakPointHitCount);
2306 v8::Script::Compile(context,
2307 v8_str(env->GetIsolate(), "function foo(){debugger;}"))
2308 .ToLocalChecked()
2309 ->Run(context)
2310 .ToLocalChecked();
2311 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
2312 env->Global()
2313 ->Get(context, v8_str(env->GetIsolate(), "foo"))
2314 .ToLocalChecked());
2315
2316 // The debugger statement triggers breakpoint hit
2317 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2318 CHECK_EQ(1, break_point_hit_count);
2319
2320 int bp = SetBreakPoint(foo, 0);
2321
2322 // Set breakpoint does not duplicate hits
2323 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2324 CHECK_EQ(2, break_point_hit_count);
2325
2326 ClearBreakPoint(bp);
2327 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2328 CheckDebuggerUnloaded(env->GetIsolate());
2329 }
2330
2331
2332 // Test that the evaluation of expressions when a break point is hit generates
2333 // the correct results.
TEST(DebugEvaluate)2334 TEST(DebugEvaluate) {
2335 DebugLocalContext env;
2336 v8::Isolate* isolate = env->GetIsolate();
2337 v8::HandleScope scope(isolate);
2338 env.ExposeDebug();
2339
2340 // Create a function for checking the evaluation when hitting a break point.
2341 evaluate_check_function = CompileFunction(&env,
2342 evaluate_check_source,
2343 "evaluate_check");
2344 // Register the debug event listener
2345 v8::Debug::SetDebugEventListener(isolate, DebugEventEvaluate);
2346
2347 // Different expected vaules of x and a when in a break point (u = undefined,
2348 // d = Hello, world!).
2349 struct EvaluateCheck checks_uu[] = {{"x", v8::Undefined(isolate)},
2350 {"a", v8::Undefined(isolate)},
2351 {NULL, v8::Local<v8::Value>()}};
2352 struct EvaluateCheck checks_hu[] = {
2353 {"x", v8_str(env->GetIsolate(), "Hello, world!")},
2354 {"a", v8::Undefined(isolate)},
2355 {NULL, v8::Local<v8::Value>()}};
2356 struct EvaluateCheck checks_hh[] = {
2357 {"x", v8_str(env->GetIsolate(), "Hello, world!")},
2358 {"a", v8_str(env->GetIsolate(), "Hello, world!")},
2359 {NULL, v8::Local<v8::Value>()}};
2360
2361 // Simple test function. The "y=0" is in the function foo to provide a break
2362 // location. For "y=0" the "y" is at position 15 in the foo function
2363 // therefore setting breakpoint at position 15 will break at "y=0" and
2364 // setting it higher will break after.
2365 v8::Local<v8::Function> foo = CompileFunction(&env,
2366 "function foo(x) {"
2367 " var a;"
2368 " y=0;" // To ensure break location 1.
2369 " a=x;"
2370 " y=0;" // To ensure break location 2.
2371 "}",
2372 "foo");
2373 const int foo_break_position_1 = 15;
2374 const int foo_break_position_2 = 29;
2375
2376 v8::Local<v8::Context> context = env.context();
2377 // Arguments with one parameter "Hello, world!"
2378 v8::Local<v8::Value> argv_foo[1] = {
2379 v8_str(env->GetIsolate(), "Hello, world!")};
2380
2381 // Call foo with breakpoint set before a=x and undefined as parameter.
2382 int bp = SetBreakPoint(foo, foo_break_position_1);
2383 checks = checks_uu;
2384 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2385
2386 // Call foo with breakpoint set before a=x and parameter "Hello, world!".
2387 checks = checks_hu;
2388 foo->Call(context, env->Global(), 1, argv_foo).ToLocalChecked();
2389
2390 // Call foo with breakpoint set after a=x and parameter "Hello, world!".
2391 ClearBreakPoint(bp);
2392 SetBreakPoint(foo, foo_break_position_2);
2393 checks = checks_hh;
2394 foo->Call(context, env->Global(), 1, argv_foo).ToLocalChecked();
2395
2396 // Test that overriding Object.prototype will not interfere into evaluation
2397 // on call frame.
2398 v8::Local<v8::Function> zoo =
2399 CompileFunction(&env,
2400 "x = undefined;"
2401 "function zoo(t) {"
2402 " var a=x;"
2403 " Object.prototype.x = 42;"
2404 " x=t;"
2405 " y=0;" // To ensure break location.
2406 " delete Object.prototype.x;"
2407 " x=a;"
2408 "}",
2409 "zoo");
2410 const int zoo_break_position = 50;
2411
2412 // Arguments with one parameter "Hello, world!"
2413 v8::Local<v8::Value> argv_zoo[1] = {
2414 v8_str(env->GetIsolate(), "Hello, world!")};
2415
2416 // Call zoo with breakpoint set at y=0.
2417 DebugEventCounterClear();
2418 bp = SetBreakPoint(zoo, zoo_break_position);
2419 checks = checks_hu;
2420 zoo->Call(context, env->Global(), 1, argv_zoo).ToLocalChecked();
2421 CHECK_EQ(1, break_point_hit_count);
2422 ClearBreakPoint(bp);
2423
2424 // Test function with an inner function. The "y=0" is in function barbar
2425 // to provide a break location. For "y=0" the "y" is at position 8 in the
2426 // barbar function therefore setting breakpoint at position 8 will break at
2427 // "y=0" and setting it higher will break after.
2428 v8::Local<v8::Function> bar = CompileFunction(&env,
2429 "y = 0;"
2430 "x = 'Goodbye, world!';"
2431 "function bar(x, b) {"
2432 " var a;"
2433 " function barbar() {"
2434 " y=0; /* To ensure break location.*/"
2435 " a=x;"
2436 " };"
2437 " debug.Debug.clearAllBreakPoints();"
2438 " barbar();"
2439 " y=0;a=x;"
2440 "}",
2441 "bar");
2442 const int barbar_break_position = 8;
2443
2444 // Call bar setting breakpoint before a=x in barbar and undefined as
2445 // parameter.
2446 checks = checks_uu;
2447 v8::Local<v8::Value> argv_bar_1[2] = {
2448 v8::Undefined(isolate), v8::Number::New(isolate, barbar_break_position)};
2449 bar->Call(context, env->Global(), 2, argv_bar_1).ToLocalChecked();
2450
2451 // Call bar setting breakpoint before a=x in barbar and parameter
2452 // "Hello, world!".
2453 checks = checks_hu;
2454 v8::Local<v8::Value> argv_bar_2[2] = {
2455 v8_str(env->GetIsolate(), "Hello, world!"),
2456 v8::Number::New(env->GetIsolate(), barbar_break_position)};
2457 bar->Call(context, env->Global(), 2, argv_bar_2).ToLocalChecked();
2458
2459 // Call bar setting breakpoint after a=x in barbar and parameter
2460 // "Hello, world!".
2461 checks = checks_hh;
2462 v8::Local<v8::Value> argv_bar_3[2] = {
2463 v8_str(env->GetIsolate(), "Hello, world!"),
2464 v8::Number::New(env->GetIsolate(), barbar_break_position + 1)};
2465 bar->Call(context, env->Global(), 2, argv_bar_3).ToLocalChecked();
2466
2467 v8::Debug::SetDebugEventListener(isolate, nullptr);
2468 CheckDebuggerUnloaded(isolate);
2469 }
2470
2471
2472 int debugEventCount = 0;
CheckDebugEvent(const v8::Debug::EventDetails & eventDetails)2473 static void CheckDebugEvent(const v8::Debug::EventDetails& eventDetails) {
2474 if (eventDetails.GetEvent() == v8::Break) ++debugEventCount;
2475 }
2476
2477
2478 // Test that the conditional breakpoints work event if code generation from
2479 // strings is prohibited in the debugee context.
TEST(ConditionalBreakpointWithCodeGenerationDisallowed)2480 TEST(ConditionalBreakpointWithCodeGenerationDisallowed) {
2481 DebugLocalContext env;
2482 v8::HandleScope scope(env->GetIsolate());
2483 env.ExposeDebug();
2484
2485 v8::Debug::SetDebugEventListener(env->GetIsolate(), CheckDebugEvent);
2486
2487 v8::Local<v8::Context> context = env.context();
2488 v8::Local<v8::Function> foo = CompileFunction(&env,
2489 "function foo(x) {\n"
2490 " var s = 'String value2';\n"
2491 " return s + x;\n"
2492 "}",
2493 "foo");
2494
2495 // Set conditional breakpoint with condition 'true'.
2496 CompileRun("debug.Debug.setBreakPoint(foo, 2, 0, 'true')");
2497
2498 debugEventCount = 0;
2499 env->AllowCodeGenerationFromStrings(false);
2500 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2501 CHECK_EQ(1, debugEventCount);
2502
2503 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2504 CheckDebuggerUnloaded(env->GetIsolate());
2505 }
2506
2507
2508 bool checkedDebugEvals = true;
2509 v8::Local<v8::Function> checkGlobalEvalFunction;
2510 v8::Local<v8::Function> checkFrameEvalFunction;
CheckDebugEval(const v8::Debug::EventDetails & eventDetails)2511 static void CheckDebugEval(const v8::Debug::EventDetails& eventDetails) {
2512 if (eventDetails.GetEvent() == v8::Break) {
2513 ++debugEventCount;
2514 v8::HandleScope handleScope(CcTest::isolate());
2515
2516 v8::Local<v8::Value> args[] = {eventDetails.GetExecutionState()};
2517 CHECK(
2518 checkGlobalEvalFunction->Call(eventDetails.GetEventContext(),
2519 eventDetails.GetEventContext()->Global(),
2520 1, args)
2521 .ToLocalChecked()
2522 ->IsTrue());
2523 CHECK(checkFrameEvalFunction->Call(eventDetails.GetEventContext(),
2524 eventDetails.GetEventContext()->Global(),
2525 1, args)
2526 .ToLocalChecked()
2527 ->IsTrue());
2528 }
2529 }
2530
2531
2532 // Test that the evaluation of expressions when a break point is hit generates
2533 // the correct results in case code generation from strings is disallowed in the
2534 // debugee context.
TEST(DebugEvaluateWithCodeGenerationDisallowed)2535 TEST(DebugEvaluateWithCodeGenerationDisallowed) {
2536 DebugLocalContext env;
2537 v8::HandleScope scope(env->GetIsolate());
2538 env.ExposeDebug();
2539
2540 v8::Debug::SetDebugEventListener(env->GetIsolate(), CheckDebugEval);
2541
2542 v8::Local<v8::Context> context = env.context();
2543 v8::Local<v8::Function> foo = CompileFunction(&env,
2544 "var global = 'Global';\n"
2545 "function foo(x) {\n"
2546 " var local = 'Local';\n"
2547 " debugger;\n"
2548 " return local + x;\n"
2549 "}",
2550 "foo");
2551 checkGlobalEvalFunction = CompileFunction(&env,
2552 "function checkGlobalEval(exec_state) {\n"
2553 " return exec_state.evaluateGlobal('global').value() === 'Global';\n"
2554 "}",
2555 "checkGlobalEval");
2556
2557 checkFrameEvalFunction = CompileFunction(&env,
2558 "function checkFrameEval(exec_state) {\n"
2559 " return exec_state.frame(0).evaluate('local').value() === 'Local';\n"
2560 "}",
2561 "checkFrameEval");
2562 debugEventCount = 0;
2563 env->AllowCodeGenerationFromStrings(false);
2564 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2565 CHECK_EQ(1, debugEventCount);
2566
2567 checkGlobalEvalFunction.Clear();
2568 checkFrameEvalFunction.Clear();
2569 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2570 CheckDebuggerUnloaded(env->GetIsolate());
2571 }
2572
2573
2574 // Copies a C string to a 16-bit string. Does not check for buffer overflow.
2575 // Does not use the V8 engine to convert strings, so it can be used
2576 // in any thread. Returns the length of the string.
AsciiToUtf16(const char * input_buffer,uint16_t * output_buffer)2577 int AsciiToUtf16(const char* input_buffer, uint16_t* output_buffer) {
2578 int i;
2579 for (i = 0; input_buffer[i] != '\0'; ++i) {
2580 // ASCII does not use chars > 127, but be careful anyway.
2581 output_buffer[i] = static_cast<unsigned char>(input_buffer[i]);
2582 }
2583 output_buffer[i] = 0;
2584 return i;
2585 }
2586
2587
2588 // Copies a 16-bit string to a C string by dropping the high byte of
2589 // each character. Does not check for buffer overflow.
2590 // Can be used in any thread. Requires string length as an input.
Utf16ToAscii(const uint16_t * input_buffer,int length,char * output_buffer,int output_len=-1)2591 int Utf16ToAscii(const uint16_t* input_buffer, int length,
2592 char* output_buffer, int output_len = -1) {
2593 if (output_len >= 0) {
2594 if (length > output_len - 1) {
2595 length = output_len - 1;
2596 }
2597 }
2598
2599 for (int i = 0; i < length; ++i) {
2600 output_buffer[i] = static_cast<char>(input_buffer[i]);
2601 }
2602 output_buffer[length] = '\0';
2603 return length;
2604 }
2605
2606
2607 // We match parts of the message to get evaluate result int value.
GetEvaluateStringResult(char * message,char * buffer,int buffer_size)2608 bool GetEvaluateStringResult(char *message, char* buffer, int buffer_size) {
2609 if (strstr(message, "\"command\":\"evaluate\"") == NULL) {
2610 return false;
2611 }
2612 const char* prefix = "\"text\":\"";
2613 char* pos1 = strstr(message, prefix);
2614 if (pos1 == NULL) {
2615 return false;
2616 }
2617 pos1 += strlen(prefix);
2618 char* pos2 = strchr(pos1, '"');
2619 if (pos2 == NULL) {
2620 return false;
2621 }
2622 Vector<char> buf(buffer, buffer_size);
2623 int len = static_cast<int>(pos2 - pos1);
2624 if (len > buffer_size - 1) {
2625 len = buffer_size - 1;
2626 }
2627 StrNCpy(buf, pos1, len);
2628 buffer[buffer_size - 1] = '\0';
2629 return true;
2630 }
2631
2632
2633 struct EvaluateResult {
2634 static const int kBufferSize = 20;
2635 char buffer[kBufferSize];
2636 };
2637
2638 struct DebugProcessDebugMessagesData {
2639 static const int kArraySize = 5;
2640 int counter;
2641 EvaluateResult results[kArraySize];
2642
resetDebugProcessDebugMessagesData2643 void reset() {
2644 counter = 0;
2645 }
currentDebugProcessDebugMessagesData2646 EvaluateResult* current() {
2647 return &results[counter % kArraySize];
2648 }
nextDebugProcessDebugMessagesData2649 void next() {
2650 counter++;
2651 }
2652 };
2653
2654 DebugProcessDebugMessagesData process_debug_messages_data;
2655
DebugProcessDebugMessagesHandler(const v8::Debug::Message & message)2656 static void DebugProcessDebugMessagesHandler(
2657 const v8::Debug::Message& message) {
2658 v8::Local<v8::String> json = message.GetJSON();
2659 v8::String::Utf8Value utf8(json);
2660 EvaluateResult* array_item = process_debug_messages_data.current();
2661
2662 bool res = GetEvaluateStringResult(*utf8,
2663 array_item->buffer,
2664 EvaluateResult::kBufferSize);
2665 if (res) {
2666 process_debug_messages_data.next();
2667 }
2668 }
2669
2670
2671 // Test that the evaluation of expressions works even from ProcessDebugMessages
2672 // i.e. with empty stack.
TEST(DebugEvaluateWithoutStack)2673 TEST(DebugEvaluateWithoutStack) {
2674 DebugLocalContext env;
2675 v8::Debug::SetMessageHandler(env->GetIsolate(),
2676 DebugProcessDebugMessagesHandler);
2677 v8::HandleScope scope(env->GetIsolate());
2678
2679 const char* source =
2680 "var v1 = 'Pinguin';\n function getAnimal() { return 'Capy' + 'bara'; }";
2681
2682 v8::Local<v8::Context> context = env.context();
2683 v8::Script::Compile(context, v8_str(env->GetIsolate(), source))
2684 .ToLocalChecked()
2685 ->Run(context)
2686 .ToLocalChecked();
2687
2688 v8::Debug::ProcessDebugMessages(env->GetIsolate());
2689
2690 const int kBufferSize = 1000;
2691 uint16_t buffer[kBufferSize];
2692
2693 const char* command_111 = "{\"seq\":111,"
2694 "\"type\":\"request\","
2695 "\"command\":\"evaluate\","
2696 "\"arguments\":{"
2697 " \"global\":true,"
2698 " \"expression\":\"v1\",\"disable_break\":true"
2699 "}}";
2700
2701 v8::Isolate* isolate = CcTest::isolate();
2702 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_111, buffer));
2703
2704 const char* command_112 = "{\"seq\":112,"
2705 "\"type\":\"request\","
2706 "\"command\":\"evaluate\","
2707 "\"arguments\":{"
2708 " \"global\":true,"
2709 " \"expression\":\"getAnimal()\",\"disable_break\":true"
2710 "}}";
2711
2712 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_112, buffer));
2713
2714 const char* command_113 = "{\"seq\":113,"
2715 "\"type\":\"request\","
2716 "\"command\":\"evaluate\","
2717 "\"arguments\":{"
2718 " \"global\":true,"
2719 " \"expression\":\"239 + 566\",\"disable_break\":true"
2720 "}}";
2721
2722 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_113, buffer));
2723
2724 v8::Debug::ProcessDebugMessages(isolate);
2725
2726 CHECK_EQ(3, process_debug_messages_data.counter);
2727
2728 CHECK_EQ(strcmp("Pinguin", process_debug_messages_data.results[0].buffer), 0);
2729 CHECK_EQ(strcmp("Capybara", process_debug_messages_data.results[1].buffer),
2730 0);
2731 CHECK_EQ(strcmp("805", process_debug_messages_data.results[2].buffer), 0);
2732
2733 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
2734 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2735 CheckDebuggerUnloaded(env->GetIsolate());
2736 }
2737
2738
2739 // Simple test of the stepping mechanism using only store ICs.
TEST(DebugStepLinear)2740 TEST(DebugStepLinear) {
2741 DebugLocalContext env;
2742 v8::HandleScope scope(env->GetIsolate());
2743
2744 // Create a function for testing stepping.
2745 v8::Local<v8::Function> foo = CompileFunction(&env,
2746 "function foo(){a=1;b=1;c=1;}",
2747 "foo");
2748
2749 // Run foo to allow it to get optimized.
2750 CompileRun("a=0; b=0; c=0; foo();");
2751
2752 // Register a debug event listener which steps and counts.
2753 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2754
2755 SetBreakPoint(foo, 3);
2756
2757 step_action = StepIn;
2758 break_point_hit_count = 0;
2759 v8::Local<v8::Context> context = env.context();
2760 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2761
2762 // With stepping all break locations are hit.
2763 CHECK_EQ(4, break_point_hit_count);
2764
2765 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2766 CheckDebuggerUnloaded(env->GetIsolate());
2767
2768 // Register a debug event listener which just counts.
2769 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2770 DebugEventBreakPointHitCount);
2771
2772 SetBreakPoint(foo, 3);
2773 break_point_hit_count = 0;
2774 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2775
2776 // Without stepping only active break points are hit.
2777 CHECK_EQ(1, break_point_hit_count);
2778
2779 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2780 CheckDebuggerUnloaded(env->GetIsolate());
2781 }
2782
2783
2784 // Test of the stepping mechanism for keyed load in a loop.
TEST(DebugStepKeyedLoadLoop)2785 TEST(DebugStepKeyedLoadLoop) {
2786 DebugLocalContext env;
2787 v8::HandleScope scope(env->GetIsolate());
2788
2789 // Register a debug event listener which steps and counts.
2790 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2791
2792 // Create a function for testing stepping of keyed load. The statement 'y=1'
2793 // is there to have more than one breakable statement in the loop, TODO(315).
2794 v8::Local<v8::Function> foo = CompileFunction(
2795 &env,
2796 "function foo(a) {\n"
2797 " var x;\n"
2798 " var len = a.length;\n"
2799 " for (var i = 0; i < len; i++) {\n"
2800 " y = 1;\n"
2801 " x = a[i];\n"
2802 " }\n"
2803 "}\n"
2804 "y=0\n",
2805 "foo");
2806
2807 v8::Local<v8::Context> context = env.context();
2808 // Create array [0,1,2,3,4,5,6,7,8,9]
2809 v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
2810 for (int i = 0; i < 10; i++) {
2811 CHECK(a->Set(context, v8::Number::New(env->GetIsolate(), i),
2812 v8::Number::New(env->GetIsolate(), i))
2813 .FromJust());
2814 }
2815
2816 // Call function without any break points to ensure inlining is in place.
2817 const int kArgc = 1;
2818 v8::Local<v8::Value> args[kArgc] = {a};
2819 foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
2820
2821 // Set up break point and step through the function.
2822 SetBreakPoint(foo, 3);
2823 step_action = StepNext;
2824 break_point_hit_count = 0;
2825 foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
2826
2827 // With stepping all break locations are hit.
2828 CHECK_EQ(45, break_point_hit_count);
2829
2830 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2831 CheckDebuggerUnloaded(env->GetIsolate());
2832 }
2833
2834
2835 // Test of the stepping mechanism for keyed store in a loop.
TEST(DebugStepKeyedStoreLoop)2836 TEST(DebugStepKeyedStoreLoop) {
2837 DebugLocalContext env;
2838 v8::HandleScope scope(env->GetIsolate());
2839
2840 // Register a debug event listener which steps and counts.
2841 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2842
2843 // Create a function for testing stepping of keyed store. The statement 'y=1'
2844 // is there to have more than one breakable statement in the loop, TODO(315).
2845 v8::Local<v8::Function> foo = CompileFunction(
2846 &env,
2847 "function foo(a) {\n"
2848 " var len = a.length;\n"
2849 " for (var i = 0; i < len; i++) {\n"
2850 " y = 1;\n"
2851 " a[i] = 42;\n"
2852 " }\n"
2853 "}\n"
2854 "y=0\n",
2855 "foo");
2856
2857 v8::Local<v8::Context> context = env.context();
2858 // Create array [0,1,2,3,4,5,6,7,8,9]
2859 v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
2860 for (int i = 0; i < 10; i++) {
2861 CHECK(a->Set(context, v8::Number::New(env->GetIsolate(), i),
2862 v8::Number::New(env->GetIsolate(), i))
2863 .FromJust());
2864 }
2865
2866 // Call function without any break points to ensure inlining is in place.
2867 const int kArgc = 1;
2868 v8::Local<v8::Value> args[kArgc] = {a};
2869 foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
2870
2871 // Set up break point and step through the function.
2872 SetBreakPoint(foo, 3);
2873 step_action = StepNext;
2874 break_point_hit_count = 0;
2875 foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
2876
2877 // With stepping all break locations are hit.
2878 CHECK_EQ(44, break_point_hit_count);
2879
2880 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2881 CheckDebuggerUnloaded(env->GetIsolate());
2882 }
2883
2884
2885 // Test of the stepping mechanism for named load in a loop.
TEST(DebugStepNamedLoadLoop)2886 TEST(DebugStepNamedLoadLoop) {
2887 DebugLocalContext env;
2888 v8::HandleScope scope(env->GetIsolate());
2889
2890 // Register a debug event listener which steps and counts.
2891 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2892
2893 v8::Local<v8::Context> context = env.context();
2894 // Create a function for testing stepping of named load.
2895 v8::Local<v8::Function> foo = CompileFunction(
2896 &env,
2897 "function foo() {\n"
2898 " var a = [];\n"
2899 " var s = \"\";\n"
2900 " for (var i = 0; i < 10; i++) {\n"
2901 " var v = new V(i, i + 1);\n"
2902 " v.y;\n"
2903 " a.length;\n" // Special case: array length.
2904 " s.length;\n" // Special case: string length.
2905 " }\n"
2906 "}\n"
2907 "function V(x, y) {\n"
2908 " this.x = x;\n"
2909 " this.y = y;\n"
2910 "}\n",
2911 "foo");
2912
2913 // Call function without any break points to ensure inlining is in place.
2914 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2915
2916 // Set up break point and step through the function.
2917 SetBreakPoint(foo, 4);
2918 step_action = StepNext;
2919 break_point_hit_count = 0;
2920 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2921
2922 // With stepping all break locations are hit.
2923 CHECK_EQ(65, break_point_hit_count);
2924
2925 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2926 CheckDebuggerUnloaded(env->GetIsolate());
2927 }
2928
2929
DoDebugStepNamedStoreLoop(int expected)2930 static void DoDebugStepNamedStoreLoop(int expected) {
2931 DebugLocalContext env;
2932 v8::HandleScope scope(env->GetIsolate());
2933
2934 // Register a debug event listener which steps and counts.
2935 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2936
2937 // Create a function for testing stepping of named store.
2938 v8::Local<v8::Context> context = env.context();
2939 v8::Local<v8::Function> foo = CompileFunction(
2940 &env,
2941 "function foo() {\n"
2942 " var a = {a:1};\n"
2943 " for (var i = 0; i < 10; i++) {\n"
2944 " a.a = 2\n"
2945 " }\n"
2946 "}\n",
2947 "foo");
2948
2949 // Call function without any break points to ensure inlining is in place.
2950 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2951
2952 // Set up break point and step through the function.
2953 SetBreakPoint(foo, 3);
2954 step_action = StepNext;
2955 break_point_hit_count = 0;
2956 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2957
2958 // With stepping all expected break locations are hit.
2959 CHECK_EQ(expected, break_point_hit_count);
2960
2961 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2962 CheckDebuggerUnloaded(env->GetIsolate());
2963 }
2964
2965
2966 // Test of the stepping mechanism for named load in a loop.
TEST(DebugStepNamedStoreLoop)2967 TEST(DebugStepNamedStoreLoop) { DoDebugStepNamedStoreLoop(34); }
2968
2969
2970 // Test the stepping mechanism with different ICs.
TEST(DebugStepLinearMixedICs)2971 TEST(DebugStepLinearMixedICs) {
2972 DebugLocalContext env;
2973 v8::HandleScope scope(env->GetIsolate());
2974
2975 // Register a debug event listener which steps and counts.
2976 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2977
2978 v8::Local<v8::Context> context = env.context();
2979 // Create a function for testing stepping.
2980 v8::Local<v8::Function> foo = CompileFunction(&env,
2981 "function bar() {};"
2982 "function foo() {"
2983 " var x;"
2984 " var index='name';"
2985 " var y = {};"
2986 " a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
2987
2988 // Run functions to allow them to get optimized.
2989 CompileRun("a=0; b=0; bar(); foo();");
2990
2991 SetBreakPoint(foo, 0);
2992
2993 step_action = StepIn;
2994 break_point_hit_count = 0;
2995 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2996
2997 // With stepping all break locations are hit.
2998 CHECK_EQ(11, break_point_hit_count);
2999
3000 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3001 CheckDebuggerUnloaded(env->GetIsolate());
3002
3003 // Register a debug event listener which just counts.
3004 v8::Debug::SetDebugEventListener(env->GetIsolate(),
3005 DebugEventBreakPointHitCount);
3006
3007 SetBreakPoint(foo, 0);
3008 break_point_hit_count = 0;
3009 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3010
3011 // Without stepping only active break points are hit.
3012 CHECK_EQ(1, break_point_hit_count);
3013
3014 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3015 CheckDebuggerUnloaded(env->GetIsolate());
3016 }
3017
3018
TEST(DebugStepDeclarations)3019 TEST(DebugStepDeclarations) {
3020 DebugLocalContext env;
3021 v8::HandleScope scope(env->GetIsolate());
3022
3023 // Register a debug event listener which steps and counts.
3024 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
3025
3026 v8::Local<v8::Context> context = env.context();
3027 // Create a function for testing stepping. Run it to allow it to get
3028 // optimized.
3029 const char* src = "function foo() { "
3030 " var a;"
3031 " var b = 1;"
3032 " var c = foo;"
3033 " var d = Math.floor;"
3034 " var e = b + d(1.2);"
3035 "}"
3036 "foo()";
3037 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3038
3039 SetBreakPoint(foo, 0);
3040
3041 // Stepping through the declarations.
3042 step_action = StepIn;
3043 break_point_hit_count = 0;
3044 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3045 CHECK_EQ(6, break_point_hit_count);
3046
3047 // Get rid of the debug event listener.
3048 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3049 CheckDebuggerUnloaded(env->GetIsolate());
3050 }
3051
3052
TEST(DebugStepLocals)3053 TEST(DebugStepLocals) {
3054 DebugLocalContext env;
3055 v8::HandleScope scope(env->GetIsolate());
3056
3057 // Register a debug event listener which steps and counts.
3058 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
3059
3060 v8::Local<v8::Context> context = env.context();
3061 // Create a function for testing stepping. Run it to allow it to get
3062 // optimized.
3063 const char* src = "function foo() { "
3064 " var a,b;"
3065 " a = 1;"
3066 " b = a + 2;"
3067 " b = 1 + 2 + 3;"
3068 " a = Math.floor(b);"
3069 "}"
3070 "foo()";
3071 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3072
3073 SetBreakPoint(foo, 0);
3074
3075 // Stepping through the declarations.
3076 step_action = StepIn;
3077 break_point_hit_count = 0;
3078 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3079 CHECK_EQ(6, break_point_hit_count);
3080
3081 // Get rid of the debug event listener.
3082 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3083 CheckDebuggerUnloaded(env->GetIsolate());
3084 }
3085
3086
TEST(DebugStepIf)3087 TEST(DebugStepIf) {
3088 DebugLocalContext env;
3089 v8::Isolate* isolate = env->GetIsolate();
3090 v8::HandleScope scope(isolate);
3091
3092 // Register a debug event listener which steps and counts.
3093 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
3094
3095 v8::Local<v8::Context> context = env.context();
3096 // Create a function for testing stepping. Run it to allow it to get
3097 // optimized.
3098 const int argc = 1;
3099 const char* src = "function foo(x) { "
3100 " a = 1;"
3101 " if (x) {"
3102 " b = 1;"
3103 " } else {"
3104 " c = 1;"
3105 " d = 1;"
3106 " }"
3107 "}"
3108 "a=0; b=0; c=0; d=0; foo()";
3109 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3110 SetBreakPoint(foo, 0);
3111
3112 // Stepping through the true part.
3113 step_action = StepIn;
3114 break_point_hit_count = 0;
3115 v8::Local<v8::Value> argv_true[argc] = {v8::True(isolate)};
3116 foo->Call(context, env->Global(), argc, argv_true).ToLocalChecked();
3117 CHECK_EQ(4, break_point_hit_count);
3118
3119 // Stepping through the false part.
3120 step_action = StepIn;
3121 break_point_hit_count = 0;
3122 v8::Local<v8::Value> argv_false[argc] = {v8::False(isolate)};
3123 foo->Call(context, env->Global(), argc, argv_false).ToLocalChecked();
3124 CHECK_EQ(5, break_point_hit_count);
3125
3126 // Get rid of the debug event listener.
3127 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3128 CheckDebuggerUnloaded(isolate);
3129 }
3130
3131
TEST(DebugStepSwitch)3132 TEST(DebugStepSwitch) {
3133 DebugLocalContext env;
3134 v8::Isolate* isolate = env->GetIsolate();
3135 v8::HandleScope scope(isolate);
3136
3137 // Register a debug event listener which steps and counts.
3138 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
3139
3140 v8::Local<v8::Context> context = env.context();
3141 // Create a function for testing stepping. Run it to allow it to get
3142 // optimized.
3143 const int argc = 1;
3144 const char* src = "function foo(x) { "
3145 " a = 1;"
3146 " switch (x) {"
3147 " case 1:"
3148 " b = 1;"
3149 " case 2:"
3150 " c = 1;"
3151 " break;"
3152 " case 3:"
3153 " d = 1;"
3154 " e = 1;"
3155 " f = 1;"
3156 " break;"
3157 " }"
3158 "}"
3159 "a=0; b=0; c=0; d=0; e=0; f=0; foo()";
3160 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3161 SetBreakPoint(foo, 0);
3162
3163 // One case with fall-through.
3164 step_action = StepIn;
3165 break_point_hit_count = 0;
3166 v8::Local<v8::Value> argv_1[argc] = {v8::Number::New(isolate, 1)};
3167 foo->Call(context, env->Global(), argc, argv_1).ToLocalChecked();
3168 CHECK_EQ(6, break_point_hit_count);
3169
3170 // Another case.
3171 step_action = StepIn;
3172 break_point_hit_count = 0;
3173 v8::Local<v8::Value> argv_2[argc] = {v8::Number::New(isolate, 2)};
3174 foo->Call(context, env->Global(), argc, argv_2).ToLocalChecked();
3175 CHECK_EQ(5, break_point_hit_count);
3176
3177 // Last case.
3178 step_action = StepIn;
3179 break_point_hit_count = 0;
3180 v8::Local<v8::Value> argv_3[argc] = {v8::Number::New(isolate, 3)};
3181 foo->Call(context, env->Global(), argc, argv_3).ToLocalChecked();
3182 CHECK_EQ(7, break_point_hit_count);
3183
3184 // Get rid of the debug event listener.
3185 v8::Debug::SetDebugEventListener(isolate, nullptr);
3186 CheckDebuggerUnloaded(isolate);
3187 }
3188
3189
TEST(DebugStepWhile)3190 TEST(DebugStepWhile) {
3191 DebugLocalContext env;
3192 v8::Isolate* isolate = env->GetIsolate();
3193 v8::HandleScope scope(isolate);
3194
3195 // Register a debug event listener which steps and counts.
3196 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
3197
3198 v8::Local<v8::Context> context = env.context();
3199 // Create a function for testing stepping. Run it to allow it to get
3200 // optimized.
3201 const int argc = 1;
3202 const char* src = "function foo(x) { "
3203 " var a = 0;"
3204 " while (a < x) {"
3205 " a++;"
3206 " }"
3207 "}"
3208 "foo()";
3209 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3210 SetBreakPoint(foo, 8); // "var a = 0;"
3211
3212 // Looping 0 times. We still should break at the while-condition once.
3213 step_action = StepIn;
3214 break_point_hit_count = 0;
3215 v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
3216 foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
3217 CHECK_EQ(3, break_point_hit_count);
3218
3219 // Looping 10 times.
3220 step_action = StepIn;
3221 break_point_hit_count = 0;
3222 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3223 foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
3224 CHECK_EQ(23, break_point_hit_count);
3225
3226 // Looping 100 times.
3227 step_action = StepIn;
3228 break_point_hit_count = 0;
3229 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3230 foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
3231 CHECK_EQ(203, break_point_hit_count);
3232
3233 // Get rid of the debug event listener.
3234 v8::Debug::SetDebugEventListener(isolate, nullptr);
3235 CheckDebuggerUnloaded(isolate);
3236 }
3237
3238
TEST(DebugStepDoWhile)3239 TEST(DebugStepDoWhile) {
3240 DebugLocalContext env;
3241 v8::Isolate* isolate = env->GetIsolate();
3242 v8::HandleScope scope(isolate);
3243
3244 // Register a debug event listener which steps and counts.
3245 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
3246
3247 v8::Local<v8::Context> context = env.context();
3248 // Create a function for testing stepping. Run it to allow it to get
3249 // optimized.
3250 const int argc = 1;
3251 const char* src = "function foo(x) { "
3252 " var a = 0;"
3253 " do {"
3254 " a++;"
3255 " } while (a < x)"
3256 "}"
3257 "foo()";
3258 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3259 SetBreakPoint(foo, 8); // "var a = 0;"
3260
3261 // Looping 0 times.
3262 step_action = StepIn;
3263 break_point_hit_count = 0;
3264 v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
3265 foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
3266 CHECK_EQ(4, break_point_hit_count);
3267
3268 // Looping 10 times.
3269 step_action = StepIn;
3270 break_point_hit_count = 0;
3271 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3272 foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
3273 CHECK_EQ(22, break_point_hit_count);
3274
3275 // Looping 100 times.
3276 step_action = StepIn;
3277 break_point_hit_count = 0;
3278 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3279 foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
3280 CHECK_EQ(202, break_point_hit_count);
3281
3282 // Get rid of the debug event listener.
3283 v8::Debug::SetDebugEventListener(isolate, nullptr);
3284 CheckDebuggerUnloaded(isolate);
3285 }
3286
3287
TEST(DebugStepFor)3288 TEST(DebugStepFor) {
3289 DebugLocalContext env;
3290 v8::Isolate* isolate = env->GetIsolate();
3291 v8::HandleScope scope(isolate);
3292
3293 // Register a debug event listener which steps and counts.
3294 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
3295
3296 v8::Local<v8::Context> context = env.context();
3297 // Create a function for testing stepping. Run it to allow it to get
3298 // optimized.
3299 const int argc = 1;
3300 const char* src = "function foo(x) { "
3301 " a = 1;"
3302 " for (i = 0; i < x; i++) {"
3303 " b = 1;"
3304 " }"
3305 "}"
3306 "a=0; b=0; i=0; foo()";
3307 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3308
3309 SetBreakPoint(foo, 8); // "a = 1;"
3310
3311 // Looping 0 times.
3312 step_action = StepIn;
3313 break_point_hit_count = 0;
3314 v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
3315 foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
3316 CHECK_EQ(4, break_point_hit_count);
3317
3318 // Looping 10 times.
3319 step_action = StepIn;
3320 break_point_hit_count = 0;
3321 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3322 foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
3323 CHECK_EQ(34, break_point_hit_count);
3324
3325 // Looping 100 times.
3326 step_action = StepIn;
3327 break_point_hit_count = 0;
3328 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3329 foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
3330 CHECK_EQ(304, break_point_hit_count);
3331
3332 // Get rid of the debug event listener.
3333 v8::Debug::SetDebugEventListener(isolate, nullptr);
3334 CheckDebuggerUnloaded(isolate);
3335 }
3336
3337
TEST(DebugStepForContinue)3338 TEST(DebugStepForContinue) {
3339 DebugLocalContext env;
3340 v8::Isolate* isolate = env->GetIsolate();
3341 v8::HandleScope scope(isolate);
3342
3343 // Register a debug event listener which steps and counts.
3344 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
3345
3346 v8::Local<v8::Context> context = env.context();
3347 // Create a function for testing stepping. Run it to allow it to get
3348 // optimized.
3349 const int argc = 1;
3350 const char* src = "function foo(x) { "
3351 " var a = 0;"
3352 " var b = 0;"
3353 " var c = 0;"
3354 " for (var i = 0; i < x; i++) {"
3355 " a++;"
3356 " if (a % 2 == 0) continue;"
3357 " b++;"
3358 " c++;"
3359 " }"
3360 " return b;"
3361 "}"
3362 "foo()";
3363 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3364 v8::Local<v8::Value> result;
3365 SetBreakPoint(foo, 8); // "var a = 0;"
3366
3367 // Each loop generates 4 or 5 steps depending on whether a is equal.
3368
3369 // Looping 10 times.
3370 step_action = StepIn;
3371 break_point_hit_count = 0;
3372 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3373 result = foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
3374 CHECK_EQ(5, result->Int32Value(context).FromJust());
3375 CHECK_EQ(62, break_point_hit_count);
3376
3377 // Looping 100 times.
3378 step_action = StepIn;
3379 break_point_hit_count = 0;
3380 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3381 result = foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
3382 CHECK_EQ(50, result->Int32Value(context).FromJust());
3383 CHECK_EQ(557, break_point_hit_count);
3384
3385 // Get rid of the debug event listener.
3386 v8::Debug::SetDebugEventListener(isolate, nullptr);
3387 CheckDebuggerUnloaded(isolate);
3388 }
3389
3390
TEST(DebugStepForBreak)3391 TEST(DebugStepForBreak) {
3392 DebugLocalContext env;
3393 v8::Isolate* isolate = env->GetIsolate();
3394 v8::HandleScope scope(isolate);
3395
3396 // Register a debug event listener which steps and counts.
3397 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
3398
3399 v8::Local<v8::Context> context = env.context();
3400 // Create a function for testing stepping. Run it to allow it to get
3401 // optimized.
3402 const int argc = 1;
3403 const char* src = "function foo(x) { "
3404 " var a = 0;"
3405 " var b = 0;"
3406 " var c = 0;"
3407 " for (var i = 0; i < 1000; i++) {"
3408 " a++;"
3409 " if (a == x) break;"
3410 " b++;"
3411 " c++;"
3412 " }"
3413 " return b;"
3414 "}"
3415 "foo()";
3416 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3417 v8::Local<v8::Value> result;
3418 SetBreakPoint(foo, 8); // "var a = 0;"
3419
3420 // Each loop generates 5 steps except for the last (when break is executed)
3421 // which only generates 4.
3422
3423 // Looping 10 times.
3424 step_action = StepIn;
3425 break_point_hit_count = 0;
3426 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3427 result = foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
3428 CHECK_EQ(9, result->Int32Value(context).FromJust());
3429 CHECK_EQ(64, break_point_hit_count);
3430
3431 // Looping 100 times.
3432 step_action = StepIn;
3433 break_point_hit_count = 0;
3434 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3435 result = foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
3436 CHECK_EQ(99, result->Int32Value(context).FromJust());
3437 CHECK_EQ(604, break_point_hit_count);
3438
3439 // Get rid of the debug event listener.
3440 v8::Debug::SetDebugEventListener(isolate, nullptr);
3441 CheckDebuggerUnloaded(isolate);
3442 }
3443
3444
TEST(DebugStepForIn)3445 TEST(DebugStepForIn) {
3446 DebugLocalContext env;
3447 v8::HandleScope scope(env->GetIsolate());
3448
3449 // Register a debug event listener which steps and counts.
3450 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
3451
3452 v8::Local<v8::Context> context = env.context();
3453 // Create a function for testing stepping. Run it to allow it to get
3454 // optimized.
3455 v8::Local<v8::Function> foo;
3456 const char* src_1 = "function foo() { "
3457 " var a = [1, 2];"
3458 " for (x in a) {"
3459 " b = 0;"
3460 " }"
3461 "}"
3462 "foo()";
3463 foo = CompileFunction(&env, src_1, "foo");
3464 SetBreakPoint(foo, 0); // "var a = ..."
3465
3466 step_action = StepIn;
3467 break_point_hit_count = 0;
3468 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3469 CHECK_EQ(8, break_point_hit_count);
3470
3471 // Create a function for testing stepping. Run it to allow it to get
3472 // optimized.
3473 const char* src_2 = "function foo() { "
3474 " var a = {a:[1, 2, 3]};"
3475 " for (x in a.a) {"
3476 " b = 0;"
3477 " }"
3478 "}"
3479 "foo()";
3480 foo = CompileFunction(&env, src_2, "foo");
3481 SetBreakPoint(foo, 0); // "var a = ..."
3482
3483 step_action = StepIn;
3484 break_point_hit_count = 0;
3485 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3486 CHECK_EQ(10, break_point_hit_count);
3487
3488 // Get rid of the debug event listener.
3489 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3490 CheckDebuggerUnloaded(env->GetIsolate());
3491 }
3492
3493
TEST(DebugStepWith)3494 TEST(DebugStepWith) {
3495 DebugLocalContext env;
3496 v8::HandleScope scope(env->GetIsolate());
3497
3498 // Register a debug event listener which steps and counts.
3499 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
3500
3501 v8::Local<v8::Context> context = env.context();
3502 // Create a function for testing stepping. Run it to allow it to get
3503 // optimized.
3504 const char* src = "function foo(x) { "
3505 " var a = {};"
3506 " with (a) {}"
3507 " with (b) {}"
3508 "}"
3509 "foo()";
3510 CHECK(env->Global()
3511 ->Set(context, v8_str(env->GetIsolate(), "b"),
3512 v8::Object::New(env->GetIsolate()))
3513 .FromJust());
3514 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3515 v8::Local<v8::Value> result;
3516 SetBreakPoint(foo, 8); // "var a = {};"
3517
3518 step_action = StepIn;
3519 break_point_hit_count = 0;
3520 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3521 CHECK_EQ(4, break_point_hit_count);
3522
3523 // Get rid of the debug event listener.
3524 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3525 CheckDebuggerUnloaded(env->GetIsolate());
3526 }
3527
3528
TEST(DebugConditional)3529 TEST(DebugConditional) {
3530 DebugLocalContext env;
3531 v8::Isolate* isolate = env->GetIsolate();
3532 v8::HandleScope scope(isolate);
3533
3534 // Register a debug event listener which steps and counts.
3535 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
3536
3537 v8::Local<v8::Context> context = env.context();
3538 // Create a function for testing stepping. Run it to allow it to get
3539 // optimized.
3540 const char* src = "function foo(x) { "
3541 " var a;"
3542 " a = x ? 1 : 2;"
3543 " return a;"
3544 "}"
3545 "foo()";
3546 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3547 SetBreakPoint(foo, 0); // "var a;"
3548
3549 step_action = StepIn;
3550 break_point_hit_count = 0;
3551 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3552 CHECK_EQ(4, break_point_hit_count);
3553
3554 step_action = StepIn;
3555 break_point_hit_count = 0;
3556 const int argc = 1;
3557 v8::Local<v8::Value> argv_true[argc] = {v8::True(isolate)};
3558 foo->Call(context, env->Global(), argc, argv_true).ToLocalChecked();
3559 CHECK_EQ(4, break_point_hit_count);
3560
3561 // Get rid of the debug event listener.
3562 v8::Debug::SetDebugEventListener(isolate, nullptr);
3563 CheckDebuggerUnloaded(isolate);
3564 }
3565
3566
TEST(StepInOutSimple)3567 TEST(StepInOutSimple) {
3568 DebugLocalContext env;
3569 v8::HandleScope scope(env->GetIsolate());
3570
3571 // Create a function for checking the function when hitting a break point.
3572 frame_function_name = CompileFunction(&env,
3573 frame_function_name_source,
3574 "frame_function_name");
3575
3576 // Register a debug event listener which steps and counts.
3577 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
3578
3579 v8::Local<v8::Context> context = env.context();
3580 // Create a function for testing stepping. Run it to allow it to get
3581 // optimized.
3582 const char* src = "function a() {b();c();}; "
3583 "function b() {c();}; "
3584 "function c() {}; "
3585 "a(); b(); c()";
3586 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3587 SetBreakPoint(a, 0);
3588
3589 // Step through invocation of a with step in.
3590 step_action = StepIn;
3591 break_point_hit_count = 0;
3592 expected_step_sequence = "abcbaca";
3593 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3594 CHECK_EQ(StrLength(expected_step_sequence),
3595 break_point_hit_count);
3596
3597 // Step through invocation of a with step next.
3598 step_action = StepNext;
3599 break_point_hit_count = 0;
3600 expected_step_sequence = "aaa";
3601 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3602 CHECK_EQ(StrLength(expected_step_sequence),
3603 break_point_hit_count);
3604
3605 // Step through invocation of a with step out.
3606 step_action = StepOut;
3607 break_point_hit_count = 0;
3608 expected_step_sequence = "a";
3609 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3610 CHECK_EQ(StrLength(expected_step_sequence),
3611 break_point_hit_count);
3612
3613 // Get rid of the debug event listener.
3614 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3615 CheckDebuggerUnloaded(env->GetIsolate());
3616 }
3617
3618
TEST(StepInOutTree)3619 TEST(StepInOutTree) {
3620 DebugLocalContext env;
3621 v8::HandleScope scope(env->GetIsolate());
3622
3623 // Create a function for checking the function when hitting a break point.
3624 frame_function_name = CompileFunction(&env,
3625 frame_function_name_source,
3626 "frame_function_name");
3627
3628 // Register a debug event listener which steps and counts.
3629 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
3630
3631 v8::Local<v8::Context> context = env.context();
3632 // Create a function for testing stepping. Run it to allow it to get
3633 // optimized.
3634 const char* src = "function a() {b(c(d()),d());c(d());d()}; "
3635 "function b(x,y) {c();}; "
3636 "function c(x) {}; "
3637 "function d() {}; "
3638 "a(); b(); c(); d()";
3639 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3640 SetBreakPoint(a, 0);
3641
3642 // Step through invocation of a with step in.
3643 step_action = StepIn;
3644 break_point_hit_count = 0;
3645 expected_step_sequence = "adacadabcbadacada";
3646 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3647 CHECK_EQ(StrLength(expected_step_sequence),
3648 break_point_hit_count);
3649
3650 // Step through invocation of a with step next.
3651 step_action = StepNext;
3652 break_point_hit_count = 0;
3653 expected_step_sequence = "aaaa";
3654 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3655 CHECK_EQ(StrLength(expected_step_sequence),
3656 break_point_hit_count);
3657
3658 // Step through invocation of a with step out.
3659 step_action = StepOut;
3660 break_point_hit_count = 0;
3661 expected_step_sequence = "a";
3662 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3663 CHECK_EQ(StrLength(expected_step_sequence),
3664 break_point_hit_count);
3665
3666 // Get rid of the debug event listener.
3667 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3668 CheckDebuggerUnloaded(env->GetIsolate(), true);
3669 }
3670
3671
TEST(StepInOutBranch)3672 TEST(StepInOutBranch) {
3673 DebugLocalContext env;
3674 v8::HandleScope scope(env->GetIsolate());
3675
3676 // Create a function for checking the function when hitting a break point.
3677 frame_function_name = CompileFunction(&env,
3678 frame_function_name_source,
3679 "frame_function_name");
3680
3681 // Register a debug event listener which steps and counts.
3682 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
3683
3684 v8::Local<v8::Context> context = env.context();
3685 // Create a function for testing stepping. Run it to allow it to get
3686 // optimized.
3687 const char* src = "function a() {b(false);c();}; "
3688 "function b(x) {if(x){c();};}; "
3689 "function c() {}; "
3690 "a(); b(); c()";
3691 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3692 SetBreakPoint(a, 0);
3693
3694 // Step through invocation of a.
3695 step_action = StepIn;
3696 break_point_hit_count = 0;
3697 expected_step_sequence = "abbaca";
3698 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3699 CHECK_EQ(StrLength(expected_step_sequence),
3700 break_point_hit_count);
3701
3702 // Get rid of the debug event listener.
3703 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3704 CheckDebuggerUnloaded(env->GetIsolate());
3705 }
3706
3707
3708 // Test that step in does not step into native functions.
TEST(DebugStepNatives)3709 TEST(DebugStepNatives) {
3710 DebugLocalContext env;
3711 v8::HandleScope scope(env->GetIsolate());
3712
3713 // Create a function for testing stepping.
3714 v8::Local<v8::Function> foo = CompileFunction(
3715 &env,
3716 "function foo(){debugger;Math.sin(1);}",
3717 "foo");
3718
3719 // Register a debug event listener which steps and counts.
3720 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
3721
3722 v8::Local<v8::Context> context = env.context();
3723 step_action = StepIn;
3724 break_point_hit_count = 0;
3725 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3726
3727 // With stepping all break locations are hit.
3728 CHECK_EQ(3, break_point_hit_count);
3729
3730 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3731 CheckDebuggerUnloaded(env->GetIsolate());
3732
3733 // Register a debug event listener which just counts.
3734 v8::Debug::SetDebugEventListener(env->GetIsolate(),
3735 DebugEventBreakPointHitCount);
3736
3737 break_point_hit_count = 0;
3738 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3739
3740 // Without stepping only active break points are hit.
3741 CHECK_EQ(1, break_point_hit_count);
3742
3743 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3744 CheckDebuggerUnloaded(env->GetIsolate());
3745 }
3746
3747
3748 // Test that step in works with function.apply.
TEST(DebugStepFunctionApply)3749 TEST(DebugStepFunctionApply) {
3750 DebugLocalContext env;
3751 v8::HandleScope scope(env->GetIsolate());
3752
3753 // Create a function for testing stepping.
3754 v8::Local<v8::Function> foo = CompileFunction(
3755 &env,
3756 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3757 "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
3758 "foo");
3759
3760 // Register a debug event listener which steps and counts.
3761 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
3762
3763 v8::Local<v8::Context> context = env.context();
3764 step_action = StepIn;
3765 break_point_hit_count = 0;
3766 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3767
3768 // With stepping all break locations are hit.
3769 CHECK_EQ(7, break_point_hit_count);
3770
3771 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3772 CheckDebuggerUnloaded(env->GetIsolate());
3773
3774 // Register a debug event listener which just counts.
3775 v8::Debug::SetDebugEventListener(env->GetIsolate(),
3776 DebugEventBreakPointHitCount);
3777
3778 break_point_hit_count = 0;
3779 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3780
3781 // Without stepping only the debugger statement is hit.
3782 CHECK_EQ(1, break_point_hit_count);
3783
3784 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3785 CheckDebuggerUnloaded(env->GetIsolate());
3786 }
3787
3788
3789 // Test that step in works with function.call.
TEST(DebugStepFunctionCall)3790 TEST(DebugStepFunctionCall) {
3791 DebugLocalContext env;
3792 v8::Isolate* isolate = env->GetIsolate();
3793 v8::HandleScope scope(isolate);
3794
3795 v8::Local<v8::Context> context = env.context();
3796 // Create a function for testing stepping.
3797 v8::Local<v8::Function> foo = CompileFunction(
3798 &env,
3799 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3800 "function foo(a){ debugger;"
3801 " if (a) {"
3802 " bar.call(this, 1, 2, 3);"
3803 " } else {"
3804 " bar.call(this, 0);"
3805 " }"
3806 "}",
3807 "foo");
3808
3809 // Register a debug event listener which steps and counts.
3810 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
3811 step_action = StepIn;
3812
3813 // Check stepping where the if condition in bar is false.
3814 break_point_hit_count = 0;
3815 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3816 CHECK_EQ(6, break_point_hit_count);
3817
3818 // Check stepping where the if condition in bar is true.
3819 break_point_hit_count = 0;
3820 const int argc = 1;
3821 v8::Local<v8::Value> argv[argc] = {v8::True(isolate)};
3822 foo->Call(context, env->Global(), argc, argv).ToLocalChecked();
3823 CHECK_EQ(8, break_point_hit_count);
3824
3825 v8::Debug::SetDebugEventListener(isolate, nullptr);
3826 CheckDebuggerUnloaded(isolate);
3827
3828 // Register a debug event listener which just counts.
3829 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
3830
3831 break_point_hit_count = 0;
3832 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3833
3834 // Without stepping only the debugger statement is hit.
3835 CHECK_EQ(1, break_point_hit_count);
3836
3837 v8::Debug::SetDebugEventListener(isolate, nullptr);
3838 CheckDebuggerUnloaded(isolate);
3839 }
3840
3841
3842 // Test that step in works with Function.call.apply.
TEST(DebugStepFunctionCallApply)3843 TEST(DebugStepFunctionCallApply) {
3844 DebugLocalContext env;
3845 v8::Isolate* isolate = env->GetIsolate();
3846 v8::HandleScope scope(isolate);
3847
3848 v8::Local<v8::Context> context = env.context();
3849 // Create a function for testing stepping.
3850 v8::Local<v8::Function> foo =
3851 CompileFunction(&env,
3852 "function bar() { }"
3853 "function foo(){ debugger;"
3854 " Function.call.apply(bar);"
3855 " Function.call.apply(Function.call, "
3856 "[Function.call, bar]);"
3857 "}",
3858 "foo");
3859
3860 // Register a debug event listener which steps and counts.
3861 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
3862 step_action = StepIn;
3863
3864 break_point_hit_count = 0;
3865 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3866 CHECK_EQ(6, break_point_hit_count);
3867
3868 v8::Debug::SetDebugEventListener(isolate, nullptr);
3869 CheckDebuggerUnloaded(isolate);
3870
3871 // Register a debug event listener which just counts.
3872 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
3873
3874 break_point_hit_count = 0;
3875 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3876
3877 // Without stepping only the debugger statement is hit.
3878 CHECK_EQ(1, break_point_hit_count);
3879
3880 v8::Debug::SetDebugEventListener(isolate, nullptr);
3881 CheckDebuggerUnloaded(isolate);
3882 }
3883
3884
3885 // Tests that breakpoint will be hit if it's set in script.
TEST(PauseInScript)3886 TEST(PauseInScript) {
3887 DebugLocalContext env;
3888 v8::HandleScope scope(env->GetIsolate());
3889 env.ExposeDebug();
3890
3891 // Register a debug event listener which counts.
3892 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
3893
3894 v8::Local<v8::Context> context = env.context();
3895 // Create a script that returns a function.
3896 const char* src = "(function (evt) {})";
3897 const char* script_name = "StepInHandlerTest";
3898
3899 // Set breakpoint in the script.
3900 SetScriptBreakPointByNameFromJS(env->GetIsolate(), script_name, 0, -1);
3901 break_point_hit_count = 0;
3902
3903 v8::ScriptOrigin origin(v8_str(env->GetIsolate(), script_name),
3904 v8::Integer::New(env->GetIsolate(), 0));
3905 v8::Local<v8::Script> script =
3906 v8::Script::Compile(context, v8_str(env->GetIsolate(), src), &origin)
3907 .ToLocalChecked();
3908 v8::Local<v8::Value> r = script->Run(context).ToLocalChecked();
3909
3910 CHECK(r->IsFunction());
3911 CHECK_EQ(1, break_point_hit_count);
3912
3913 // Get rid of the debug event listener.
3914 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3915 CheckDebuggerUnloaded(env->GetIsolate());
3916 }
3917
3918
DebugEventCounterCheck(int caught,int uncaught,int message)3919 static void DebugEventCounterCheck(int caught, int uncaught, int message) {
3920 CHECK_EQ(caught, exception_hit_count);
3921 CHECK_EQ(uncaught, uncaught_exception_hit_count);
3922 CHECK_EQ(message, message_callback_count);
3923 }
3924
3925
3926 // Test break on exceptions. For each exception break combination the number
3927 // of debug event exception callbacks and message callbacks are collected. The
3928 // number of debug event exception callbacks are used to check that the
3929 // debugger is called correctly and the number of message callbacks is used to
3930 // check that uncaught exceptions are still returned even if there is a break
3931 // for them.
TEST(BreakOnException)3932 TEST(BreakOnException) {
3933 DebugLocalContext env;
3934 v8::HandleScope scope(env->GetIsolate());
3935 env.ExposeDebug();
3936
3937 v8::Local<v8::Context> context = env.context();
3938 // Create functions for testing break on exception.
3939 CompileFunction(&env, "function throws(){throw 1;}", "throws");
3940 v8::Local<v8::Function> caught =
3941 CompileFunction(&env,
3942 "function caught(){try {throws();} catch(e) {};}",
3943 "caught");
3944 v8::Local<v8::Function> notCaught =
3945 CompileFunction(&env, "function notCaught(){throws();}", "notCaught");
3946 v8::Local<v8::Function> notCaughtFinally = CompileFunction(
3947 &env, "function notCaughtFinally(){try{throws();}finally{}}",
3948 "notCaughtFinally");
3949 // In this edge case, even though this finally does not propagate the
3950 // exception, the debugger considers this uncaught, since we want to break
3951 // at the first throw for the general case where finally implicitly rethrows.
3952 v8::Local<v8::Function> edgeCaseFinally = CompileFunction(
3953 &env, "function caughtFinally(){L:try{throws();}finally{break L;}}",
3954 "caughtFinally");
3955
3956 env->GetIsolate()->AddMessageListener(MessageCallbackCount);
3957 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
3958
3959 // Initial state should be no break on exceptions.
3960 DebugEventCounterClear();
3961 MessageCallbackCountClear();
3962 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3963 DebugEventCounterCheck(0, 0, 0);
3964 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3965 DebugEventCounterCheck(0, 0, 1);
3966 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3967 DebugEventCounterCheck(0, 0, 2);
3968 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3969 DebugEventCounterCheck(0, 0, 2);
3970
3971 // No break on exception
3972 DebugEventCounterClear();
3973 MessageCallbackCountClear();
3974 ChangeBreakOnException(false, false);
3975 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3976 DebugEventCounterCheck(0, 0, 0);
3977 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3978 DebugEventCounterCheck(0, 0, 1);
3979 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3980 DebugEventCounterCheck(0, 0, 2);
3981 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3982 DebugEventCounterCheck(0, 0, 2);
3983
3984 // Break on uncaught exception
3985 DebugEventCounterClear();
3986 MessageCallbackCountClear();
3987 ChangeBreakOnException(false, true);
3988 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3989 DebugEventCounterCheck(0, 0, 0);
3990 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3991 DebugEventCounterCheck(1, 1, 1);
3992 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3993 DebugEventCounterCheck(2, 2, 2);
3994 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3995 DebugEventCounterCheck(3, 3, 2);
3996
3997 // Break on exception and uncaught exception
3998 DebugEventCounterClear();
3999 MessageCallbackCountClear();
4000 ChangeBreakOnException(true, true);
4001 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4002 DebugEventCounterCheck(1, 0, 0);
4003 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
4004 DebugEventCounterCheck(2, 1, 1);
4005 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
4006 DebugEventCounterCheck(3, 2, 2);
4007 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4008 DebugEventCounterCheck(4, 3, 2);
4009
4010 // Break on exception
4011 DebugEventCounterClear();
4012 MessageCallbackCountClear();
4013 ChangeBreakOnException(true, false);
4014 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4015 DebugEventCounterCheck(1, 0, 0);
4016 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
4017 DebugEventCounterCheck(2, 1, 1);
4018 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
4019 DebugEventCounterCheck(3, 2, 2);
4020 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4021 DebugEventCounterCheck(4, 3, 2);
4022
4023 // No break on exception using JavaScript
4024 DebugEventCounterClear();
4025 MessageCallbackCountClear();
4026 ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, false);
4027 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4028 DebugEventCounterCheck(0, 0, 0);
4029 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
4030 DebugEventCounterCheck(0, 0, 1);
4031 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
4032 DebugEventCounterCheck(0, 0, 2);
4033 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4034 DebugEventCounterCheck(0, 0, 2);
4035
4036 // Break on uncaught exception using JavaScript
4037 DebugEventCounterClear();
4038 MessageCallbackCountClear();
4039 ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, true);
4040 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4041 DebugEventCounterCheck(0, 0, 0);
4042 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
4043 DebugEventCounterCheck(1, 1, 1);
4044 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
4045 DebugEventCounterCheck(2, 2, 2);
4046 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4047 DebugEventCounterCheck(3, 3, 2);
4048
4049 // Break on exception and uncaught exception using JavaScript
4050 DebugEventCounterClear();
4051 MessageCallbackCountClear();
4052 ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, true);
4053 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4054 DebugEventCounterCheck(1, 0, 0);
4055 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
4056 DebugEventCounterCheck(2, 1, 1);
4057 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
4058 DebugEventCounterCheck(3, 2, 2);
4059 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4060 DebugEventCounterCheck(4, 3, 2);
4061
4062 // Break on exception using JavaScript
4063 DebugEventCounterClear();
4064 MessageCallbackCountClear();
4065 ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, false);
4066 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4067 DebugEventCounterCheck(1, 0, 0);
4068 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
4069 DebugEventCounterCheck(2, 1, 1);
4070 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
4071 DebugEventCounterCheck(3, 2, 2);
4072 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4073 DebugEventCounterCheck(4, 3, 2);
4074
4075 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
4076 CheckDebuggerUnloaded(env->GetIsolate());
4077 env->GetIsolate()->RemoveMessageListeners(MessageCallbackCount);
4078 }
4079
4080
try_finally_original_message(v8::Local<v8::Message> message,v8::Local<v8::Value> data)4081 static void try_finally_original_message(v8::Local<v8::Message> message,
4082 v8::Local<v8::Value> data) {
4083 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
4084 CHECK_EQ(2, message->GetLineNumber(context).FromJust());
4085 CHECK_EQ(2, message->GetStartColumn(context).FromJust());
4086 message_callback_count++;
4087 }
4088
4089
TEST(TryFinallyOriginalMessage)4090 TEST(TryFinallyOriginalMessage) {
4091 // Test that the debugger plays nicely with the pending message.
4092 message_callback_count = 0;
4093 DebugEventCounterClear();
4094 DebugLocalContext env;
4095 v8::Isolate* isolate = CcTest::isolate();
4096 isolate->AddMessageListener(try_finally_original_message);
4097 v8::Debug::SetDebugEventListener(isolate, DebugEventCounter);
4098 ChangeBreakOnException(true, true);
4099 v8::HandleScope scope(isolate);
4100 CompileRun(
4101 "try {\n"
4102 " throw 1;\n"
4103 "} finally {\n"
4104 "}\n");
4105 DebugEventCounterCheck(1, 1, 1);
4106 v8::Debug::SetDebugEventListener(isolate, nullptr);
4107 isolate->RemoveMessageListeners(try_finally_original_message);
4108 }
4109
4110
TEST(EvalJSInDebugEventListenerOnNativeReThrownException)4111 TEST(EvalJSInDebugEventListenerOnNativeReThrownException) {
4112 DebugLocalContext env;
4113 v8::HandleScope scope(env->GetIsolate());
4114 env.ExposeDebug();
4115
4116 // Create functions for testing break on exception.
4117 v8::Local<v8::Function> noThrowJS = CompileFunction(
4118 &env, "function noThrowJS(){var a=[1]; a.push(2); return a.length;}",
4119 "noThrowJS");
4120
4121 debug_event_listener_callback = noThrowJS;
4122 debug_event_listener_callback_result = 2;
4123
4124 env->GetIsolate()->AddMessageListener(MessageCallbackCount);
4125 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
4126 // Break on uncaught exception
4127 ChangeBreakOnException(false, true);
4128 DebugEventCounterClear();
4129 MessageCallbackCountClear();
4130
4131 // ReThrow native error
4132 {
4133 v8::TryCatch tryCatch(env->GetIsolate());
4134 env->GetIsolate()->ThrowException(
4135 v8::Exception::TypeError(v8_str(env->GetIsolate(), "Type error")));
4136 CHECK(tryCatch.HasCaught());
4137 tryCatch.ReThrow();
4138 }
4139 CHECK_EQ(1, exception_hit_count);
4140 CHECK_EQ(1, uncaught_exception_hit_count);
4141 CHECK_EQ(0, message_callback_count); // FIXME: Should it be 1 ?
4142 CHECK(!debug_event_listener_callback.IsEmpty());
4143
4144 debug_event_listener_callback.Clear();
4145 }
4146
4147
4148 // Test break on exception from compiler errors. When compiling using
4149 // v8::Script::Compile there is no JavaScript stack whereas when compiling using
4150 // eval there are JavaScript frames.
TEST(BreakOnCompileException)4151 TEST(BreakOnCompileException) {
4152 DebugLocalContext env;
4153 v8::HandleScope scope(env->GetIsolate());
4154
4155 v8::Local<v8::Context> context = env.context();
4156 // For this test, we want to break on uncaught exceptions:
4157 ChangeBreakOnException(false, true);
4158
4159 // Create a function for checking the function when hitting a break point.
4160 frame_count = CompileFunction(&env, frame_count_source, "frame_count");
4161
4162 env->GetIsolate()->AddMessageListener(MessageCallbackCount);
4163 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
4164
4165 DebugEventCounterClear();
4166 MessageCallbackCountClear();
4167
4168 // Check initial state.
4169 CHECK_EQ(0, exception_hit_count);
4170 CHECK_EQ(0, uncaught_exception_hit_count);
4171 CHECK_EQ(0, message_callback_count);
4172 CHECK_EQ(-1, last_js_stack_height);
4173
4174 // Throws SyntaxError: Unexpected end of input
4175 CHECK(
4176 v8::Script::Compile(context, v8_str(env->GetIsolate(), "+++")).IsEmpty());
4177 CHECK_EQ(1, exception_hit_count);
4178 CHECK_EQ(1, uncaught_exception_hit_count);
4179 CHECK_EQ(1, message_callback_count);
4180 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
4181
4182 // Throws SyntaxError: Unexpected identifier
4183 CHECK(
4184 v8::Script::Compile(context, v8_str(env->GetIsolate(), "x x")).IsEmpty());
4185 CHECK_EQ(2, exception_hit_count);
4186 CHECK_EQ(2, uncaught_exception_hit_count);
4187 CHECK_EQ(2, message_callback_count);
4188 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
4189
4190 // Throws SyntaxError: Unexpected end of input
4191 CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "eval('+++')"))
4192 .ToLocalChecked()
4193 ->Run(context)
4194 .IsEmpty());
4195 CHECK_EQ(3, exception_hit_count);
4196 CHECK_EQ(3, uncaught_exception_hit_count);
4197 CHECK_EQ(3, message_callback_count);
4198 CHECK_EQ(1, last_js_stack_height);
4199
4200 // Throws SyntaxError: Unexpected identifier
4201 CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "eval('x x')"))
4202 .ToLocalChecked()
4203 ->Run(context)
4204 .IsEmpty());
4205 CHECK_EQ(4, exception_hit_count);
4206 CHECK_EQ(4, uncaught_exception_hit_count);
4207 CHECK_EQ(4, message_callback_count);
4208 CHECK_EQ(1, last_js_stack_height);
4209 }
4210
4211
TEST(StepWithException)4212 TEST(StepWithException) {
4213 DebugLocalContext env;
4214 v8::HandleScope scope(env->GetIsolate());
4215
4216 // For this test, we want to break on uncaught exceptions:
4217 ChangeBreakOnException(false, true);
4218
4219 // Create a function for checking the function when hitting a break point.
4220 frame_function_name = CompileFunction(&env,
4221 frame_function_name_source,
4222 "frame_function_name");
4223
4224 // Register a debug event listener which steps and counts.
4225 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
4226
4227 v8::Local<v8::Context> context = env.context();
4228 // Create functions for testing stepping.
4229 const char* src = "function a() { n(); }; "
4230 "function b() { c(); }; "
4231 "function c() { n(); }; "
4232 "function d() { x = 1; try { e(); } catch(x) { x = 2; } }; "
4233 "function e() { n(); }; "
4234 "function f() { x = 1; try { g(); } catch(x) { x = 2; } }; "
4235 "function g() { h(); }; "
4236 "function h() { x = 1; throw 1; }; ";
4237
4238 // Step through invocation of a.
4239 ClearStepping();
4240 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
4241 SetBreakPoint(a, 0);
4242 step_action = StepIn;
4243 break_point_hit_count = 0;
4244 expected_step_sequence = "aa";
4245 CHECK(a->Call(context, env->Global(), 0, NULL).IsEmpty());
4246 CHECK_EQ(StrLength(expected_step_sequence),
4247 break_point_hit_count);
4248
4249 // Step through invocation of b + c.
4250 ClearStepping();
4251 v8::Local<v8::Function> b = CompileFunction(&env, src, "b");
4252 SetBreakPoint(b, 0);
4253 step_action = StepIn;
4254 break_point_hit_count = 0;
4255 expected_step_sequence = "bcc";
4256 CHECK(b->Call(context, env->Global(), 0, NULL).IsEmpty());
4257 CHECK_EQ(StrLength(expected_step_sequence),
4258 break_point_hit_count);
4259
4260 // Step through invocation of d + e.
4261 ClearStepping();
4262 v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
4263 SetBreakPoint(d, 0);
4264 ChangeBreakOnException(false, true);
4265 step_action = StepIn;
4266 break_point_hit_count = 0;
4267 expected_step_sequence = "ddedd";
4268 d->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4269 CHECK_EQ(StrLength(expected_step_sequence),
4270 break_point_hit_count);
4271
4272 // Step through invocation of d + e now with break on caught exceptions.
4273 ChangeBreakOnException(true, true);
4274 step_action = StepIn;
4275 break_point_hit_count = 0;
4276 expected_step_sequence = "ddeedd";
4277 d->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4278 CHECK_EQ(StrLength(expected_step_sequence),
4279 break_point_hit_count);
4280
4281 // Step through invocation of f + g + h.
4282 ClearStepping();
4283 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
4284 SetBreakPoint(f, 0);
4285 ChangeBreakOnException(false, true);
4286 step_action = StepIn;
4287 break_point_hit_count = 0;
4288 expected_step_sequence = "ffghhff";
4289 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4290 CHECK_EQ(StrLength(expected_step_sequence),
4291 break_point_hit_count);
4292
4293 // Step through invocation of f + g + h now with break on caught exceptions.
4294 ChangeBreakOnException(true, true);
4295 step_action = StepIn;
4296 break_point_hit_count = 0;
4297 expected_step_sequence = "ffghhhff";
4298 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4299 CHECK_EQ(StrLength(expected_step_sequence),
4300 break_point_hit_count);
4301
4302 // Get rid of the debug event listener.
4303 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
4304 CheckDebuggerUnloaded(env->GetIsolate());
4305 }
4306
4307
TEST(DebugBreak)4308 TEST(DebugBreak) {
4309 i::FLAG_stress_compaction = false;
4310 #ifdef VERIFY_HEAP
4311 i::FLAG_verify_heap = true;
4312 #endif
4313 DebugLocalContext env;
4314 v8::Isolate* isolate = env->GetIsolate();
4315 v8::HandleScope scope(isolate);
4316
4317 // Register a debug event listener which sets the break flag and counts.
4318 v8::Debug::SetDebugEventListener(isolate, DebugEventBreak);
4319
4320 v8::Local<v8::Context> context = env.context();
4321 // Create a function for testing stepping.
4322 const char* src = "function f0() {}"
4323 "function f1(x1) {}"
4324 "function f2(x1,x2) {}"
4325 "function f3(x1,x2,x3) {}";
4326 v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
4327 v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
4328 v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
4329 v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
4330
4331 // Call the function to make sure it is compiled.
4332 v8::Local<v8::Value> argv[] = {
4333 v8::Number::New(isolate, 1), v8::Number::New(isolate, 1),
4334 v8::Number::New(isolate, 1), v8::Number::New(isolate, 1)};
4335
4336 // Call all functions to make sure that they are compiled.
4337 f0->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4338 f1->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4339 f2->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4340 f3->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4341
4342 // Set the debug break flag.
4343 v8::Debug::DebugBreak(env->GetIsolate());
4344 CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate()));
4345
4346 // Call all functions with different argument count.
4347 break_point_hit_count = 0;
4348 for (unsigned int i = 0; i < arraysize(argv); i++) {
4349 f0->Call(context, env->Global(), i, argv).ToLocalChecked();
4350 f1->Call(context, env->Global(), i, argv).ToLocalChecked();
4351 f2->Call(context, env->Global(), i, argv).ToLocalChecked();
4352 f3->Call(context, env->Global(), i, argv).ToLocalChecked();
4353 }
4354
4355 // One break for each function called.
4356 CHECK(4 * arraysize(argv) == break_point_hit_count);
4357
4358 // Get rid of the debug event listener.
4359 v8::Debug::SetDebugEventListener(isolate, nullptr);
4360 CheckDebuggerUnloaded(isolate);
4361 }
4362
4363
4364 // Test to ensure that JavaScript code keeps running while the debug break
4365 // through the stack limit flag is set but breaks are disabled.
TEST(DisableBreak)4366 TEST(DisableBreak) {
4367 DebugLocalContext env;
4368 v8::HandleScope scope(env->GetIsolate());
4369
4370 // Register a debug event listener which sets the break flag and counts.
4371 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
4372
4373 v8::Local<v8::Context> context = env.context();
4374 // Create a function for testing stepping.
4375 const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
4376 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
4377
4378 // Set, test and cancel debug break.
4379 v8::Debug::DebugBreak(env->GetIsolate());
4380 CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate()));
4381 v8::Debug::CancelDebugBreak(env->GetIsolate());
4382 CHECK(!v8::Debug::CheckDebugBreak(env->GetIsolate()));
4383
4384 // Set the debug break flag.
4385 v8::Debug::DebugBreak(env->GetIsolate());
4386
4387 // Call all functions with different argument count.
4388 break_point_hit_count = 0;
4389 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4390 CHECK_EQ(1, break_point_hit_count);
4391
4392 {
4393 v8::Debug::DebugBreak(env->GetIsolate());
4394 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
4395 v8::internal::DisableBreak disable_break(isolate->debug(), true);
4396 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4397 CHECK_EQ(1, break_point_hit_count);
4398 }
4399
4400 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4401 CHECK_EQ(2, break_point_hit_count);
4402
4403 // Get rid of the debug event listener.
4404 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
4405 CheckDebuggerUnloaded(env->GetIsolate());
4406 }
4407
4408
TEST(DisableDebuggerStatement)4409 TEST(DisableDebuggerStatement) {
4410 DebugLocalContext env;
4411 v8::HandleScope scope(env->GetIsolate());
4412
4413 // Register a debug event listener which sets the break flag and counts.
4414 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
4415 CompileRun("debugger;");
4416 CHECK_EQ(1, break_point_hit_count);
4417
4418 // Check that we ignore debugger statement when breakpoints aren't active.
4419 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
4420 isolate->debug()->set_break_points_active(false);
4421 CompileRun("debugger;");
4422 CHECK_EQ(1, break_point_hit_count);
4423 }
4424
4425 static const char* kSimpleExtensionSource =
4426 "(function Foo() {"
4427 " return 4;"
4428 "})() ";
4429
4430 // http://crbug.com/28933
4431 // Test that debug break is disabled when bootstrapper is active.
TEST(NoBreakWhenBootstrapping)4432 TEST(NoBreakWhenBootstrapping) {
4433 v8::Isolate* isolate = CcTest::isolate();
4434 v8::HandleScope scope(isolate);
4435
4436 // Register a debug event listener which sets the break flag and counts.
4437 v8::Debug::SetDebugEventListener(isolate, DebugEventCounter);
4438
4439 // Set the debug break flag.
4440 v8::Debug::DebugBreak(isolate);
4441 break_point_hit_count = 0;
4442 {
4443 // Create a context with an extension to make sure that some JavaScript
4444 // code is executed during bootstrapping.
4445 v8::RegisterExtension(new v8::Extension("simpletest",
4446 kSimpleExtensionSource));
4447 const char* extension_names[] = { "simpletest" };
4448 v8::ExtensionConfiguration extensions(1, extension_names);
4449 v8::HandleScope handle_scope(isolate);
4450 v8::Context::New(isolate, &extensions);
4451 }
4452 // Check that no DebugBreak events occured during the context creation.
4453 CHECK_EQ(0, break_point_hit_count);
4454
4455 // Get rid of the debug event listener.
4456 v8::Debug::SetDebugEventListener(isolate, nullptr);
4457 CheckDebuggerUnloaded(isolate);
4458 }
4459
4460
NamedEnum(const v8::PropertyCallbackInfo<v8::Array> & info)4461 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
4462 v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
4463 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
4464 CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 0),
4465 v8_str(info.GetIsolate(), "a"))
4466 .FromJust());
4467 CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 1),
4468 v8_str(info.GetIsolate(), "b"))
4469 .FromJust());
4470 CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 2),
4471 v8_str(info.GetIsolate(), "c"))
4472 .FromJust());
4473 info.GetReturnValue().Set(result);
4474 }
4475
4476
IndexedEnum(const v8::PropertyCallbackInfo<v8::Array> & info)4477 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
4478 v8::Isolate* isolate = info.GetIsolate();
4479 v8::Local<v8::Array> result = v8::Array::New(isolate, 2);
4480 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
4481 CHECK(result->Set(context, v8::Integer::New(isolate, 0),
4482 v8::Number::New(isolate, 1))
4483 .FromJust());
4484 CHECK(result->Set(context, v8::Integer::New(isolate, 1),
4485 v8::Number::New(isolate, 10))
4486 .FromJust());
4487 info.GetReturnValue().Set(result);
4488 }
4489
4490
NamedGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)4491 static void NamedGetter(v8::Local<v8::Name> name,
4492 const v8::PropertyCallbackInfo<v8::Value>& info) {
4493 if (name->IsSymbol()) return;
4494 v8::String::Utf8Value n(v8::Local<v8::String>::Cast(name));
4495 if (strcmp(*n, "a") == 0) {
4496 info.GetReturnValue().Set(v8_str(info.GetIsolate(), "AA"));
4497 return;
4498 } else if (strcmp(*n, "b") == 0) {
4499 info.GetReturnValue().Set(v8_str(info.GetIsolate(), "BB"));
4500 return;
4501 } else if (strcmp(*n, "c") == 0) {
4502 info.GetReturnValue().Set(v8_str(info.GetIsolate(), "CC"));
4503 return;
4504 } else {
4505 info.GetReturnValue().SetUndefined();
4506 return;
4507 }
4508 info.GetReturnValue().Set(name);
4509 }
4510
4511
IndexedGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)4512 static void IndexedGetter(uint32_t index,
4513 const v8::PropertyCallbackInfo<v8::Value>& info) {
4514 info.GetReturnValue().Set(static_cast<double>(index + 1));
4515 }
4516
4517
TEST(InterceptorPropertyMirror)4518 TEST(InterceptorPropertyMirror) {
4519 // Create a V8 environment with debug access.
4520 DebugLocalContext env;
4521 v8::Isolate* isolate = env->GetIsolate();
4522 v8::HandleScope scope(isolate);
4523 env.ExposeDebug();
4524
4525 v8::Local<v8::Context> context = env.context();
4526 // Create object with named interceptor.
4527 v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4528 named->SetHandler(v8::NamedPropertyHandlerConfiguration(
4529 NamedGetter, NULL, NULL, NULL, NamedEnum));
4530 CHECK(env->Global()
4531 ->Set(context, v8_str(isolate, "intercepted_named"),
4532 named->NewInstance(context).ToLocalChecked())
4533 .FromJust());
4534
4535 // Create object with indexed interceptor.
4536 v8::Local<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New(isolate);
4537 indexed->SetHandler(v8::IndexedPropertyHandlerConfiguration(
4538 IndexedGetter, NULL, NULL, NULL, IndexedEnum));
4539 CHECK(env->Global()
4540 ->Set(context, v8_str(isolate, "intercepted_indexed"),
4541 indexed->NewInstance(context).ToLocalChecked())
4542 .FromJust());
4543
4544 // Create object with both named and indexed interceptor.
4545 v8::Local<v8::ObjectTemplate> both = v8::ObjectTemplate::New(isolate);
4546 both->SetHandler(v8::NamedPropertyHandlerConfiguration(
4547 NamedGetter, NULL, NULL, NULL, NamedEnum));
4548 both->SetHandler(v8::IndexedPropertyHandlerConfiguration(
4549 IndexedGetter, NULL, NULL, NULL, IndexedEnum));
4550 CHECK(env->Global()
4551 ->Set(context, v8_str(isolate, "intercepted_both"),
4552 both->NewInstance(context).ToLocalChecked())
4553 .FromJust());
4554
4555 // Get mirrors for the three objects with interceptor.
4556 CompileRun(
4557 "var named_mirror = debug.MakeMirror(intercepted_named);"
4558 "var indexed_mirror = debug.MakeMirror(intercepted_indexed);"
4559 "var both_mirror = debug.MakeMirror(intercepted_both)");
4560 CHECK(CompileRun("named_mirror instanceof debug.ObjectMirror")
4561 ->BooleanValue(context)
4562 .FromJust());
4563 CHECK(CompileRun("indexed_mirror instanceof debug.ObjectMirror")
4564 ->BooleanValue(context)
4565 .FromJust());
4566 CHECK(CompileRun("both_mirror instanceof debug.ObjectMirror")
4567 ->BooleanValue(context)
4568 .FromJust());
4569
4570 // Get the property names from the interceptors
4571 CompileRun(
4572 "named_names = named_mirror.propertyNames();"
4573 "indexed_names = indexed_mirror.propertyNames();"
4574 "both_names = both_mirror.propertyNames()");
4575 CHECK_EQ(3, CompileRun("named_names.length")->Int32Value(context).FromJust());
4576 CHECK_EQ(2,
4577 CompileRun("indexed_names.length")->Int32Value(context).FromJust());
4578 CHECK_EQ(5, CompileRun("both_names.length")->Int32Value(context).FromJust());
4579
4580 // Check the expected number of properties.
4581 const char* source;
4582 source = "named_mirror.properties().length";
4583 CHECK_EQ(3, CompileRun(source)->Int32Value(context).FromJust());
4584
4585 source = "indexed_mirror.properties().length";
4586 CHECK_EQ(2, CompileRun(source)->Int32Value(context).FromJust());
4587
4588 source = "both_mirror.properties().length";
4589 CHECK_EQ(5, CompileRun(source)->Int32Value(context).FromJust());
4590
4591 // Get the interceptor properties for the object with only named interceptor.
4592 CompileRun("var named_values = named_mirror.properties()");
4593
4594 // Check that the properties are interceptor properties.
4595 for (int i = 0; i < 3; i++) {
4596 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4597 SNPrintF(buffer,
4598 "named_values[%d] instanceof debug.PropertyMirror", i);
4599 CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
4600
4601 SNPrintF(buffer, "named_values[%d].isNative()", i);
4602 CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
4603 }
4604
4605 // Get the interceptor properties for the object with only indexed
4606 // interceptor.
4607 CompileRun("var indexed_values = indexed_mirror.properties()");
4608
4609 // Check that the properties are interceptor properties.
4610 for (int i = 0; i < 2; i++) {
4611 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4612 SNPrintF(buffer,
4613 "indexed_values[%d] instanceof debug.PropertyMirror", i);
4614 CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
4615 }
4616
4617 // Get the interceptor properties for the object with both types of
4618 // interceptors.
4619 CompileRun("var both_values = both_mirror.properties()");
4620
4621 // Check that the properties are interceptor properties.
4622 for (int i = 0; i < 5; i++) {
4623 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4624 SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i);
4625 CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
4626 }
4627
4628 // Check the property names.
4629 source = "both_values[0].name() == '1'";
4630 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
4631
4632 source = "both_values[1].name() == '10'";
4633 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
4634
4635 source = "both_values[2].name() == 'a'";
4636 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
4637
4638 source = "both_values[3].name() == 'b'";
4639 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
4640
4641 source = "both_values[4].name() == 'c'";
4642 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
4643 }
4644
4645
TEST(HiddenPrototypePropertyMirror)4646 TEST(HiddenPrototypePropertyMirror) {
4647 // Create a V8 environment with debug access.
4648 DebugLocalContext env;
4649 v8::Isolate* isolate = env->GetIsolate();
4650 v8::HandleScope scope(isolate);
4651 env.ExposeDebug();
4652
4653 v8::Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
4654 t0->InstanceTemplate()->Set(v8_str(isolate, "x"),
4655 v8::Number::New(isolate, 0));
4656 v8::Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
4657 t1->SetHiddenPrototype(true);
4658 t1->InstanceTemplate()->Set(v8_str(isolate, "y"),
4659 v8::Number::New(isolate, 1));
4660 v8::Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
4661 t2->SetHiddenPrototype(true);
4662 t2->InstanceTemplate()->Set(v8_str(isolate, "z"),
4663 v8::Number::New(isolate, 2));
4664 v8::Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
4665 t3->InstanceTemplate()->Set(v8_str(isolate, "u"),
4666 v8::Number::New(isolate, 3));
4667
4668 v8::Local<v8::Context> context = env.context();
4669 // Create object and set them on the global object.
4670 v8::Local<v8::Object> o0 = t0->GetFunction(context)
4671 .ToLocalChecked()
4672 ->NewInstance(context)
4673 .ToLocalChecked();
4674 CHECK(env->Global()->Set(context, v8_str(isolate, "o0"), o0).FromJust());
4675 v8::Local<v8::Object> o1 = t1->GetFunction(context)
4676 .ToLocalChecked()
4677 ->NewInstance(context)
4678 .ToLocalChecked();
4679 CHECK(env->Global()->Set(context, v8_str(isolate, "o1"), o1).FromJust());
4680 v8::Local<v8::Object> o2 = t2->GetFunction(context)
4681 .ToLocalChecked()
4682 ->NewInstance(context)
4683 .ToLocalChecked();
4684 CHECK(env->Global()->Set(context, v8_str(isolate, "o2"), o2).FromJust());
4685 v8::Local<v8::Object> o3 = t3->GetFunction(context)
4686 .ToLocalChecked()
4687 ->NewInstance(context)
4688 .ToLocalChecked();
4689 CHECK(env->Global()->Set(context, v8_str(isolate, "o3"), o3).FromJust());
4690
4691 // Get mirrors for the four objects.
4692 CompileRun(
4693 "var o0_mirror = debug.MakeMirror(o0);"
4694 "var o1_mirror = debug.MakeMirror(o1);"
4695 "var o2_mirror = debug.MakeMirror(o2);"
4696 "var o3_mirror = debug.MakeMirror(o3)");
4697 CHECK(CompileRun("o0_mirror instanceof debug.ObjectMirror")
4698 ->BooleanValue(context)
4699 .FromJust());
4700 CHECK(CompileRun("o1_mirror instanceof debug.ObjectMirror")
4701 ->BooleanValue(context)
4702 .FromJust());
4703 CHECK(CompileRun("o2_mirror instanceof debug.ObjectMirror")
4704 ->BooleanValue(context)
4705 .FromJust());
4706 CHECK(CompileRun("o3_mirror instanceof debug.ObjectMirror")
4707 ->BooleanValue(context)
4708 .FromJust());
4709
4710 // Check that each object has one property.
4711 CHECK_EQ(1, CompileRun("o0_mirror.propertyNames().length")
4712 ->Int32Value(context)
4713 .FromJust());
4714 CHECK_EQ(1, CompileRun("o1_mirror.propertyNames().length")
4715 ->Int32Value(context)
4716 .FromJust());
4717 CHECK_EQ(1, CompileRun("o2_mirror.propertyNames().length")
4718 ->Int32Value(context)
4719 .FromJust());
4720 CHECK_EQ(1, CompileRun("o3_mirror.propertyNames().length")
4721 ->Int32Value(context)
4722 .FromJust());
4723
4724 // Set o1 as prototype for o0. o1 has the hidden prototype flag so all
4725 // properties on o1 should be seen on o0.
4726 CHECK(o0->Set(context, v8_str(isolate, "__proto__"), o1).FromJust());
4727 CHECK_EQ(2, CompileRun("o0_mirror.propertyNames().length")
4728 ->Int32Value(context)
4729 .FromJust());
4730 CHECK_EQ(0, CompileRun("o0_mirror.property('x').value().value()")
4731 ->Int32Value(context)
4732 .FromJust());
4733 CHECK_EQ(1, CompileRun("o0_mirror.property('y').value().value()")
4734 ->Int32Value(context)
4735 .FromJust());
4736
4737 // Set o2 as prototype for o0 (it will end up after o1 as o1 has the hidden
4738 // prototype flag. o2 also has the hidden prototype flag so all properties
4739 // on o2 should be seen on o0 as well as properties on o1.
4740 CHECK(o0->Set(context, v8_str(isolate, "__proto__"), o2).FromJust());
4741 CHECK_EQ(3, CompileRun("o0_mirror.propertyNames().length")
4742 ->Int32Value(context)
4743 .FromJust());
4744 CHECK_EQ(0, CompileRun("o0_mirror.property('x').value().value()")
4745 ->Int32Value(context)
4746 .FromJust());
4747 CHECK_EQ(1, CompileRun("o0_mirror.property('y').value().value()")
4748 ->Int32Value(context)
4749 .FromJust());
4750 CHECK_EQ(2, CompileRun("o0_mirror.property('z').value().value()")
4751 ->Int32Value(context)
4752 .FromJust());
4753
4754 // Set o3 as prototype for o0 (it will end up after o1 and o2 as both o1 and
4755 // o2 has the hidden prototype flag. o3 does not have the hidden prototype
4756 // flag so properties on o3 should not be seen on o0 whereas the properties
4757 // from o1 and o2 should still be seen on o0.
4758 // Final prototype chain: o0 -> o1 -> o2 -> o3
4759 // Hidden prototypes: ^^ ^^
4760 CHECK(o0->Set(context, v8_str(isolate, "__proto__"), o3).FromJust());
4761 CHECK_EQ(3, CompileRun("o0_mirror.propertyNames().length")
4762 ->Int32Value(context)
4763 .FromJust());
4764 CHECK_EQ(1, CompileRun("o3_mirror.propertyNames().length")
4765 ->Int32Value(context)
4766 .FromJust());
4767 CHECK_EQ(0, CompileRun("o0_mirror.property('x').value().value()")
4768 ->Int32Value(context)
4769 .FromJust());
4770 CHECK_EQ(1, CompileRun("o0_mirror.property('y').value().value()")
4771 ->Int32Value(context)
4772 .FromJust());
4773 CHECK_EQ(2, CompileRun("o0_mirror.property('z').value().value()")
4774 ->Int32Value(context)
4775 .FromJust());
4776 CHECK(CompileRun("o0_mirror.property('u').isUndefined()")
4777 ->BooleanValue(context)
4778 .FromJust());
4779
4780 // The prototype (__proto__) for o0 should be o3 as o1 and o2 are hidden.
4781 CHECK(CompileRun("o0_mirror.protoObject() == o3_mirror")
4782 ->BooleanValue(context)
4783 .FromJust());
4784 }
4785
4786
ProtperyXNativeGetter(v8::Local<v8::String> property,const v8::PropertyCallbackInfo<v8::Value> & info)4787 static void ProtperyXNativeGetter(
4788 v8::Local<v8::String> property,
4789 const v8::PropertyCallbackInfo<v8::Value>& info) {
4790 info.GetReturnValue().Set(10);
4791 }
4792
4793
TEST(NativeGetterPropertyMirror)4794 TEST(NativeGetterPropertyMirror) {
4795 // Create a V8 environment with debug access.
4796 DebugLocalContext env;
4797 v8::Isolate* isolate = env->GetIsolate();
4798 v8::HandleScope scope(isolate);
4799 env.ExposeDebug();
4800
4801 v8::Local<v8::Context> context = env.context();
4802 v8::Local<v8::String> name = v8_str(isolate, "x");
4803 // Create object with named accessor.
4804 v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4805 named->SetAccessor(name, &ProtperyXNativeGetter, NULL, v8::Local<v8::Value>(),
4806 v8::DEFAULT, v8::None);
4807
4808 // Create object with named property getter.
4809 CHECK(env->Global()
4810 ->Set(context, v8_str(isolate, "instance"),
4811 named->NewInstance(context).ToLocalChecked())
4812 .FromJust());
4813 CHECK_EQ(10, CompileRun("instance.x")->Int32Value(context).FromJust());
4814
4815 // Get mirror for the object with property getter.
4816 CompileRun("var instance_mirror = debug.MakeMirror(instance);");
4817 CHECK(CompileRun("instance_mirror instanceof debug.ObjectMirror")
4818 ->BooleanValue(context)
4819 .FromJust());
4820
4821 CompileRun("var named_names = instance_mirror.propertyNames();");
4822 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value(context).FromJust());
4823 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue(context).FromJust());
4824 CHECK(CompileRun("instance_mirror.property('x').value().isNumber()")
4825 ->BooleanValue(context)
4826 .FromJust());
4827 CHECK(CompileRun("instance_mirror.property('x').value().value() == 10")
4828 ->BooleanValue(context)
4829 .FromJust());
4830 }
4831
4832
ProtperyXNativeGetterThrowingError(v8::Local<v8::String> property,const v8::PropertyCallbackInfo<v8::Value> & info)4833 static void ProtperyXNativeGetterThrowingError(
4834 v8::Local<v8::String> property,
4835 const v8::PropertyCallbackInfo<v8::Value>& info) {
4836 CompileRun("throw new Error('Error message');");
4837 }
4838
4839
TEST(NativeGetterThrowingErrorPropertyMirror)4840 TEST(NativeGetterThrowingErrorPropertyMirror) {
4841 // Create a V8 environment with debug access.
4842 DebugLocalContext env;
4843 v8::Isolate* isolate = env->GetIsolate();
4844 v8::HandleScope scope(isolate);
4845 env.ExposeDebug();
4846
4847 v8::Local<v8::Context> context = env.context();
4848 v8::Local<v8::String> name = v8_str(isolate, "x");
4849 // Create object with named accessor.
4850 v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4851 named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, NULL,
4852 v8::Local<v8::Value>(), v8::DEFAULT, v8::None);
4853
4854 // Create object with named property getter.
4855 CHECK(env->Global()
4856 ->Set(context, v8_str(isolate, "instance"),
4857 named->NewInstance(context).ToLocalChecked())
4858 .FromJust());
4859
4860 // Get mirror for the object with property getter.
4861 CompileRun("var instance_mirror = debug.MakeMirror(instance);");
4862 CHECK(CompileRun("instance_mirror instanceof debug.ObjectMirror")
4863 ->BooleanValue(context)
4864 .FromJust());
4865 CompileRun("named_names = instance_mirror.propertyNames();");
4866 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value(context).FromJust());
4867 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue(context).FromJust());
4868 CHECK(CompileRun("instance_mirror.property('x').value().isError()")
4869 ->BooleanValue(context)
4870 .FromJust());
4871
4872 // Check that the message is that passed to the Error constructor.
4873 CHECK(
4874 CompileRun(
4875 "instance_mirror.property('x').value().message() == 'Error message'")
4876 ->BooleanValue(context)
4877 .FromJust());
4878 }
4879
4880
4881 // Test that hidden properties object is not returned as an unnamed property
4882 // among regular properties.
4883 // See http://crbug.com/26491
TEST(NoHiddenProperties)4884 TEST(NoHiddenProperties) {
4885 // Create a V8 environment with debug access.
4886 DebugLocalContext env;
4887 v8::Isolate* isolate = env->GetIsolate();
4888 v8::HandleScope scope(isolate);
4889 env.ExposeDebug();
4890
4891 v8::Local<v8::Context> context = env.context();
4892 // Create an object in the global scope.
4893 const char* source = "var obj = {a: 1};";
4894 v8::Script::Compile(context, v8_str(isolate, source))
4895 .ToLocalChecked()
4896 ->Run(context)
4897 .ToLocalChecked();
4898 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
4899 env->Global()->Get(context, v8_str(isolate, "obj")).ToLocalChecked());
4900 // Set a hidden property on the object.
4901 obj->SetPrivate(
4902 env.context(),
4903 v8::Private::New(isolate, v8_str(isolate, "v8::test-debug::a")),
4904 v8::Int32::New(isolate, 11))
4905 .FromJust();
4906
4907 // Get mirror for the object with property getter.
4908 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4909 CHECK(CompileRun("obj_mirror instanceof debug.ObjectMirror")
4910 ->BooleanValue(context)
4911 .FromJust());
4912 CompileRun("var named_names = obj_mirror.propertyNames();");
4913 // There should be exactly one property. But there is also an unnamed
4914 // property whose value is hidden properties dictionary. The latter
4915 // property should not be in the list of reguar properties.
4916 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value(context).FromJust());
4917 CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue(context).FromJust());
4918 CHECK(CompileRun("obj_mirror.property('a').value().value() == 1")
4919 ->BooleanValue(context)
4920 .FromJust());
4921
4922 // Object created by t0 will become hidden prototype of object 'obj'.
4923 v8::Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
4924 t0->InstanceTemplate()->Set(v8_str(isolate, "b"),
4925 v8::Number::New(isolate, 2));
4926 t0->SetHiddenPrototype(true);
4927 v8::Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
4928 t1->InstanceTemplate()->Set(v8_str(isolate, "c"),
4929 v8::Number::New(isolate, 3));
4930
4931 // Create proto objects, add hidden properties to them and set them on
4932 // the global object.
4933 v8::Local<v8::Object> protoObj = t0->GetFunction(context)
4934 .ToLocalChecked()
4935 ->NewInstance(context)
4936 .ToLocalChecked();
4937 protoObj->SetPrivate(
4938 env.context(),
4939 v8::Private::New(isolate, v8_str(isolate, "v8::test-debug::b")),
4940 v8::Int32::New(isolate, 12))
4941 .FromJust();
4942 CHECK(env->Global()
4943 ->Set(context, v8_str(isolate, "protoObj"), protoObj)
4944 .FromJust());
4945 v8::Local<v8::Object> grandProtoObj = t1->GetFunction(context)
4946 .ToLocalChecked()
4947 ->NewInstance(context)
4948 .ToLocalChecked();
4949 grandProtoObj->SetPrivate(env.context(),
4950 v8::Private::New(
4951 isolate, v8_str(isolate, "v8::test-debug::c")),
4952 v8::Int32::New(isolate, 13))
4953 .FromJust();
4954 CHECK(env->Global()
4955 ->Set(context, v8_str(isolate, "grandProtoObj"), grandProtoObj)
4956 .FromJust());
4957
4958 // Setting prototypes: obj->protoObj->grandProtoObj
4959 CHECK(protoObj->Set(context, v8_str(isolate, "__proto__"), grandProtoObj)
4960 .FromJust());
4961 CHECK(obj->Set(context, v8_str(isolate, "__proto__"), protoObj).FromJust());
4962
4963 // Get mirror for the object with property getter.
4964 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4965 CHECK(CompileRun("obj_mirror instanceof debug.ObjectMirror")
4966 ->BooleanValue(context)
4967 .FromJust());
4968 CompileRun("var named_names = obj_mirror.propertyNames();");
4969 // There should be exactly two properties - one from the object itself and
4970 // another from its hidden prototype.
4971 CHECK_EQ(2, CompileRun("named_names.length")->Int32Value(context).FromJust());
4972 CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&"
4973 "named_names[1] == 'b'")
4974 ->BooleanValue(context)
4975 .FromJust());
4976 CHECK(CompileRun("obj_mirror.property('a').value().value() == 1")
4977 ->BooleanValue(context)
4978 .FromJust());
4979 CHECK(CompileRun("obj_mirror.property('b').value().value() == 2")
4980 ->BooleanValue(context)
4981 .FromJust());
4982 }
4983
4984
4985 // Multithreaded tests of JSON debugger protocol
4986
4987 // Support classes
4988
4989 // Provides synchronization between N threads, where N is a template parameter.
4990 // The Wait() call blocks a thread until it is called for the Nth time, then all
4991 // calls return. Each ThreadBarrier object can only be used once.
4992 template <int N>
4993 class ThreadBarrier final {
4994 public:
ThreadBarrier()4995 ThreadBarrier() : num_blocked_(0) {}
4996
~ThreadBarrier()4997 ~ThreadBarrier() {
4998 LockGuard<Mutex> lock_guard(&mutex_);
4999 if (num_blocked_ != 0) {
5000 CHECK_EQ(N, num_blocked_);
5001 }
5002 }
5003
Wait()5004 void Wait() {
5005 LockGuard<Mutex> lock_guard(&mutex_);
5006 CHECK_LT(num_blocked_, N);
5007 num_blocked_++;
5008 if (N == num_blocked_) {
5009 // Signal and unblock all waiting threads.
5010 cv_.NotifyAll();
5011 printf("BARRIER\n\n");
5012 fflush(stdout);
5013 } else { // Wait for the semaphore.
5014 while (num_blocked_ < N) {
5015 cv_.Wait(&mutex_);
5016 }
5017 }
5018 CHECK_EQ(N, num_blocked_);
5019 }
5020
5021 private:
5022 ConditionVariable cv_;
5023 Mutex mutex_;
5024 int num_blocked_;
5025
5026 STATIC_ASSERT(N > 0);
5027
5028 DISALLOW_COPY_AND_ASSIGN(ThreadBarrier);
5029 };
5030
5031
5032 // A set containing enough barriers and semaphores for any of the tests.
5033 class Barriers {
5034 public:
Barriers()5035 Barriers() : semaphore_1(0), semaphore_2(0) {}
5036 ThreadBarrier<2> barrier_1;
5037 ThreadBarrier<2> barrier_2;
5038 ThreadBarrier<2> barrier_3;
5039 ThreadBarrier<2> barrier_4;
5040 ThreadBarrier<2> barrier_5;
5041 v8::base::Semaphore semaphore_1;
5042 v8::base::Semaphore semaphore_2;
5043 };
5044
5045
5046 // We match parts of the message to decide if it is a break message.
IsBreakEventMessage(char * message)5047 bool IsBreakEventMessage(char *message) {
5048 const char* type_event = "\"type\":\"event\"";
5049 const char* event_break = "\"event\":\"break\"";
5050 // Does the message contain both type:event and event:break?
5051 return strstr(message, type_event) != NULL &&
5052 strstr(message, event_break) != NULL;
5053 }
5054
5055
5056 // We match parts of the message to decide if it is a exception message.
IsExceptionEventMessage(char * message)5057 bool IsExceptionEventMessage(char *message) {
5058 const char* type_event = "\"type\":\"event\"";
5059 const char* event_exception = "\"event\":\"exception\"";
5060 // Does the message contain both type:event and event:exception?
5061 return strstr(message, type_event) != NULL &&
5062 strstr(message, event_exception) != NULL;
5063 }
5064
5065
5066 // We match the message wether it is an evaluate response message.
IsEvaluateResponseMessage(char * message)5067 bool IsEvaluateResponseMessage(char* message) {
5068 const char* type_response = "\"type\":\"response\"";
5069 const char* command_evaluate = "\"command\":\"evaluate\"";
5070 // Does the message contain both type:response and command:evaluate?
5071 return strstr(message, type_response) != NULL &&
5072 strstr(message, command_evaluate) != NULL;
5073 }
5074
5075
StringToInt(const char * s)5076 static int StringToInt(const char* s) {
5077 return atoi(s); // NOLINT
5078 }
5079
5080
5081 // We match parts of the message to get evaluate result int value.
GetEvaluateIntResult(char * message)5082 int GetEvaluateIntResult(char *message) {
5083 const char* value = "\"value\":";
5084 char* pos = strstr(message, value);
5085 if (pos == NULL) {
5086 return -1;
5087 }
5088 int res = -1;
5089 res = StringToInt(pos + strlen(value));
5090 return res;
5091 }
5092
5093
5094 // We match parts of the message to get hit breakpoint id.
GetBreakpointIdFromBreakEventMessage(char * message)5095 int GetBreakpointIdFromBreakEventMessage(char *message) {
5096 const char* breakpoints = "\"breakpoints\":[";
5097 char* pos = strstr(message, breakpoints);
5098 if (pos == NULL) {
5099 return -1;
5100 }
5101 int res = -1;
5102 res = StringToInt(pos + strlen(breakpoints));
5103 return res;
5104 }
5105
5106
5107 // We match parts of the message to get total frames number.
GetTotalFramesInt(char * message)5108 int GetTotalFramesInt(char *message) {
5109 const char* prefix = "\"totalFrames\":";
5110 char* pos = strstr(message, prefix);
5111 if (pos == NULL) {
5112 return -1;
5113 }
5114 pos += strlen(prefix);
5115 int res = StringToInt(pos);
5116 return res;
5117 }
5118
5119
5120 // We match parts of the message to get source line.
GetSourceLineFromBreakEventMessage(char * message)5121 int GetSourceLineFromBreakEventMessage(char *message) {
5122 const char* source_line = "\"sourceLine\":";
5123 char* pos = strstr(message, source_line);
5124 if (pos == NULL) {
5125 return -1;
5126 }
5127 int res = -1;
5128 res = StringToInt(pos + strlen(source_line));
5129 return res;
5130 }
5131
5132
5133 /* Test MessageQueues */
5134 /* Tests the message queues that hold debugger commands and
5135 * response messages to the debugger. Fills queues and makes
5136 * them grow.
5137 */
5138 Barriers message_queue_barriers;
5139
5140 // This is the debugger thread, that executes no v8 calls except
5141 // placing JSON debugger commands in the queue.
5142 class MessageQueueDebuggerThread : public v8::base::Thread {
5143 public:
MessageQueueDebuggerThread()5144 MessageQueueDebuggerThread()
5145 : Thread(Options("MessageQueueDebuggerThread")) {}
5146 void Run();
5147 };
5148
5149
MessageHandler(const v8::Debug::Message & message)5150 static void MessageHandler(const v8::Debug::Message& message) {
5151 v8::Local<v8::String> json = message.GetJSON();
5152 v8::String::Utf8Value utf8(json);
5153 if (IsBreakEventMessage(*utf8)) {
5154 // Lets test script wait until break occurs to send commands.
5155 // Signals when a break is reported.
5156 message_queue_barriers.semaphore_2.Signal();
5157 }
5158
5159 // Allow message handler to block on a semaphore, to test queueing of
5160 // messages while blocked.
5161 message_queue_barriers.semaphore_1.Wait();
5162 }
5163
5164
Run()5165 void MessageQueueDebuggerThread::Run() {
5166 const int kBufferSize = 1000;
5167 uint16_t buffer_1[kBufferSize];
5168 uint16_t buffer_2[kBufferSize];
5169 const char* command_1 =
5170 "{\"seq\":117,"
5171 "\"type\":\"request\","
5172 "\"command\":\"evaluate\","
5173 "\"arguments\":{\"expression\":\"1+2\"}}";
5174 const char* command_2 =
5175 "{\"seq\":118,"
5176 "\"type\":\"request\","
5177 "\"command\":\"evaluate\","
5178 "\"arguments\":{\"expression\":\"1+a\"}}";
5179 const char* command_3 =
5180 "{\"seq\":119,"
5181 "\"type\":\"request\","
5182 "\"command\":\"evaluate\","
5183 "\"arguments\":{\"expression\":\"c.d * b\"}}";
5184 const char* command_continue =
5185 "{\"seq\":106,"
5186 "\"type\":\"request\","
5187 "\"command\":\"continue\"}";
5188 const char* command_single_step =
5189 "{\"seq\":107,"
5190 "\"type\":\"request\","
5191 "\"command\":\"continue\","
5192 "\"arguments\":{\"stepaction\":\"next\"}}";
5193
5194 /* Interleaved sequence of actions by the two threads:*/
5195 // Main thread compiles and runs source_1
5196 message_queue_barriers.semaphore_1.Signal();
5197 message_queue_barriers.barrier_1.Wait();
5198 // Post 6 commands, filling the command queue and making it expand.
5199 // These calls return immediately, but the commands stay on the queue
5200 // until the execution of source_2.
5201 // Note: AsciiToUtf16 executes before SendCommand, so command is copied
5202 // to buffer before buffer is sent to SendCommand.
5203 v8::Isolate* isolate = CcTest::isolate();
5204 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1));
5205 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2));
5206 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
5207 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
5208 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
5209 message_queue_barriers.barrier_2.Wait();
5210 // Main thread compiles and runs source_2.
5211 // Queued commands are executed at the start of compilation of source_2(
5212 // beforeCompile event).
5213 // Free the message handler to process all the messages from the queue. 7
5214 // messages are expected: 2 afterCompile events and 5 responses.
5215 // All the commands added so far will fail to execute as long as call stack
5216 // is empty on beforeCompile event.
5217 for (int i = 0; i < 6 ; ++i) {
5218 message_queue_barriers.semaphore_1.Signal();
5219 }
5220 message_queue_barriers.barrier_3.Wait();
5221 // Main thread compiles and runs source_3.
5222 // Don't stop in the afterCompile handler.
5223 message_queue_barriers.semaphore_1.Signal();
5224 // source_3 includes a debugger statement, which causes a break event.
5225 // Wait on break event from hitting "debugger" statement
5226 message_queue_barriers.semaphore_2.Wait();
5227 // These should execute after the "debugger" statement in source_2
5228 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1));
5229 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2));
5230 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
5231 v8::Debug::SendCommand(
5232 isolate, buffer_2, AsciiToUtf16(command_single_step, buffer_2));
5233 // Run after 2 break events, 4 responses.
5234 for (int i = 0; i < 6 ; ++i) {
5235 message_queue_barriers.semaphore_1.Signal();
5236 }
5237 // Wait on break event after a single step executes.
5238 message_queue_barriers.semaphore_2.Wait();
5239 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_2, buffer_1));
5240 v8::Debug::SendCommand(
5241 isolate, buffer_2, AsciiToUtf16(command_continue, buffer_2));
5242 // Run after 2 responses.
5243 for (int i = 0; i < 2 ; ++i) {
5244 message_queue_barriers.semaphore_1.Signal();
5245 }
5246 // Main thread continues running source_3 to end, waits for this thread.
5247 }
5248
5249
5250 // This thread runs the v8 engine.
TEST(MessageQueues)5251 TEST(MessageQueues) {
5252 MessageQueueDebuggerThread message_queue_debugger_thread;
5253
5254 // Create a V8 environment
5255 DebugLocalContext env;
5256 v8::HandleScope scope(env->GetIsolate());
5257 v8::Debug::SetMessageHandler(env->GetIsolate(), MessageHandler);
5258 message_queue_debugger_thread.Start();
5259
5260 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
5261 const char* source_2 = "e = 17;";
5262 const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;";
5263
5264 // See MessageQueueDebuggerThread::Run for interleaved sequence of
5265 // API calls and events in the two threads.
5266 CompileRun(source_1);
5267 message_queue_barriers.barrier_1.Wait();
5268 message_queue_barriers.barrier_2.Wait();
5269 CompileRun(source_2);
5270 message_queue_barriers.barrier_3.Wait();
5271 CompileRun(source_3);
5272 message_queue_debugger_thread.Join();
5273 fflush(stdout);
5274 }
5275
5276
5277 class TestClientData : public v8::Debug::ClientData {
5278 public:
TestClientData()5279 TestClientData() {
5280 constructor_call_counter++;
5281 }
~TestClientData()5282 virtual ~TestClientData() {
5283 destructor_call_counter++;
5284 }
5285
ResetCounters()5286 static void ResetCounters() {
5287 constructor_call_counter = 0;
5288 destructor_call_counter = 0;
5289 }
5290
5291 static int constructor_call_counter;
5292 static int destructor_call_counter;
5293 };
5294
5295 int TestClientData::constructor_call_counter = 0;
5296 int TestClientData::destructor_call_counter = 0;
5297
5298
5299 // Tests that MessageQueue doesn't destroy client data when expands and
5300 // does destroy when it dies.
TEST(MessageQueueExpandAndDestroy)5301 TEST(MessageQueueExpandAndDestroy) {
5302 TestClientData::ResetCounters();
5303 { // Create a scope for the queue.
5304 CommandMessageQueue queue(1);
5305 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5306 new TestClientData()));
5307 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5308 new TestClientData()));
5309 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5310 new TestClientData()));
5311 CHECK_EQ(0, TestClientData::destructor_call_counter);
5312 queue.Get().Dispose();
5313 CHECK_EQ(1, TestClientData::destructor_call_counter);
5314 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5315 new TestClientData()));
5316 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5317 new TestClientData()));
5318 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5319 new TestClientData()));
5320 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5321 new TestClientData()));
5322 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5323 new TestClientData()));
5324 CHECK_EQ(1, TestClientData::destructor_call_counter);
5325 queue.Get().Dispose();
5326 CHECK_EQ(2, TestClientData::destructor_call_counter);
5327 }
5328 // All the client data should be destroyed when the queue is destroyed.
5329 CHECK_EQ(TestClientData::destructor_call_counter,
5330 TestClientData::destructor_call_counter);
5331 }
5332
5333
5334 static int handled_client_data_instances_count = 0;
MessageHandlerCountingClientData(const v8::Debug::Message & message)5335 static void MessageHandlerCountingClientData(
5336 const v8::Debug::Message& message) {
5337 if (message.GetClientData() != NULL) {
5338 handled_client_data_instances_count++;
5339 }
5340 }
5341
5342
5343 // Tests that all client data passed to the debugger are sent to the handler.
TEST(SendClientDataToHandler)5344 TEST(SendClientDataToHandler) {
5345 // Create a V8 environment
5346 DebugLocalContext env;
5347 v8::Isolate* isolate = env->GetIsolate();
5348 v8::HandleScope scope(isolate);
5349 TestClientData::ResetCounters();
5350 handled_client_data_instances_count = 0;
5351 v8::Debug::SetMessageHandler(isolate, MessageHandlerCountingClientData);
5352 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
5353 const int kBufferSize = 1000;
5354 uint16_t buffer[kBufferSize];
5355 const char* command_1 =
5356 "{\"seq\":117,"
5357 "\"type\":\"request\","
5358 "\"command\":\"evaluate\","
5359 "\"arguments\":{\"expression\":\"1+2\"}}";
5360 const char* command_2 =
5361 "{\"seq\":118,"
5362 "\"type\":\"request\","
5363 "\"command\":\"evaluate\","
5364 "\"arguments\":{\"expression\":\"1+a\"}}";
5365 const char* command_continue =
5366 "{\"seq\":106,"
5367 "\"type\":\"request\","
5368 "\"command\":\"continue\"}";
5369
5370 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_1, buffer),
5371 new TestClientData());
5372 v8::Debug::SendCommand(
5373 isolate, buffer, AsciiToUtf16(command_2, buffer), NULL);
5374 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer),
5375 new TestClientData());
5376 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer),
5377 new TestClientData());
5378 // All the messages will be processed on beforeCompile event.
5379 CompileRun(source_1);
5380 v8::Debug::SendCommand(
5381 isolate, buffer, AsciiToUtf16(command_continue, buffer));
5382 CHECK_EQ(3, TestClientData::constructor_call_counter);
5383 CHECK_EQ(TestClientData::constructor_call_counter,
5384 handled_client_data_instances_count);
5385 CHECK_EQ(TestClientData::constructor_call_counter,
5386 TestClientData::destructor_call_counter);
5387 }
5388
5389
5390 /* Test ThreadedDebugging */
5391 /* This test interrupts a running infinite loop that is
5392 * occupying the v8 thread by a break command from the
5393 * debugger thread. It then changes the value of a
5394 * global object, to make the loop terminate.
5395 */
5396
5397 Barriers threaded_debugging_barriers;
5398
5399 class V8Thread : public v8::base::Thread {
5400 public:
V8Thread()5401 V8Thread() : Thread(Options("V8Thread")) {}
5402 void Run();
isolate()5403 v8::Isolate* isolate() { return isolate_; }
5404
5405 private:
5406 v8::Isolate* isolate_;
5407 };
5408
5409 class DebuggerThread : public v8::base::Thread {
5410 public:
DebuggerThread(v8::Isolate * isolate)5411 explicit DebuggerThread(v8::Isolate* isolate)
5412 : Thread(Options("DebuggerThread")), isolate_(isolate) {}
5413 void Run();
5414
5415 private:
5416 v8::Isolate* isolate_;
5417 };
5418
5419
ThreadedAtBarrier1(const v8::FunctionCallbackInfo<v8::Value> & args)5420 static void ThreadedAtBarrier1(
5421 const v8::FunctionCallbackInfo<v8::Value>& args) {
5422 threaded_debugging_barriers.barrier_1.Wait();
5423 }
5424
5425
ThreadedMessageHandler(const v8::Debug::Message & message)5426 static void ThreadedMessageHandler(const v8::Debug::Message& message) {
5427 static char print_buffer[1000];
5428 v8::String::Value json(message.GetJSON());
5429 Utf16ToAscii(*json, json.length(), print_buffer);
5430 if (IsBreakEventMessage(print_buffer)) {
5431 // Check that we are inside the while loop.
5432 int source_line = GetSourceLineFromBreakEventMessage(print_buffer);
5433 CHECK(4 <= source_line && source_line <= 10);
5434 threaded_debugging_barriers.barrier_2.Wait();
5435 }
5436 }
5437
5438
Run()5439 void V8Thread::Run() {
5440 const char* source =
5441 "flag = true;\n"
5442 "\n"
5443 "function foo() {\n"
5444 " var x = 1;\n"
5445 " while ( flag == true ) {\n"
5446 " if ( x == 1 ) {\n"
5447 " ThreadedAtBarrier1();\n"
5448 " }\n"
5449 " x = x + 1;\n"
5450 " }\n"
5451 "}\n"
5452 "\n"
5453 "foo();\n";
5454
5455 v8::Isolate::CreateParams create_params;
5456 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
5457 isolate_ = v8::Isolate::New(create_params);
5458 threaded_debugging_barriers.barrier_3.Wait();
5459 {
5460 v8::Isolate::Scope isolate_scope(isolate_);
5461 DebugLocalContext env(isolate_);
5462 v8::HandleScope scope(isolate_);
5463 v8::Debug::SetMessageHandler(isolate_, &ThreadedMessageHandler);
5464 v8::Local<v8::ObjectTemplate> global_template =
5465 v8::ObjectTemplate::New(env->GetIsolate());
5466 global_template->Set(
5467 v8_str(env->GetIsolate(), "ThreadedAtBarrier1"),
5468 v8::FunctionTemplate::New(isolate_, ThreadedAtBarrier1));
5469 v8::Local<v8::Context> context =
5470 v8::Context::New(isolate_, NULL, global_template);
5471 v8::Context::Scope context_scope(context);
5472
5473 CompileRun(source);
5474 }
5475 threaded_debugging_barriers.barrier_4.Wait();
5476 isolate_->Dispose();
5477 }
5478
5479
Run()5480 void DebuggerThread::Run() {
5481 const int kBufSize = 1000;
5482 uint16_t buffer[kBufSize];
5483
5484 const char* command_1 =
5485 "{\"seq\":102,"
5486 "\"type\":\"request\","
5487 "\"command\":\"evaluate\","
5488 "\"arguments\":{\"expression\":\"flag = false\"}}";
5489 const char* command_2 = "{\"seq\":103,"
5490 "\"type\":\"request\","
5491 "\"command\":\"continue\"}";
5492
5493 threaded_debugging_barriers.barrier_1.Wait();
5494 v8::Debug::DebugBreak(isolate_);
5495 threaded_debugging_barriers.barrier_2.Wait();
5496 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer));
5497 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer));
5498 threaded_debugging_barriers.barrier_4.Wait();
5499 }
5500
5501
TEST(ThreadedDebugging)5502 TEST(ThreadedDebugging) {
5503 V8Thread v8_thread;
5504
5505 // Create a V8 environment
5506 v8_thread.Start();
5507 threaded_debugging_barriers.barrier_3.Wait();
5508 DebuggerThread debugger_thread(v8_thread.isolate());
5509 debugger_thread.Start();
5510
5511 v8_thread.Join();
5512 debugger_thread.Join();
5513 }
5514
5515
5516 /* Test RecursiveBreakpoints */
5517 /* In this test, the debugger evaluates a function with a breakpoint, after
5518 * hitting a breakpoint in another function. We do this with both values
5519 * of the flag enabling recursive breakpoints, and verify that the second
5520 * breakpoint is hit when enabled, and missed when disabled.
5521 */
5522
5523 class BreakpointsV8Thread : public v8::base::Thread {
5524 public:
BreakpointsV8Thread()5525 BreakpointsV8Thread() : Thread(Options("BreakpointsV8Thread")) {}
5526 void Run();
5527
isolate()5528 v8::Isolate* isolate() { return isolate_; }
5529
5530 private:
5531 v8::Isolate* isolate_;
5532 };
5533
5534 class BreakpointsDebuggerThread : public v8::base::Thread {
5535 public:
BreakpointsDebuggerThread(bool global_evaluate,v8::Isolate * isolate)5536 BreakpointsDebuggerThread(bool global_evaluate, v8::Isolate* isolate)
5537 : Thread(Options("BreakpointsDebuggerThread")),
5538 global_evaluate_(global_evaluate),
5539 isolate_(isolate) {}
5540 void Run();
5541
5542 private:
5543 bool global_evaluate_;
5544 v8::Isolate* isolate_;
5545 };
5546
5547
5548 Barriers* breakpoints_barriers;
5549 int break_event_breakpoint_id;
5550 int evaluate_int_result;
5551
BreakpointsMessageHandler(const v8::Debug::Message & message)5552 static void BreakpointsMessageHandler(const v8::Debug::Message& message) {
5553 static char print_buffer[1000];
5554 v8::String::Value json(message.GetJSON());
5555 Utf16ToAscii(*json, json.length(), print_buffer);
5556
5557 if (IsBreakEventMessage(print_buffer)) {
5558 break_event_breakpoint_id =
5559 GetBreakpointIdFromBreakEventMessage(print_buffer);
5560 breakpoints_barriers->semaphore_1.Signal();
5561 } else if (IsEvaluateResponseMessage(print_buffer)) {
5562 evaluate_int_result = GetEvaluateIntResult(print_buffer);
5563 breakpoints_barriers->semaphore_1.Signal();
5564 }
5565 }
5566
5567
Run()5568 void BreakpointsV8Thread::Run() {
5569 const char* source_1 = "var y_global = 3;\n"
5570 "function cat( new_value ) {\n"
5571 " var x = new_value;\n"
5572 " y_global = y_global + 4;\n"
5573 " x = 3 * x + 1;\n"
5574 " y_global = y_global + 5;\n"
5575 " return x;\n"
5576 "}\n"
5577 "\n"
5578 "function dog() {\n"
5579 " var x = 1;\n"
5580 " x = y_global;"
5581 " var z = 3;"
5582 " x += 100;\n"
5583 " return x;\n"
5584 "}\n"
5585 "\n";
5586 const char* source_2 = "cat(17);\n"
5587 "cat(19);\n";
5588
5589 v8::Isolate::CreateParams create_params;
5590 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
5591 isolate_ = v8::Isolate::New(create_params);
5592 breakpoints_barriers->barrier_3.Wait();
5593 {
5594 v8::Isolate::Scope isolate_scope(isolate_);
5595 DebugLocalContext env(isolate_);
5596 v8::HandleScope scope(isolate_);
5597 v8::Debug::SetMessageHandler(isolate_, &BreakpointsMessageHandler);
5598
5599 CompileRun(source_1);
5600 breakpoints_barriers->barrier_1.Wait();
5601 breakpoints_barriers->barrier_2.Wait();
5602 CompileRun(source_2);
5603 }
5604 breakpoints_barriers->barrier_4.Wait();
5605 isolate_->Dispose();
5606 }
5607
5608
Run()5609 void BreakpointsDebuggerThread::Run() {
5610 const int kBufSize = 1000;
5611 uint16_t buffer[kBufSize];
5612
5613 const char* command_1 = "{\"seq\":101,"
5614 "\"type\":\"request\","
5615 "\"command\":\"setbreakpoint\","
5616 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
5617 const char* command_2 = "{\"seq\":102,"
5618 "\"type\":\"request\","
5619 "\"command\":\"setbreakpoint\","
5620 "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}";
5621 const char* command_3;
5622 if (this->global_evaluate_) {
5623 command_3 = "{\"seq\":103,"
5624 "\"type\":\"request\","
5625 "\"command\":\"evaluate\","
5626 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false,"
5627 "\"global\":true}}";
5628 } else {
5629 command_3 = "{\"seq\":103,"
5630 "\"type\":\"request\","
5631 "\"command\":\"evaluate\","
5632 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}";
5633 }
5634 const char* command_4;
5635 if (this->global_evaluate_) {
5636 command_4 = "{\"seq\":104,"
5637 "\"type\":\"request\","
5638 "\"command\":\"evaluate\","
5639 "\"arguments\":{\"expression\":\"100 + 8\",\"disable_break\":true,"
5640 "\"global\":true}}";
5641 } else {
5642 command_4 = "{\"seq\":104,"
5643 "\"type\":\"request\","
5644 "\"command\":\"evaluate\","
5645 "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}";
5646 }
5647 const char* command_5 = "{\"seq\":105,"
5648 "\"type\":\"request\","
5649 "\"command\":\"continue\"}";
5650 const char* command_6 = "{\"seq\":106,"
5651 "\"type\":\"request\","
5652 "\"command\":\"continue\"}";
5653 const char* command_7;
5654 if (this->global_evaluate_) {
5655 command_7 = "{\"seq\":107,"
5656 "\"type\":\"request\","
5657 "\"command\":\"evaluate\","
5658 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true,"
5659 "\"global\":true}}";
5660 } else {
5661 command_7 = "{\"seq\":107,"
5662 "\"type\":\"request\","
5663 "\"command\":\"evaluate\","
5664 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}";
5665 }
5666 const char* command_8 = "{\"seq\":108,"
5667 "\"type\":\"request\","
5668 "\"command\":\"continue\"}";
5669
5670
5671 // v8 thread initializes, runs source_1
5672 breakpoints_barriers->barrier_1.Wait();
5673 // 1:Set breakpoint in cat() (will get id 1).
5674 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer));
5675 // 2:Set breakpoint in dog() (will get id 2).
5676 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer));
5677 breakpoints_barriers->barrier_2.Wait();
5678 // V8 thread starts compiling source_2.
5679 // Automatic break happens, to run queued commands
5680 // breakpoints_barriers->semaphore_1.Wait();
5681 // Commands 1 through 3 run, thread continues.
5682 // v8 thread runs source_2 to breakpoint in cat().
5683 // message callback receives break event.
5684 breakpoints_barriers->semaphore_1.Wait();
5685 // Must have hit breakpoint #1.
5686 CHECK_EQ(1, break_event_breakpoint_id);
5687 // 4:Evaluate dog() (which has a breakpoint).
5688 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_3, buffer));
5689 // V8 thread hits breakpoint in dog().
5690 breakpoints_barriers->semaphore_1.Wait(); // wait for break event
5691 // Must have hit breakpoint #2.
5692 CHECK_EQ(2, break_event_breakpoint_id);
5693 // 5:Evaluate (x + 1).
5694 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_4, buffer));
5695 // Evaluate (x + 1) finishes.
5696 breakpoints_barriers->semaphore_1.Wait();
5697 // Must have result 108.
5698 CHECK_EQ(108, evaluate_int_result);
5699 // 6:Continue evaluation of dog().
5700 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_5, buffer));
5701 // Evaluate dog() finishes.
5702 breakpoints_barriers->semaphore_1.Wait();
5703 // Must have result 107.
5704 CHECK_EQ(107, evaluate_int_result);
5705 // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint
5706 // in cat(19).
5707 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_6, buffer));
5708 // Message callback gets break event.
5709 breakpoints_barriers->semaphore_1.Wait(); // wait for break event
5710 // Must have hit breakpoint #1.
5711 CHECK_EQ(1, break_event_breakpoint_id);
5712 // 8: Evaluate dog() with breaks disabled.
5713 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_7, buffer));
5714 // Evaluate dog() finishes.
5715 breakpoints_barriers->semaphore_1.Wait();
5716 // Must have result 116.
5717 CHECK_EQ(116, evaluate_int_result);
5718 // 9: Continue evaluation of source2, reach end.
5719 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_8, buffer));
5720 breakpoints_barriers->barrier_4.Wait();
5721 }
5722
5723
TestRecursiveBreakpointsGeneric(bool global_evaluate)5724 void TestRecursiveBreakpointsGeneric(bool global_evaluate) {
5725 BreakpointsV8Thread breakpoints_v8_thread;
5726
5727 // Create a V8 environment
5728 Barriers stack_allocated_breakpoints_barriers;
5729 breakpoints_barriers = &stack_allocated_breakpoints_barriers;
5730
5731 breakpoints_v8_thread.Start();
5732 breakpoints_barriers->barrier_3.Wait();
5733 BreakpointsDebuggerThread breakpoints_debugger_thread(
5734 global_evaluate, breakpoints_v8_thread.isolate());
5735 breakpoints_debugger_thread.Start();
5736
5737 breakpoints_v8_thread.Join();
5738 breakpoints_debugger_thread.Join();
5739 }
5740
5741
TEST(RecursiveBreakpoints)5742 TEST(RecursiveBreakpoints) {
5743 TestRecursiveBreakpointsGeneric(false);
5744 }
5745
5746
TEST(RecursiveBreakpointsGlobal)5747 TEST(RecursiveBreakpointsGlobal) {
5748 TestRecursiveBreakpointsGeneric(true);
5749 }
5750
5751
TEST(SetDebugEventListenerOnUninitializedVM)5752 TEST(SetDebugEventListenerOnUninitializedVM) {
5753 v8::Debug::SetDebugEventListener(CcTest::isolate(), DummyDebugEventListener);
5754 }
5755
5756
DummyMessageHandler(const v8::Debug::Message & message)5757 static void DummyMessageHandler(const v8::Debug::Message& message) {
5758 }
5759
5760
TEST(SetMessageHandlerOnUninitializedVM)5761 TEST(SetMessageHandlerOnUninitializedVM) {
5762 v8::Debug::SetMessageHandler(CcTest::isolate(), DummyMessageHandler);
5763 }
5764
5765
5766 // Source for a JavaScript function which returns the data parameter of a
5767 // function called in the context of the debugger. If no data parameter is
5768 // passed it throws an exception.
5769 static const char* debugger_call_with_data_source =
5770 "function debugger_call_with_data(exec_state, data) {"
5771 " if (data) return data;"
5772 " throw 'No data!'"
5773 "}";
5774 v8::Local<v8::Function> debugger_call_with_data;
5775
5776
5777 // Source for a JavaScript function which returns the data parameter of a
5778 // function called in the context of the debugger. If no data parameter is
5779 // passed it throws an exception.
5780 static const char* debugger_call_with_closure_source =
5781 "var x = 3;"
5782 "(function (exec_state) {"
5783 " if (exec_state.y) return x - 1;"
5784 " exec_state.y = x;"
5785 " return exec_state.y"
5786 "})";
5787 v8::Local<v8::Function> debugger_call_with_closure;
5788
5789 // Function to retrieve the number of JavaScript frames by calling a JavaScript
5790 // in the debugger.
CheckFrameCount(const v8::FunctionCallbackInfo<v8::Value> & args)5791 static void CheckFrameCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
5792 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5793 CHECK(v8::Debug::Call(context, frame_count).ToLocalChecked()->IsNumber());
5794 CHECK_EQ(args[0]->Int32Value(context).FromJust(),
5795 v8::Debug::Call(context, frame_count)
5796 .ToLocalChecked()
5797 ->Int32Value(context)
5798 .FromJust());
5799 }
5800
5801
5802 // Function to retrieve the source line of the top JavaScript frame by calling a
5803 // JavaScript function in the debugger.
CheckSourceLine(const v8::FunctionCallbackInfo<v8::Value> & args)5804 static void CheckSourceLine(const v8::FunctionCallbackInfo<v8::Value>& args) {
5805 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5806 CHECK(
5807 v8::Debug::Call(context, frame_source_line).ToLocalChecked()->IsNumber());
5808 CHECK_EQ(args[0]->Int32Value(context).FromJust(),
5809 v8::Debug::Call(context, frame_source_line)
5810 .ToLocalChecked()
5811 ->Int32Value(context)
5812 .FromJust());
5813 }
5814
5815
5816 // Function to test passing an additional parameter to a JavaScript function
5817 // called in the debugger. It also tests that functions called in the debugger
5818 // can throw exceptions.
CheckDataParameter(const v8::FunctionCallbackInfo<v8::Value> & args)5819 static void CheckDataParameter(
5820 const v8::FunctionCallbackInfo<v8::Value>& args) {
5821 v8::Local<v8::String> data = v8_str(args.GetIsolate(), "Test");
5822 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5823 CHECK(v8::Debug::Call(context, debugger_call_with_data, data)
5824 .ToLocalChecked()
5825 ->IsString());
5826
5827 for (int i = 0; i < 3; i++) {
5828 v8::TryCatch catcher(args.GetIsolate());
5829 CHECK(v8::Debug::Call(context, debugger_call_with_data).IsEmpty());
5830 CHECK(catcher.HasCaught());
5831 CHECK(catcher.Exception()->IsString());
5832 }
5833 }
5834
5835
5836 // Function to test using a JavaScript with closure in the debugger.
CheckClosure(const v8::FunctionCallbackInfo<v8::Value> & args)5837 static void CheckClosure(const v8::FunctionCallbackInfo<v8::Value>& args) {
5838 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5839 CHECK(v8::Debug::Call(context, debugger_call_with_closure)
5840 .ToLocalChecked()
5841 ->IsNumber());
5842 CHECK_EQ(3, v8::Debug::Call(context, debugger_call_with_closure)
5843 .ToLocalChecked()
5844 ->Int32Value(context)
5845 .FromJust());
5846 }
5847
5848
5849 // Test functions called through the debugger.
TEST(CallFunctionInDebugger)5850 TEST(CallFunctionInDebugger) {
5851 // Create and enter a context with the functions CheckFrameCount,
5852 // CheckSourceLine and CheckDataParameter installed.
5853 v8::Isolate* isolate = CcTest::isolate();
5854 v8::HandleScope scope(isolate);
5855 v8::Local<v8::ObjectTemplate> global_template =
5856 v8::ObjectTemplate::New(isolate);
5857 global_template->Set(v8_str(isolate, "CheckFrameCount"),
5858 v8::FunctionTemplate::New(isolate, CheckFrameCount));
5859 global_template->Set(v8_str(isolate, "CheckSourceLine"),
5860 v8::FunctionTemplate::New(isolate, CheckSourceLine));
5861 global_template->Set(v8_str(isolate, "CheckDataParameter"),
5862 v8::FunctionTemplate::New(isolate, CheckDataParameter));
5863 global_template->Set(v8_str(isolate, "CheckClosure"),
5864 v8::FunctionTemplate::New(isolate, CheckClosure));
5865 v8::Local<v8::Context> context =
5866 v8::Context::New(isolate, NULL, global_template);
5867 v8::Context::Scope context_scope(context);
5868
5869 // Compile a function for checking the number of JavaScript frames.
5870 v8::Script::Compile(context, v8_str(isolate, frame_count_source))
5871 .ToLocalChecked()
5872 ->Run(context)
5873 .ToLocalChecked();
5874 frame_count = v8::Local<v8::Function>::Cast(
5875 context->Global()
5876 ->Get(context, v8_str(isolate, "frame_count"))
5877 .ToLocalChecked());
5878
5879 // Compile a function for returning the source line for the top frame.
5880 v8::Script::Compile(context, v8_str(isolate, frame_source_line_source))
5881 .ToLocalChecked()
5882 ->Run(context)
5883 .ToLocalChecked();
5884 frame_source_line = v8::Local<v8::Function>::Cast(
5885 context->Global()
5886 ->Get(context, v8_str(isolate, "frame_source_line"))
5887 .ToLocalChecked());
5888
5889 // Compile a function returning the data parameter.
5890 v8::Script::Compile(context, v8_str(isolate, debugger_call_with_data_source))
5891 .ToLocalChecked()
5892 ->Run(context)
5893 .ToLocalChecked();
5894 debugger_call_with_data = v8::Local<v8::Function>::Cast(
5895 context->Global()
5896 ->Get(context, v8_str(isolate, "debugger_call_with_data"))
5897 .ToLocalChecked());
5898
5899 // Compile a function capturing closure.
5900 debugger_call_with_closure = v8::Local<v8::Function>::Cast(
5901 v8::Script::Compile(context,
5902 v8_str(isolate, debugger_call_with_closure_source))
5903 .ToLocalChecked()
5904 ->Run(context)
5905 .ToLocalChecked());
5906
5907 // Calling a function through the debugger returns 0 frames if there are
5908 // no JavaScript frames.
5909 CHECK(v8::Integer::New(isolate, 0)
5910 ->Equals(context,
5911 v8::Debug::Call(context, frame_count).ToLocalChecked())
5912 .FromJust());
5913
5914 // Test that the number of frames can be retrieved.
5915 v8::Script::Compile(context, v8_str(isolate, "CheckFrameCount(1)"))
5916 .ToLocalChecked()
5917 ->Run(context)
5918 .ToLocalChecked();
5919 v8::Script::Compile(context, v8_str(isolate,
5920 "function f() {"
5921 " CheckFrameCount(2);"
5922 "}; f()"))
5923 .ToLocalChecked()
5924 ->Run(context)
5925 .ToLocalChecked();
5926
5927 // Test that the source line can be retrieved.
5928 v8::Script::Compile(context, v8_str(isolate, "CheckSourceLine(0)"))
5929 .ToLocalChecked()
5930 ->Run(context)
5931 .ToLocalChecked();
5932 v8::Script::Compile(context, v8_str(isolate,
5933 "function f() {\n"
5934 " CheckSourceLine(1)\n"
5935 " CheckSourceLine(2)\n"
5936 " CheckSourceLine(3)\n"
5937 "}; f()"))
5938 .ToLocalChecked()
5939 ->Run(context)
5940 .ToLocalChecked();
5941
5942 // Test that a parameter can be passed to a function called in the debugger.
5943 v8::Script::Compile(context, v8_str(isolate, "CheckDataParameter()"))
5944 .ToLocalChecked()
5945 ->Run(context)
5946 .ToLocalChecked();
5947
5948 // Test that a function with closure can be run in the debugger.
5949 v8::Script::Compile(context, v8_str(isolate, "CheckClosure()"))
5950 .ToLocalChecked()
5951 ->Run(context)
5952 .ToLocalChecked();
5953
5954 // Test that the source line is correct when there is a line offset.
5955 v8::ScriptOrigin origin(v8_str(isolate, "test"),
5956 v8::Integer::New(isolate, 7));
5957 v8::Script::Compile(context, v8_str(isolate, "CheckSourceLine(7)"), &origin)
5958 .ToLocalChecked()
5959 ->Run(context)
5960 .ToLocalChecked();
5961 v8::Script::Compile(context, v8_str(isolate,
5962 "function f() {\n"
5963 " CheckSourceLine(8)\n"
5964 " CheckSourceLine(9)\n"
5965 " CheckSourceLine(10)\n"
5966 "}; f()"),
5967 &origin)
5968 .ToLocalChecked()
5969 ->Run(context)
5970 .ToLocalChecked();
5971 }
5972
5973
5974 // Debugger message handler which counts the number of breaks.
5975 static void SendContinueCommand();
MessageHandlerBreakPointHitCount(const v8::Debug::Message & message)5976 static void MessageHandlerBreakPointHitCount(
5977 const v8::Debug::Message& message) {
5978 if (message.IsEvent() && message.GetEvent() == v8::Break) {
5979 // Count the number of breaks.
5980 break_point_hit_count++;
5981
5982 SendContinueCommand();
5983 }
5984 }
5985
5986
5987 // Test that clearing the debug event listener actually clears all break points
5988 // and related information.
TEST(DebuggerUnload)5989 TEST(DebuggerUnload) {
5990 DebugLocalContext env;
5991
5992 // Check debugger is unloaded before it is used.
5993 CheckDebuggerUnloaded(env->GetIsolate());
5994
5995 // Set a debug event listener.
5996 break_point_hit_count = 0;
5997 v8::Debug::SetDebugEventListener(env->GetIsolate(),
5998 DebugEventBreakPointHitCount);
5999 v8::Local<v8::Context> context = env.context();
6000 {
6001 v8::HandleScope scope(env->GetIsolate());
6002 // Create a couple of functions for the test.
6003 v8::Local<v8::Function> foo =
6004 CompileFunction(&env, "function foo(){x=1}", "foo");
6005 v8::Local<v8::Function> bar =
6006 CompileFunction(&env, "function bar(){y=2}", "bar");
6007
6008 // Set some break points.
6009 SetBreakPoint(foo, 0);
6010 SetBreakPoint(foo, 4);
6011 SetBreakPoint(bar, 0);
6012 SetBreakPoint(bar, 4);
6013
6014 // Make sure that the break points are there.
6015 break_point_hit_count = 0;
6016 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
6017 CHECK_EQ(2, break_point_hit_count);
6018 bar->Call(context, env->Global(), 0, NULL).ToLocalChecked();
6019 CHECK_EQ(4, break_point_hit_count);
6020 }
6021
6022 // Remove the debug event listener without clearing breakpoints. Do this
6023 // outside a handle scope.
6024 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
6025 CheckDebuggerUnloaded(env->GetIsolate(), true);
6026
6027 // Now set a debug message handler.
6028 break_point_hit_count = 0;
6029 v8::Debug::SetMessageHandler(env->GetIsolate(),
6030 MessageHandlerBreakPointHitCount);
6031 {
6032 v8::HandleScope scope(env->GetIsolate());
6033
6034 // Get the test functions again.
6035 v8::Local<v8::Function> foo(v8::Local<v8::Function>::Cast(
6036 env->Global()
6037 ->Get(context, v8_str(env->GetIsolate(), "foo"))
6038 .ToLocalChecked()));
6039
6040 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
6041 CHECK_EQ(0, break_point_hit_count);
6042
6043 // Set break points and run again.
6044 SetBreakPoint(foo, 0);
6045 SetBreakPoint(foo, 4);
6046 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
6047 CHECK_EQ(2, break_point_hit_count);
6048 }
6049
6050 // Remove the debug message handler without clearing breakpoints. Do this
6051 // outside a handle scope.
6052 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6053 CheckDebuggerUnloaded(env->GetIsolate(), true);
6054 }
6055
6056
6057 // Sends continue command to the debugger.
SendContinueCommand()6058 static void SendContinueCommand() {
6059 const int kBufferSize = 1000;
6060 uint16_t buffer[kBufferSize];
6061 const char* command_continue =
6062 "{\"seq\":0,"
6063 "\"type\":\"request\","
6064 "\"command\":\"continue\"}";
6065
6066 v8::Debug::SendCommand(
6067 CcTest::isolate(), buffer, AsciiToUtf16(command_continue, buffer));
6068 }
6069
6070
6071 // Debugger message handler which counts the number of times it is called.
6072 static int message_handler_hit_count = 0;
MessageHandlerHitCount(const v8::Debug::Message & message)6073 static void MessageHandlerHitCount(const v8::Debug::Message& message) {
6074 message_handler_hit_count++;
6075
6076 static char print_buffer[1000];
6077 v8::String::Value json(message.GetJSON());
6078 Utf16ToAscii(*json, json.length(), print_buffer);
6079 if (IsExceptionEventMessage(print_buffer)) {
6080 // Send a continue command for exception events.
6081 SendContinueCommand();
6082 }
6083 }
6084
6085
6086 // Test clearing the debug message handler.
TEST(DebuggerClearMessageHandler)6087 TEST(DebuggerClearMessageHandler) {
6088 DebugLocalContext env;
6089 v8::HandleScope scope(env->GetIsolate());
6090
6091 // Check debugger is unloaded before it is used.
6092 CheckDebuggerUnloaded(env->GetIsolate());
6093
6094 // Set a debug message handler.
6095 v8::Debug::SetMessageHandler(env->GetIsolate(), MessageHandlerHitCount);
6096
6097 // Run code to throw a unhandled exception. This should end up in the message
6098 // handler.
6099 CompileRun("throw 1");
6100
6101 // The message handler should be called.
6102 CHECK_GT(message_handler_hit_count, 0);
6103
6104 // Clear debug message handler.
6105 message_handler_hit_count = 0;
6106 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6107
6108 // Run code to throw a unhandled exception. This should end up in the message
6109 // handler.
6110 CompileRun("throw 1");
6111
6112 // The message handler should not be called more.
6113 CHECK_EQ(0, message_handler_hit_count);
6114
6115 CheckDebuggerUnloaded(env->GetIsolate(), true);
6116 }
6117
6118
6119 // Debugger message handler which clears the message handler while active.
MessageHandlerClearingMessageHandler(const v8::Debug::Message & message)6120 static void MessageHandlerClearingMessageHandler(
6121 const v8::Debug::Message& message) {
6122 message_handler_hit_count++;
6123
6124 // Clear debug message handler.
6125 v8::Debug::SetMessageHandler(message.GetIsolate(), nullptr);
6126 }
6127
6128
6129 // Test clearing the debug message handler while processing a debug event.
TEST(DebuggerClearMessageHandlerWhileActive)6130 TEST(DebuggerClearMessageHandlerWhileActive) {
6131 DebugLocalContext env;
6132 v8::HandleScope scope(env->GetIsolate());
6133
6134 // Check debugger is unloaded before it is used.
6135 CheckDebuggerUnloaded(env->GetIsolate());
6136
6137 // Set a debug message handler.
6138 v8::Debug::SetMessageHandler(env->GetIsolate(),
6139 MessageHandlerClearingMessageHandler);
6140
6141 // Run code to throw a unhandled exception. This should end up in the message
6142 // handler.
6143 CompileRun("throw 1");
6144
6145 // The message handler should be called.
6146 CHECK_EQ(1, message_handler_hit_count);
6147
6148 CheckDebuggerUnloaded(env->GetIsolate(), true);
6149 }
6150
6151
6152 // Test for issue http://code.google.com/p/v8/issues/detail?id=289.
6153 // Make sure that DebugGetLoadedScripts doesn't return scripts
6154 // with disposed external source.
6155 class EmptyExternalStringResource : public v8::String::ExternalStringResource {
6156 public:
EmptyExternalStringResource()6157 EmptyExternalStringResource() { empty_[0] = 0; }
~EmptyExternalStringResource()6158 virtual ~EmptyExternalStringResource() {}
length() const6159 virtual size_t length() const { return empty_.length(); }
data() const6160 virtual const uint16_t* data() const { return empty_.start(); }
6161 private:
6162 ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
6163 };
6164
6165
TEST(DebugGetLoadedScripts)6166 TEST(DebugGetLoadedScripts) {
6167 DebugLocalContext env;
6168 v8::HandleScope scope(env->GetIsolate());
6169 env.ExposeDebug();
6170
6171 v8::Local<v8::Context> context = env.context();
6172 EmptyExternalStringResource source_ext_str;
6173 v8::Local<v8::String> source =
6174 v8::String::NewExternalTwoByte(env->GetIsolate(), &source_ext_str)
6175 .ToLocalChecked();
6176 CHECK(v8::Script::Compile(context, source).IsEmpty());
6177 Handle<i::ExternalTwoByteString> i_source(
6178 i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
6179 // This situation can happen if source was an external string disposed
6180 // by its owner.
6181 i_source->set_resource(0);
6182
6183 bool allow_natives_syntax = i::FLAG_allow_natives_syntax;
6184 i::FLAG_allow_natives_syntax = true;
6185 EnableDebugger(env->GetIsolate());
6186 v8::MaybeLocal<v8::Value> result =
6187 CompileRun(env.context(),
6188 "var scripts = %DebugGetLoadedScripts();"
6189 "var count = scripts.length;"
6190 "for (var i = 0; i < count; ++i) {"
6191 " var lines = scripts[i].lineCount();"
6192 " if (lines < 1) throw 'lineCount';"
6193 " var last = -1;"
6194 " for (var j = 0; j < lines; ++j) {"
6195 " var end = scripts[i].lineEnd(j);"
6196 " if (last >= end) throw 'lineEnd';"
6197 " last = end;"
6198 " }"
6199 "}");
6200 CHECK(!result.IsEmpty());
6201 DisableDebugger(env->GetIsolate());
6202 // Must not crash while accessing line_ends.
6203 i::FLAG_allow_natives_syntax = allow_natives_syntax;
6204
6205 // Some scripts are retrieved - at least the number of native scripts.
6206 CHECK_GT(env->Global()
6207 ->Get(context, v8_str(env->GetIsolate(), "count"))
6208 .ToLocalChecked()
6209 ->Int32Value(context)
6210 .FromJust(),
6211 8);
6212 }
6213
6214
6215 // Test script break points set on lines.
TEST(ScriptNameAndData)6216 TEST(ScriptNameAndData) {
6217 DebugLocalContext env;
6218 v8::HandleScope scope(env->GetIsolate());
6219 env.ExposeDebug();
6220
6221 // Create functions for retrieving script name and data for the function on
6222 // the top frame when hitting a break point.
6223 frame_script_name = CompileFunction(&env,
6224 frame_script_name_source,
6225 "frame_script_name");
6226
6227 v8::Debug::SetDebugEventListener(env->GetIsolate(),
6228 DebugEventBreakPointHitCount);
6229
6230 v8::Local<v8::Context> context = env.context();
6231 // Test function source.
6232 v8::Local<v8::String> script = v8_str(env->GetIsolate(),
6233 "function f() {\n"
6234 " debugger;\n"
6235 "}\n");
6236
6237 v8::ScriptOrigin origin1 =
6238 v8::ScriptOrigin(v8_str(env->GetIsolate(), "name"));
6239 v8::Local<v8::Script> script1 =
6240 v8::Script::Compile(context, script, &origin1).ToLocalChecked();
6241 script1->Run(context).ToLocalChecked();
6242 v8::Local<v8::Function> f;
6243 f = v8::Local<v8::Function>::Cast(
6244 env->Global()
6245 ->Get(context, v8_str(env->GetIsolate(), "f"))
6246 .ToLocalChecked());
6247
6248 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
6249 CHECK_EQ(1, break_point_hit_count);
6250 CHECK_EQ(0, strcmp("name", last_script_name_hit));
6251
6252 // Compile the same script again without setting data. As the compilation
6253 // cache is disabled when debugging expect the data to be missing.
6254 v8::Script::Compile(context, script, &origin1)
6255 .ToLocalChecked()
6256 ->Run(context)
6257 .ToLocalChecked();
6258 f = v8::Local<v8::Function>::Cast(
6259 env->Global()
6260 ->Get(context, v8_str(env->GetIsolate(), "f"))
6261 .ToLocalChecked());
6262 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
6263 CHECK_EQ(2, break_point_hit_count);
6264 CHECK_EQ(0, strcmp("name", last_script_name_hit));
6265
6266 v8::Local<v8::String> data_obj_source =
6267 v8_str(env->GetIsolate(),
6268 "({ a: 'abc',\n"
6269 " b: 123,\n"
6270 " toString: function() { return this.a + ' ' + this.b; }\n"
6271 "})\n");
6272 v8::Script::Compile(context, data_obj_source)
6273 .ToLocalChecked()
6274 ->Run(context)
6275 .ToLocalChecked();
6276 v8::ScriptOrigin origin2 =
6277 v8::ScriptOrigin(v8_str(env->GetIsolate(), "new name"));
6278 v8::Local<v8::Script> script2 =
6279 v8::Script::Compile(context, script, &origin2).ToLocalChecked();
6280 script2->Run(context).ToLocalChecked();
6281 f = v8::Local<v8::Function>::Cast(
6282 env->Global()
6283 ->Get(context, v8_str(env->GetIsolate(), "f"))
6284 .ToLocalChecked());
6285 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
6286 CHECK_EQ(3, break_point_hit_count);
6287 CHECK_EQ(0, strcmp("new name", last_script_name_hit));
6288
6289 v8::Local<v8::Script> script3 =
6290 v8::Script::Compile(context, script, &origin2).ToLocalChecked();
6291 script3->Run(context).ToLocalChecked();
6292 f = v8::Local<v8::Function>::Cast(
6293 env->Global()
6294 ->Get(context, v8_str(env->GetIsolate(), "f"))
6295 .ToLocalChecked());
6296 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
6297 CHECK_EQ(4, break_point_hit_count);
6298 }
6299
6300
6301 static v8::Local<v8::Context> expected_context;
6302 static v8::Local<v8::Value> expected_context_data;
6303
6304
6305 // Check that the expected context is the one generating the debug event.
ContextCheckMessageHandler(const v8::Debug::Message & message)6306 static void ContextCheckMessageHandler(const v8::Debug::Message& message) {
6307 CHECK(message.GetEventContext() == expected_context);
6308 CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals(
6309 expected_context_data));
6310 message_handler_hit_count++;
6311
6312 static char print_buffer[1000];
6313 v8::String::Value json(message.GetJSON());
6314 Utf16ToAscii(*json, json.length(), print_buffer);
6315
6316 // Send a continue command for break events.
6317 if (IsBreakEventMessage(print_buffer)) {
6318 SendContinueCommand();
6319 }
6320 }
6321
6322
6323 // Test which creates two contexts and sets different embedder data on each.
6324 // Checks that this data is set correctly and that when the debug message
6325 // handler is called the expected context is the one active.
TEST(ContextData)6326 TEST(ContextData) {
6327 v8::Isolate* isolate = CcTest::isolate();
6328 v8::HandleScope scope(isolate);
6329
6330 // Create two contexts.
6331 v8::Local<v8::Context> context_1;
6332 v8::Local<v8::Context> context_2;
6333 v8::Local<v8::ObjectTemplate> global_template =
6334 v8::Local<v8::ObjectTemplate>();
6335 v8::Local<v8::Value> global_object = v8::Local<v8::Value>();
6336 context_1 = v8::Context::New(isolate, NULL, global_template, global_object);
6337 context_2 = v8::Context::New(isolate, NULL, global_template, global_object);
6338
6339 v8::Debug::SetMessageHandler(isolate, ContextCheckMessageHandler);
6340
6341 // Default data value is undefined.
6342 CHECK(context_1->GetEmbedderData(0)->IsUndefined());
6343 CHECK(context_2->GetEmbedderData(0)->IsUndefined());
6344
6345 // Set and check different data values.
6346 v8::Local<v8::String> data_1 = v8_str(isolate, "1");
6347 v8::Local<v8::String> data_2 = v8_str(isolate, "2");
6348 context_1->SetEmbedderData(0, data_1);
6349 context_2->SetEmbedderData(0, data_2);
6350 CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
6351 CHECK(context_2->GetEmbedderData(0)->StrictEquals(data_2));
6352
6353 // Simple test function which causes a break.
6354 const char* source = "function f() { debugger; }";
6355
6356 // Enter and run function in the first context.
6357 {
6358 v8::Context::Scope context_scope(context_1);
6359 expected_context = context_1;
6360 expected_context_data = data_1;
6361 v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
6362 f->Call(context_1, context_1->Global(), 0, NULL).ToLocalChecked();
6363 }
6364
6365
6366 // Enter and run function in the second context.
6367 {
6368 v8::Context::Scope context_scope(context_2);
6369 expected_context = context_2;
6370 expected_context_data = data_2;
6371 v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
6372 f->Call(context_2, context_2->Global(), 0, NULL).ToLocalChecked();
6373 }
6374
6375 // Two times compile event and two times break event.
6376 CHECK_GT(message_handler_hit_count, 4);
6377
6378 v8::Debug::SetMessageHandler(isolate, nullptr);
6379 CheckDebuggerUnloaded(isolate);
6380 }
6381
6382
6383 // Debug message handler which issues a debug break when it hits a break event.
6384 static int message_handler_break_hit_count = 0;
DebugBreakMessageHandler(const v8::Debug::Message & message)6385 static void DebugBreakMessageHandler(const v8::Debug::Message& message) {
6386 // Schedule a debug break for break events.
6387 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6388 message_handler_break_hit_count++;
6389 if (message_handler_break_hit_count == 1) {
6390 v8::Debug::DebugBreak(message.GetIsolate());
6391 }
6392 }
6393
6394 // Issue a continue command if this event will not cause the VM to start
6395 // running.
6396 if (!message.WillStartRunning()) {
6397 SendContinueCommand();
6398 }
6399 }
6400
6401
6402 // Test that a debug break can be scheduled while in a message handler.
TEST(DebugBreakInMessageHandler)6403 TEST(DebugBreakInMessageHandler) {
6404 i::FLAG_turbo_inlining = false; // Make sure g is not inlined into f.
6405 DebugLocalContext env;
6406 v8::HandleScope scope(env->GetIsolate());
6407
6408 v8::Debug::SetMessageHandler(env->GetIsolate(), DebugBreakMessageHandler);
6409
6410 v8::Local<v8::Context> context = env.context();
6411 // Test functions.
6412 const char* script = "function f() { debugger; g(); } function g() { }";
6413 CompileRun(script);
6414 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
6415 env->Global()
6416 ->Get(context, v8_str(env->GetIsolate(), "f"))
6417 .ToLocalChecked());
6418 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
6419 env->Global()
6420 ->Get(context, v8_str(env->GetIsolate(), "g"))
6421 .ToLocalChecked());
6422
6423 // Call f then g. The debugger statement in f will cause a break which will
6424 // cause another break.
6425 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
6426 CHECK_EQ(2, message_handler_break_hit_count);
6427 // Calling g will not cause any additional breaks.
6428 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
6429 CHECK_EQ(2, message_handler_break_hit_count);
6430 }
6431
6432
6433 #ifndef V8_INTERPRETED_REGEXP
6434 // Debug event handler which gets the function on the top frame and schedules a
6435 // break a number of times.
DebugEventDebugBreak(const v8::Debug::EventDetails & event_details)6436 static void DebugEventDebugBreak(
6437 const v8::Debug::EventDetails& event_details) {
6438 v8::DebugEvent event = event_details.GetEvent();
6439 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
6440 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
6441 if (event == v8::Break) {
6442 break_point_hit_count++;
6443
6444 // Get the name of the top frame function.
6445 if (!frame_function_name.IsEmpty()) {
6446 // Get the name of the function.
6447 const int argc = 2;
6448 v8::Local<v8::Value> argv[argc] = {
6449 exec_state, v8::Integer::New(CcTest::isolate(), 0)};
6450 v8::Local<v8::Value> result =
6451 frame_function_name->Call(context, exec_state, argc, argv)
6452 .ToLocalChecked();
6453 if (result->IsUndefined()) {
6454 last_function_hit[0] = '\0';
6455 } else {
6456 CHECK(result->IsString());
6457 v8::Local<v8::String> function_name(
6458 result->ToString(context).ToLocalChecked());
6459 function_name->WriteUtf8(last_function_hit);
6460 }
6461 }
6462
6463 // Keep forcing breaks.
6464 if (break_point_hit_count < 20) {
6465 v8::Debug::DebugBreak(CcTest::isolate());
6466 }
6467 }
6468 }
6469
6470
TEST(RegExpDebugBreak)6471 TEST(RegExpDebugBreak) {
6472 // This test only applies to native regexps.
6473 DebugLocalContext env;
6474 v8::HandleScope scope(env->GetIsolate());
6475 v8::Local<v8::Context> context = env.context();
6476 // Create a function for checking the function when hitting a break point.
6477 frame_function_name = CompileFunction(&env,
6478 frame_function_name_source,
6479 "frame_function_name");
6480
6481 // Test RegExp which matches white spaces and comments at the begining of a
6482 // source line.
6483 const char* script =
6484 "var sourceLineBeginningSkip = /^(?:[ \\v\\h]*(?:\\/\\*.*?\\*\\/)*)*/;\n"
6485 "function f(s) { return s.match(sourceLineBeginningSkip)[0].length; }";
6486
6487 v8::Local<v8::Function> f = CompileFunction(env->GetIsolate(), script, "f");
6488 const int argc = 1;
6489 v8::Local<v8::Value> argv[argc] = {
6490 v8_str(env->GetIsolate(), " /* xxx */ a=0;")};
6491 v8::Local<v8::Value> result =
6492 f->Call(context, env->Global(), argc, argv).ToLocalChecked();
6493 CHECK_EQ(12, result->Int32Value(context).FromJust());
6494
6495 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventDebugBreak);
6496 v8::Debug::DebugBreak(env->GetIsolate());
6497 result = f->Call(context, env->Global(), argc, argv).ToLocalChecked();
6498
6499 // Check that there was only one break event. Matching RegExp should not
6500 // cause Break events.
6501 CHECK_EQ(1, break_point_hit_count);
6502 CHECK_EQ(0, strcmp("f", last_function_hit));
6503 }
6504 #endif // V8_INTERPRETED_REGEXP
6505
6506
6507 // Common part of EvalContextData and NestedBreakEventContextData tests.
ExecuteScriptForContextCheck(v8::Debug::MessageHandler message_handler)6508 static void ExecuteScriptForContextCheck(
6509 v8::Debug::MessageHandler message_handler) {
6510 // Create a context.
6511 v8::Local<v8::Context> context_1;
6512 v8::Local<v8::ObjectTemplate> global_template =
6513 v8::Local<v8::ObjectTemplate>();
6514 context_1 =
6515 v8::Context::New(CcTest::isolate(), NULL, global_template);
6516
6517 v8::Debug::SetMessageHandler(CcTest::isolate(), message_handler);
6518
6519 // Default data value is undefined.
6520 CHECK(context_1->GetEmbedderData(0)->IsUndefined());
6521
6522 // Set and check a data value.
6523 v8::Local<v8::String> data_1 = v8_str(CcTest::isolate(), "1");
6524 context_1->SetEmbedderData(0, data_1);
6525 CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
6526
6527 // Simple test function with eval that causes a break.
6528 const char* source = "function f() { eval('debugger;'); }";
6529
6530 // Enter and run function in the context.
6531 {
6532 v8::Context::Scope context_scope(context_1);
6533 expected_context = context_1;
6534 expected_context_data = data_1;
6535 v8::Local<v8::Function> f = CompileFunction(CcTest::isolate(), source, "f");
6536 f->Call(context_1, context_1->Global(), 0, NULL).ToLocalChecked();
6537 }
6538
6539 v8::Debug::SetMessageHandler(CcTest::isolate(), nullptr);
6540 }
6541
6542
6543 // Test which creates a context and sets embedder data on it. Checks that this
6544 // data is set correctly and that when the debug message handler is called for
6545 // break event in an eval statement the expected context is the one returned by
6546 // Message.GetEventContext.
TEST(EvalContextData)6547 TEST(EvalContextData) {
6548 v8::HandleScope scope(CcTest::isolate());
6549
6550 ExecuteScriptForContextCheck(ContextCheckMessageHandler);
6551
6552 // One time compile event and one time break event.
6553 CHECK_GT(message_handler_hit_count, 2);
6554 CheckDebuggerUnloaded(CcTest::isolate());
6555 }
6556
6557
6558 static bool sent_eval = false;
6559 static int break_count = 0;
6560 static int continue_command_send_count = 0;
6561 // Check that the expected context is the one generating the debug event
6562 // including the case of nested break event.
DebugEvalContextCheckMessageHandler(const v8::Debug::Message & message)6563 static void DebugEvalContextCheckMessageHandler(
6564 const v8::Debug::Message& message) {
6565 CHECK(message.GetEventContext() == expected_context);
6566 CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals(
6567 expected_context_data));
6568 message_handler_hit_count++;
6569
6570 static char print_buffer[1000];
6571 v8::String::Value json(message.GetJSON());
6572 Utf16ToAscii(*json, json.length(), print_buffer);
6573
6574 v8::Isolate* isolate = message.GetIsolate();
6575 if (IsBreakEventMessage(print_buffer)) {
6576 break_count++;
6577 if (!sent_eval) {
6578 sent_eval = true;
6579
6580 const int kBufferSize = 1000;
6581 uint16_t buffer[kBufferSize];
6582 const char* eval_command =
6583 "{\"seq\":0,"
6584 "\"type\":\"request\","
6585 "\"command\":\"evaluate\","
6586 "\"arguments\":{\"expression\":\"debugger;\","
6587 "\"global\":true,\"disable_break\":false}}";
6588
6589 // Send evaluate command.
6590 v8::Debug::SendCommand(
6591 isolate, buffer, AsciiToUtf16(eval_command, buffer));
6592 return;
6593 } else {
6594 // It's a break event caused by the evaluation request above.
6595 SendContinueCommand();
6596 continue_command_send_count++;
6597 }
6598 } else if (IsEvaluateResponseMessage(print_buffer) &&
6599 continue_command_send_count < 2) {
6600 // Response to the evaluation request. We're still on the breakpoint so
6601 // send continue.
6602 SendContinueCommand();
6603 continue_command_send_count++;
6604 }
6605 }
6606
6607
6608 // Tests that context returned for break event is correct when the event occurs
6609 // in 'evaluate' debugger request.
TEST(NestedBreakEventContextData)6610 TEST(NestedBreakEventContextData) {
6611 v8::HandleScope scope(CcTest::isolate());
6612 break_count = 0;
6613 message_handler_hit_count = 0;
6614
6615 ExecuteScriptForContextCheck(DebugEvalContextCheckMessageHandler);
6616
6617 // One time compile event and two times break event.
6618 CHECK_GT(message_handler_hit_count, 3);
6619
6620 // One break from the source and another from the evaluate request.
6621 CHECK_EQ(break_count, 2);
6622 CheckDebuggerUnloaded(CcTest::isolate());
6623 }
6624
6625
6626 // Debug event listener which counts the after compile events.
6627 int after_compile_message_count = 0;
AfterCompileMessageHandler(const v8::Debug::Message & message)6628 static void AfterCompileMessageHandler(const v8::Debug::Message& message) {
6629 // Count the number of scripts collected.
6630 if (message.IsEvent()) {
6631 if (message.GetEvent() == v8::AfterCompile) {
6632 after_compile_message_count++;
6633 } else if (message.GetEvent() == v8::Break) {
6634 SendContinueCommand();
6635 }
6636 }
6637 }
6638
6639
6640 // Tests that after compile event is sent as many times as there are scripts
6641 // compiled.
TEST(AfterCompileMessageWhenMessageHandlerIsReset)6642 TEST(AfterCompileMessageWhenMessageHandlerIsReset) {
6643 DebugLocalContext env;
6644 v8::HandleScope scope(env->GetIsolate());
6645 v8::Local<v8::Context> context = env.context();
6646 after_compile_message_count = 0;
6647 const char* script = "var a=1";
6648
6649 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6650 v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
6651 .ToLocalChecked()
6652 ->Run(context)
6653 .ToLocalChecked();
6654 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6655
6656 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6657 v8::Debug::DebugBreak(env->GetIsolate());
6658 v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
6659 .ToLocalChecked()
6660 ->Run(context)
6661 .ToLocalChecked();
6662
6663 // Setting listener to NULL should cause debugger unload.
6664 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6665 CheckDebuggerUnloaded(env->GetIsolate());
6666
6667 // Compilation cache should be disabled when debugger is active.
6668 CHECK_EQ(2, after_compile_message_count);
6669 }
6670
6671
6672 // Syntax error event handler which counts a number of events.
6673 int compile_error_event_count = 0;
6674
CompileErrorEventCounterClear()6675 static void CompileErrorEventCounterClear() {
6676 compile_error_event_count = 0;
6677 }
6678
CompileErrorEventCounter(const v8::Debug::EventDetails & event_details)6679 static void CompileErrorEventCounter(
6680 const v8::Debug::EventDetails& event_details) {
6681 v8::DebugEvent event = event_details.GetEvent();
6682
6683 if (event == v8::CompileError) {
6684 compile_error_event_count++;
6685 }
6686 }
6687
6688
6689 // Tests that syntax error event is sent as many times as there are scripts
6690 // with syntax error compiled.
TEST(SyntaxErrorMessageOnSyntaxException)6691 TEST(SyntaxErrorMessageOnSyntaxException) {
6692 DebugLocalContext env;
6693 v8::HandleScope scope(env->GetIsolate());
6694
6695 // For this test, we want to break on uncaught exceptions:
6696 ChangeBreakOnException(false, true);
6697
6698 v8::Debug::SetDebugEventListener(env->GetIsolate(), CompileErrorEventCounter);
6699 v8::Local<v8::Context> context = env.context();
6700
6701 CompileErrorEventCounterClear();
6702
6703 // Check initial state.
6704 CHECK_EQ(0, compile_error_event_count);
6705
6706 // Throws SyntaxError: Unexpected end of input
6707 CHECK(
6708 v8::Script::Compile(context, v8_str(env->GetIsolate(), "+++")).IsEmpty());
6709 CHECK_EQ(1, compile_error_event_count);
6710
6711 CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "/sel\\/: \\"))
6712 .IsEmpty());
6713 CHECK_EQ(2, compile_error_event_count);
6714
6715 v8::Local<v8::Script> script =
6716 v8::Script::Compile(context,
6717 v8_str(env->GetIsolate(), "JSON.parse('1234:')"))
6718 .ToLocalChecked();
6719 CHECK_EQ(2, compile_error_event_count);
6720 CHECK(script->Run(context).IsEmpty());
6721 CHECK_EQ(3, compile_error_event_count);
6722
6723 v8::Script::Compile(context,
6724 v8_str(env->GetIsolate(), "new RegExp('/\\/\\\\');"))
6725 .ToLocalChecked();
6726 CHECK_EQ(3, compile_error_event_count);
6727
6728 v8::Script::Compile(context, v8_str(env->GetIsolate(), "throw 1;"))
6729 .ToLocalChecked();
6730 CHECK_EQ(3, compile_error_event_count);
6731 }
6732
6733
6734 // Tests that break event is sent when message handler is reset.
TEST(BreakMessageWhenMessageHandlerIsReset)6735 TEST(BreakMessageWhenMessageHandlerIsReset) {
6736 DebugLocalContext env;
6737 v8::HandleScope scope(env->GetIsolate());
6738 v8::Local<v8::Context> context = env.context();
6739 after_compile_message_count = 0;
6740 const char* script = "function f() {};";
6741
6742 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6743 v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
6744 .ToLocalChecked()
6745 ->Run(context)
6746 .ToLocalChecked();
6747 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6748
6749 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6750 v8::Debug::DebugBreak(env->GetIsolate());
6751 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
6752 env->Global()
6753 ->Get(context, v8_str(env->GetIsolate(), "f"))
6754 .ToLocalChecked());
6755 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
6756
6757 // Setting message handler to NULL should cause debugger unload.
6758 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6759 CheckDebuggerUnloaded(env->GetIsolate());
6760
6761 // Compilation cache should be disabled when debugger is active.
6762 CHECK_EQ(1, after_compile_message_count);
6763 }
6764
6765
6766 static int exception_event_count = 0;
ExceptionMessageHandler(const v8::Debug::Message & message)6767 static void ExceptionMessageHandler(const v8::Debug::Message& message) {
6768 if (message.IsEvent() && message.GetEvent() == v8::Exception) {
6769 exception_event_count++;
6770 SendContinueCommand();
6771 }
6772 }
6773
6774
6775 // Tests that exception event is sent when message handler is reset.
TEST(ExceptionMessageWhenMessageHandlerIsReset)6776 TEST(ExceptionMessageWhenMessageHandlerIsReset) {
6777 DebugLocalContext env;
6778 v8::HandleScope scope(env->GetIsolate());
6779
6780 v8::Local<v8::Context> context = env.context();
6781 // For this test, we want to break on uncaught exceptions:
6782 ChangeBreakOnException(false, true);
6783
6784 exception_event_count = 0;
6785 const char* script = "function f() {throw new Error()};";
6786
6787 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6788 v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
6789 .ToLocalChecked()
6790 ->Run(context)
6791 .ToLocalChecked();
6792 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6793
6794 v8::Debug::SetMessageHandler(env->GetIsolate(), ExceptionMessageHandler);
6795 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
6796 env->Global()
6797 ->Get(context, v8_str(env->GetIsolate(), "f"))
6798 .ToLocalChecked());
6799 CHECK(f->Call(context, env->Global(), 0, NULL).IsEmpty());
6800
6801 // Setting message handler to NULL should cause debugger unload.
6802 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6803 CheckDebuggerUnloaded(env->GetIsolate());
6804
6805 CHECK_EQ(1, exception_event_count);
6806 }
6807
6808
6809 // Tests after compile event is sent when there are some provisional
6810 // breakpoints out of the scripts lines range.
TEST(ProvisionalBreakpointOnLineOutOfRange)6811 TEST(ProvisionalBreakpointOnLineOutOfRange) {
6812 DebugLocalContext env;
6813 v8::HandleScope scope(env->GetIsolate());
6814 env.ExposeDebug();
6815 const char* script = "function f() {};";
6816 const char* resource_name = "test_resource";
6817
6818 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6819 v8::Local<v8::Context> context = env.context();
6820
6821 // Set a couple of provisional breakpoint on lines out of the script lines
6822 // range.
6823 int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name,
6824 3, -1 /* no column */);
6825 int sbp2 =
6826 SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, 5, 5);
6827
6828 after_compile_message_count = 0;
6829
6830 v8::ScriptOrigin origin(v8_str(env->GetIsolate(), resource_name),
6831 v8::Integer::New(env->GetIsolate(), 10),
6832 v8::Integer::New(env->GetIsolate(), 1));
6833 // Compile a script whose first line number is greater than the breakpoints'
6834 // lines.
6835 v8::Script::Compile(context, v8_str(env->GetIsolate(), script), &origin)
6836 .ToLocalChecked()
6837 ->Run(context)
6838 .ToLocalChecked();
6839
6840 // If the script is compiled successfully there is exactly one after compile
6841 // event. In case of an exception in debugger code after compile event is not
6842 // sent.
6843 CHECK_EQ(1, after_compile_message_count);
6844
6845 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
6846 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
6847 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6848 }
6849
6850
BreakMessageHandler(const v8::Debug::Message & message)6851 static void BreakMessageHandler(const v8::Debug::Message& message) {
6852 i::Isolate* isolate = CcTest::i_isolate();
6853 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6854 // Count the number of breaks.
6855 break_point_hit_count++;
6856
6857 i::HandleScope scope(isolate);
6858 message.GetJSON();
6859
6860 SendContinueCommand();
6861 } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
6862 i::HandleScope scope(isolate);
6863
6864 int current_count = break_point_hit_count;
6865
6866 // Force serialization to trigger some internal JS execution.
6867 message.GetJSON();
6868
6869 CHECK_EQ(current_count, break_point_hit_count);
6870 }
6871 }
6872
6873
6874 // Test that if DebugBreak is forced it is ignored when code from
6875 // debug-delay.js is executed.
TEST(NoDebugBreakInAfterCompileMessageHandler)6876 TEST(NoDebugBreakInAfterCompileMessageHandler) {
6877 DebugLocalContext env;
6878 v8::HandleScope scope(env->GetIsolate());
6879 v8::Local<v8::Context> context = env.context();
6880
6881 // Register a debug event listener which sets the break flag and counts.
6882 v8::Debug::SetMessageHandler(env->GetIsolate(), BreakMessageHandler);
6883
6884 // Set the debug break flag.
6885 v8::Debug::DebugBreak(env->GetIsolate());
6886
6887 // Create a function for testing stepping.
6888 const char* src = "function f() { eval('var x = 10;'); } ";
6889 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
6890
6891 // There should be only one break event.
6892 CHECK_EQ(1, break_point_hit_count);
6893
6894 // Set the debug break flag again.
6895 v8::Debug::DebugBreak(env->GetIsolate());
6896 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
6897 // There should be one more break event when the script is evaluated in 'f'.
6898 CHECK_EQ(2, break_point_hit_count);
6899
6900 // Get rid of the debug message handler.
6901 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6902 CheckDebuggerUnloaded(env->GetIsolate());
6903 }
6904
6905
6906 static int counting_message_handler_counter;
6907
CountingMessageHandler(const v8::Debug::Message & message)6908 static void CountingMessageHandler(const v8::Debug::Message& message) {
6909 if (message.IsResponse()) counting_message_handler_counter++;
6910 }
6911
6912
6913 // Test that debug messages get processed when ProcessDebugMessages is called.
TEST(ProcessDebugMessages)6914 TEST(ProcessDebugMessages) {
6915 DebugLocalContext env;
6916 v8::Isolate* isolate = env->GetIsolate();
6917 v8::HandleScope scope(isolate);
6918
6919 counting_message_handler_counter = 0;
6920
6921 v8::Debug::SetMessageHandler(isolate, CountingMessageHandler);
6922
6923 const int kBufferSize = 1000;
6924 uint16_t buffer[kBufferSize];
6925 const char* scripts_command =
6926 "{\"seq\":0,"
6927 "\"type\":\"request\","
6928 "\"command\":\"scripts\"}";
6929
6930 // Send scripts command.
6931 v8::Debug::SendCommand(
6932 isolate, buffer, AsciiToUtf16(scripts_command, buffer));
6933
6934 CHECK_EQ(0, counting_message_handler_counter);
6935 v8::Debug::ProcessDebugMessages(isolate);
6936 // At least one message should come
6937 CHECK_GE(counting_message_handler_counter, 1);
6938
6939 counting_message_handler_counter = 0;
6940
6941 v8::Debug::SendCommand(
6942 isolate, buffer, AsciiToUtf16(scripts_command, buffer));
6943 v8::Debug::SendCommand(
6944 isolate, buffer, AsciiToUtf16(scripts_command, buffer));
6945 CHECK_EQ(0, counting_message_handler_counter);
6946 v8::Debug::ProcessDebugMessages(isolate);
6947 // At least two messages should come
6948 CHECK_GE(counting_message_handler_counter, 2);
6949
6950 // Get rid of the debug message handler.
6951 v8::Debug::SetMessageHandler(isolate, nullptr);
6952 CheckDebuggerUnloaded(isolate);
6953 }
6954
6955
6956 class SendCommandThread;
6957 static SendCommandThread* send_command_thread_ = NULL;
6958
6959
6960 class SendCommandThread : public v8::base::Thread {
6961 public:
SendCommandThread(v8::Isolate * isolate)6962 explicit SendCommandThread(v8::Isolate* isolate)
6963 : Thread(Options("SendCommandThread")),
6964 semaphore_(0),
6965 isolate_(isolate) {}
6966
CountingAndSignallingMessageHandler(const v8::Debug::Message & message)6967 static void CountingAndSignallingMessageHandler(
6968 const v8::Debug::Message& message) {
6969 if (message.IsResponse()) {
6970 counting_message_handler_counter++;
6971 send_command_thread_->semaphore_.Signal();
6972 }
6973 }
6974
Run()6975 virtual void Run() {
6976 semaphore_.Wait();
6977 const int kBufferSize = 1000;
6978 uint16_t buffer[kBufferSize];
6979 const char* scripts_command =
6980 "{\"seq\":0,"
6981 "\"type\":\"request\","
6982 "\"command\":\"scripts\"}";
6983 int length = AsciiToUtf16(scripts_command, buffer);
6984 // Send scripts command.
6985
6986 for (int i = 0; i < 20; i++) {
6987 v8::base::ElapsedTimer timer;
6988 timer.Start();
6989 CHECK_EQ(i, counting_message_handler_counter);
6990 // Queue debug message.
6991 v8::Debug::SendCommand(isolate_, buffer, length);
6992 // Wait for the message handler to pick up the response.
6993 semaphore_.Wait();
6994 i::PrintF("iteration %d took %f ms\n", i,
6995 timer.Elapsed().InMillisecondsF());
6996 }
6997
6998 isolate_->TerminateExecution();
6999 }
7000
StartSending()7001 void StartSending() { semaphore_.Signal(); }
7002
7003 private:
7004 v8::base::Semaphore semaphore_;
7005 v8::Isolate* isolate_;
7006 };
7007
7008
StartSendingCommands(const v8::FunctionCallbackInfo<v8::Value> & info)7009 static void StartSendingCommands(
7010 const v8::FunctionCallbackInfo<v8::Value>& info) {
7011 send_command_thread_->StartSending();
7012 }
7013
7014
TEST(ProcessDebugMessagesThreaded)7015 TEST(ProcessDebugMessagesThreaded) {
7016 DebugLocalContext env;
7017 v8::Isolate* isolate = env->GetIsolate();
7018 v8::HandleScope scope(isolate);
7019 v8::Local<v8::Context> context = env.context();
7020
7021 counting_message_handler_counter = 0;
7022
7023 v8::Debug::SetMessageHandler(
7024 isolate, SendCommandThread::CountingAndSignallingMessageHandler);
7025 send_command_thread_ = new SendCommandThread(isolate);
7026 send_command_thread_->Start();
7027
7028 v8::Local<v8::FunctionTemplate> start =
7029 v8::FunctionTemplate::New(isolate, StartSendingCommands);
7030 CHECK(env->Global()
7031 ->Set(context, v8_str("start"),
7032 start->GetFunction(context).ToLocalChecked())
7033 .FromJust());
7034
7035 CompileRun("start(); while (true) { }");
7036
7037 CHECK_EQ(20, counting_message_handler_counter);
7038
7039 v8::Debug::SetMessageHandler(isolate, nullptr);
7040 CheckDebuggerUnloaded(isolate);
7041 }
7042
7043
7044 struct BacktraceData {
7045 static int frame_counter;
MessageHandlerBacktraceData7046 static void MessageHandler(const v8::Debug::Message& message) {
7047 char print_buffer[1000];
7048 v8::String::Value json(message.GetJSON());
7049 Utf16ToAscii(*json, json.length(), print_buffer, 1000);
7050
7051 if (strstr(print_buffer, "backtrace") == NULL) {
7052 return;
7053 }
7054 frame_counter = GetTotalFramesInt(print_buffer);
7055 }
7056 };
7057
7058 int BacktraceData::frame_counter;
7059
7060
7061 // Test that debug messages get processed when ProcessDebugMessages is called.
TEST(Backtrace)7062 TEST(Backtrace) {
7063 DebugLocalContext env;
7064 v8::Isolate* isolate = env->GetIsolate();
7065 v8::HandleScope scope(isolate);
7066 v8::Local<v8::Context> context = env.context();
7067
7068 v8::Debug::SetMessageHandler(isolate, BacktraceData::MessageHandler);
7069
7070 const int kBufferSize = 1000;
7071 uint16_t buffer[kBufferSize];
7072 const char* scripts_command =
7073 "{\"seq\":0,"
7074 "\"type\":\"request\","
7075 "\"command\":\"backtrace\"}";
7076
7077 // Check backtrace from ProcessDebugMessages.
7078 BacktraceData::frame_counter = -10;
7079 v8::Debug::SendCommand(
7080 isolate,
7081 buffer,
7082 AsciiToUtf16(scripts_command, buffer),
7083 NULL);
7084 v8::Debug::ProcessDebugMessages(isolate);
7085 CHECK_EQ(BacktraceData::frame_counter, 0);
7086
7087 v8::Local<v8::String> void0 = v8_str(env->GetIsolate(), "void(0)");
7088 v8::Local<v8::Script> script = CompileWithOrigin(void0, void0);
7089
7090 // Check backtrace from "void(0)" script.
7091 BacktraceData::frame_counter = -10;
7092 v8::Debug::SendCommand(
7093 isolate,
7094 buffer,
7095 AsciiToUtf16(scripts_command, buffer),
7096 NULL);
7097 script->Run(context).ToLocalChecked();
7098 CHECK_EQ(BacktraceData::frame_counter, 1);
7099
7100 // Get rid of the debug message handler.
7101 v8::Debug::SetMessageHandler(isolate, nullptr);
7102 CheckDebuggerUnloaded(isolate);
7103 }
7104
7105
TEST(GetMirror)7106 TEST(GetMirror) {
7107 DebugLocalContext env;
7108 v8::Isolate* isolate = env->GetIsolate();
7109 v8::HandleScope scope(isolate);
7110 v8::Local<v8::Context> context = env.context();
7111 v8::Local<v8::Value> obj =
7112 v8::Debug::GetMirror(context, v8_str(isolate, "hodja")).ToLocalChecked();
7113 v8::ScriptCompiler::Source source(v8_str(
7114 "function runTest(mirror) {"
7115 " return mirror.isString() && (mirror.length() == 5);"
7116 "}"
7117 ""
7118 "runTest;"));
7119 v8::Local<v8::Function> run_test = v8::Local<v8::Function>::Cast(
7120 v8::ScriptCompiler::CompileUnboundScript(isolate, &source)
7121 .ToLocalChecked()
7122 ->BindToCurrentContext()
7123 ->Run(context)
7124 .ToLocalChecked());
7125 v8::Local<v8::Value> result =
7126 run_test->Call(context, env->Global(), 1, &obj).ToLocalChecked();
7127 CHECK(result->IsTrue());
7128 }
7129
7130
7131 // Test that the debug break flag works with function.apply.
TEST(DebugBreakFunctionApply)7132 TEST(DebugBreakFunctionApply) {
7133 DebugLocalContext env;
7134 v8::HandleScope scope(env->GetIsolate());
7135 v8::Local<v8::Context> context = env.context();
7136
7137 // Create a function for testing breaking in apply.
7138 v8::Local<v8::Function> foo = CompileFunction(
7139 &env,
7140 "function baz(x) { }"
7141 "function bar(x) { baz(); }"
7142 "function foo(){ bar.apply(this, [1]); }",
7143 "foo");
7144
7145 // Register a debug event listener which steps and counts.
7146 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventBreakMax);
7147
7148 // Set the debug break flag before calling the code using function.apply.
7149 v8::Debug::DebugBreak(env->GetIsolate());
7150
7151 // Limit the number of debug breaks. This is a regression test for issue 493
7152 // where this test would enter an infinite loop.
7153 break_point_hit_count = 0;
7154 max_break_point_hit_count = 10000; // 10000 => infinite loop.
7155 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
7156
7157 // When keeping the debug break several break will happen.
7158 CHECK_GT(break_point_hit_count, 1);
7159
7160 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
7161 CheckDebuggerUnloaded(env->GetIsolate());
7162 }
7163
7164
7165 v8::Local<v8::Context> debugee_context;
7166 v8::Local<v8::Context> debugger_context;
7167
7168
7169 // Property getter that checks that current and calling contexts
7170 // are both the debugee contexts.
NamedGetterWithCallingContextCheck(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)7171 static void NamedGetterWithCallingContextCheck(
7172 v8::Local<v8::String> name,
7173 const v8::PropertyCallbackInfo<v8::Value>& info) {
7174 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(name), "a"));
7175 v8::Local<v8::Context> current = info.GetIsolate()->GetCurrentContext();
7176 CHECK(current == debugee_context);
7177 CHECK(current != debugger_context);
7178 info.GetReturnValue().Set(1);
7179 }
7180
7181
7182 // Debug event listener that checks if the first argument of a function is
7183 // an object with property 'a' == 1. If the property has custom accessor
7184 // this handler will eventually invoke it.
DebugEventGetAtgumentPropertyValue(const v8::Debug::EventDetails & event_details)7185 static void DebugEventGetAtgumentPropertyValue(
7186 const v8::Debug::EventDetails& event_details) {
7187 v8::DebugEvent event = event_details.GetEvent();
7188 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
7189 if (event == v8::Break) {
7190 break_point_hit_count++;
7191 CHECK(debugger_context == CcTest::isolate()->GetCurrentContext());
7192 v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(CompileRun(
7193 "(function(exec_state) {\n"
7194 " return (exec_state.frame(0).argumentValue(0).property('a').\n"
7195 " value().value() == 1);\n"
7196 "})"));
7197 const int argc = 1;
7198 v8::Local<v8::Value> argv[argc] = {exec_state};
7199 v8::Local<v8::Value> result =
7200 func->Call(debugger_context, exec_state, argc, argv).ToLocalChecked();
7201 CHECK(result->IsTrue());
7202 }
7203 }
7204
7205
TEST(CallingContextIsNotDebugContext)7206 TEST(CallingContextIsNotDebugContext) {
7207 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
7208 // Create and enter a debugee context.
7209 DebugLocalContext env;
7210 v8::Isolate* isolate = env->GetIsolate();
7211 v8::HandleScope scope(isolate);
7212 env.ExposeDebug();
7213
7214 // Save handles to the debugger and debugee contexts to be used in
7215 // NamedGetterWithCallingContextCheck.
7216 debugee_context = env.context();
7217 debugger_context = v8::Utils::ToLocal(debug->debug_context());
7218
7219 // Create object with 'a' property accessor.
7220 v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
7221 named->SetAccessor(v8_str(isolate, "a"), NamedGetterWithCallingContextCheck);
7222 CHECK(env->Global()
7223 ->Set(debugee_context, v8_str(isolate, "obj"),
7224 named->NewInstance(debugee_context).ToLocalChecked())
7225 .FromJust());
7226
7227 // Register the debug event listener
7228 v8::Debug::SetDebugEventListener(isolate, DebugEventGetAtgumentPropertyValue);
7229
7230 // Create a function that invokes debugger.
7231 v8::Local<v8::Function> foo = CompileFunction(
7232 &env,
7233 "function bar(x) { debugger; }"
7234 "function foo(){ bar(obj); }",
7235 "foo");
7236
7237 break_point_hit_count = 0;
7238 foo->Call(debugee_context, env->Global(), 0, NULL).ToLocalChecked();
7239 CHECK_EQ(1, break_point_hit_count);
7240
7241 v8::Debug::SetDebugEventListener(isolate, nullptr);
7242 debugee_context = v8::Local<v8::Context>();
7243 debugger_context = v8::Local<v8::Context>();
7244 CheckDebuggerUnloaded(isolate);
7245 }
7246
7247
TEST(DebugContextIsPreservedBetweenAccesses)7248 TEST(DebugContextIsPreservedBetweenAccesses) {
7249 v8::HandleScope scope(CcTest::isolate());
7250 v8::Debug::SetDebugEventListener(CcTest::isolate(),
7251 DebugEventBreakPointHitCount);
7252 v8::Local<v8::Context> context1 =
7253 v8::Debug::GetDebugContext(CcTest::isolate());
7254 v8::Local<v8::Context> context2 =
7255 v8::Debug::GetDebugContext(CcTest::isolate());
7256 CHECK(v8::Utils::OpenHandle(*context1).is_identical_to(
7257 v8::Utils::OpenHandle(*context2)));
7258 v8::Debug::SetDebugEventListener(CcTest::isolate(), nullptr);
7259 }
7260
7261
TEST(NoDebugContextWhenDebuggerDisabled)7262 TEST(NoDebugContextWhenDebuggerDisabled) {
7263 v8::HandleScope scope(CcTest::isolate());
7264 v8::Local<v8::Context> context =
7265 v8::Debug::GetDebugContext(CcTest::isolate());
7266 CHECK(context.IsEmpty());
7267 }
7268
7269
7270 static v8::Local<v8::Value> expected_callback_data;
DebugEventContextChecker(const v8::Debug::EventDetails & details)7271 static void DebugEventContextChecker(const v8::Debug::EventDetails& details) {
7272 CHECK(details.GetEventContext() == expected_context);
7273 CHECK(expected_callback_data->Equals(details.GetEventContext(),
7274 details.GetCallbackData())
7275 .FromJust());
7276 }
7277
7278
7279 // Check that event details contain context where debug event occured.
TEST(DebugEventContext)7280 TEST(DebugEventContext) {
7281 v8::Isolate* isolate = CcTest::isolate();
7282 v8::HandleScope scope(isolate);
7283 expected_context = v8::Context::New(isolate);
7284 expected_callback_data = v8::Int32::New(isolate, 2010);
7285 v8::Debug::SetDebugEventListener(isolate, DebugEventContextChecker,
7286 expected_callback_data);
7287 v8::Context::Scope context_scope(expected_context);
7288 v8::Script::Compile(expected_context,
7289 v8_str(isolate, "(function(){debugger;})();"))
7290 .ToLocalChecked()
7291 ->Run(expected_context)
7292 .ToLocalChecked();
7293 expected_context.Clear();
7294 v8::Debug::SetDebugEventListener(isolate, nullptr);
7295 expected_context_data = v8::Local<v8::Value>();
7296 CheckDebuggerUnloaded(isolate);
7297 }
7298
7299
7300 static bool debug_event_break_deoptimize_done = false;
7301
DebugEventBreakDeoptimize(const v8::Debug::EventDetails & event_details)7302 static void DebugEventBreakDeoptimize(
7303 const v8::Debug::EventDetails& event_details) {
7304 v8::DebugEvent event = event_details.GetEvent();
7305 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
7306 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
7307 if (event == v8::Break) {
7308 if (!frame_function_name.IsEmpty()) {
7309 // Get the name of the function.
7310 const int argc = 2;
7311 v8::Local<v8::Value> argv[argc] = {
7312 exec_state, v8::Integer::New(CcTest::isolate(), 0)};
7313 v8::Local<v8::Value> result =
7314 frame_function_name->Call(context, exec_state, argc, argv)
7315 .ToLocalChecked();
7316 if (!result->IsUndefined()) {
7317 char fn[80];
7318 CHECK(result->IsString());
7319 v8::Local<v8::String> function_name(
7320 result->ToString(context).ToLocalChecked());
7321 function_name->WriteUtf8(fn);
7322 if (strcmp(fn, "bar") == 0) {
7323 i::Deoptimizer::DeoptimizeAll(CcTest::i_isolate());
7324 debug_event_break_deoptimize_done = true;
7325 }
7326 }
7327 }
7328
7329 v8::Debug::DebugBreak(CcTest::isolate());
7330 }
7331 }
7332
7333
7334 // Test deoptimization when execution is broken using the debug break stack
7335 // check interrupt.
TEST(DeoptimizeDuringDebugBreak)7336 TEST(DeoptimizeDuringDebugBreak) {
7337 DebugLocalContext env;
7338 v8::HandleScope scope(env->GetIsolate());
7339 env.ExposeDebug();
7340 v8::Local<v8::Context> context = env.context();
7341
7342 // Create a function for checking the function when hitting a break point.
7343 frame_function_name = CompileFunction(&env,
7344 frame_function_name_source,
7345 "frame_function_name");
7346
7347 // Set a debug event listener which will keep interrupting execution until
7348 // debug break. When inside function bar it will deoptimize all functions.
7349 // This tests lazy deoptimization bailout for the stack check, as the first
7350 // time in function bar when using debug break and no break points will be at
7351 // the initial stack check.
7352 v8::Debug::SetDebugEventListener(env->GetIsolate(),
7353 DebugEventBreakDeoptimize);
7354
7355 // Compile and run function bar which will optimize it for some flag settings.
7356 v8::Local<v8::Function> f = CompileFunction(&env, "function bar(){}", "bar");
7357 f->Call(context, v8::Undefined(env->GetIsolate()), 0, NULL).ToLocalChecked();
7358
7359 // Set debug break and call bar again.
7360 v8::Debug::DebugBreak(env->GetIsolate());
7361 f->Call(context, v8::Undefined(env->GetIsolate()), 0, NULL).ToLocalChecked();
7362
7363 CHECK(debug_event_break_deoptimize_done);
7364
7365 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
7366 }
7367
7368
DebugEventBreakWithOptimizedStack(const v8::Debug::EventDetails & event_details)7369 static void DebugEventBreakWithOptimizedStack(
7370 const v8::Debug::EventDetails& event_details) {
7371 v8::Isolate* isolate = event_details.GetEventContext()->GetIsolate();
7372 v8::DebugEvent event = event_details.GetEvent();
7373 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
7374 v8::Local<v8::Context> context = isolate->GetCurrentContext();
7375 if (event == v8::Break) {
7376 if (!frame_function_name.IsEmpty()) {
7377 for (int i = 0; i < 2; i++) {
7378 const int argc = 2;
7379 v8::Local<v8::Value> argv[argc] = {exec_state,
7380 v8::Integer::New(isolate, i)};
7381 // Get the name of the function in frame i.
7382 v8::Local<v8::Value> result =
7383 frame_function_name->Call(context, exec_state, argc, argv)
7384 .ToLocalChecked();
7385 CHECK(result->IsString());
7386 v8::Local<v8::String> function_name(
7387 result->ToString(context).ToLocalChecked());
7388 CHECK(
7389 function_name->Equals(context, v8_str(isolate, "loop")).FromJust());
7390 // Get the name of the first argument in frame i.
7391 result = frame_argument_name->Call(context, exec_state, argc, argv)
7392 .ToLocalChecked();
7393 CHECK(result->IsString());
7394 v8::Local<v8::String> argument_name(
7395 result->ToString(context).ToLocalChecked());
7396 CHECK(argument_name->Equals(context, v8_str(isolate, "count"))
7397 .FromJust());
7398 // Get the value of the first argument in frame i. If the
7399 // funtion is optimized the value will be undefined, otherwise
7400 // the value will be '1 - i'.
7401 //
7402 // TODO(3141533): We should be able to get the real value for
7403 // optimized frames.
7404 result = frame_argument_value->Call(context, exec_state, argc, argv)
7405 .ToLocalChecked();
7406 CHECK(result->IsUndefined() ||
7407 (result->Int32Value(context).FromJust() == 1 - i));
7408 // Get the name of the first local variable.
7409 result = frame_local_name->Call(context, exec_state, argc, argv)
7410 .ToLocalChecked();
7411 CHECK(result->IsString());
7412 v8::Local<v8::String> local_name(
7413 result->ToString(context).ToLocalChecked());
7414 CHECK(local_name->Equals(context, v8_str(isolate, "local")).FromJust());
7415 // Get the value of the first local variable. If the function
7416 // is optimized the value will be undefined, otherwise it will
7417 // be 42.
7418 //
7419 // TODO(3141533): We should be able to get the real value for
7420 // optimized frames.
7421 result = frame_local_value->Call(context, exec_state, argc, argv)
7422 .ToLocalChecked();
7423 CHECK(result->IsUndefined() ||
7424 (result->Int32Value(context).FromJust() == 42));
7425 }
7426 }
7427 }
7428 }
7429
7430
ScheduleBreak(const v8::FunctionCallbackInfo<v8::Value> & args)7431 static void ScheduleBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
7432 v8::Debug::SetDebugEventListener(args.GetIsolate(),
7433 DebugEventBreakWithOptimizedStack);
7434 v8::Debug::DebugBreak(args.GetIsolate());
7435 }
7436
7437
TEST(DebugBreakStackInspection)7438 TEST(DebugBreakStackInspection) {
7439 DebugLocalContext env;
7440 v8::HandleScope scope(env->GetIsolate());
7441 v8::Local<v8::Context> context = env.context();
7442
7443 frame_function_name =
7444 CompileFunction(&env, frame_function_name_source, "frame_function_name");
7445 frame_argument_name =
7446 CompileFunction(&env, frame_argument_name_source, "frame_argument_name");
7447 frame_argument_value = CompileFunction(&env,
7448 frame_argument_value_source,
7449 "frame_argument_value");
7450 frame_local_name =
7451 CompileFunction(&env, frame_local_name_source, "frame_local_name");
7452 frame_local_value =
7453 CompileFunction(&env, frame_local_value_source, "frame_local_value");
7454
7455 v8::Local<v8::FunctionTemplate> schedule_break_template =
7456 v8::FunctionTemplate::New(env->GetIsolate(), ScheduleBreak);
7457 v8::Local<v8::Function> schedule_break =
7458 schedule_break_template->GetFunction(context).ToLocalChecked();
7459 CHECK(env->Global()
7460 ->Set(context, v8_str("scheduleBreak"), schedule_break)
7461 .FromJust());
7462
7463 const char* src =
7464 "function loop(count) {"
7465 " var local = 42;"
7466 " if (count < 1) { scheduleBreak(); loop(count + 1); }"
7467 "}"
7468 "loop(0);";
7469 v8::Script::Compile(context, v8_str(env->GetIsolate(), src))
7470 .ToLocalChecked()
7471 ->Run(context)
7472 .ToLocalChecked();
7473 }
7474
7475
7476 // Test that setting the terminate execution flag during debug break processing.
TestDebugBreakInLoop(const char * loop_head,const char ** loop_bodies,const char * loop_tail)7477 static void TestDebugBreakInLoop(const char* loop_head,
7478 const char** loop_bodies,
7479 const char* loop_tail) {
7480 // Receive 10 breaks for each test and then terminate JavaScript execution.
7481 static const int kBreaksPerTest = 10;
7482
7483 for (int i = 0; loop_bodies[i] != NULL; i++) {
7484 // Perform a lazy deoptimization after various numbers of breaks
7485 // have been hit.
7486
7487 EmbeddedVector<char, 1024> buffer;
7488 SNPrintF(buffer, "function f() {%s%s%s}", loop_head, loop_bodies[i],
7489 loop_tail);
7490
7491 i::PrintF("%s\n", buffer.start());
7492
7493 for (int j = 0; j < 3; j++) {
7494 break_point_hit_count_deoptimize = j;
7495 if (j == 2) {
7496 break_point_hit_count_deoptimize = kBreaksPerTest;
7497 }
7498
7499 break_point_hit_count = 0;
7500 max_break_point_hit_count = kBreaksPerTest;
7501 terminate_after_max_break_point_hit = true;
7502
7503 // Function with infinite loop.
7504 CompileRun(buffer.start());
7505
7506 // Set the debug break to enter the debugger as soon as possible.
7507 v8::Debug::DebugBreak(CcTest::isolate());
7508
7509 // Call function with infinite loop.
7510 CompileRun("f();");
7511 CHECK_EQ(kBreaksPerTest, break_point_hit_count);
7512
7513 CHECK(!CcTest::isolate()->IsExecutionTerminating());
7514 }
7515 }
7516 }
7517
7518
7519 static const char* loop_bodies_1[] = {"",
7520 "g()",
7521 "if (a == 0) { g() }",
7522 "if (a == 1) { g() }",
7523 "if (a == 0) { g() } else { h() }",
7524 "if (a == 0) { continue }",
7525 NULL};
7526
7527
7528 static const char* loop_bodies_2[] = {
7529 "if (a == 1) { continue }",
7530 "switch (a) { case 1: g(); }",
7531 "switch (a) { case 1: continue; }",
7532 "switch (a) { case 1: g(); break; default: h() }",
7533 "switch (a) { case 1: continue; break; default: h() }",
7534 NULL};
7535
7536
DebugBreakLoop(const char * loop_header,const char ** loop_bodies,const char * loop_footer)7537 void DebugBreakLoop(const char* loop_header, const char** loop_bodies,
7538 const char* loop_footer) {
7539 DebugLocalContext env;
7540 v8::HandleScope scope(env->GetIsolate());
7541
7542 // Register a debug event listener which sets the break flag and counts.
7543 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventBreakMax);
7544
7545 CompileRun(
7546 "var a = 1;\n"
7547 "function g() { }\n"
7548 "function h() { }");
7549
7550 TestDebugBreakInLoop(loop_header, loop_bodies, loop_footer);
7551
7552 // Get rid of the debug event listener.
7553 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
7554 CheckDebuggerUnloaded(env->GetIsolate());
7555 }
7556
7557
TEST(DebugBreakInWhileTrue1)7558 TEST(DebugBreakInWhileTrue1) {
7559 DebugBreakLoop("while (true) {", loop_bodies_1, "}");
7560 }
7561
7562
TEST(DebugBreakInWhileTrue2)7563 TEST(DebugBreakInWhileTrue2) {
7564 DebugBreakLoop("while (true) {", loop_bodies_2, "}");
7565 }
7566
7567
TEST(DebugBreakInWhileCondition1)7568 TEST(DebugBreakInWhileCondition1) {
7569 DebugBreakLoop("while (a == 1) {", loop_bodies_1, "}");
7570 }
7571
7572
TEST(DebugBreakInWhileCondition2)7573 TEST(DebugBreakInWhileCondition2) {
7574 DebugBreakLoop("while (a == 1) {", loop_bodies_2, "}");
7575 }
7576
7577
TEST(DebugBreakInDoWhileTrue1)7578 TEST(DebugBreakInDoWhileTrue1) {
7579 DebugBreakLoop("do {", loop_bodies_1, "} while (true)");
7580 }
7581
7582
TEST(DebugBreakInDoWhileTrue2)7583 TEST(DebugBreakInDoWhileTrue2) {
7584 DebugBreakLoop("do {", loop_bodies_2, "} while (true)");
7585 }
7586
7587
TEST(DebugBreakInDoWhileCondition1)7588 TEST(DebugBreakInDoWhileCondition1) {
7589 DebugBreakLoop("do {", loop_bodies_1, "} while (a == 1)");
7590 }
7591
7592
TEST(DebugBreakInDoWhileCondition2)7593 TEST(DebugBreakInDoWhileCondition2) {
7594 DebugBreakLoop("do {", loop_bodies_2, "} while (a == 1)");
7595 }
7596
7597
TEST(DebugBreakInFor1)7598 TEST(DebugBreakInFor1) { DebugBreakLoop("for (;;) {", loop_bodies_1, "}"); }
7599
7600
TEST(DebugBreakInFor2)7601 TEST(DebugBreakInFor2) { DebugBreakLoop("for (;;) {", loop_bodies_2, "}"); }
7602
7603
TEST(DebugBreakInForCondition1)7604 TEST(DebugBreakInForCondition1) {
7605 DebugBreakLoop("for (;a == 1;) {", loop_bodies_1, "}");
7606 }
7607
7608
TEST(DebugBreakInForCondition2)7609 TEST(DebugBreakInForCondition2) {
7610 DebugBreakLoop("for (;a == 1;) {", loop_bodies_2, "}");
7611 }
7612
7613
7614 v8::Local<v8::Script> inline_script;
7615
DebugBreakInlineListener(const v8::Debug::EventDetails & event_details)7616 static void DebugBreakInlineListener(
7617 const v8::Debug::EventDetails& event_details) {
7618 v8::DebugEvent event = event_details.GetEvent();
7619 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
7620 if (event != v8::Break) return;
7621
7622 int expected_frame_count = 4;
7623 int expected_line_number[] = {1, 4, 7, 12};
7624
7625 i::Handle<i::Object> compiled_script = v8::Utils::OpenHandle(*inline_script);
7626 i::Handle<i::Script> source_script = i::Handle<i::Script>(i::Script::cast(
7627 i::JSFunction::cast(*compiled_script)->shared()->script()));
7628
7629 int break_id = CcTest::i_isolate()->debug()->break_id();
7630 char script[128];
7631 i::Vector<char> script_vector(script, sizeof(script));
7632 SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
7633 v8::Local<v8::Value> result = CompileRun(script);
7634
7635 int frame_count = result->Int32Value(context).FromJust();
7636 CHECK_EQ(expected_frame_count, frame_count);
7637
7638 for (int i = 0; i < frame_count; i++) {
7639 // The 5. element in the returned array of GetFrameDetails contains the
7640 // source position of that frame.
7641 SNPrintF(script_vector, "%%GetFrameDetails(%d, %d)[5]", break_id, i);
7642 v8::Local<v8::Value> result = CompileRun(script);
7643 CHECK_EQ(expected_line_number[i],
7644 i::Script::GetLineNumber(source_script,
7645 result->Int32Value(context).FromJust()));
7646 }
7647 v8::Debug::SetDebugEventListener(CcTest::isolate(), nullptr);
7648 CcTest::isolate()->TerminateExecution();
7649 }
7650
7651
TEST(DebugBreakInline)7652 TEST(DebugBreakInline) {
7653 i::FLAG_allow_natives_syntax = true;
7654 DebugLocalContext env;
7655 v8::HandleScope scope(env->GetIsolate());
7656 v8::Local<v8::Context> context = env.context();
7657 const char* source =
7658 "function debug(b) { \n"
7659 " if (b) debugger; \n"
7660 "} \n"
7661 "function f(b) { \n"
7662 " debug(b) \n"
7663 "}; \n"
7664 "function g(b) { \n"
7665 " f(b); \n"
7666 "}; \n"
7667 "g(false); \n"
7668 "g(false); \n"
7669 "%OptimizeFunctionOnNextCall(g); \n"
7670 "g(true);";
7671 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugBreakInlineListener);
7672 inline_script =
7673 v8::Script::Compile(context, v8_str(env->GetIsolate(), source))
7674 .ToLocalChecked();
7675 inline_script->Run(context).ToLocalChecked();
7676 }
7677
7678
DebugEventStepNext(const v8::Debug::EventDetails & event_details)7679 static void DebugEventStepNext(
7680 const v8::Debug::EventDetails& event_details) {
7681 v8::DebugEvent event = event_details.GetEvent();
7682 if (event == v8::Break) {
7683 PrepareStep(StepNext);
7684 }
7685 }
7686
7687
RunScriptInANewCFrame(const char * source)7688 static void RunScriptInANewCFrame(const char* source) {
7689 v8::TryCatch try_catch(CcTest::isolate());
7690 CompileRun(source);
7691 CHECK(try_catch.HasCaught());
7692 }
7693
7694
TEST(Regress131642)7695 TEST(Regress131642) {
7696 // Bug description:
7697 // When doing StepNext through the first script, the debugger is not reset
7698 // after exiting through exception. A flawed implementation enabling the
7699 // debugger to step into Array.prototype.forEach breaks inside the callback
7700 // for forEach in the second script under the assumption that we are in a
7701 // recursive call. In an attempt to step out, we crawl the stack using the
7702 // recorded frame pointer from the first script and fail when not finding it
7703 // on the stack.
7704 DebugLocalContext env;
7705 v8::HandleScope scope(env->GetIsolate());
7706 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepNext);
7707
7708 // We step through the first script. It exits through an exception. We run
7709 // this inside a new frame to record a different FP than the second script
7710 // would expect.
7711 const char* script_1 = "debugger; throw new Error();";
7712 RunScriptInANewCFrame(script_1);
7713
7714 // The second script uses forEach.
7715 const char* script_2 = "[0].forEach(function() { });";
7716 CompileRun(script_2);
7717
7718 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
7719 }
7720
7721
7722 // Import from test-heap.cc
7723 namespace v8 {
7724 namespace internal {
7725
7726 int CountNativeContexts();
7727 }
7728 }
7729
7730
NopListener(const v8::Debug::EventDetails & event_details)7731 static void NopListener(const v8::Debug::EventDetails& event_details) {
7732 }
7733
7734
TEST(DebuggerCreatesContextIffActive)7735 TEST(DebuggerCreatesContextIffActive) {
7736 DebugLocalContext env;
7737 v8::HandleScope scope(env->GetIsolate());
7738 CHECK_EQ(1, v8::internal::CountNativeContexts());
7739
7740 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
7741 CompileRun("debugger;");
7742 CHECK_EQ(1, v8::internal::CountNativeContexts());
7743
7744 v8::Debug::SetDebugEventListener(env->GetIsolate(), NopListener);
7745 CompileRun("debugger;");
7746 CHECK_EQ(2, v8::internal::CountNativeContexts());
7747
7748 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
7749 }
7750
7751
TEST(LiveEditEnabled)7752 TEST(LiveEditEnabled) {
7753 v8::internal::FLAG_allow_natives_syntax = true;
7754 LocalContext env;
7755 v8::HandleScope scope(env->GetIsolate());
7756 v8::Debug::SetLiveEditEnabled(env->GetIsolate(), true);
7757 CompileRun("%LiveEditCompareStrings('', '')");
7758 }
7759
7760
TEST(LiveEditDisabled)7761 TEST(LiveEditDisabled) {
7762 v8::internal::FLAG_allow_natives_syntax = true;
7763 LocalContext env;
7764 v8::HandleScope scope(env->GetIsolate());
7765 v8::Debug::SetLiveEditEnabled(env->GetIsolate(), false);
7766 CompileRun("%LiveEditCompareStrings('', '')");
7767 }
7768
7769
TEST(PrecompiledFunction)7770 TEST(PrecompiledFunction) {
7771 // Regression test for crbug.com/346207. If we have preparse data, parsing the
7772 // function in the presence of the debugger (and breakpoints) should still
7773 // succeed. The bug was that preparsing was done lazily and parsing was done
7774 // eagerly, so, the symbol streams didn't match.
7775 DebugLocalContext env;
7776 v8::HandleScope scope(env->GetIsolate());
7777 env.ExposeDebug();
7778 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugBreakInlineListener);
7779
7780 v8::Local<v8::Function> break_here =
7781 CompileFunction(&env, "function break_here(){}", "break_here");
7782 SetBreakPoint(break_here, 0);
7783
7784 const char* source =
7785 "var a = b = c = 1; \n"
7786 "function this_is_lazy() { \n"
7787 // This symbol won't appear in the preparse data.
7788 " var a; \n"
7789 "} \n"
7790 "function bar() { \n"
7791 " return \"bar\"; \n"
7792 "}; \n"
7793 "a = b = c = 2; \n"
7794 "bar(); \n";
7795 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
7796 CHECK(result->IsString());
7797 v8::String::Utf8Value utf8(result);
7798 CHECK_EQ(0, strcmp("bar", *utf8));
7799
7800 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
7801 CheckDebuggerUnloaded(env->GetIsolate());
7802 }
7803
7804
DebugBreakStackTraceListener(const v8::Debug::EventDetails & event_details)7805 static void DebugBreakStackTraceListener(
7806 const v8::Debug::EventDetails& event_details) {
7807 v8::StackTrace::CurrentStackTrace(CcTest::isolate(), 10);
7808 }
7809
7810
AddDebugBreak(const v8::FunctionCallbackInfo<v8::Value> & args)7811 static void AddDebugBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
7812 v8::Debug::DebugBreak(args.GetIsolate());
7813 }
7814
7815
TEST(DebugBreakStackTrace)7816 TEST(DebugBreakStackTrace) {
7817 DebugLocalContext env;
7818 v8::HandleScope scope(env->GetIsolate());
7819 v8::Debug::SetDebugEventListener(env->GetIsolate(),
7820 DebugBreakStackTraceListener);
7821 v8::Local<v8::Context> context = env.context();
7822 v8::Local<v8::FunctionTemplate> add_debug_break_template =
7823 v8::FunctionTemplate::New(env->GetIsolate(), AddDebugBreak);
7824 v8::Local<v8::Function> add_debug_break =
7825 add_debug_break_template->GetFunction(context).ToLocalChecked();
7826 CHECK(env->Global()
7827 ->Set(context, v8_str("add_debug_break"), add_debug_break)
7828 .FromJust());
7829
7830 CompileRun("(function loop() {"
7831 " for (var j = 0; j < 1000; j++) {"
7832 " for (var i = 0; i < 1000; i++) {"
7833 " if (i == 999) add_debug_break();"
7834 " }"
7835 " }"
7836 "})()");
7837 }
7838
7839
7840 v8::base::Semaphore terminate_requested_semaphore(0);
7841 v8::base::Semaphore terminate_fired_semaphore(0);
7842 bool terminate_already_fired = false;
7843
7844
DebugBreakTriggerTerminate(const v8::Debug::EventDetails & event_details)7845 static void DebugBreakTriggerTerminate(
7846 const v8::Debug::EventDetails& event_details) {
7847 if (event_details.GetEvent() != v8::Break || terminate_already_fired) return;
7848 terminate_requested_semaphore.Signal();
7849 // Wait for at most 2 seconds for the terminate request.
7850 CHECK(terminate_fired_semaphore.WaitFor(v8::base::TimeDelta::FromSeconds(2)));
7851 terminate_already_fired = true;
7852 }
7853
7854
7855 class TerminationThread : public v8::base::Thread {
7856 public:
TerminationThread(v8::Isolate * isolate)7857 explicit TerminationThread(v8::Isolate* isolate)
7858 : Thread(Options("terminator")), isolate_(isolate) {}
7859
Run()7860 virtual void Run() {
7861 terminate_requested_semaphore.Wait();
7862 isolate_->TerminateExecution();
7863 terminate_fired_semaphore.Signal();
7864 }
7865
7866 private:
7867 v8::Isolate* isolate_;
7868 };
7869
7870
TEST(DebugBreakOffThreadTerminate)7871 TEST(DebugBreakOffThreadTerminate) {
7872 DebugLocalContext env;
7873 v8::Isolate* isolate = env->GetIsolate();
7874 v8::HandleScope scope(isolate);
7875 v8::Debug::SetDebugEventListener(isolate, DebugBreakTriggerTerminate);
7876 TerminationThread terminator(isolate);
7877 terminator.Start();
7878 v8::TryCatch try_catch(env->GetIsolate());
7879 v8::Debug::DebugBreak(isolate);
7880 CompileRun("while (true);");
7881 CHECK(try_catch.HasTerminated());
7882 }
7883
7884
DebugEventExpectNoException(const v8::Debug::EventDetails & event_details)7885 static void DebugEventExpectNoException(
7886 const v8::Debug::EventDetails& event_details) {
7887 v8::DebugEvent event = event_details.GetEvent();
7888 CHECK_NE(v8::Exception, event);
7889 }
7890
7891
TryCatchWrappedThrowCallback(const v8::FunctionCallbackInfo<v8::Value> & args)7892 static void TryCatchWrappedThrowCallback(
7893 const v8::FunctionCallbackInfo<v8::Value>& args) {
7894 v8::TryCatch try_catch(args.GetIsolate());
7895 CompileRun("throw 'rejection';");
7896 CHECK(try_catch.HasCaught());
7897 }
7898
7899
TEST(DebugPromiseInterceptedByTryCatch)7900 TEST(DebugPromiseInterceptedByTryCatch) {
7901 DebugLocalContext env;
7902 v8::Isolate* isolate = env->GetIsolate();
7903 v8::HandleScope scope(isolate);
7904 v8::Debug::SetDebugEventListener(isolate, &DebugEventExpectNoException);
7905 v8::Local<v8::Context> context = env.context();
7906 ChangeBreakOnException(false, true);
7907
7908 v8::Local<v8::FunctionTemplate> fun =
7909 v8::FunctionTemplate::New(isolate, TryCatchWrappedThrowCallback);
7910 CHECK(env->Global()
7911 ->Set(context, v8_str("fun"),
7912 fun->GetFunction(context).ToLocalChecked())
7913 .FromJust());
7914
7915 CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
7916 CompileRun(
7917 "var r;"
7918 "p.chain(function() { r = 'resolved'; },"
7919 " function() { r = 'rejected'; });");
7920 CHECK(CompileRun("r")->Equals(context, v8_str("resolved")).FromJust());
7921 }
7922
7923
7924 static int exception_event_counter = 0;
7925
7926
DebugEventCountException(const v8::Debug::EventDetails & event_details)7927 static void DebugEventCountException(
7928 const v8::Debug::EventDetails& event_details) {
7929 v8::DebugEvent event = event_details.GetEvent();
7930 if (event == v8::Exception) exception_event_counter++;
7931 }
7932
7933
ThrowCallback(const v8::FunctionCallbackInfo<v8::Value> & args)7934 static void ThrowCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
7935 CompileRun("throw 'rejection';");
7936 }
7937
7938
TEST(DebugPromiseRejectedByCallback)7939 TEST(DebugPromiseRejectedByCallback) {
7940 DebugLocalContext env;
7941 v8::Isolate* isolate = env->GetIsolate();
7942 v8::HandleScope scope(isolate);
7943 v8::Debug::SetDebugEventListener(isolate, &DebugEventCountException);
7944 v8::Local<v8::Context> context = env.context();
7945 ChangeBreakOnException(false, true);
7946 exception_event_counter = 0;
7947
7948 v8::Local<v8::FunctionTemplate> fun =
7949 v8::FunctionTemplate::New(isolate, ThrowCallback);
7950 CHECK(env->Global()
7951 ->Set(context, v8_str("fun"),
7952 fun->GetFunction(context).ToLocalChecked())
7953 .FromJust());
7954
7955 CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
7956 CompileRun(
7957 "var r;"
7958 "p.chain(function() { r = 'resolved'; },"
7959 " function(e) { r = 'rejected' + e; });");
7960 CHECK(
7961 CompileRun("r")->Equals(context, v8_str("rejectedrejection")).FromJust());
7962 CHECK_EQ(1, exception_event_counter);
7963 }
7964
7965
TEST(DebugBreakOnExceptionInObserveCallback)7966 TEST(DebugBreakOnExceptionInObserveCallback) {
7967 i::FLAG_harmony_object_observe = true;
7968 DebugLocalContext env;
7969 v8::Isolate* isolate = env->GetIsolate();
7970 v8::HandleScope scope(isolate);
7971 v8::Debug::SetDebugEventListener(isolate, &DebugEventCountException);
7972 v8::Local<v8::Context> context = env.context();
7973 // Break on uncaught exception
7974 ChangeBreakOnException(false, true);
7975 exception_event_counter = 0;
7976
7977 v8::Local<v8::FunctionTemplate> fun =
7978 v8::FunctionTemplate::New(isolate, ThrowCallback);
7979 CHECK(env->Global()
7980 ->Set(context, v8_str("fun"),
7981 fun->GetFunction(context).ToLocalChecked())
7982 .FromJust());
7983
7984 CompileRun(
7985 "var obj = {};"
7986 "var callbackRan = false;"
7987 "Object.observe(obj, function() {"
7988 " callbackRan = true;"
7989 " throw Error('foo');"
7990 "});"
7991 "obj.prop = 1");
7992 CHECK(CompileRun("callbackRan")->BooleanValue(context).FromJust());
7993 CHECK_EQ(1, exception_event_counter);
7994 }
7995
7996
DebugHarmonyScopingListener(const v8::Debug::EventDetails & event_details)7997 static void DebugHarmonyScopingListener(
7998 const v8::Debug::EventDetails& event_details) {
7999 v8::DebugEvent event = event_details.GetEvent();
8000 if (event != v8::Break) return;
8001
8002 int break_id = CcTest::i_isolate()->debug()->break_id();
8003
8004 char script[128];
8005 i::Vector<char> script_vector(script, sizeof(script));
8006 SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
8007 ExpectInt32(script, 1);
8008
8009 SNPrintF(script_vector, "var frame = new FrameMirror(%d, 0);", break_id);
8010 CompileRun(script);
8011 ExpectInt32("frame.evaluate('x').value_", 1);
8012 ExpectInt32("frame.evaluate('y').value_", 2);
8013
8014 CompileRun("var allScopes = frame.allScopes()");
8015 ExpectInt32("allScopes.length", 2);
8016
8017 ExpectBoolean("allScopes[0].scopeType() === ScopeType.Script", true);
8018
8019 ExpectInt32("allScopes[0].scopeObject().value_.x", 1);
8020
8021 ExpectInt32("allScopes[0].scopeObject().value_.y", 2);
8022
8023 CompileRun("allScopes[0].setVariableValue('x', 5);");
8024 CompileRun("allScopes[0].setVariableValue('y', 6);");
8025 ExpectInt32("frame.evaluate('x + y').value_", 11);
8026 }
8027
8028
TEST(DebugBreakInLexicalScopes)8029 TEST(DebugBreakInLexicalScopes) {
8030 i::FLAG_allow_natives_syntax = true;
8031
8032 DebugLocalContext env;
8033 v8::Isolate* isolate = env->GetIsolate();
8034 v8::HandleScope scope(isolate);
8035 v8::Debug::SetDebugEventListener(isolate, DebugHarmonyScopingListener);
8036
8037 CompileRun(
8038 "'use strict'; \n"
8039 "let x = 1; \n");
8040 ExpectInt32(
8041 "'use strict'; \n"
8042 "let y = 2; \n"
8043 "debugger; \n"
8044 "x * y",
8045 30);
8046 ExpectInt32(
8047 "x = 1; y = 2; \n"
8048 "debugger;"
8049 "x * y",
8050 30);
8051 }
8052
8053 static int after_compile_handler_depth = 0;
HandleInterrupt(v8::Isolate * isolate,void * data)8054 static void HandleInterrupt(v8::Isolate* isolate, void* data) {
8055 CHECK_EQ(0, after_compile_handler_depth);
8056 }
8057
NoInterruptsOnDebugEvent(const v8::Debug::EventDetails & event_details)8058 static void NoInterruptsOnDebugEvent(
8059 const v8::Debug::EventDetails& event_details) {
8060 if (event_details.GetEvent() != v8::AfterCompile) return;
8061 ++after_compile_handler_depth;
8062 // Do not allow nested AfterCompile events.
8063 CHECK(after_compile_handler_depth <= 1);
8064 v8::Isolate* isolate = event_details.GetEventContext()->GetIsolate();
8065 isolate->RequestInterrupt(&HandleInterrupt, nullptr);
8066 CompileRun("function foo() {}; foo();");
8067 --after_compile_handler_depth;
8068 }
8069
8070
TEST(NoInterruptsInDebugListener)8071 TEST(NoInterruptsInDebugListener) {
8072 DebugLocalContext env;
8073 v8::Debug::SetDebugEventListener(env->GetIsolate(), NoInterruptsOnDebugEvent);
8074 CompileRun("void(0);");
8075 }
8076