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