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