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: 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 } 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 } 94 inline ~DebugLocalContext() { 95 context_->Exit(); 96 } 97 inline v8::Local<v8::Context> context() { return context_; } 98 inline v8::Context* operator->() { return *context_; } 99 inline v8::Context* operator*() { return *context_; } 100 inline v8::Isolate* GetIsolate() { return context_->GetIsolate(); } 101 inline bool IsReady() { return !context_.IsEmpty(); } 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. 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. 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? 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. 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. 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. 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. 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. 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. 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. 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 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 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 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 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. 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. 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. 342 static void PrepareStep(StepAction step_action) { 343 v8::internal::Debug* debug = CcTest::i_isolate()->debug(); 344 debug->PrepareStep(step_action); 345 } 346 347 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. 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. 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. 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; 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 615 static void DebugEventCounterClear() { 616 break_point_hit_count = 0; 617 exception_hit_count = 0; 618 uncaught_exception_hit_count = 0; 619 } 620 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. 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; 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. 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. 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. 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. 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; 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 894 static void MessageCallbackCountClear() { 895 message_callback_count = 0; 896 } 897 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. 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. 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. 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. 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. 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. 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. 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 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. 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. 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. 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. 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. 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 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. 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. 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. 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. 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 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. 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. 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. 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. 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. 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. 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. 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. 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; 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. 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; 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. 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. 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. 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. 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 2643 void reset() { 2644 counter = 0; 2645 } 2646 EvaluateResult* current() { 2647 return &results[counter % kArraySize]; 2648 } 2649 void next() { 2650 counter++; 2651 } 2652 }; 2653 2654 DebugProcessDebugMessagesData process_debug_messages_data; 2655 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. 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. 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. 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. 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. 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 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. 2967 TEST(DebugStepNamedStoreLoop) { DoDebugStepNamedStoreLoop(34); } 2968 2969 2970 // Test the stepping mechanism with different ICs. 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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. 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. 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. 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. 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. 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 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. 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 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 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 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. 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 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 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. 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 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. 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 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 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 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 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 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 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 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 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 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 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 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: 4995 ThreadBarrier() : num_blocked_(0) {} 4996 4997 ~ThreadBarrier() { 4998 LockGuard<Mutex> lock_guard(&mutex_); 4999 if (num_blocked_ != 0) { 5000 CHECK_EQ(N, num_blocked_); 5001 } 5002 } 5003 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: 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. 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. 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. 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 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. 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. 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. 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. 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: 5144 MessageQueueDebuggerThread() 5145 : Thread(Options("MessageQueueDebuggerThread")) {} 5146 void Run(); 5147 }; 5148 5149 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 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. 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: 5279 TestClientData() { 5280 constructor_call_counter++; 5281 } 5282 virtual ~TestClientData() { 5283 destructor_call_counter++; 5284 } 5285 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. 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; 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. 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: 5401 V8Thread() : Thread(Options("V8Thread")) {} 5402 void Run(); 5403 v8::Isolate* isolate() { return isolate_; } 5404 5405 private: 5406 v8::Isolate* isolate_; 5407 }; 5408 5409 class DebuggerThread : public v8::base::Thread { 5410 public: 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 5420 static void ThreadedAtBarrier1( 5421 const v8::FunctionCallbackInfo<v8::Value>& args) { 5422 threaded_debugging_barriers.barrier_1.Wait(); 5423 } 5424 5425 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 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 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 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: 5525 BreakpointsV8Thread() : Thread(Options("BreakpointsV8Thread")) {} 5526 void Run(); 5527 5528 v8::Isolate* isolate() { return isolate_; } 5529 5530 private: 5531 v8::Isolate* isolate_; 5532 }; 5533 5534 class BreakpointsDebuggerThread : public v8::base::Thread { 5535 public: 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 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 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 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 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 5742 TEST(RecursiveBreakpoints) { 5743 TestRecursiveBreakpointsGeneric(false); 5744 } 5745 5746 5747 TEST(RecursiveBreakpointsGlobal) { 5748 TestRecursiveBreakpointsGeneric(true); 5749 } 5750 5751 5752 TEST(SetDebugEventListenerOnUninitializedVM) { 5753 v8::Debug::SetDebugEventListener(CcTest::isolate(), DummyDebugEventListener); 5754 } 5755 5756 5757 static void DummyMessageHandler(const v8::Debug::Message& message) { 5758 } 5759 5760 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. 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. 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. 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. 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. 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(); 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. 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. 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; 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. 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. 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. 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: 6157 EmptyExternalStringResource() { empty_[0] = 0; } 6158 virtual ~EmptyExternalStringResource() {} 6159 virtual size_t length() const { return empty_.length(); } 6160 virtual const uint16_t* data() const { return empty_.start(); } 6161 private: 6162 ::v8::internal::EmbeddedVector<uint16_t, 1> empty_; 6163 }; 6164 6165 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. 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. 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. 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; 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. 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. 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 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. 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. 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. 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. 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; 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. 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 6675 static void CompileErrorEventCounterClear() { 6676 compile_error_event_count = 0; 6677 } 6678 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. 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. 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; 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. 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. 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 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. 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 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. 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: 6962 explicit SendCommandThread(v8::Isolate* isolate) 6963 : Thread(Options("SendCommandThread")), 6964 semaphore_(0), 6965 isolate_(isolate) {} 6966 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 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 7001 void StartSending() { semaphore_.Signal(); } 7002 7003 private: 7004 v8::base::Semaphore semaphore_; 7005 v8::Isolate* isolate_; 7006 }; 7007 7008 7009 static void StartSendingCommands( 7010 const v8::FunctionCallbackInfo<v8::Value>& info) { 7011 send_command_thread_->StartSending(); 7012 } 7013 7014 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; 7046 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. 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 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. 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. 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. 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 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 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 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; 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. 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 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. 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 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 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 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. 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 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 7558 TEST(DebugBreakInWhileTrue1) { 7559 DebugBreakLoop("while (true) {", loop_bodies_1, "}"); 7560 } 7561 7562 7563 TEST(DebugBreakInWhileTrue2) { 7564 DebugBreakLoop("while (true) {", loop_bodies_2, "}"); 7565 } 7566 7567 7568 TEST(DebugBreakInWhileCondition1) { 7569 DebugBreakLoop("while (a == 1) {", loop_bodies_1, "}"); 7570 } 7571 7572 7573 TEST(DebugBreakInWhileCondition2) { 7574 DebugBreakLoop("while (a == 1) {", loop_bodies_2, "}"); 7575 } 7576 7577 7578 TEST(DebugBreakInDoWhileTrue1) { 7579 DebugBreakLoop("do {", loop_bodies_1, "} while (true)"); 7580 } 7581 7582 7583 TEST(DebugBreakInDoWhileTrue2) { 7584 DebugBreakLoop("do {", loop_bodies_2, "} while (true)"); 7585 } 7586 7587 7588 TEST(DebugBreakInDoWhileCondition1) { 7589 DebugBreakLoop("do {", loop_bodies_1, "} while (a == 1)"); 7590 } 7591 7592 7593 TEST(DebugBreakInDoWhileCondition2) { 7594 DebugBreakLoop("do {", loop_bodies_2, "} while (a == 1)"); 7595 } 7596 7597 7598 TEST(DebugBreakInFor1) { DebugBreakLoop("for (;;) {", loop_bodies_1, "}"); } 7599 7600 7601 TEST(DebugBreakInFor2) { DebugBreakLoop("for (;;) {", loop_bodies_2, "}"); } 7602 7603 7604 TEST(DebugBreakInForCondition1) { 7605 DebugBreakLoop("for (;a == 1;) {", loop_bodies_1, "}"); 7606 } 7607 7608 7609 TEST(DebugBreakInForCondition2) { 7610 DebugBreakLoop("for (;a == 1;) {", loop_bodies_2, "}"); 7611 } 7612 7613 7614 v8::Local<v8::Script> inline_script; 7615 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 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 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 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 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 7731 static void NopListener(const v8::Debug::EventDetails& event_details) { 7732 } 7733 7734 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 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 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 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 7805 static void DebugBreakStackTraceListener( 7806 const v8::Debug::EventDetails& event_details) { 7807 v8::StackTrace::CurrentStackTrace(CcTest::isolate(), 10); 7808 } 7809 7810 7811 static void AddDebugBreak(const v8::FunctionCallbackInfo<v8::Value>& args) { 7812 v8::Debug::DebugBreak(args.GetIsolate()); 7813 } 7814 7815 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 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: 7857 explicit TerminationThread(v8::Isolate* isolate) 7858 : Thread(Options("terminator")), isolate_(isolate) {} 7859 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 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 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 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 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 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 7934 static void ThrowCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 7935 CompileRun("throw 'rejection';"); 7936 } 7937 7938 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 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 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 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; 8054 static void HandleInterrupt(v8::Isolate* isolate, void* data) { 8055 CHECK_EQ(0, after_compile_handler_depth); 8056 } 8057 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 8071 TEST(NoInterruptsInDebugListener) { 8072 DebugLocalContext env; 8073 v8::Debug::SetDebugEventListener(env->GetIsolate(), NoInterruptsOnDebugEvent); 8074 CompileRun("void(0);"); 8075 } 8076