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