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