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