1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "api.h" 31 #include "arguments.h" 32 #include "bootstrapper.h" 33 #include "code-stubs.h" 34 #include "codegen.h" 35 #include "compilation-cache.h" 36 #include "compiler.h" 37 #include "debug.h" 38 #include "execution.h" 39 #include "global-handles.h" 40 #include "ic.h" 41 #include "ic-inl.h" 42 #include "natives.h" 43 #include "stub-cache.h" 44 #include "log.h" 45 46 #include "../include/v8-debug.h" 47 48 namespace v8 { 49 namespace internal { 50 51 #ifdef ENABLE_DEBUGGER_SUPPORT 52 static void PrintLn(v8::Local<v8::Value> value) { 53 v8::Local<v8::String> s = value->ToString(); 54 char* data = NewArray<char>(s->Length() + 1); 55 if (data == NULL) { 56 V8::FatalProcessOutOfMemory("PrintLn"); 57 return; 58 } 59 s->WriteAscii(data); 60 PrintF("%s\n", data); 61 DeleteArray(data); 62 } 63 64 65 static Handle<Code> ComputeCallDebugBreak(int argc) { 66 CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugBreak(argc), Code); 67 } 68 69 70 static Handle<Code> ComputeCallDebugPrepareStepIn(int argc) { 71 CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugPrepareStepIn(argc), Code); 72 } 73 74 75 BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info, 76 BreakLocatorType type) { 77 debug_info_ = debug_info; 78 type_ = type; 79 reloc_iterator_ = NULL; 80 reloc_iterator_original_ = NULL; 81 Reset(); // Initialize the rest of the member variables. 82 } 83 84 85 BreakLocationIterator::~BreakLocationIterator() { 86 ASSERT(reloc_iterator_ != NULL); 87 ASSERT(reloc_iterator_original_ != NULL); 88 delete reloc_iterator_; 89 delete reloc_iterator_original_; 90 } 91 92 93 void BreakLocationIterator::Next() { 94 AssertNoAllocation nogc; 95 ASSERT(!RinfoDone()); 96 97 // Iterate through reloc info for code and original code stopping at each 98 // breakable code target. 99 bool first = break_point_ == -1; 100 while (!RinfoDone()) { 101 if (!first) RinfoNext(); 102 first = false; 103 if (RinfoDone()) return; 104 105 // Whenever a statement position or (plain) position is passed update the 106 // current value of these. 107 if (RelocInfo::IsPosition(rmode())) { 108 if (RelocInfo::IsStatementPosition(rmode())) { 109 statement_position_ = static_cast<int>( 110 rinfo()->data() - debug_info_->shared()->start_position()); 111 } 112 // Always update the position as we don't want that to be before the 113 // statement position. 114 position_ = static_cast<int>( 115 rinfo()->data() - debug_info_->shared()->start_position()); 116 ASSERT(position_ >= 0); 117 ASSERT(statement_position_ >= 0); 118 } 119 120 // Check for breakable code target. Look in the original code as setting 121 // break points can cause the code targets in the running (debugged) code to 122 // be of a different kind than in the original code. 123 if (RelocInfo::IsCodeTarget(rmode())) { 124 Address target = original_rinfo()->target_address(); 125 Code* code = Code::GetCodeFromTargetAddress(target); 126 if (code->is_inline_cache_stub() || RelocInfo::IsConstructCall(rmode())) { 127 break_point_++; 128 return; 129 } 130 if (code->kind() == Code::STUB) { 131 if (IsDebuggerStatement()) { 132 break_point_++; 133 return; 134 } 135 if (type_ == ALL_BREAK_LOCATIONS) { 136 if (Debug::IsBreakStub(code)) { 137 break_point_++; 138 return; 139 } 140 } else { 141 ASSERT(type_ == SOURCE_BREAK_LOCATIONS); 142 if (Debug::IsSourceBreakStub(code)) { 143 break_point_++; 144 return; 145 } 146 } 147 } 148 } 149 150 // Check for break at return. 151 if (RelocInfo::IsJSReturn(rmode())) { 152 // Set the positions to the end of the function. 153 if (debug_info_->shared()->HasSourceCode()) { 154 position_ = debug_info_->shared()->end_position() - 155 debug_info_->shared()->start_position(); 156 } else { 157 position_ = 0; 158 } 159 statement_position_ = position_; 160 break_point_++; 161 return; 162 } 163 } 164 } 165 166 167 void BreakLocationIterator::Next(int count) { 168 while (count > 0) { 169 Next(); 170 count--; 171 } 172 } 173 174 175 // Find the break point closest to the supplied address. 176 void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) { 177 // Run through all break points to locate the one closest to the address. 178 int closest_break_point = 0; 179 int distance = kMaxInt; 180 while (!Done()) { 181 // Check if this break point is closer that what was previously found. 182 if (this->pc() < pc && pc - this->pc() < distance) { 183 closest_break_point = break_point(); 184 distance = static_cast<int>(pc - this->pc()); 185 // Check whether we can't get any closer. 186 if (distance == 0) break; 187 } 188 Next(); 189 } 190 191 // Move to the break point found. 192 Reset(); 193 Next(closest_break_point); 194 } 195 196 197 // Find the break point closest to the supplied source position. 198 void BreakLocationIterator::FindBreakLocationFromPosition(int position) { 199 // Run through all break points to locate the one closest to the source 200 // position. 201 int closest_break_point = 0; 202 int distance = kMaxInt; 203 while (!Done()) { 204 // Check if this break point is closer that what was previously found. 205 if (position <= statement_position() && 206 statement_position() - position < distance) { 207 closest_break_point = break_point(); 208 distance = statement_position() - position; 209 // Check whether we can't get any closer. 210 if (distance == 0) break; 211 } 212 Next(); 213 } 214 215 // Move to the break point found. 216 Reset(); 217 Next(closest_break_point); 218 } 219 220 221 void BreakLocationIterator::Reset() { 222 // Create relocation iterators for the two code objects. 223 if (reloc_iterator_ != NULL) delete reloc_iterator_; 224 if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_; 225 reloc_iterator_ = new RelocIterator(debug_info_->code()); 226 reloc_iterator_original_ = new RelocIterator(debug_info_->original_code()); 227 228 // Position at the first break point. 229 break_point_ = -1; 230 position_ = 1; 231 statement_position_ = 1; 232 Next(); 233 } 234 235 236 bool BreakLocationIterator::Done() const { 237 return RinfoDone(); 238 } 239 240 241 void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) { 242 // If there is not already a real break point here patch code with debug 243 // break. 244 if (!HasBreakPoint()) { 245 SetDebugBreak(); 246 } 247 ASSERT(IsDebugBreak() || IsDebuggerStatement()); 248 // Set the break point information. 249 DebugInfo::SetBreakPoint(debug_info_, code_position(), 250 position(), statement_position(), 251 break_point_object); 252 } 253 254 255 void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) { 256 // Clear the break point information. 257 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object); 258 // If there are no more break points here remove the debug break. 259 if (!HasBreakPoint()) { 260 ClearDebugBreak(); 261 ASSERT(!IsDebugBreak()); 262 } 263 } 264 265 266 void BreakLocationIterator::SetOneShot() { 267 // Debugger statement always calls debugger. No need to modify it. 268 if (IsDebuggerStatement()) { 269 return; 270 } 271 272 // If there is a real break point here no more to do. 273 if (HasBreakPoint()) { 274 ASSERT(IsDebugBreak()); 275 return; 276 } 277 278 // Patch code with debug break. 279 SetDebugBreak(); 280 } 281 282 283 void BreakLocationIterator::ClearOneShot() { 284 // Debugger statement always calls debugger. No need to modify it. 285 if (IsDebuggerStatement()) { 286 return; 287 } 288 289 // If there is a real break point here no more to do. 290 if (HasBreakPoint()) { 291 ASSERT(IsDebugBreak()); 292 return; 293 } 294 295 // Patch code removing debug break. 296 ClearDebugBreak(); 297 ASSERT(!IsDebugBreak()); 298 } 299 300 301 void BreakLocationIterator::SetDebugBreak() { 302 // Debugger statement always calls debugger. No need to modify it. 303 if (IsDebuggerStatement()) { 304 return; 305 } 306 307 // If there is already a break point here just return. This might happen if 308 // the same code is flooded with break points twice. Flooding the same 309 // function twice might happen when stepping in a function with an exception 310 // handler as the handler and the function is the same. 311 if (IsDebugBreak()) { 312 return; 313 } 314 315 if (RelocInfo::IsJSReturn(rmode())) { 316 // Patch the frame exit code with a break point. 317 SetDebugBreakAtReturn(); 318 } else { 319 // Patch the IC call. 320 SetDebugBreakAtIC(); 321 } 322 ASSERT(IsDebugBreak()); 323 } 324 325 326 void BreakLocationIterator::ClearDebugBreak() { 327 // Debugger statement always calls debugger. No need to modify it. 328 if (IsDebuggerStatement()) { 329 return; 330 } 331 332 if (RelocInfo::IsJSReturn(rmode())) { 333 // Restore the frame exit code. 334 ClearDebugBreakAtReturn(); 335 } else { 336 // Patch the IC call. 337 ClearDebugBreakAtIC(); 338 } 339 ASSERT(!IsDebugBreak()); 340 } 341 342 343 void BreakLocationIterator::PrepareStepIn() { 344 HandleScope scope; 345 346 // Step in can only be prepared if currently positioned on an IC call, 347 // construct call or CallFunction stub call. 348 Address target = rinfo()->target_address(); 349 Handle<Code> code(Code::GetCodeFromTargetAddress(target)); 350 if (code->is_call_stub()) { 351 // Step in through IC call is handled by the runtime system. Therefore make 352 // sure that the any current IC is cleared and the runtime system is 353 // called. If the executing code has a debug break at the location change 354 // the call in the original code as it is the code there that will be 355 // executed in place of the debug break call. 356 Handle<Code> stub = ComputeCallDebugPrepareStepIn(code->arguments_count()); 357 if (IsDebugBreak()) { 358 original_rinfo()->set_target_address(stub->entry()); 359 } else { 360 rinfo()->set_target_address(stub->entry()); 361 } 362 } else { 363 #ifdef DEBUG 364 // All the following stuff is needed only for assertion checks so the code 365 // is wrapped in ifdef. 366 Handle<Code> maybe_call_function_stub = code; 367 if (IsDebugBreak()) { 368 Address original_target = original_rinfo()->target_address(); 369 maybe_call_function_stub = 370 Handle<Code>(Code::GetCodeFromTargetAddress(original_target)); 371 } 372 bool is_call_function_stub = 373 (maybe_call_function_stub->kind() == Code::STUB && 374 maybe_call_function_stub->major_key() == CodeStub::CallFunction); 375 376 // Step in through construct call requires no changes to the running code. 377 // Step in through getters/setters should already be prepared as well 378 // because caller of this function (Debug::PrepareStep) is expected to 379 // flood the top frame's function with one shot breakpoints. 380 // Step in through CallFunction stub should also be prepared by caller of 381 // this function (Debug::PrepareStep) which should flood target function 382 // with breakpoints. 383 ASSERT(RelocInfo::IsConstructCall(rmode()) || code->is_inline_cache_stub() 384 || is_call_function_stub); 385 #endif 386 } 387 } 388 389 390 // Check whether the break point is at a position which will exit the function. 391 bool BreakLocationIterator::IsExit() const { 392 return (RelocInfo::IsJSReturn(rmode())); 393 } 394 395 396 bool BreakLocationIterator::HasBreakPoint() { 397 return debug_info_->HasBreakPoint(code_position()); 398 } 399 400 401 // Check whether there is a debug break at the current position. 402 bool BreakLocationIterator::IsDebugBreak() { 403 if (RelocInfo::IsJSReturn(rmode())) { 404 return IsDebugBreakAtReturn(); 405 } else { 406 return Debug::IsDebugBreak(rinfo()->target_address()); 407 } 408 } 409 410 411 void BreakLocationIterator::SetDebugBreakAtIC() { 412 // Patch the original code with the current address as the current address 413 // might have changed by the inline caching since the code was copied. 414 original_rinfo()->set_target_address(rinfo()->target_address()); 415 416 RelocInfo::Mode mode = rmode(); 417 if (RelocInfo::IsCodeTarget(mode)) { 418 Address target = rinfo()->target_address(); 419 Handle<Code> code(Code::GetCodeFromTargetAddress(target)); 420 421 // Patch the code to invoke the builtin debug break function matching the 422 // calling convention used by the call site. 423 Handle<Code> dbgbrk_code(Debug::FindDebugBreak(code, mode)); 424 rinfo()->set_target_address(dbgbrk_code->entry()); 425 426 // For stubs that refer back to an inlined version clear the cached map for 427 // the inlined case to always go through the IC. As long as the break point 428 // is set the patching performed by the runtime system will take place in 429 // the code copy and will therefore have no effect on the running code 430 // keeping it from using the inlined code. 431 if (code->is_keyed_load_stub()) KeyedLoadIC::ClearInlinedVersion(pc()); 432 if (code->is_keyed_store_stub()) KeyedStoreIC::ClearInlinedVersion(pc()); 433 } 434 } 435 436 437 void BreakLocationIterator::ClearDebugBreakAtIC() { 438 // Patch the code to the original invoke. 439 rinfo()->set_target_address(original_rinfo()->target_address()); 440 441 RelocInfo::Mode mode = rmode(); 442 if (RelocInfo::IsCodeTarget(mode)) { 443 Address target = original_rinfo()->target_address(); 444 Handle<Code> code(Code::GetCodeFromTargetAddress(target)); 445 446 // Restore the inlined version of keyed stores to get back to the 447 // fast case. We need to patch back the keyed store because no 448 // patching happens when running normally. For keyed loads, the 449 // map check will get patched back when running normally after ICs 450 // have been cleared at GC. 451 if (code->is_keyed_store_stub()) KeyedStoreIC::RestoreInlinedVersion(pc()); 452 } 453 } 454 455 456 bool BreakLocationIterator::IsDebuggerStatement() { 457 return RelocInfo::DEBUG_BREAK == rmode(); 458 } 459 460 461 Object* BreakLocationIterator::BreakPointObjects() { 462 return debug_info_->GetBreakPointObjects(code_position()); 463 } 464 465 466 // Clear out all the debug break code. This is ONLY supposed to be used when 467 // shutting down the debugger as it will leave the break point information in 468 // DebugInfo even though the code is patched back to the non break point state. 469 void BreakLocationIterator::ClearAllDebugBreak() { 470 while (!Done()) { 471 ClearDebugBreak(); 472 Next(); 473 } 474 } 475 476 477 bool BreakLocationIterator::RinfoDone() const { 478 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done()); 479 return reloc_iterator_->done(); 480 } 481 482 483 void BreakLocationIterator::RinfoNext() { 484 reloc_iterator_->next(); 485 reloc_iterator_original_->next(); 486 #ifdef DEBUG 487 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done()); 488 if (!reloc_iterator_->done()) { 489 ASSERT(rmode() == original_rmode()); 490 } 491 #endif 492 } 493 494 495 bool Debug::has_break_points_ = false; 496 ScriptCache* Debug::script_cache_ = NULL; 497 DebugInfoListNode* Debug::debug_info_list_ = NULL; 498 499 500 // Threading support. 501 void Debug::ThreadInit() { 502 thread_local_.break_count_ = 0; 503 thread_local_.break_id_ = 0; 504 thread_local_.break_frame_id_ = StackFrame::NO_ID; 505 thread_local_.last_step_action_ = StepNone; 506 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; 507 thread_local_.step_count_ = 0; 508 thread_local_.last_fp_ = 0; 509 thread_local_.step_into_fp_ = 0; 510 thread_local_.step_out_fp_ = 0; 511 thread_local_.after_break_target_ = 0; 512 thread_local_.debugger_entry_ = NULL; 513 thread_local_.pending_interrupts_ = 0; 514 } 515 516 517 JSCallerSavedBuffer Debug::registers_; 518 Debug::ThreadLocal Debug::thread_local_; 519 520 521 char* Debug::ArchiveDebug(char* storage) { 522 char* to = storage; 523 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); 524 to += sizeof(ThreadLocal); 525 memcpy(to, reinterpret_cast<char*>(®isters_), sizeof(registers_)); 526 ThreadInit(); 527 ASSERT(to <= storage + ArchiveSpacePerThread()); 528 return storage + ArchiveSpacePerThread(); 529 } 530 531 532 char* Debug::RestoreDebug(char* storage) { 533 char* from = storage; 534 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal)); 535 from += sizeof(ThreadLocal); 536 memcpy(reinterpret_cast<char*>(®isters_), from, sizeof(registers_)); 537 ASSERT(from <= storage + ArchiveSpacePerThread()); 538 return storage + ArchiveSpacePerThread(); 539 } 540 541 542 int Debug::ArchiveSpacePerThread() { 543 return sizeof(ThreadLocal) + sizeof(registers_); 544 } 545 546 547 // Default break enabled. 548 bool Debug::disable_break_ = false; 549 550 // Default call debugger on uncaught exception. 551 bool Debug::break_on_exception_ = false; 552 bool Debug::break_on_uncaught_exception_ = true; 553 554 Handle<Context> Debug::debug_context_ = Handle<Context>(); 555 Code* Debug::debug_break_return_ = NULL; 556 557 558 void ScriptCache::Add(Handle<Script> script) { 559 // Create an entry in the hash map for the script. 560 int id = Smi::cast(script->id())->value(); 561 HashMap::Entry* entry = 562 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true); 563 if (entry->value != NULL) { 564 ASSERT(*script == *reinterpret_cast<Script**>(entry->value)); 565 return; 566 } 567 568 // Globalize the script object, make it weak and use the location of the 569 // global handle as the value in the hash map. 570 Handle<Script> script_ = 571 Handle<Script>::cast((GlobalHandles::Create(*script))); 572 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()), 573 this, ScriptCache::HandleWeakScript); 574 entry->value = script_.location(); 575 } 576 577 578 Handle<FixedArray> ScriptCache::GetScripts() { 579 Handle<FixedArray> instances = Factory::NewFixedArray(occupancy()); 580 int count = 0; 581 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) { 582 ASSERT(entry->value != NULL); 583 if (entry->value != NULL) { 584 instances->set(count, *reinterpret_cast<Script**>(entry->value)); 585 count++; 586 } 587 } 588 return instances; 589 } 590 591 592 void ScriptCache::ProcessCollectedScripts() { 593 for (int i = 0; i < collected_scripts_.length(); i++) { 594 Debugger::OnScriptCollected(collected_scripts_[i]); 595 } 596 collected_scripts_.Clear(); 597 } 598 599 600 void ScriptCache::Clear() { 601 // Iterate the script cache to get rid of all the weak handles. 602 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) { 603 ASSERT(entry != NULL); 604 Object** location = reinterpret_cast<Object**>(entry->value); 605 ASSERT((*location)->IsScript()); 606 GlobalHandles::ClearWeakness(location); 607 GlobalHandles::Destroy(location); 608 } 609 // Clear the content of the hash map. 610 HashMap::Clear(); 611 } 612 613 614 void ScriptCache::HandleWeakScript(v8::Persistent<v8::Value> obj, void* data) { 615 ScriptCache* script_cache = reinterpret_cast<ScriptCache*>(data); 616 // Find the location of the global handle. 617 Script** location = 618 reinterpret_cast<Script**>(Utils::OpenHandle(*obj).location()); 619 ASSERT((*location)->IsScript()); 620 621 // Remove the entry from the cache. 622 int id = Smi::cast((*location)->id())->value(); 623 script_cache->Remove(reinterpret_cast<void*>(id), Hash(id)); 624 script_cache->collected_scripts_.Add(id); 625 626 // Clear the weak handle. 627 obj.Dispose(); 628 obj.Clear(); 629 } 630 631 632 void Debug::Setup(bool create_heap_objects) { 633 ThreadInit(); 634 if (create_heap_objects) { 635 // Get code to handle debug break on return. 636 debug_break_return_ = 637 Builtins::builtin(Builtins::Return_DebugBreak); 638 ASSERT(debug_break_return_->IsCode()); 639 } 640 } 641 642 643 void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) { 644 DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data); 645 RemoveDebugInfo(node->debug_info()); 646 #ifdef DEBUG 647 node = Debug::debug_info_list_; 648 while (node != NULL) { 649 ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data)); 650 node = node->next(); 651 } 652 #endif 653 } 654 655 656 DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) { 657 // Globalize the request debug info object and make it weak. 658 debug_info_ = Handle<DebugInfo>::cast((GlobalHandles::Create(debug_info))); 659 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()), 660 this, Debug::HandleWeakDebugInfo); 661 } 662 663 664 DebugInfoListNode::~DebugInfoListNode() { 665 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location())); 666 } 667 668 669 bool Debug::CompileDebuggerScript(int index) { 670 HandleScope scope; 671 672 // Bail out if the index is invalid. 673 if (index == -1) { 674 return false; 675 } 676 677 // Find source and name for the requested script. 678 Handle<String> source_code = Bootstrapper::NativesSourceLookup(index); 679 Vector<const char> name = Natives::GetScriptName(index); 680 Handle<String> script_name = Factory::NewStringFromAscii(name); 681 682 // Compile the script. 683 bool allow_natives_syntax = FLAG_allow_natives_syntax; 684 FLAG_allow_natives_syntax = true; 685 Handle<JSFunction> boilerplate; 686 boilerplate = Compiler::Compile(source_code, 687 script_name, 688 0, 689 0, 690 NULL, 691 NULL, 692 Handle<String>::null(), 693 NATIVES_CODE); 694 FLAG_allow_natives_syntax = allow_natives_syntax; 695 696 // Silently ignore stack overflows during compilation. 697 if (boilerplate.is_null()) { 698 ASSERT(Top::has_pending_exception()); 699 Top::clear_pending_exception(); 700 return false; 701 } 702 703 // Execute the boilerplate function in the debugger context. 704 Handle<Context> context = Top::global_context(); 705 bool caught_exception = false; 706 Handle<JSFunction> function = 707 Factory::NewFunctionFromBoilerplate(boilerplate, context); 708 Handle<Object> result = 709 Execution::TryCall(function, Handle<Object>(context->global()), 710 0, NULL, &caught_exception); 711 712 // Check for caught exceptions. 713 if (caught_exception) { 714 Handle<Object> message = MessageHandler::MakeMessageObject( 715 "error_loading_debugger", NULL, Vector<Handle<Object> >::empty(), 716 Handle<String>()); 717 MessageHandler::ReportMessage(NULL, message); 718 return false; 719 } 720 721 // Mark this script as native and return successfully. 722 Handle<Script> script(Script::cast(function->shared()->script())); 723 return true; 724 } 725 726 727 bool Debug::Load() { 728 // Return if debugger is already loaded. 729 if (IsLoaded()) return true; 730 731 // Bail out if we're already in the process of compiling the native 732 // JavaScript source code for the debugger. 733 if (Debugger::compiling_natives() || Debugger::is_loading_debugger()) 734 return false; 735 Debugger::set_loading_debugger(true); 736 737 // Disable breakpoints and interrupts while compiling and running the 738 // debugger scripts including the context creation code. 739 DisableBreak disable(true); 740 PostponeInterruptsScope postpone; 741 742 // Create the debugger context. 743 HandleScope scope; 744 Handle<Context> context = 745 Bootstrapper::CreateEnvironment(Handle<Object>::null(), 746 v8::Handle<ObjectTemplate>(), 747 NULL); 748 749 // Use the debugger context. 750 SaveContext save; 751 Top::set_context(*context); 752 753 // Expose the builtins object in the debugger context. 754 Handle<String> key = Factory::LookupAsciiSymbol("builtins"); 755 Handle<GlobalObject> global = Handle<GlobalObject>(context->global()); 756 SetProperty(global, key, Handle<Object>(global->builtins()), NONE); 757 758 // Compile the JavaScript for the debugger in the debugger context. 759 Debugger::set_compiling_natives(true); 760 bool caught_exception = 761 !CompileDebuggerScript(Natives::GetIndex("mirror")) || 762 !CompileDebuggerScript(Natives::GetIndex("debug")); 763 Debugger::set_compiling_natives(false); 764 765 // Make sure we mark the debugger as not loading before we might 766 // return. 767 Debugger::set_loading_debugger(false); 768 769 // Check for caught exceptions. 770 if (caught_exception) return false; 771 772 // Debugger loaded. 773 debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context)); 774 775 return true; 776 } 777 778 779 void Debug::Unload() { 780 // Return debugger is not loaded. 781 if (!IsLoaded()) { 782 return; 783 } 784 785 // Clear the script cache. 786 DestroyScriptCache(); 787 788 // Clear debugger context global handle. 789 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location())); 790 debug_context_ = Handle<Context>(); 791 } 792 793 794 // Set the flag indicating that preemption happened during debugging. 795 void Debug::PreemptionWhileInDebugger() { 796 ASSERT(InDebugger()); 797 Debug::set_interrupts_pending(PREEMPT); 798 } 799 800 801 void Debug::Iterate(ObjectVisitor* v) { 802 v->VisitPointer(bit_cast<Object**, Code**>(&(debug_break_return_))); 803 } 804 805 806 Object* Debug::Break(Arguments args) { 807 HandleScope scope; 808 ASSERT(args.length() == 0); 809 810 // Get the top-most JavaScript frame. 811 JavaScriptFrameIterator it; 812 JavaScriptFrame* frame = it.frame(); 813 814 // Just continue if breaks are disabled or debugger cannot be loaded. 815 if (disable_break() || !Load()) { 816 SetAfterBreakTarget(frame); 817 return Heap::undefined_value(); 818 } 819 820 // Enter the debugger. 821 EnterDebugger debugger; 822 if (debugger.FailedToEnter()) { 823 return Heap::undefined_value(); 824 } 825 826 // Postpone interrupt during breakpoint processing. 827 PostponeInterruptsScope postpone; 828 829 // Get the debug info (create it if it does not exist). 830 Handle<SharedFunctionInfo> shared = 831 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared()); 832 Handle<DebugInfo> debug_info = GetDebugInfo(shared); 833 834 // Find the break point where execution has stopped. 835 BreakLocationIterator break_location_iterator(debug_info, 836 ALL_BREAK_LOCATIONS); 837 break_location_iterator.FindBreakLocationFromAddress(frame->pc()); 838 839 // Check whether step next reached a new statement. 840 if (!StepNextContinue(&break_location_iterator, frame)) { 841 // Decrease steps left if performing multiple steps. 842 if (thread_local_.step_count_ > 0) { 843 thread_local_.step_count_--; 844 } 845 } 846 847 // If there is one or more real break points check whether any of these are 848 // triggered. 849 Handle<Object> break_points_hit(Heap::undefined_value()); 850 if (break_location_iterator.HasBreakPoint()) { 851 Handle<Object> break_point_objects = 852 Handle<Object>(break_location_iterator.BreakPointObjects()); 853 break_points_hit = CheckBreakPoints(break_point_objects); 854 } 855 856 // If step out is active skip everything until the frame where we need to step 857 // out to is reached, unless real breakpoint is hit. 858 if (Debug::StepOutActive() && frame->fp() != Debug::step_out_fp() && 859 break_points_hit->IsUndefined() ) { 860 // Step count should always be 0 for StepOut. 861 ASSERT(thread_local_.step_count_ == 0); 862 } else if (!break_points_hit->IsUndefined() || 863 (thread_local_.last_step_action_ != StepNone && 864 thread_local_.step_count_ == 0)) { 865 // Notify debugger if a real break point is triggered or if performing 866 // single stepping with no more steps to perform. Otherwise do another step. 867 868 // Clear all current stepping setup. 869 ClearStepping(); 870 871 // Notify the debug event listeners. 872 Debugger::OnDebugBreak(break_points_hit, false); 873 } else if (thread_local_.last_step_action_ != StepNone) { 874 // Hold on to last step action as it is cleared by the call to 875 // ClearStepping. 876 StepAction step_action = thread_local_.last_step_action_; 877 int step_count = thread_local_.step_count_; 878 879 // Clear all current stepping setup. 880 ClearStepping(); 881 882 // Set up for the remaining steps. 883 PrepareStep(step_action, step_count); 884 } 885 886 // Install jump to the call address which was overwritten. 887 SetAfterBreakTarget(frame); 888 889 return Heap::undefined_value(); 890 } 891 892 893 // Check the break point objects for whether one or more are actually 894 // triggered. This function returns a JSArray with the break point objects 895 // which is triggered. 896 Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) { 897 int break_points_hit_count = 0; 898 Handle<JSArray> break_points_hit = Factory::NewJSArray(1); 899 900 // If there are multiple break points they are in a FixedArray. 901 ASSERT(!break_point_objects->IsUndefined()); 902 if (break_point_objects->IsFixedArray()) { 903 Handle<FixedArray> array(FixedArray::cast(*break_point_objects)); 904 for (int i = 0; i < array->length(); i++) { 905 Handle<Object> o(array->get(i)); 906 if (CheckBreakPoint(o)) { 907 break_points_hit->SetElement(break_points_hit_count++, *o); 908 } 909 } 910 } else { 911 if (CheckBreakPoint(break_point_objects)) { 912 break_points_hit->SetElement(break_points_hit_count++, 913 *break_point_objects); 914 } 915 } 916 917 // Return undefined if no break points where triggered. 918 if (break_points_hit_count == 0) { 919 return Factory::undefined_value(); 920 } 921 return break_points_hit; 922 } 923 924 925 // Check whether a single break point object is triggered. 926 bool Debug::CheckBreakPoint(Handle<Object> break_point_object) { 927 HandleScope scope; 928 929 // Ignore check if break point object is not a JSObject. 930 if (!break_point_object->IsJSObject()) return true; 931 932 // Get the function CheckBreakPoint (defined in debug.js). 933 Handle<JSFunction> check_break_point = 934 Handle<JSFunction>(JSFunction::cast( 935 debug_context()->global()->GetProperty( 936 *Factory::LookupAsciiSymbol("IsBreakPointTriggered")))); 937 938 // Get the break id as an object. 939 Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id()); 940 941 // Call HandleBreakPointx. 942 bool caught_exception = false; 943 const int argc = 2; 944 Object** argv[argc] = { 945 break_id.location(), 946 reinterpret_cast<Object**>(break_point_object.location()) 947 }; 948 Handle<Object> result = Execution::TryCall(check_break_point, 949 Top::builtins(), argc, argv, 950 &caught_exception); 951 952 // If exception or non boolean result handle as not triggered 953 if (caught_exception || !result->IsBoolean()) { 954 return false; 955 } 956 957 // Return whether the break point is triggered. 958 return *result == Heap::true_value(); 959 } 960 961 962 // Check whether the function has debug information. 963 bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) { 964 return !shared->debug_info()->IsUndefined(); 965 } 966 967 968 // Return the debug info for this function. EnsureDebugInfo must be called 969 // prior to ensure the debug info has been generated for shared. 970 Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) { 971 ASSERT(HasDebugInfo(shared)); 972 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info())); 973 } 974 975 976 void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared, 977 int source_position, 978 Handle<Object> break_point_object) { 979 HandleScope scope; 980 981 if (!EnsureDebugInfo(shared)) { 982 // Return if retrieving debug info failed. 983 return; 984 } 985 986 Handle<DebugInfo> debug_info = GetDebugInfo(shared); 987 // Source positions starts with zero. 988 ASSERT(source_position >= 0); 989 990 // Find the break point and change it. 991 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS); 992 it.FindBreakLocationFromPosition(source_position); 993 it.SetBreakPoint(break_point_object); 994 995 // At least one active break point now. 996 ASSERT(debug_info->GetBreakPointCount() > 0); 997 } 998 999 1000 void Debug::ClearBreakPoint(Handle<Object> break_point_object) { 1001 HandleScope scope; 1002 1003 DebugInfoListNode* node = debug_info_list_; 1004 while (node != NULL) { 1005 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(), 1006 break_point_object); 1007 if (!result->IsUndefined()) { 1008 // Get information in the break point. 1009 BreakPointInfo* break_point_info = BreakPointInfo::cast(result); 1010 Handle<DebugInfo> debug_info = node->debug_info(); 1011 Handle<SharedFunctionInfo> shared(debug_info->shared()); 1012 int source_position = break_point_info->statement_position()->value(); 1013 1014 // Source positions starts with zero. 1015 ASSERT(source_position >= 0); 1016 1017 // Find the break point and clear it. 1018 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS); 1019 it.FindBreakLocationFromPosition(source_position); 1020 it.ClearBreakPoint(break_point_object); 1021 1022 // If there are no more break points left remove the debug info for this 1023 // function. 1024 if (debug_info->GetBreakPointCount() == 0) { 1025 RemoveDebugInfo(debug_info); 1026 } 1027 1028 return; 1029 } 1030 node = node->next(); 1031 } 1032 } 1033 1034 1035 void Debug::ClearAllBreakPoints() { 1036 DebugInfoListNode* node = debug_info_list_; 1037 while (node != NULL) { 1038 // Remove all debug break code. 1039 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS); 1040 it.ClearAllDebugBreak(); 1041 node = node->next(); 1042 } 1043 1044 // Remove all debug info. 1045 while (debug_info_list_ != NULL) { 1046 RemoveDebugInfo(debug_info_list_->debug_info()); 1047 } 1048 } 1049 1050 1051 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) { 1052 // Make sure the function has setup the debug info. 1053 if (!EnsureDebugInfo(shared)) { 1054 // Return if we failed to retrieve the debug info. 1055 return; 1056 } 1057 1058 // Flood the function with break points. 1059 BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS); 1060 while (!it.Done()) { 1061 it.SetOneShot(); 1062 it.Next(); 1063 } 1064 } 1065 1066 1067 void Debug::FloodHandlerWithOneShot() { 1068 // Iterate through the JavaScript stack looking for handlers. 1069 StackFrame::Id id = break_frame_id(); 1070 if (id == StackFrame::NO_ID) { 1071 // If there is no JavaScript stack don't do anything. 1072 return; 1073 } 1074 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) { 1075 JavaScriptFrame* frame = it.frame(); 1076 if (frame->HasHandler()) { 1077 Handle<SharedFunctionInfo> shared = 1078 Handle<SharedFunctionInfo>( 1079 JSFunction::cast(frame->function())->shared()); 1080 // Flood the function with the catch block with break points 1081 FloodWithOneShot(shared); 1082 return; 1083 } 1084 } 1085 } 1086 1087 1088 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { 1089 if (type == BreakUncaughtException) { 1090 break_on_uncaught_exception_ = enable; 1091 } else { 1092 break_on_exception_ = enable; 1093 } 1094 } 1095 1096 1097 void Debug::PrepareStep(StepAction step_action, int step_count) { 1098 HandleScope scope; 1099 ASSERT(Debug::InDebugger()); 1100 1101 // Remember this step action and count. 1102 thread_local_.last_step_action_ = step_action; 1103 if (step_action == StepOut) { 1104 // For step out target frame will be found on the stack so there is no need 1105 // to set step counter for it. It's expected to always be 0 for StepOut. 1106 thread_local_.step_count_ = 0; 1107 } else { 1108 thread_local_.step_count_ = step_count; 1109 } 1110 1111 // Get the frame where the execution has stopped and skip the debug frame if 1112 // any. The debug frame will only be present if execution was stopped due to 1113 // hitting a break point. In other situations (e.g. unhandled exception) the 1114 // debug frame is not present. 1115 StackFrame::Id id = break_frame_id(); 1116 if (id == StackFrame::NO_ID) { 1117 // If there is no JavaScript stack don't do anything. 1118 return; 1119 } 1120 JavaScriptFrameIterator frames_it(id); 1121 JavaScriptFrame* frame = frames_it.frame(); 1122 1123 // First of all ensure there is one-shot break points in the top handler 1124 // if any. 1125 FloodHandlerWithOneShot(); 1126 1127 // If the function on the top frame is unresolved perform step out. This will 1128 // be the case when calling unknown functions and having the debugger stopped 1129 // in an unhandled exception. 1130 if (!frame->function()->IsJSFunction()) { 1131 // Step out: Find the calling JavaScript frame and flood it with 1132 // breakpoints. 1133 frames_it.Advance(); 1134 // Fill the function to return to with one-shot break points. 1135 JSFunction* function = JSFunction::cast(frames_it.frame()->function()); 1136 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared())); 1137 return; 1138 } 1139 1140 // Get the debug info (create it if it does not exist). 1141 Handle<SharedFunctionInfo> shared = 1142 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared()); 1143 if (!EnsureDebugInfo(shared)) { 1144 // Return if ensuring debug info failed. 1145 return; 1146 } 1147 Handle<DebugInfo> debug_info = GetDebugInfo(shared); 1148 1149 // Find the break location where execution has stopped. 1150 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS); 1151 it.FindBreakLocationFromAddress(frame->pc()); 1152 1153 // Compute whether or not the target is a call target. 1154 bool is_call_target = false; 1155 bool is_load_or_store = false; 1156 bool is_inline_cache_stub = false; 1157 Handle<Code> call_function_stub; 1158 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) { 1159 Address target = it.rinfo()->target_address(); 1160 Code* code = Code::GetCodeFromTargetAddress(target); 1161 if (code->is_call_stub()) { 1162 is_call_target = true; 1163 } 1164 if (code->is_inline_cache_stub()) { 1165 is_inline_cache_stub = true; 1166 is_load_or_store = !is_call_target; 1167 } 1168 1169 // Check if target code is CallFunction stub. 1170 Code* maybe_call_function_stub = code; 1171 // If there is a breakpoint at this line look at the original code to 1172 // check if it is a CallFunction stub. 1173 if (it.IsDebugBreak()) { 1174 Address original_target = it.original_rinfo()->target_address(); 1175 maybe_call_function_stub = 1176 Code::GetCodeFromTargetAddress(original_target); 1177 } 1178 if (maybe_call_function_stub->kind() == Code::STUB && 1179 maybe_call_function_stub->major_key() == CodeStub::CallFunction) { 1180 // Save reference to the code as we may need it to find out arguments 1181 // count for 'step in' later. 1182 call_function_stub = Handle<Code>(maybe_call_function_stub); 1183 } 1184 } 1185 1186 // If this is the last break code target step out is the only possibility. 1187 if (it.IsExit() || step_action == StepOut) { 1188 if (step_action == StepOut) { 1189 // Skip step_count frames starting with the current one. 1190 while (step_count-- > 0 && !frames_it.done()) { 1191 frames_it.Advance(); 1192 } 1193 } else { 1194 ASSERT(it.IsExit()); 1195 frames_it.Advance(); 1196 } 1197 // Skip builtin functions on the stack. 1198 while (!frames_it.done() && 1199 JSFunction::cast(frames_it.frame()->function())->IsBuiltin()) { 1200 frames_it.Advance(); 1201 } 1202 // Step out: If there is a JavaScript caller frame, we need to 1203 // flood it with breakpoints. 1204 if (!frames_it.done()) { 1205 // Fill the function to return to with one-shot break points. 1206 JSFunction* function = JSFunction::cast(frames_it.frame()->function()); 1207 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared())); 1208 // Set target frame pointer. 1209 ActivateStepOut(frames_it.frame()); 1210 } 1211 } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) || 1212 !call_function_stub.is_null()) 1213 || step_action == StepNext || step_action == StepMin) { 1214 // Step next or step min. 1215 1216 // Fill the current function with one-shot break points. 1217 FloodWithOneShot(shared); 1218 1219 // Remember source position and frame to handle step next. 1220 thread_local_.last_statement_position_ = 1221 debug_info->code()->SourceStatementPosition(frame->pc()); 1222 thread_local_.last_fp_ = frame->fp(); 1223 } else { 1224 // If it's CallFunction stub ensure target function is compiled and flood 1225 // it with one shot breakpoints. 1226 if (!call_function_stub.is_null()) { 1227 // Find out number of arguments from the stub minor key. 1228 // Reverse lookup required as the minor key cannot be retrieved 1229 // from the code object. 1230 Handle<Object> obj( 1231 Heap::code_stubs()->SlowReverseLookup(*call_function_stub)); 1232 ASSERT(*obj != Heap::undefined_value()); 1233 ASSERT(obj->IsSmi()); 1234 // Get the STUB key and extract major and minor key. 1235 uint32_t key = Smi::cast(*obj)->value(); 1236 // Argc in the stub is the number of arguments passed - not the 1237 // expected arguments of the called function. 1238 int call_function_arg_count = 1239 CallFunctionStub::ExtractArgcFromMinorKey( 1240 CodeStub::MinorKeyFromKey(key)); 1241 ASSERT(call_function_stub->major_key() == 1242 CodeStub::MajorKeyFromKey(key)); 1243 1244 // Find target function on the expression stack. 1245 // Expression stack looks like this (top to bottom): 1246 // argN 1247 // ... 1248 // arg0 1249 // Receiver 1250 // Function to call 1251 int expressions_count = frame->ComputeExpressionsCount(); 1252 ASSERT(expressions_count - 2 - call_function_arg_count >= 0); 1253 Object* fun = frame->GetExpression( 1254 expressions_count - 2 - call_function_arg_count); 1255 if (fun->IsJSFunction()) { 1256 Handle<JSFunction> js_function(JSFunction::cast(fun)); 1257 // Don't step into builtins. 1258 if (!js_function->IsBuiltin()) { 1259 // It will also compile target function if it's not compiled yet. 1260 FloodWithOneShot(Handle<SharedFunctionInfo>(js_function->shared())); 1261 } 1262 } 1263 } 1264 1265 // Fill the current function with one-shot break points even for step in on 1266 // a call target as the function called might be a native function for 1267 // which step in will not stop. It also prepares for stepping in 1268 // getters/setters. 1269 FloodWithOneShot(shared); 1270 1271 if (is_load_or_store) { 1272 // Remember source position and frame to handle step in getter/setter. If 1273 // there is a custom getter/setter it will be handled in 1274 // Object::Get/SetPropertyWithCallback, otherwise the step action will be 1275 // propagated on the next Debug::Break. 1276 thread_local_.last_statement_position_ = 1277 debug_info->code()->SourceStatementPosition(frame->pc()); 1278 thread_local_.last_fp_ = frame->fp(); 1279 } 1280 1281 // Step in or Step in min 1282 it.PrepareStepIn(); 1283 ActivateStepIn(frame); 1284 } 1285 } 1286 1287 1288 // Check whether the current debug break should be reported to the debugger. It 1289 // is used to have step next and step in only report break back to the debugger 1290 // if on a different frame or in a different statement. In some situations 1291 // there will be several break points in the same statement when the code is 1292 // flooded with one-shot break points. This function helps to perform several 1293 // steps before reporting break back to the debugger. 1294 bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator, 1295 JavaScriptFrame* frame) { 1296 // If the step last action was step next or step in make sure that a new 1297 // statement is hit. 1298 if (thread_local_.last_step_action_ == StepNext || 1299 thread_local_.last_step_action_ == StepIn) { 1300 // Never continue if returning from function. 1301 if (break_location_iterator->IsExit()) return false; 1302 1303 // Continue if we are still on the same frame and in the same statement. 1304 int current_statement_position = 1305 break_location_iterator->code()->SourceStatementPosition(frame->pc()); 1306 return thread_local_.last_fp_ == frame->fp() && 1307 thread_local_.last_statement_position_ == current_statement_position; 1308 } 1309 1310 // No step next action - don't continue. 1311 return false; 1312 } 1313 1314 1315 // Check whether the code object at the specified address is a debug break code 1316 // object. 1317 bool Debug::IsDebugBreak(Address addr) { 1318 Code* code = Code::GetCodeFromTargetAddress(addr); 1319 return code->ic_state() == DEBUG_BREAK; 1320 } 1321 1322 1323 // Check whether a code stub with the specified major key is a possible break 1324 // point location when looking for source break locations. 1325 bool Debug::IsSourceBreakStub(Code* code) { 1326 CodeStub::Major major_key = code->major_key(); 1327 return major_key == CodeStub::CallFunction; 1328 } 1329 1330 1331 // Check whether a code stub with the specified major key is a possible break 1332 // location. 1333 bool Debug::IsBreakStub(Code* code) { 1334 CodeStub::Major major_key = code->major_key(); 1335 return major_key == CodeStub::CallFunction || 1336 major_key == CodeStub::StackCheck; 1337 } 1338 1339 1340 // Find the builtin to use for invoking the debug break 1341 Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) { 1342 // Find the builtin debug break function matching the calling convention 1343 // used by the call site. 1344 if (code->is_inline_cache_stub()) { 1345 if (code->is_call_stub()) { 1346 return ComputeCallDebugBreak(code->arguments_count()); 1347 } 1348 if (code->is_load_stub()) { 1349 return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak)); 1350 } 1351 if (code->is_store_stub()) { 1352 return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak)); 1353 } 1354 if (code->is_keyed_load_stub()) { 1355 Handle<Code> result = 1356 Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak)); 1357 return result; 1358 } 1359 if (code->is_keyed_store_stub()) { 1360 Handle<Code> result = 1361 Handle<Code>(Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak)); 1362 return result; 1363 } 1364 } 1365 if (RelocInfo::IsConstructCall(mode)) { 1366 Handle<Code> result = 1367 Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak)); 1368 return result; 1369 } 1370 if (code->kind() == Code::STUB) { 1371 ASSERT(code->major_key() == CodeStub::CallFunction || 1372 code->major_key() == CodeStub::StackCheck); 1373 Handle<Code> result = 1374 Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak)); 1375 return result; 1376 } 1377 1378 UNREACHABLE(); 1379 return Handle<Code>::null(); 1380 } 1381 1382 1383 // Simple function for returning the source positions for active break points. 1384 Handle<Object> Debug::GetSourceBreakLocations( 1385 Handle<SharedFunctionInfo> shared) { 1386 if (!HasDebugInfo(shared)) return Handle<Object>(Heap::undefined_value()); 1387 Handle<DebugInfo> debug_info = GetDebugInfo(shared); 1388 if (debug_info->GetBreakPointCount() == 0) { 1389 return Handle<Object>(Heap::undefined_value()); 1390 } 1391 Handle<FixedArray> locations = 1392 Factory::NewFixedArray(debug_info->GetBreakPointCount()); 1393 int count = 0; 1394 for (int i = 0; i < debug_info->break_points()->length(); i++) { 1395 if (!debug_info->break_points()->get(i)->IsUndefined()) { 1396 BreakPointInfo* break_point_info = 1397 BreakPointInfo::cast(debug_info->break_points()->get(i)); 1398 if (break_point_info->GetBreakPointCount() > 0) { 1399 locations->set(count++, break_point_info->statement_position()); 1400 } 1401 } 1402 } 1403 return locations; 1404 } 1405 1406 1407 void Debug::NewBreak(StackFrame::Id break_frame_id) { 1408 thread_local_.break_frame_id_ = break_frame_id; 1409 thread_local_.break_id_ = ++thread_local_.break_count_; 1410 } 1411 1412 1413 void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) { 1414 thread_local_.break_frame_id_ = break_frame_id; 1415 thread_local_.break_id_ = break_id; 1416 } 1417 1418 1419 // Handle stepping into a function. 1420 void Debug::HandleStepIn(Handle<JSFunction> function, 1421 Handle<Object> holder, 1422 Address fp, 1423 bool is_constructor) { 1424 // If the frame pointer is not supplied by the caller find it. 1425 if (fp == 0) { 1426 StackFrameIterator it; 1427 it.Advance(); 1428 // For constructor functions skip another frame. 1429 if (is_constructor) { 1430 ASSERT(it.frame()->is_construct()); 1431 it.Advance(); 1432 } 1433 fp = it.frame()->fp(); 1434 } 1435 1436 // Flood the function with one-shot break points if it is called from where 1437 // step into was requested. 1438 if (fp == Debug::step_in_fp()) { 1439 // Don't allow step into functions in the native context. 1440 if (!function->IsBuiltin()) { 1441 if (function->shared()->code() == 1442 Builtins::builtin(Builtins::FunctionApply) || 1443 function->shared()->code() == 1444 Builtins::builtin(Builtins::FunctionCall)) { 1445 // Handle function.apply and function.call separately to flood the 1446 // function to be called and not the code for Builtins::FunctionApply or 1447 // Builtins::FunctionCall. The receiver of call/apply is the target 1448 // function. 1449 if (!holder.is_null() && holder->IsJSFunction() && 1450 !JSFunction::cast(*holder)->IsBuiltin()) { 1451 Handle<SharedFunctionInfo> shared_info( 1452 JSFunction::cast(*holder)->shared()); 1453 Debug::FloodWithOneShot(shared_info); 1454 } 1455 } else { 1456 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared())); 1457 } 1458 } 1459 } 1460 } 1461 1462 1463 void Debug::ClearStepping() { 1464 // Clear the various stepping setup. 1465 ClearOneShot(); 1466 ClearStepIn(); 1467 ClearStepOut(); 1468 ClearStepNext(); 1469 1470 // Clear multiple step counter. 1471 thread_local_.step_count_ = 0; 1472 } 1473 1474 // Clears all the one-shot break points that are currently set. Normally this 1475 // function is called each time a break point is hit as one shot break points 1476 // are used to support stepping. 1477 void Debug::ClearOneShot() { 1478 // The current implementation just runs through all the breakpoints. When the 1479 // last break point for a function is removed that function is automatically 1480 // removed from the list. 1481 1482 DebugInfoListNode* node = debug_info_list_; 1483 while (node != NULL) { 1484 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS); 1485 while (!it.Done()) { 1486 it.ClearOneShot(); 1487 it.Next(); 1488 } 1489 node = node->next(); 1490 } 1491 } 1492 1493 1494 void Debug::ActivateStepIn(StackFrame* frame) { 1495 ASSERT(!StepOutActive()); 1496 thread_local_.step_into_fp_ = frame->fp(); 1497 } 1498 1499 1500 void Debug::ClearStepIn() { 1501 thread_local_.step_into_fp_ = 0; 1502 } 1503 1504 1505 void Debug::ActivateStepOut(StackFrame* frame) { 1506 ASSERT(!StepInActive()); 1507 thread_local_.step_out_fp_ = frame->fp(); 1508 } 1509 1510 1511 void Debug::ClearStepOut() { 1512 thread_local_.step_out_fp_ = 0; 1513 } 1514 1515 1516 void Debug::ClearStepNext() { 1517 thread_local_.last_step_action_ = StepNone; 1518 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; 1519 thread_local_.last_fp_ = 0; 1520 } 1521 1522 1523 // Ensures the debug information is present for shared. 1524 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { 1525 // Return if we already have the debug info for shared. 1526 if (HasDebugInfo(shared)) return true; 1527 1528 // Ensure shared in compiled. Return false if this failed. 1529 if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false; 1530 1531 // Create the debug info object. 1532 Handle<DebugInfo> debug_info = Factory::NewDebugInfo(shared); 1533 1534 // Add debug info to the list. 1535 DebugInfoListNode* node = new DebugInfoListNode(*debug_info); 1536 node->set_next(debug_info_list_); 1537 debug_info_list_ = node; 1538 1539 // Now there is at least one break point. 1540 has_break_points_ = true; 1541 1542 return true; 1543 } 1544 1545 1546 void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) { 1547 ASSERT(debug_info_list_ != NULL); 1548 // Run through the debug info objects to find this one and remove it. 1549 DebugInfoListNode* prev = NULL; 1550 DebugInfoListNode* current = debug_info_list_; 1551 while (current != NULL) { 1552 if (*current->debug_info() == *debug_info) { 1553 // Unlink from list. If prev is NULL we are looking at the first element. 1554 if (prev == NULL) { 1555 debug_info_list_ = current->next(); 1556 } else { 1557 prev->set_next(current->next()); 1558 } 1559 current->debug_info()->shared()->set_debug_info(Heap::undefined_value()); 1560 delete current; 1561 1562 // If there are no more debug info objects there are not more break 1563 // points. 1564 has_break_points_ = debug_info_list_ != NULL; 1565 1566 return; 1567 } 1568 // Move to next in list. 1569 prev = current; 1570 current = current->next(); 1571 } 1572 UNREACHABLE(); 1573 } 1574 1575 1576 void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { 1577 HandleScope scope; 1578 1579 // Get the executing function in which the debug break occurred. 1580 Handle<SharedFunctionInfo> shared = 1581 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared()); 1582 if (!EnsureDebugInfo(shared)) { 1583 // Return if we failed to retrieve the debug info. 1584 return; 1585 } 1586 Handle<DebugInfo> debug_info = GetDebugInfo(shared); 1587 Handle<Code> code(debug_info->code()); 1588 Handle<Code> original_code(debug_info->original_code()); 1589 #ifdef DEBUG 1590 // Get the code which is actually executing. 1591 Handle<Code> frame_code(frame->code()); 1592 ASSERT(frame_code.is_identical_to(code)); 1593 #endif 1594 1595 // Find the call address in the running code. This address holds the call to 1596 // either a DebugBreakXXX or to the debug break return entry code if the 1597 // break point is still active after processing the break point. 1598 Address addr = frame->pc() - Assembler::kCallTargetAddressOffset; 1599 1600 // Check if the location is at JS exit. 1601 bool at_js_return = false; 1602 bool break_at_js_return_active = false; 1603 RelocIterator it(debug_info->code()); 1604 while (!it.done()) { 1605 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) { 1606 at_js_return = (it.rinfo()->pc() == 1607 addr - Assembler::kPatchReturnSequenceAddressOffset); 1608 break_at_js_return_active = it.rinfo()->IsPatchedReturnSequence(); 1609 } 1610 it.next(); 1611 } 1612 1613 // Handle the jump to continue execution after break point depending on the 1614 // break location. 1615 if (at_js_return) { 1616 // If the break point as return is still active jump to the corresponding 1617 // place in the original code. If not the break point was removed during 1618 // break point processing. 1619 if (break_at_js_return_active) { 1620 addr += original_code->instruction_start() - code->instruction_start(); 1621 } 1622 1623 // Move back to where the call instruction sequence started. 1624 thread_local_.after_break_target_ = 1625 addr - Assembler::kPatchReturnSequenceAddressOffset; 1626 } else { 1627 // Check if there still is a debug break call at the target address. If the 1628 // break point has been removed it will have disappeared. If it have 1629 // disappeared don't try to look in the original code as the running code 1630 // will have the right address. This takes care of the case where the last 1631 // break point is removed from the function and therefore no "original code" 1632 // is available. If the debug break call is still there find the address in 1633 // the original code. 1634 if (IsDebugBreak(Assembler::target_address_at(addr))) { 1635 // If the break point is still there find the call address which was 1636 // overwritten in the original code by the call to DebugBreakXXX. 1637 1638 // Find the corresponding address in the original code. 1639 addr += original_code->instruction_start() - code->instruction_start(); 1640 } 1641 1642 // Install jump to the call address in the original code. This will be the 1643 // call which was overwritten by the call to DebugBreakXXX. 1644 thread_local_.after_break_target_ = Assembler::target_address_at(addr); 1645 } 1646 } 1647 1648 1649 bool Debug::IsDebugGlobal(GlobalObject* global) { 1650 return IsLoaded() && global == Debug::debug_context()->global(); 1651 } 1652 1653 1654 void Debug::ClearMirrorCache() { 1655 HandleScope scope; 1656 ASSERT(Top::context() == *Debug::debug_context()); 1657 1658 // Clear the mirror cache. 1659 Handle<String> function_name = 1660 Factory::LookupSymbol(CStrVector("ClearMirrorCache")); 1661 Handle<Object> fun(Top::global()->GetProperty(*function_name)); 1662 ASSERT(fun->IsJSFunction()); 1663 bool caught_exception; 1664 Handle<Object> js_object = Execution::TryCall( 1665 Handle<JSFunction>::cast(fun), 1666 Handle<JSObject>(Debug::debug_context()->global()), 1667 0, NULL, &caught_exception); 1668 } 1669 1670 1671 void Debug::CreateScriptCache() { 1672 HandleScope scope; 1673 1674 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets 1675 // rid of all the cached script wrappers and the second gets rid of the 1676 // scripts which are no longer referenced. 1677 Heap::CollectAllGarbage(false); 1678 Heap::CollectAllGarbage(false); 1679 1680 ASSERT(script_cache_ == NULL); 1681 script_cache_ = new ScriptCache(); 1682 1683 // Scan heap for Script objects. 1684 int count = 0; 1685 HeapIterator iterator; 1686 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { 1687 if (obj->IsScript() && Script::cast(obj)->HasValidSource()) { 1688 script_cache_->Add(Handle<Script>(Script::cast(obj))); 1689 count++; 1690 } 1691 } 1692 } 1693 1694 1695 void Debug::DestroyScriptCache() { 1696 // Get rid of the script cache if it was created. 1697 if (script_cache_ != NULL) { 1698 delete script_cache_; 1699 script_cache_ = NULL; 1700 } 1701 } 1702 1703 1704 void Debug::AddScriptToScriptCache(Handle<Script> script) { 1705 if (script_cache_ != NULL) { 1706 script_cache_->Add(script); 1707 } 1708 } 1709 1710 1711 Handle<FixedArray> Debug::GetLoadedScripts() { 1712 // Create and fill the script cache when the loaded scripts is requested for 1713 // the first time. 1714 if (script_cache_ == NULL) { 1715 CreateScriptCache(); 1716 } 1717 1718 // If the script cache is not active just return an empty array. 1719 ASSERT(script_cache_ != NULL); 1720 if (script_cache_ == NULL) { 1721 Factory::NewFixedArray(0); 1722 } 1723 1724 // Perform GC to get unreferenced scripts evicted from the cache before 1725 // returning the content. 1726 Heap::CollectAllGarbage(false); 1727 1728 // Get the scripts from the cache. 1729 return script_cache_->GetScripts(); 1730 } 1731 1732 1733 void Debug::AfterGarbageCollection() { 1734 // Generate events for collected scripts. 1735 if (script_cache_ != NULL) { 1736 script_cache_->ProcessCollectedScripts(); 1737 } 1738 } 1739 1740 1741 Mutex* Debugger::debugger_access_ = OS::CreateMutex(); 1742 Handle<Object> Debugger::event_listener_ = Handle<Object>(); 1743 Handle<Object> Debugger::event_listener_data_ = Handle<Object>(); 1744 bool Debugger::compiling_natives_ = false; 1745 bool Debugger::is_loading_debugger_ = false; 1746 bool Debugger::never_unload_debugger_ = false; 1747 v8::Debug::MessageHandler2 Debugger::message_handler_ = NULL; 1748 bool Debugger::debugger_unload_pending_ = false; 1749 v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL; 1750 Mutex* Debugger::dispatch_handler_access_ = OS::CreateMutex(); 1751 v8::Debug::DebugMessageDispatchHandler 1752 Debugger::debug_message_dispatch_handler_ = NULL; 1753 MessageDispatchHelperThread* Debugger::message_dispatch_helper_thread_ = NULL; 1754 int Debugger::host_dispatch_micros_ = 100 * 1000; 1755 DebuggerAgent* Debugger::agent_ = NULL; 1756 LockingCommandMessageQueue Debugger::command_queue_(kQueueInitialSize); 1757 Semaphore* Debugger::command_received_ = OS::CreateSemaphore(0); 1758 1759 1760 Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name, 1761 int argc, Object*** argv, 1762 bool* caught_exception) { 1763 ASSERT(Top::context() == *Debug::debug_context()); 1764 1765 // Create the execution state object. 1766 Handle<String> constructor_str = Factory::LookupSymbol(constructor_name); 1767 Handle<Object> constructor(Top::global()->GetProperty(*constructor_str)); 1768 ASSERT(constructor->IsJSFunction()); 1769 if (!constructor->IsJSFunction()) { 1770 *caught_exception = true; 1771 return Factory::undefined_value(); 1772 } 1773 Handle<Object> js_object = Execution::TryCall( 1774 Handle<JSFunction>::cast(constructor), 1775 Handle<JSObject>(Debug::debug_context()->global()), argc, argv, 1776 caught_exception); 1777 return js_object; 1778 } 1779 1780 1781 Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) { 1782 // Create the execution state object. 1783 Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id()); 1784 const int argc = 1; 1785 Object** argv[argc] = { break_id.location() }; 1786 return MakeJSObject(CStrVector("MakeExecutionState"), 1787 argc, argv, caught_exception); 1788 } 1789 1790 1791 Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state, 1792 Handle<Object> break_points_hit, 1793 bool* caught_exception) { 1794 // Create the new break event object. 1795 const int argc = 2; 1796 Object** argv[argc] = { exec_state.location(), 1797 break_points_hit.location() }; 1798 return MakeJSObject(CStrVector("MakeBreakEvent"), 1799 argc, 1800 argv, 1801 caught_exception); 1802 } 1803 1804 1805 Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state, 1806 Handle<Object> exception, 1807 bool uncaught, 1808 bool* caught_exception) { 1809 // Create the new exception event object. 1810 const int argc = 3; 1811 Object** argv[argc] = { exec_state.location(), 1812 exception.location(), 1813 uncaught ? Factory::true_value().location() : 1814 Factory::false_value().location()}; 1815 return MakeJSObject(CStrVector("MakeExceptionEvent"), 1816 argc, argv, caught_exception); 1817 } 1818 1819 1820 Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function, 1821 bool* caught_exception) { 1822 // Create the new function event object. 1823 const int argc = 1; 1824 Object** argv[argc] = { function.location() }; 1825 return MakeJSObject(CStrVector("MakeNewFunctionEvent"), 1826 argc, argv, caught_exception); 1827 } 1828 1829 1830 Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script, 1831 bool before, 1832 bool* caught_exception) { 1833 // Create the compile event object. 1834 Handle<Object> exec_state = MakeExecutionState(caught_exception); 1835 Handle<Object> script_wrapper = GetScriptWrapper(script); 1836 const int argc = 3; 1837 Object** argv[argc] = { exec_state.location(), 1838 script_wrapper.location(), 1839 before ? Factory::true_value().location() : 1840 Factory::false_value().location() }; 1841 1842 return MakeJSObject(CStrVector("MakeCompileEvent"), 1843 argc, 1844 argv, 1845 caught_exception); 1846 } 1847 1848 1849 Handle<Object> Debugger::MakeScriptCollectedEvent(int id, 1850 bool* caught_exception) { 1851 // Create the script collected event object. 1852 Handle<Object> exec_state = MakeExecutionState(caught_exception); 1853 Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id)); 1854 const int argc = 2; 1855 Object** argv[argc] = { exec_state.location(), id_object.location() }; 1856 1857 return MakeJSObject(CStrVector("MakeScriptCollectedEvent"), 1858 argc, 1859 argv, 1860 caught_exception); 1861 } 1862 1863 1864 void Debugger::OnException(Handle<Object> exception, bool uncaught) { 1865 HandleScope scope; 1866 1867 // Bail out based on state or if there is no listener for this event 1868 if (Debug::InDebugger()) return; 1869 if (!Debugger::EventActive(v8::Exception)) return; 1870 1871 // Bail out if exception breaks are not active 1872 if (uncaught) { 1873 // Uncaught exceptions are reported by either flags. 1874 if (!(Debug::break_on_uncaught_exception() || 1875 Debug::break_on_exception())) return; 1876 } else { 1877 // Caught exceptions are reported is activated. 1878 if (!Debug::break_on_exception()) return; 1879 } 1880 1881 // Enter the debugger. 1882 EnterDebugger debugger; 1883 if (debugger.FailedToEnter()) return; 1884 1885 // Clear all current stepping setup. 1886 Debug::ClearStepping(); 1887 // Create the event data object. 1888 bool caught_exception = false; 1889 Handle<Object> exec_state = MakeExecutionState(&caught_exception); 1890 Handle<Object> event_data; 1891 if (!caught_exception) { 1892 event_data = MakeExceptionEvent(exec_state, exception, uncaught, 1893 &caught_exception); 1894 } 1895 // Bail out and don't call debugger if exception. 1896 if (caught_exception) { 1897 return; 1898 } 1899 1900 // Process debug event. 1901 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false); 1902 // Return to continue execution from where the exception was thrown. 1903 } 1904 1905 1906 void Debugger::OnDebugBreak(Handle<Object> break_points_hit, 1907 bool auto_continue) { 1908 HandleScope scope; 1909 1910 // Debugger has already been entered by caller. 1911 ASSERT(Top::context() == *Debug::debug_context()); 1912 1913 // Bail out if there is no listener for this event 1914 if (!Debugger::EventActive(v8::Break)) return; 1915 1916 // Debugger must be entered in advance. 1917 ASSERT(Top::context() == *Debug::debug_context()); 1918 1919 // Create the event data object. 1920 bool caught_exception = false; 1921 Handle<Object> exec_state = MakeExecutionState(&caught_exception); 1922 Handle<Object> event_data; 1923 if (!caught_exception) { 1924 event_data = MakeBreakEvent(exec_state, break_points_hit, 1925 &caught_exception); 1926 } 1927 // Bail out and don't call debugger if exception. 1928 if (caught_exception) { 1929 return; 1930 } 1931 1932 // Process debug event. 1933 ProcessDebugEvent(v8::Break, 1934 Handle<JSObject>::cast(event_data), 1935 auto_continue); 1936 } 1937 1938 1939 void Debugger::OnBeforeCompile(Handle<Script> script) { 1940 HandleScope scope; 1941 1942 // Bail out based on state or if there is no listener for this event 1943 if (Debug::InDebugger()) return; 1944 if (compiling_natives()) return; 1945 if (!EventActive(v8::BeforeCompile)) return; 1946 1947 // Enter the debugger. 1948 EnterDebugger debugger; 1949 if (debugger.FailedToEnter()) return; 1950 1951 // Create the event data object. 1952 bool caught_exception = false; 1953 Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception); 1954 // Bail out and don't call debugger if exception. 1955 if (caught_exception) { 1956 return; 1957 } 1958 1959 // Process debug event. 1960 ProcessDebugEvent(v8::BeforeCompile, 1961 Handle<JSObject>::cast(event_data), 1962 true); 1963 } 1964 1965 1966 // Handle debugger actions when a new script is compiled. 1967 void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction> fun) { 1968 HandleScope scope; 1969 1970 // Add the newly compiled script to the script cache. 1971 Debug::AddScriptToScriptCache(script); 1972 1973 // No more to do if not debugging. 1974 if (!IsDebuggerActive()) return; 1975 1976 // No compile events while compiling natives. 1977 if (compiling_natives()) return; 1978 1979 // Store whether in debugger before entering debugger. 1980 bool in_debugger = Debug::InDebugger(); 1981 1982 // Enter the debugger. 1983 EnterDebugger debugger; 1984 if (debugger.FailedToEnter()) return; 1985 1986 // If debugging there might be script break points registered for this 1987 // script. Make sure that these break points are set. 1988 1989 // Get the function UpdateScriptBreakPoints (defined in debug-debugger.js). 1990 Handle<Object> update_script_break_points = 1991 Handle<Object>(Debug::debug_context()->global()->GetProperty( 1992 *Factory::LookupAsciiSymbol("UpdateScriptBreakPoints"))); 1993 if (!update_script_break_points->IsJSFunction()) { 1994 return; 1995 } 1996 ASSERT(update_script_break_points->IsJSFunction()); 1997 1998 // Wrap the script object in a proper JS object before passing it 1999 // to JavaScript. 2000 Handle<JSValue> wrapper = GetScriptWrapper(script); 2001 2002 // Call UpdateScriptBreakPoints expect no exceptions. 2003 bool caught_exception = false; 2004 const int argc = 1; 2005 Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) }; 2006 Handle<Object> result = Execution::TryCall( 2007 Handle<JSFunction>::cast(update_script_break_points), 2008 Top::builtins(), argc, argv, 2009 &caught_exception); 2010 if (caught_exception) { 2011 return; 2012 } 2013 // Bail out based on state or if there is no listener for this event 2014 if (in_debugger) return; 2015 if (!Debugger::EventActive(v8::AfterCompile)) return; 2016 2017 // Create the compile state object. 2018 Handle<Object> event_data = MakeCompileEvent(script, 2019 false, 2020 &caught_exception); 2021 // Bail out and don't call debugger if exception. 2022 if (caught_exception) { 2023 return; 2024 } 2025 // Process debug event. 2026 ProcessDebugEvent(v8::AfterCompile, 2027 Handle<JSObject>::cast(event_data), 2028 true); 2029 } 2030 2031 2032 void Debugger::OnNewFunction(Handle<JSFunction> function) { 2033 return; 2034 HandleScope scope; 2035 2036 // Bail out based on state or if there is no listener for this event 2037 if (Debug::InDebugger()) return; 2038 if (compiling_natives()) return; 2039 if (!Debugger::EventActive(v8::NewFunction)) return; 2040 2041 // Enter the debugger. 2042 EnterDebugger debugger; 2043 if (debugger.FailedToEnter()) return; 2044 2045 // Create the event object. 2046 bool caught_exception = false; 2047 Handle<Object> event_data = MakeNewFunctionEvent(function, &caught_exception); 2048 // Bail out and don't call debugger if exception. 2049 if (caught_exception) { 2050 return; 2051 } 2052 // Process debug event. 2053 ProcessDebugEvent(v8::NewFunction, Handle<JSObject>::cast(event_data), true); 2054 } 2055 2056 2057 void Debugger::OnScriptCollected(int id) { 2058 HandleScope scope; 2059 2060 // No more to do if not debugging. 2061 if (!IsDebuggerActive()) return; 2062 if (!Debugger::EventActive(v8::ScriptCollected)) return; 2063 2064 // Enter the debugger. 2065 EnterDebugger debugger; 2066 if (debugger.FailedToEnter()) return; 2067 2068 // Create the script collected state object. 2069 bool caught_exception = false; 2070 Handle<Object> event_data = MakeScriptCollectedEvent(id, 2071 &caught_exception); 2072 // Bail out and don't call debugger if exception. 2073 if (caught_exception) { 2074 return; 2075 } 2076 2077 // Process debug event. 2078 ProcessDebugEvent(v8::ScriptCollected, 2079 Handle<JSObject>::cast(event_data), 2080 true); 2081 } 2082 2083 2084 void Debugger::ProcessDebugEvent(v8::DebugEvent event, 2085 Handle<JSObject> event_data, 2086 bool auto_continue) { 2087 HandleScope scope; 2088 2089 // Clear any pending debug break if this is a real break. 2090 if (!auto_continue) { 2091 Debug::clear_interrupt_pending(DEBUGBREAK); 2092 } 2093 2094 // Create the execution state. 2095 bool caught_exception = false; 2096 Handle<Object> exec_state = MakeExecutionState(&caught_exception); 2097 if (caught_exception) { 2098 return; 2099 } 2100 // First notify the message handler if any. 2101 if (message_handler_ != NULL) { 2102 NotifyMessageHandler(event, 2103 Handle<JSObject>::cast(exec_state), 2104 event_data, 2105 auto_continue); 2106 } 2107 // Notify registered debug event listener. This can be either a C or a 2108 // JavaScript function. 2109 if (!event_listener_.is_null()) { 2110 if (event_listener_->IsProxy()) { 2111 // C debug event listener. 2112 Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_)); 2113 v8::Debug::EventCallback callback = 2114 FUNCTION_CAST<v8::Debug::EventCallback>(callback_obj->proxy()); 2115 callback(event, 2116 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), 2117 v8::Utils::ToLocal(event_data), 2118 v8::Utils::ToLocal(Handle<Object>::cast(event_listener_data_))); 2119 } else { 2120 // JavaScript debug event listener. 2121 ASSERT(event_listener_->IsJSFunction()); 2122 Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_)); 2123 2124 // Invoke the JavaScript debug event listener. 2125 const int argc = 4; 2126 Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(), 2127 exec_state.location(), 2128 Handle<Object>::cast(event_data).location(), 2129 event_listener_data_.location() }; 2130 Handle<Object> result = Execution::TryCall(fun, Top::global(), 2131 argc, argv, &caught_exception); 2132 // Silently ignore exceptions from debug event listeners. 2133 } 2134 } 2135 } 2136 2137 2138 void Debugger::UnloadDebugger() { 2139 // Make sure that there are no breakpoints left. 2140 Debug::ClearAllBreakPoints(); 2141 2142 // Unload the debugger if feasible. 2143 if (!never_unload_debugger_) { 2144 Debug::Unload(); 2145 } 2146 2147 // Clear the flag indicating that the debugger should be unloaded. 2148 debugger_unload_pending_ = false; 2149 } 2150 2151 2152 void Debugger::NotifyMessageHandler(v8::DebugEvent event, 2153 Handle<JSObject> exec_state, 2154 Handle<JSObject> event_data, 2155 bool auto_continue) { 2156 HandleScope scope; 2157 2158 if (!Debug::Load()) return; 2159 2160 // Process the individual events. 2161 bool sendEventMessage = false; 2162 switch (event) { 2163 case v8::Break: 2164 sendEventMessage = !auto_continue; 2165 break; 2166 case v8::Exception: 2167 sendEventMessage = true; 2168 break; 2169 case v8::BeforeCompile: 2170 break; 2171 case v8::AfterCompile: 2172 sendEventMessage = true; 2173 break; 2174 case v8::ScriptCollected: 2175 sendEventMessage = true; 2176 break; 2177 case v8::NewFunction: 2178 break; 2179 default: 2180 UNREACHABLE(); 2181 } 2182 2183 // The debug command interrupt flag might have been set when the command was 2184 // added. It should be enough to clear the flag only once while we are in the 2185 // debugger. 2186 ASSERT(Debug::InDebugger()); 2187 StackGuard::Continue(DEBUGCOMMAND); 2188 2189 // Notify the debugger that a debug event has occurred unless auto continue is 2190 // active in which case no event is send. 2191 if (sendEventMessage) { 2192 MessageImpl message = MessageImpl::NewEvent( 2193 event, 2194 auto_continue, 2195 Handle<JSObject>::cast(exec_state), 2196 Handle<JSObject>::cast(event_data)); 2197 InvokeMessageHandler(message); 2198 } 2199 2200 // If auto continue don't make the event cause a break, but process messages 2201 // in the queue if any. For script collected events don't even process 2202 // messages in the queue as the execution state might not be what is expected 2203 // by the client. 2204 if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) { 2205 return; 2206 } 2207 2208 v8::TryCatch try_catch; 2209 2210 // DebugCommandProcessor goes here. 2211 v8::Local<v8::Object> cmd_processor; 2212 { 2213 v8::Local<v8::Object> api_exec_state = 2214 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)); 2215 v8::Local<v8::String> fun_name = 2216 v8::String::New("debugCommandProcessor"); 2217 v8::Local<v8::Function> fun = 2218 v8::Function::Cast(*api_exec_state->Get(fun_name)); 2219 2220 v8::Handle<v8::Boolean> running = 2221 auto_continue ? v8::True() : v8::False(); 2222 static const int kArgc = 1; 2223 v8::Handle<Value> argv[kArgc] = { running }; 2224 cmd_processor = v8::Object::Cast(*fun->Call(api_exec_state, kArgc, argv)); 2225 if (try_catch.HasCaught()) { 2226 PrintLn(try_catch.Exception()); 2227 return; 2228 } 2229 } 2230 2231 bool running = auto_continue; 2232 2233 // Process requests from the debugger. 2234 while (true) { 2235 // Wait for new command in the queue. 2236 if (Debugger::host_dispatch_handler_) { 2237 // In case there is a host dispatch - do periodic dispatches. 2238 if (!command_received_->Wait(host_dispatch_micros_)) { 2239 // Timout expired, do the dispatch. 2240 Debugger::host_dispatch_handler_(); 2241 continue; 2242 } 2243 } else { 2244 // In case there is no host dispatch - just wait. 2245 command_received_->Wait(); 2246 } 2247 2248 // Get the command from the queue. 2249 CommandMessage command = command_queue_.Get(); 2250 Logger::DebugTag("Got request from command queue, in interactive loop."); 2251 if (!Debugger::IsDebuggerActive()) { 2252 // Delete command text and user data. 2253 command.Dispose(); 2254 return; 2255 } 2256 2257 // Invoke JavaScript to process the debug request. 2258 v8::Local<v8::String> fun_name; 2259 v8::Local<v8::Function> fun; 2260 v8::Local<v8::Value> request; 2261 v8::TryCatch try_catch; 2262 fun_name = v8::String::New("processDebugRequest"); 2263 fun = v8::Function::Cast(*cmd_processor->Get(fun_name)); 2264 2265 request = v8::String::New(command.text().start(), 2266 command.text().length()); 2267 static const int kArgc = 1; 2268 v8::Handle<Value> argv[kArgc] = { request }; 2269 v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv); 2270 2271 // Get the response. 2272 v8::Local<v8::String> response; 2273 if (!try_catch.HasCaught()) { 2274 // Get response string. 2275 if (!response_val->IsUndefined()) { 2276 response = v8::String::Cast(*response_val); 2277 } else { 2278 response = v8::String::New(""); 2279 } 2280 2281 // Log the JSON request/response. 2282 if (FLAG_trace_debug_json) { 2283 PrintLn(request); 2284 PrintLn(response); 2285 } 2286 2287 // Get the running state. 2288 fun_name = v8::String::New("isRunning"); 2289 fun = v8::Function::Cast(*cmd_processor->Get(fun_name)); 2290 static const int kArgc = 1; 2291 v8::Handle<Value> argv[kArgc] = { response }; 2292 v8::Local<v8::Value> running_val = fun->Call(cmd_processor, kArgc, argv); 2293 if (!try_catch.HasCaught()) { 2294 running = running_val->ToBoolean()->Value(); 2295 } 2296 } else { 2297 // In case of failure the result text is the exception text. 2298 response = try_catch.Exception()->ToString(); 2299 } 2300 2301 // Return the result. 2302 MessageImpl message = MessageImpl::NewResponse( 2303 event, 2304 running, 2305 Handle<JSObject>::cast(exec_state), 2306 Handle<JSObject>::cast(event_data), 2307 Handle<String>(Utils::OpenHandle(*response)), 2308 command.client_data()); 2309 InvokeMessageHandler(message); 2310 command.Dispose(); 2311 2312 // Return from debug event processing if either the VM is put into the 2313 // runnning state (through a continue command) or auto continue is active 2314 // and there are no more commands queued. 2315 if (running && !HasCommands()) { 2316 return; 2317 } 2318 } 2319 } 2320 2321 2322 void Debugger::SetEventListener(Handle<Object> callback, 2323 Handle<Object> data) { 2324 HandleScope scope; 2325 2326 // Clear the global handles for the event listener and the event listener data 2327 // object. 2328 if (!event_listener_.is_null()) { 2329 GlobalHandles::Destroy( 2330 reinterpret_cast<Object**>(event_listener_.location())); 2331 event_listener_ = Handle<Object>(); 2332 } 2333 if (!event_listener_data_.is_null()) { 2334 GlobalHandles::Destroy( 2335 reinterpret_cast<Object**>(event_listener_data_.location())); 2336 event_listener_data_ = Handle<Object>(); 2337 } 2338 2339 // If there is a new debug event listener register it together with its data 2340 // object. 2341 if (!callback->IsUndefined() && !callback->IsNull()) { 2342 event_listener_ = Handle<Object>::cast(GlobalHandles::Create(*callback)); 2343 if (data.is_null()) { 2344 data = Factory::undefined_value(); 2345 } 2346 event_listener_data_ = Handle<Object>::cast(GlobalHandles::Create(*data)); 2347 } 2348 2349 ListenersChanged(); 2350 } 2351 2352 2353 void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) { 2354 ScopedLock with(debugger_access_); 2355 2356 message_handler_ = handler; 2357 ListenersChanged(); 2358 if (handler == NULL) { 2359 // Send an empty command to the debugger if in a break to make JavaScript 2360 // run again if the debugger is closed. 2361 if (Debug::InDebugger()) { 2362 ProcessCommand(Vector<const uint16_t>::empty()); 2363 } 2364 } 2365 } 2366 2367 2368 void Debugger::ListenersChanged() { 2369 if (IsDebuggerActive()) { 2370 // Disable the compilation cache when the debugger is active. 2371 CompilationCache::Disable(); 2372 debugger_unload_pending_ = false; 2373 } else { 2374 CompilationCache::Enable(); 2375 // Unload the debugger if event listener and message handler cleared. 2376 // Schedule this for later, because we may be in non-V8 thread. 2377 debugger_unload_pending_ = true; 2378 } 2379 } 2380 2381 2382 void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler, 2383 int period) { 2384 host_dispatch_handler_ = handler; 2385 host_dispatch_micros_ = period * 1000; 2386 } 2387 2388 2389 void Debugger::SetDebugMessageDispatchHandler( 2390 v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) { 2391 ScopedLock with(dispatch_handler_access_); 2392 debug_message_dispatch_handler_ = handler; 2393 2394 if (provide_locker && message_dispatch_helper_thread_ == NULL) { 2395 message_dispatch_helper_thread_ = new MessageDispatchHelperThread; 2396 message_dispatch_helper_thread_->Start(); 2397 } 2398 } 2399 2400 2401 // Calls the registered debug message handler. This callback is part of the 2402 // public API. 2403 void Debugger::InvokeMessageHandler(MessageImpl message) { 2404 ScopedLock with(debugger_access_); 2405 2406 if (message_handler_ != NULL) { 2407 message_handler_(message); 2408 } 2409 } 2410 2411 2412 // Puts a command coming from the public API on the queue. Creates 2413 // a copy of the command string managed by the debugger. Up to this 2414 // point, the command data was managed by the API client. Called 2415 // by the API client thread. 2416 void Debugger::ProcessCommand(Vector<const uint16_t> command, 2417 v8::Debug::ClientData* client_data) { 2418 // Need to cast away const. 2419 CommandMessage message = CommandMessage::New( 2420 Vector<uint16_t>(const_cast<uint16_t*>(command.start()), 2421 command.length()), 2422 client_data); 2423 Logger::DebugTag("Put command on command_queue."); 2424 command_queue_.Put(message); 2425 command_received_->Signal(); 2426 2427 // Set the debug command break flag to have the command processed. 2428 if (!Debug::InDebugger()) { 2429 StackGuard::DebugCommand(); 2430 } 2431 2432 MessageDispatchHelperThread* dispatch_thread; 2433 { 2434 ScopedLock with(dispatch_handler_access_); 2435 dispatch_thread = message_dispatch_helper_thread_; 2436 } 2437 2438 if (dispatch_thread == NULL) { 2439 CallMessageDispatchHandler(); 2440 } else { 2441 dispatch_thread->Schedule(); 2442 } 2443 } 2444 2445 2446 bool Debugger::HasCommands() { 2447 return !command_queue_.IsEmpty(); 2448 } 2449 2450 2451 bool Debugger::IsDebuggerActive() { 2452 ScopedLock with(debugger_access_); 2453 2454 return message_handler_ != NULL || !event_listener_.is_null(); 2455 } 2456 2457 2458 Handle<Object> Debugger::Call(Handle<JSFunction> fun, 2459 Handle<Object> data, 2460 bool* pending_exception) { 2461 // When calling functions in the debugger prevent it from beeing unloaded. 2462 Debugger::never_unload_debugger_ = true; 2463 2464 // Enter the debugger. 2465 EnterDebugger debugger; 2466 if (debugger.FailedToEnter() || !debugger.HasJavaScriptFrames()) { 2467 return Factory::undefined_value(); 2468 } 2469 2470 // Create the execution state. 2471 bool caught_exception = false; 2472 Handle<Object> exec_state = MakeExecutionState(&caught_exception); 2473 if (caught_exception) { 2474 return Factory::undefined_value(); 2475 } 2476 2477 static const int kArgc = 2; 2478 Object** argv[kArgc] = { exec_state.location(), data.location() }; 2479 Handle<Object> result = Execution::Call(fun, Factory::undefined_value(), 2480 kArgc, argv, pending_exception); 2481 return result; 2482 } 2483 2484 2485 static void StubMessageHandler2(const v8::Debug::Message& message) { 2486 // Simply ignore message. 2487 } 2488 2489 2490 bool Debugger::StartAgent(const char* name, int port, 2491 bool wait_for_connection) { 2492 if (wait_for_connection) { 2493 // Suspend V8 if it is already running or set V8 to suspend whenever 2494 // it starts. 2495 // Provide stub message handler; V8 auto-continues each suspend 2496 // when there is no message handler; we doesn't need it. 2497 // Once become suspended, V8 will stay so indefinitely long, until remote 2498 // debugger connects and issues "continue" command. 2499 Debugger::message_handler_ = StubMessageHandler2; 2500 v8::Debug::DebugBreak(); 2501 } 2502 2503 if (Socket::Setup()) { 2504 agent_ = new DebuggerAgent(name, port); 2505 agent_->Start(); 2506 return true; 2507 } 2508 2509 return false; 2510 } 2511 2512 2513 void Debugger::StopAgent() { 2514 if (agent_ != NULL) { 2515 agent_->Shutdown(); 2516 agent_->Join(); 2517 delete agent_; 2518 agent_ = NULL; 2519 } 2520 } 2521 2522 2523 void Debugger::WaitForAgent() { 2524 if (agent_ != NULL) 2525 agent_->WaitUntilListening(); 2526 } 2527 2528 2529 void Debugger::CallMessageDispatchHandler() { 2530 v8::Debug::DebugMessageDispatchHandler handler; 2531 { 2532 ScopedLock with(dispatch_handler_access_); 2533 handler = Debugger::debug_message_dispatch_handler_; 2534 } 2535 if (handler != NULL) { 2536 handler(); 2537 } 2538 } 2539 2540 2541 MessageImpl MessageImpl::NewEvent(DebugEvent event, 2542 bool running, 2543 Handle<JSObject> exec_state, 2544 Handle<JSObject> event_data) { 2545 MessageImpl message(true, event, running, 2546 exec_state, event_data, Handle<String>(), NULL); 2547 return message; 2548 } 2549 2550 2551 MessageImpl MessageImpl::NewResponse(DebugEvent event, 2552 bool running, 2553 Handle<JSObject> exec_state, 2554 Handle<JSObject> event_data, 2555 Handle<String> response_json, 2556 v8::Debug::ClientData* client_data) { 2557 MessageImpl message(false, event, running, 2558 exec_state, event_data, response_json, client_data); 2559 return message; 2560 } 2561 2562 2563 MessageImpl::MessageImpl(bool is_event, 2564 DebugEvent event, 2565 bool running, 2566 Handle<JSObject> exec_state, 2567 Handle<JSObject> event_data, 2568 Handle<String> response_json, 2569 v8::Debug::ClientData* client_data) 2570 : is_event_(is_event), 2571 event_(event), 2572 running_(running), 2573 exec_state_(exec_state), 2574 event_data_(event_data), 2575 response_json_(response_json), 2576 client_data_(client_data) {} 2577 2578 2579 bool MessageImpl::IsEvent() const { 2580 return is_event_; 2581 } 2582 2583 2584 bool MessageImpl::IsResponse() const { 2585 return !is_event_; 2586 } 2587 2588 2589 DebugEvent MessageImpl::GetEvent() const { 2590 return event_; 2591 } 2592 2593 2594 bool MessageImpl::WillStartRunning() const { 2595 return running_; 2596 } 2597 2598 2599 v8::Handle<v8::Object> MessageImpl::GetExecutionState() const { 2600 return v8::Utils::ToLocal(exec_state_); 2601 } 2602 2603 2604 v8::Handle<v8::Object> MessageImpl::GetEventData() const { 2605 return v8::Utils::ToLocal(event_data_); 2606 } 2607 2608 2609 v8::Handle<v8::String> MessageImpl::GetJSON() const { 2610 v8::HandleScope scope; 2611 2612 if (IsEvent()) { 2613 // Call toJSONProtocol on the debug event object. 2614 Handle<Object> fun = GetProperty(event_data_, "toJSONProtocol"); 2615 if (!fun->IsJSFunction()) { 2616 return v8::Handle<v8::String>(); 2617 } 2618 bool caught_exception; 2619 Handle<Object> json = Execution::TryCall(Handle<JSFunction>::cast(fun), 2620 event_data_, 2621 0, NULL, &caught_exception); 2622 if (caught_exception || !json->IsString()) { 2623 return v8::Handle<v8::String>(); 2624 } 2625 return scope.Close(v8::Utils::ToLocal(Handle<String>::cast(json))); 2626 } else { 2627 return v8::Utils::ToLocal(response_json_); 2628 } 2629 } 2630 2631 2632 v8::Handle<v8::Context> MessageImpl::GetEventContext() const { 2633 Handle<Context> context = Debug::debugger_entry()->GetContext(); 2634 // Top::context() may have been NULL when "script collected" event occured. 2635 if (*context == NULL) { 2636 ASSERT(event_ == v8::ScriptCollected); 2637 return v8::Local<v8::Context>(); 2638 } 2639 Handle<Context> global_context(context->global_context()); 2640 return v8::Utils::ToLocal(global_context); 2641 } 2642 2643 2644 v8::Debug::ClientData* MessageImpl::GetClientData() const { 2645 return client_data_; 2646 } 2647 2648 2649 CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()), 2650 client_data_(NULL) { 2651 } 2652 2653 2654 CommandMessage::CommandMessage(const Vector<uint16_t>& text, 2655 v8::Debug::ClientData* data) 2656 : text_(text), 2657 client_data_(data) { 2658 } 2659 2660 2661 CommandMessage::~CommandMessage() { 2662 } 2663 2664 2665 void CommandMessage::Dispose() { 2666 text_.Dispose(); 2667 delete client_data_; 2668 client_data_ = NULL; 2669 } 2670 2671 2672 CommandMessage CommandMessage::New(const Vector<uint16_t>& command, 2673 v8::Debug::ClientData* data) { 2674 return CommandMessage(command.Clone(), data); 2675 } 2676 2677 2678 CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0), 2679 size_(size) { 2680 messages_ = NewArray<CommandMessage>(size); 2681 } 2682 2683 2684 CommandMessageQueue::~CommandMessageQueue() { 2685 while (!IsEmpty()) { 2686 CommandMessage m = Get(); 2687 m.Dispose(); 2688 } 2689 DeleteArray(messages_); 2690 } 2691 2692 2693 CommandMessage CommandMessageQueue::Get() { 2694 ASSERT(!IsEmpty()); 2695 int result = start_; 2696 start_ = (start_ + 1) % size_; 2697 return messages_[result]; 2698 } 2699 2700 2701 void CommandMessageQueue::Put(const CommandMessage& message) { 2702 if ((end_ + 1) % size_ == start_) { 2703 Expand(); 2704 } 2705 messages_[end_] = message; 2706 end_ = (end_ + 1) % size_; 2707 } 2708 2709 2710 void CommandMessageQueue::Expand() { 2711 CommandMessageQueue new_queue(size_ * 2); 2712 while (!IsEmpty()) { 2713 new_queue.Put(Get()); 2714 } 2715 CommandMessage* array_to_free = messages_; 2716 *this = new_queue; 2717 new_queue.messages_ = array_to_free; 2718 // Make the new_queue empty so that it doesn't call Dispose on any messages. 2719 new_queue.start_ = new_queue.end_; 2720 // Automatic destructor called on new_queue, freeing array_to_free. 2721 } 2722 2723 2724 LockingCommandMessageQueue::LockingCommandMessageQueue(int size) 2725 : queue_(size) { 2726 lock_ = OS::CreateMutex(); 2727 } 2728 2729 2730 LockingCommandMessageQueue::~LockingCommandMessageQueue() { 2731 delete lock_; 2732 } 2733 2734 2735 bool LockingCommandMessageQueue::IsEmpty() const { 2736 ScopedLock sl(lock_); 2737 return queue_.IsEmpty(); 2738 } 2739 2740 2741 CommandMessage LockingCommandMessageQueue::Get() { 2742 ScopedLock sl(lock_); 2743 CommandMessage result = queue_.Get(); 2744 Logger::DebugEvent("Get", result.text()); 2745 return result; 2746 } 2747 2748 2749 void LockingCommandMessageQueue::Put(const CommandMessage& message) { 2750 ScopedLock sl(lock_); 2751 queue_.Put(message); 2752 Logger::DebugEvent("Put", message.text()); 2753 } 2754 2755 2756 void LockingCommandMessageQueue::Clear() { 2757 ScopedLock sl(lock_); 2758 queue_.Clear(); 2759 } 2760 2761 2762 MessageDispatchHelperThread::MessageDispatchHelperThread() 2763 : sem_(OS::CreateSemaphore(0)), mutex_(OS::CreateMutex()), 2764 already_signalled_(false) { 2765 } 2766 2767 2768 MessageDispatchHelperThread::~MessageDispatchHelperThread() { 2769 delete mutex_; 2770 delete sem_; 2771 } 2772 2773 2774 void MessageDispatchHelperThread::Schedule() { 2775 { 2776 ScopedLock lock(mutex_); 2777 if (already_signalled_) { 2778 return; 2779 } 2780 already_signalled_ = true; 2781 } 2782 sem_->Signal(); 2783 } 2784 2785 2786 void MessageDispatchHelperThread::Run() { 2787 while (true) { 2788 sem_->Wait(); 2789 { 2790 ScopedLock lock(mutex_); 2791 already_signalled_ = false; 2792 } 2793 { 2794 Locker locker; 2795 Debugger::CallMessageDispatchHandler(); 2796 } 2797 } 2798 } 2799 2800 #endif // ENABLE_DEBUGGER_SUPPORT 2801 2802 } } // namespace v8::internal 2803