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