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