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