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