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