| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 496 reloc_iterator_->next(); | 496 reloc_iterator_->next(); |
| 497 reloc_iterator_original_->next(); | 497 reloc_iterator_original_->next(); |
| 498 #ifdef DEBUG | 498 #ifdef DEBUG |
| 499 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done()); | 499 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done()); |
| 500 if (!reloc_iterator_->done()) { | 500 if (!reloc_iterator_->done()) { |
| 501 ASSERT(rmode() == original_rmode()); | 501 ASSERT(rmode() == original_rmode()); |
| 502 } | 502 } |
| 503 #endif | 503 #endif |
| 504 } | 504 } |
| 505 | 505 |
| 506 | 506 DebugData::DebugData() |
| 507 bool Debug::has_break_points_ = false; | 507 :has_break_points_(false), |
| 508 ScriptCache* Debug::script_cache_ = NULL; | 508 script_cache_(NULL), |
| 509 DebugInfoListNode* Debug::debug_info_list_ = NULL; | 509 debug_info_list_(NULL), |
| 510 | 510 disable_break_(false), |
| 511 break_on_exception_(false), |
| 512 break_on_uncaught_exception_(true), |
| 513 debug_context_(Handle<Context>()), |
| 514 debug_break_return_(NULL) { |
| 515 } |
| 511 | 516 |
| 512 // Threading support. | 517 // Threading support. |
| 513 void Debug::ThreadInit() { | 518 void Debug::ThreadInit() { |
| 514 thread_local_.break_count_ = 0; | 519 ThreadLocal& thread_local = v8_context()->debug_data_.thread_local_; |
| 515 thread_local_.break_id_ = 0; | 520 thread_local.break_count_ = 0; |
| 516 thread_local_.break_frame_id_ = StackFrame::NO_ID; | 521 thread_local.break_id_ = 0; |
| 517 thread_local_.last_step_action_ = StepNone; | 522 thread_local.break_frame_id_ = StackFrame::NO_ID; |
| 518 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; | 523 thread_local.last_step_action_ = StepNone; |
| 519 thread_local_.step_count_ = 0; | 524 thread_local.last_statement_position_ = RelocInfo::kNoPosition; |
| 520 thread_local_.last_fp_ = 0; | 525 thread_local.step_count_ = 0; |
| 521 thread_local_.step_into_fp_ = 0; | 526 thread_local.last_fp_ = 0; |
| 522 thread_local_.step_out_fp_ = 0; | 527 thread_local.step_into_fp_ = 0; |
| 523 thread_local_.after_break_target_ = 0; | 528 thread_local.step_out_fp_ = 0; |
| 524 thread_local_.debugger_entry_ = NULL; | 529 thread_local.after_break_target_ = 0; |
| 525 thread_local_.pending_interrupts_ = 0; | 530 thread_local.debugger_entry_ = NULL; |
| 531 thread_local.pending_interrupts_ = 0; |
| 526 } | 532 } |
| 527 | 533 |
| 528 | |
| 529 JSCallerSavedBuffer Debug::registers_; | |
| 530 Debug::ThreadLocal Debug::thread_local_; | |
| 531 | |
| 532 | |
| 533 char* Debug::ArchiveDebug(char* storage) { | 534 char* Debug::ArchiveDebug(char* storage) { |
| 534 char* to = storage; | 535 char* to = storage; |
| 535 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); | 536 DebugData& data = v8_context()->debug_data_; |
| 537 memcpy(to, reinterpret_cast<char*>(&data.thread_local_), |
| 538 sizeof(ThreadLocal)); |
| 536 to += sizeof(ThreadLocal); | 539 to += sizeof(ThreadLocal); |
| 537 memcpy(to, reinterpret_cast<char*>(®isters_), sizeof(registers_)); | 540 memcpy(to, reinterpret_cast<char*>(&data.registers_), |
| 541 sizeof(JSCallerSavedBuffer)); |
| 538 ThreadInit(); | 542 ThreadInit(); |
| 539 ASSERT(to <= storage + ArchiveSpacePerThread()); | 543 ASSERT(to <= storage + ArchiveSpacePerThread()); |
| 540 return storage + ArchiveSpacePerThread(); | 544 return storage + ArchiveSpacePerThread(); |
| 541 } | 545 } |
| 542 | 546 |
| 543 | 547 |
| 544 char* Debug::RestoreDebug(char* storage) { | 548 char* Debug::RestoreDebug(char* storage) { |
| 545 char* from = storage; | 549 char* from = storage; |
| 546 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal)); | 550 DebugData& data = v8_context()->debug_data_; |
| 551 memcpy(reinterpret_cast<char*>(&data.thread_local_), from, |
| 552 sizeof(ThreadLocal)); |
| 547 from += sizeof(ThreadLocal); | 553 from += sizeof(ThreadLocal); |
| 548 memcpy(reinterpret_cast<char*>(®isters_), from, sizeof(registers_)); | 554 memcpy(reinterpret_cast<char*>(&data.registers_), from, |
| 555 sizeof(JSCallerSavedBuffer)); |
| 549 ASSERT(from <= storage + ArchiveSpacePerThread()); | 556 ASSERT(from <= storage + ArchiveSpacePerThread()); |
| 550 return storage + ArchiveSpacePerThread(); | 557 return storage + ArchiveSpacePerThread(); |
| 551 } | 558 } |
| 552 | 559 |
| 553 | 560 |
| 554 int Debug::ArchiveSpacePerThread() { | 561 int Debug::ArchiveSpacePerThread() { |
| 555 return sizeof(ThreadLocal) + sizeof(registers_); | 562 return sizeof(ThreadLocal) + sizeof(JSCallerSavedBuffer); |
| 556 } | 563 } |
| 557 | 564 |
| 558 | |
| 559 // Default break enabled. | |
| 560 bool Debug::disable_break_ = false; | |
| 561 | |
| 562 // Default call debugger on uncaught exception. | |
| 563 bool Debug::break_on_exception_ = false; | |
| 564 bool Debug::break_on_uncaught_exception_ = true; | |
| 565 | |
| 566 Handle<Context> Debug::debug_context_ = Handle<Context>(); | |
| 567 Code* Debug::debug_break_return_ = NULL; | |
| 568 | |
| 569 | |
| 570 void ScriptCache::Add(Handle<Script> script) { | 565 void ScriptCache::Add(Handle<Script> script) { |
| 571 // Create an entry in the hash map for the script. | 566 // Create an entry in the hash map for the script. |
| 572 int id = Smi::cast(script->id())->value(); | 567 int id = Smi::cast(script->id())->value(); |
| 573 HashMap::Entry* entry = | 568 HashMap::Entry* entry = |
| 574 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true); | 569 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true); |
| 575 if (entry->value != NULL) { | 570 if (entry->value != NULL) { |
| 576 ASSERT(*script == *reinterpret_cast<Script**>(entry->value)); | 571 ASSERT(*script == *reinterpret_cast<Script**>(entry->value)); |
| 577 return; | 572 return; |
| 578 } | 573 } |
| 579 | 574 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 637 | 632 |
| 638 // Clear the weak handle. | 633 // Clear the weak handle. |
| 639 obj.Dispose(); | 634 obj.Dispose(); |
| 640 obj.Clear(); | 635 obj.Clear(); |
| 641 } | 636 } |
| 642 | 637 |
| 643 | 638 |
| 644 void Debug::Setup(bool create_heap_objects) { | 639 void Debug::Setup(bool create_heap_objects) { |
| 645 ThreadInit(); | 640 ThreadInit(); |
| 646 if (create_heap_objects) { | 641 if (create_heap_objects) { |
| 642 DebugData& data = v8_context()->debug_data_; |
| 647 // Get code to handle debug break on return. | 643 // Get code to handle debug break on return. |
| 648 debug_break_return_ = | 644 data.debug_break_return_ = |
| 649 Builtins::builtin(Builtins::Return_DebugBreak); | 645 Builtins::builtin(Builtins::Return_DebugBreak); |
| 650 ASSERT(debug_break_return_->IsCode()); | 646 ASSERT(data.debug_break_return_->IsCode()); |
| 651 } | 647 } |
| 652 } | 648 } |
| 653 | 649 |
| 654 | 650 |
| 655 void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) { | 651 void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) { |
| 656 DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data); | 652 DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data); |
| 657 RemoveDebugInfo(node->debug_info()); | 653 RemoveDebugInfo(node->debug_info()); |
| 658 #ifdef DEBUG | 654 #ifdef DEBUG |
| 659 node = Debug::debug_info_list_; | 655 node = v8_context()->debug_data_.debug_info_list_; |
| 660 while (node != NULL) { | 656 while (node != NULL) { |
| 661 ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data)); | 657 ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data)); |
| 662 node = node->next(); | 658 node = node->next(); |
| 663 } | 659 } |
| 664 #endif | 660 #endif |
| 665 } | 661 } |
| 666 | 662 |
| 667 | 663 |
| 668 DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) { | 664 DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) { |
| 669 // Globalize the request debug info object and make it weak. | 665 // Globalize the request debug info object and make it weak. |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 769 Debugger::set_compiling_natives(false); | 765 Debugger::set_compiling_natives(false); |
| 770 | 766 |
| 771 // Make sure we mark the debugger as not loading before we might | 767 // Make sure we mark the debugger as not loading before we might |
| 772 // return. | 768 // return. |
| 773 Debugger::set_loading_debugger(false); | 769 Debugger::set_loading_debugger(false); |
| 774 | 770 |
| 775 // Check for caught exceptions. | 771 // Check for caught exceptions. |
| 776 if (caught_exception) return false; | 772 if (caught_exception) return false; |
| 777 | 773 |
| 778 // Debugger loaded. | 774 // Debugger loaded. |
| 779 debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context)); | 775 v8_context()->debug_data_.debug_context_ = |
| 776 Handle<Context>::cast(GlobalHandles::Create(*context)); |
| 780 | 777 |
| 781 return true; | 778 return true; |
| 782 } | 779 } |
| 783 | 780 |
| 784 | 781 |
| 785 void Debug::Unload() { | 782 void Debug::Unload() { |
| 786 // Return debugger is not loaded. | 783 // Return debugger is not loaded. |
| 787 if (!IsLoaded()) { | 784 if (!IsLoaded()) { |
| 788 return; | 785 return; |
| 789 } | 786 } |
| 790 | 787 |
| 791 // Clear the script cache. | 788 // Clear the script cache. |
| 792 DestroyScriptCache(); | 789 DestroyScriptCache(); |
| 793 | 790 |
| 791 DebugData& data = v8_context()->debug_data_; |
| 794 // Clear debugger context global handle. | 792 // Clear debugger context global handle. |
| 795 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location())); | 793 GlobalHandles::Destroy( |
| 796 debug_context_ = Handle<Context>(); | 794 reinterpret_cast<Object**>(data.debug_context_.location())); |
| 795 data.debug_context_ = Handle<Context>(); |
| 797 } | 796 } |
| 798 | 797 |
| 799 | 798 |
| 800 // Set the flag indicating that preemption happened during debugging. | 799 // Set the flag indicating that preemption happened during debugging. |
| 801 void Debug::PreemptionWhileInDebugger() { | 800 void Debug::PreemptionWhileInDebugger() { |
| 802 ASSERT(InDebugger()); | 801 ASSERT(InDebugger()); |
| 803 Debug::set_interrupts_pending(PREEMPT); | 802 Debug::set_interrupts_pending(PREEMPT); |
| 804 } | 803 } |
| 805 | 804 |
| 806 | 805 |
| 807 void Debug::Iterate(ObjectVisitor* v) { | 806 void Debug::Iterate(ObjectVisitor* v) { |
| 808 v->VisitPointer(bit_cast<Object**, Code**>(&(debug_break_return_))); | 807 v->VisitPointer(bit_cast<Object**, Code**>( |
| 808 &(v8_context()->debug_data_.debug_break_return_))); |
| 809 } | 809 } |
| 810 | 810 |
| 811 | 811 |
| 812 Object* Debug::Break(Arguments args) { | 812 Object* Debug::Break(Arguments args) { |
| 813 HandleScope scope; | 813 HandleScope scope; |
| 814 ASSERT(args.length() == 0); | 814 ASSERT(args.length() == 0); |
| 815 | 815 |
| 816 // Get the top-most JavaScript frame. | 816 // Get the top-most JavaScript frame. |
| 817 JavaScriptFrameIterator it; | 817 JavaScriptFrameIterator it; |
| 818 JavaScriptFrame* frame = it.frame(); | 818 JavaScriptFrame* frame = it.frame(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 834 | 834 |
| 835 // Get the debug info (create it if it does not exist). | 835 // Get the debug info (create it if it does not exist). |
| 836 Handle<SharedFunctionInfo> shared = | 836 Handle<SharedFunctionInfo> shared = |
| 837 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared()); | 837 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared()); |
| 838 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 838 Handle<DebugInfo> debug_info = GetDebugInfo(shared); |
| 839 | 839 |
| 840 // Find the break point where execution has stopped. | 840 // Find the break point where execution has stopped. |
| 841 BreakLocationIterator break_location_iterator(debug_info, | 841 BreakLocationIterator break_location_iterator(debug_info, |
| 842 ALL_BREAK_LOCATIONS); | 842 ALL_BREAK_LOCATIONS); |
| 843 break_location_iterator.FindBreakLocationFromAddress(frame->pc()); | 843 break_location_iterator.FindBreakLocationFromAddress(frame->pc()); |
| 844 ThreadLocal& thread_local = v8_context()->debug_data_.thread_local_; |
| 844 | 845 |
| 845 // Check whether step next reached a new statement. | 846 // Check whether step next reached a new statement. |
| 846 if (!StepNextContinue(&break_location_iterator, frame)) { | 847 if (!StepNextContinue(&break_location_iterator, frame)) { |
| 847 // Decrease steps left if performing multiple steps. | 848 // Decrease steps left if performing multiple steps. |
| 848 if (thread_local_.step_count_ > 0) { | 849 if (thread_local.step_count_ > 0) { |
| 849 thread_local_.step_count_--; | 850 thread_local.step_count_--; |
| 850 } | 851 } |
| 851 } | 852 } |
| 852 | 853 |
| 853 // If there is one or more real break points check whether any of these are | 854 // If there is one or more real break points check whether any of these are |
| 854 // triggered. | 855 // triggered. |
| 855 Handle<Object> break_points_hit(Heap::undefined_value()); | 856 Handle<Object> break_points_hit(Heap::undefined_value()); |
| 856 if (break_location_iterator.HasBreakPoint()) { | 857 if (break_location_iterator.HasBreakPoint()) { |
| 857 Handle<Object> break_point_objects = | 858 Handle<Object> break_point_objects = |
| 858 Handle<Object>(break_location_iterator.BreakPointObjects()); | 859 Handle<Object>(break_location_iterator.BreakPointObjects()); |
| 859 break_points_hit = CheckBreakPoints(break_point_objects); | 860 break_points_hit = CheckBreakPoints(break_point_objects); |
| 860 } | 861 } |
| 861 | 862 |
| 862 // If step out is active skip everything until the frame where we need to step | 863 // If step out is active skip everything until the frame where we need to step |
| 863 // out to is reached, unless real breakpoint is hit. | 864 // out to is reached, unless real breakpoint is hit. |
| 864 if (Debug::StepOutActive() && frame->fp() != Debug::step_out_fp() && | 865 if (Debug::StepOutActive() && frame->fp() != Debug::step_out_fp() && |
| 865 break_points_hit->IsUndefined() ) { | 866 break_points_hit->IsUndefined() ) { |
| 866 // Step count should always be 0 for StepOut. | 867 // Step count should always be 0 for StepOut. |
| 867 ASSERT(thread_local_.step_count_ == 0); | 868 ASSERT(thread_local.step_count_ == 0); |
| 868 } else if (!break_points_hit->IsUndefined() || | 869 } else if (!break_points_hit->IsUndefined() || |
| 869 (thread_local_.last_step_action_ != StepNone && | 870 (thread_local.last_step_action_ != StepNone && |
| 870 thread_local_.step_count_ == 0)) { | 871 thread_local.step_count_ == 0)) { |
| 871 // Notify debugger if a real break point is triggered or if performing | 872 // Notify debugger if a real break point is triggered or if performing |
| 872 // single stepping with no more steps to perform. Otherwise do another step. | 873 // single stepping with no more steps to perform. Otherwise do another step. |
| 873 | 874 |
| 874 // Clear all current stepping setup. | 875 // Clear all current stepping setup. |
| 875 ClearStepping(); | 876 ClearStepping(); |
| 876 | 877 |
| 877 // Notify the debug event listeners. | 878 // Notify the debug event listeners. |
| 878 Debugger::OnDebugBreak(break_points_hit, false); | 879 Debugger::OnDebugBreak(break_points_hit, false); |
| 879 } else if (thread_local_.last_step_action_ != StepNone) { | 880 } else if (thread_local.last_step_action_ != StepNone) { |
| 880 // Hold on to last step action as it is cleared by the call to | 881 // Hold on to last step action as it is cleared by the call to |
| 881 // ClearStepping. | 882 // ClearStepping. |
| 882 StepAction step_action = thread_local_.last_step_action_; | 883 StepAction step_action = thread_local.last_step_action_; |
| 883 int step_count = thread_local_.step_count_; | 884 int step_count = thread_local.step_count_; |
| 884 | 885 |
| 885 // Clear all current stepping setup. | 886 // Clear all current stepping setup. |
| 886 ClearStepping(); | 887 ClearStepping(); |
| 887 | 888 |
| 888 // Set up for the remaining steps. | 889 // Set up for the remaining steps. |
| 889 PrepareStep(step_action, step_count); | 890 PrepareStep(step_action, step_count); |
| 890 } | 891 } |
| 891 | 892 |
| 892 // Install jump to the call address which was overwritten. | 893 // Install jump to the call address which was overwritten. |
| 893 SetAfterBreakTarget(frame); | 894 SetAfterBreakTarget(frame); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 999 it.SetBreakPoint(break_point_object); | 1000 it.SetBreakPoint(break_point_object); |
| 1000 | 1001 |
| 1001 // At least one active break point now. | 1002 // At least one active break point now. |
| 1002 ASSERT(debug_info->GetBreakPointCount() > 0); | 1003 ASSERT(debug_info->GetBreakPointCount() > 0); |
| 1003 } | 1004 } |
| 1004 | 1005 |
| 1005 | 1006 |
| 1006 void Debug::ClearBreakPoint(Handle<Object> break_point_object) { | 1007 void Debug::ClearBreakPoint(Handle<Object> break_point_object) { |
| 1007 HandleScope scope; | 1008 HandleScope scope; |
| 1008 | 1009 |
| 1009 DebugInfoListNode* node = debug_info_list_; | 1010 DebugData& data = v8_context()->debug_data_; |
| 1011 DebugInfoListNode* node = data.debug_info_list_; |
| 1010 while (node != NULL) { | 1012 while (node != NULL) { |
| 1011 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(), | 1013 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(), |
| 1012 break_point_object); | 1014 break_point_object); |
| 1013 if (!result->IsUndefined()) { | 1015 if (!result->IsUndefined()) { |
| 1014 // Get information in the break point. | 1016 // Get information in the break point. |
| 1015 BreakPointInfo* break_point_info = BreakPointInfo::cast(result); | 1017 BreakPointInfo* break_point_info = BreakPointInfo::cast(result); |
| 1016 Handle<DebugInfo> debug_info = node->debug_info(); | 1018 Handle<DebugInfo> debug_info = node->debug_info(); |
| 1017 Handle<SharedFunctionInfo> shared(debug_info->shared()); | 1019 Handle<SharedFunctionInfo> shared(debug_info->shared()); |
| 1018 int source_position = break_point_info->statement_position()->value(); | 1020 int source_position = break_point_info->statement_position()->value(); |
| 1019 | 1021 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1032 } | 1034 } |
| 1033 | 1035 |
| 1034 return; | 1036 return; |
| 1035 } | 1037 } |
| 1036 node = node->next(); | 1038 node = node->next(); |
| 1037 } | 1039 } |
| 1038 } | 1040 } |
| 1039 | 1041 |
| 1040 | 1042 |
| 1041 void Debug::ClearAllBreakPoints() { | 1043 void Debug::ClearAllBreakPoints() { |
| 1042 DebugInfoListNode* node = debug_info_list_; | 1044 DebugData& data = v8_context()->debug_data_; |
| 1045 DebugInfoListNode* node = data.debug_info_list_; |
| 1043 while (node != NULL) { | 1046 while (node != NULL) { |
| 1044 // Remove all debug break code. | 1047 // Remove all debug break code. |
| 1045 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS); | 1048 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS); |
| 1046 it.ClearAllDebugBreak(); | 1049 it.ClearAllDebugBreak(); |
| 1047 node = node->next(); | 1050 node = node->next(); |
| 1048 } | 1051 } |
| 1049 | 1052 |
| 1050 // Remove all debug info. | 1053 // Remove all debug info. |
| 1051 while (debug_info_list_ != NULL) { | 1054 while (data.debug_info_list_ != NULL) { |
| 1052 RemoveDebugInfo(debug_info_list_->debug_info()); | 1055 RemoveDebugInfo(data.debug_info_list_->debug_info()); |
| 1053 } | 1056 } |
| 1054 } | 1057 } |
| 1055 | 1058 |
| 1056 | 1059 |
| 1057 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) { | 1060 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) { |
| 1058 // Make sure the function has setup the debug info. | 1061 // Make sure the function has setup the debug info. |
| 1059 if (!EnsureDebugInfo(shared)) { | 1062 if (!EnsureDebugInfo(shared)) { |
| 1060 // Return if we failed to retrieve the debug info. | 1063 // Return if we failed to retrieve the debug info. |
| 1061 return; | 1064 return; |
| 1062 } | 1065 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1085 JSFunction::cast(frame->function())->shared()); | 1088 JSFunction::cast(frame->function())->shared()); |
| 1086 // Flood the function with the catch block with break points | 1089 // Flood the function with the catch block with break points |
| 1087 FloodWithOneShot(shared); | 1090 FloodWithOneShot(shared); |
| 1088 return; | 1091 return; |
| 1089 } | 1092 } |
| 1090 } | 1093 } |
| 1091 } | 1094 } |
| 1092 | 1095 |
| 1093 | 1096 |
| 1094 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { | 1097 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { |
| 1098 DebugData& data = v8_context()->debug_data_; |
| 1095 if (type == BreakUncaughtException) { | 1099 if (type == BreakUncaughtException) { |
| 1096 break_on_uncaught_exception_ = enable; | 1100 data.break_on_uncaught_exception_ = enable; |
| 1097 } else { | 1101 } else { |
| 1098 break_on_exception_ = enable; | 1102 data.break_on_exception_ = enable; |
| 1099 } | 1103 } |
| 1100 } | 1104 } |
| 1101 | 1105 |
| 1102 | 1106 |
| 1103 void Debug::PrepareStep(StepAction step_action, int step_count) { | 1107 void Debug::PrepareStep(StepAction step_action, int step_count) { |
| 1104 HandleScope scope; | 1108 HandleScope scope; |
| 1105 ASSERT(Debug::InDebugger()); | 1109 ASSERT(Debug::InDebugger()); |
| 1110 ThreadLocal& thread_local = v8_context()->debug_data_.thread_local_; |
| 1106 | 1111 |
| 1107 // Remember this step action and count. | 1112 // Remember this step action and count. |
| 1108 thread_local_.last_step_action_ = step_action; | 1113 thread_local.last_step_action_ = step_action; |
| 1109 if (step_action == StepOut) { | 1114 if (step_action == StepOut) { |
| 1110 // For step out target frame will be found on the stack so there is no need | 1115 // For step out target frame will be found on the stack so there is no need |
| 1111 // to set step counter for it. It's expected to always be 0 for StepOut. | 1116 // to set step counter for it. It's expected to always be 0 for StepOut. |
| 1112 thread_local_.step_count_ = 0; | 1117 thread_local.step_count_ = 0; |
| 1113 } else { | 1118 } else { |
| 1114 thread_local_.step_count_ = step_count; | 1119 thread_local.step_count_ = step_count; |
| 1115 } | 1120 } |
| 1116 | 1121 |
| 1117 // Get the frame where the execution has stopped and skip the debug frame if | 1122 // Get the frame where the execution has stopped and skip the debug frame if |
| 1118 // any. The debug frame will only be present if execution was stopped due to | 1123 // any. The debug frame will only be present if execution was stopped due to |
| 1119 // hitting a break point. In other situations (e.g. unhandled exception) the | 1124 // hitting a break point. In other situations (e.g. unhandled exception) the |
| 1120 // debug frame is not present. | 1125 // debug frame is not present. |
| 1121 StackFrame::Id id = break_frame_id(); | 1126 StackFrame::Id id = break_frame_id(); |
| 1122 if (id == StackFrame::NO_ID) { | 1127 if (id == StackFrame::NO_ID) { |
| 1123 // If there is no JavaScript stack don't do anything. | 1128 // If there is no JavaScript stack don't do anything. |
| 1124 return; | 1129 return; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1216 } | 1221 } |
| 1217 } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) || | 1222 } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) || |
| 1218 !call_function_stub.is_null()) | 1223 !call_function_stub.is_null()) |
| 1219 || step_action == StepNext || step_action == StepMin) { | 1224 || step_action == StepNext || step_action == StepMin) { |
| 1220 // Step next or step min. | 1225 // Step next or step min. |
| 1221 | 1226 |
| 1222 // Fill the current function with one-shot break points. | 1227 // Fill the current function with one-shot break points. |
| 1223 FloodWithOneShot(shared); | 1228 FloodWithOneShot(shared); |
| 1224 | 1229 |
| 1225 // Remember source position and frame to handle step next. | 1230 // Remember source position and frame to handle step next. |
| 1226 thread_local_.last_statement_position_ = | 1231 thread_local.last_statement_position_ = |
| 1227 debug_info->code()->SourceStatementPosition(frame->pc()); | 1232 debug_info->code()->SourceStatementPosition(frame->pc()); |
| 1228 thread_local_.last_fp_ = frame->fp(); | 1233 thread_local.last_fp_ = frame->fp(); |
| 1229 } else { | 1234 } else { |
| 1230 // If it's CallFunction stub ensure target function is compiled and flood | 1235 // If it's CallFunction stub ensure target function is compiled and flood |
| 1231 // it with one shot breakpoints. | 1236 // it with one shot breakpoints. |
| 1232 if (!call_function_stub.is_null()) { | 1237 if (!call_function_stub.is_null()) { |
| 1233 // Find out number of arguments from the stub minor key. | 1238 // Find out number of arguments from the stub minor key. |
| 1234 // Reverse lookup required as the minor key cannot be retrieved | 1239 // Reverse lookup required as the minor key cannot be retrieved |
| 1235 // from the code object. | 1240 // from the code object. |
| 1236 Handle<Object> obj( | 1241 Handle<Object> obj( |
| 1237 Heap::code_stubs()->SlowReverseLookup(*call_function_stub)); | 1242 Heap::code_stubs()->SlowReverseLookup(*call_function_stub)); |
| 1238 ASSERT(*obj != Heap::undefined_value()); | 1243 ASSERT(*obj != Heap::undefined_value()); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1270 // a call target as the function called might be a native function for | 1275 // a call target as the function called might be a native function for |
| 1271 // which step in will not stop. It also prepares for stepping in | 1276 // which step in will not stop. It also prepares for stepping in |
| 1272 // getters/setters. | 1277 // getters/setters. |
| 1273 FloodWithOneShot(shared); | 1278 FloodWithOneShot(shared); |
| 1274 | 1279 |
| 1275 if (is_load_or_store) { | 1280 if (is_load_or_store) { |
| 1276 // Remember source position and frame to handle step in getter/setter. If | 1281 // Remember source position and frame to handle step in getter/setter. If |
| 1277 // there is a custom getter/setter it will be handled in | 1282 // there is a custom getter/setter it will be handled in |
| 1278 // Object::Get/SetPropertyWithCallback, otherwise the step action will be | 1283 // Object::Get/SetPropertyWithCallback, otherwise the step action will be |
| 1279 // propagated on the next Debug::Break. | 1284 // propagated on the next Debug::Break. |
| 1280 thread_local_.last_statement_position_ = | 1285 thread_local.last_statement_position_ = |
| 1281 debug_info->code()->SourceStatementPosition(frame->pc()); | 1286 debug_info->code()->SourceStatementPosition(frame->pc()); |
| 1282 thread_local_.last_fp_ = frame->fp(); | 1287 thread_local.last_fp_ = frame->fp(); |
| 1283 } | 1288 } |
| 1284 | 1289 |
| 1285 // Step in or Step in min | 1290 // Step in or Step in min |
| 1286 it.PrepareStepIn(); | 1291 it.PrepareStepIn(); |
| 1287 ActivateStepIn(frame); | 1292 ActivateStepIn(frame); |
| 1288 } | 1293 } |
| 1289 } | 1294 } |
| 1290 | 1295 |
| 1291 | 1296 |
| 1292 // Check whether the current debug break should be reported to the debugger. It | 1297 // Check whether the current debug break should be reported to the debugger. It |
| 1293 // is used to have step next and step in only report break back to the debugger | 1298 // is used to have step next and step in only report break back to the debugger |
| 1294 // if on a different frame or in a different statement. In some situations | 1299 // if on a different frame or in a different statement. In some situations |
| 1295 // there will be several break points in the same statement when the code is | 1300 // there will be several break points in the same statement when the code is |
| 1296 // flooded with one-shot break points. This function helps to perform several | 1301 // flooded with one-shot break points. This function helps to perform several |
| 1297 // steps before reporting break back to the debugger. | 1302 // steps before reporting break back to the debugger. |
| 1298 bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator, | 1303 bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator, |
| 1299 JavaScriptFrame* frame) { | 1304 JavaScriptFrame* frame) { |
| 1305 ThreadLocal& thread_local = v8_context()->debug_data_.thread_local_; |
| 1300 // If the step last action was step next or step in make sure that a new | 1306 // If the step last action was step next or step in make sure that a new |
| 1301 // statement is hit. | 1307 // statement is hit. |
| 1302 if (thread_local_.last_step_action_ == StepNext || | 1308 if (thread_local.last_step_action_ == StepNext || |
| 1303 thread_local_.last_step_action_ == StepIn) { | 1309 thread_local.last_step_action_ == StepIn) { |
| 1304 // Never continue if returning from function. | 1310 // Never continue if returning from function. |
| 1305 if (break_location_iterator->IsExit()) return false; | 1311 if (break_location_iterator->IsExit()) return false; |
| 1306 | 1312 |
| 1307 // Continue if we are still on the same frame and in the same statement. | 1313 // Continue if we are still on the same frame and in the same statement. |
| 1308 int current_statement_position = | 1314 int current_statement_position = |
| 1309 break_location_iterator->code()->SourceStatementPosition(frame->pc()); | 1315 break_location_iterator->code()->SourceStatementPosition(frame->pc()); |
| 1310 return thread_local_.last_fp_ == frame->fp() && | 1316 return thread_local.last_fp_ == frame->fp() && |
| 1311 thread_local_.last_statement_position_ == current_statement_position; | 1317 thread_local.last_statement_position_ == current_statement_position; |
| 1312 } | 1318 } |
| 1313 | 1319 |
| 1314 // No step next action - don't continue. | 1320 // No step next action - don't continue. |
| 1315 return false; | 1321 return false; |
| 1316 } | 1322 } |
| 1317 | 1323 |
| 1318 | 1324 |
| 1319 // Check whether the code object at the specified address is a debug break code | 1325 // Check whether the code object at the specified address is a debug break code |
| 1320 // object. | 1326 // object. |
| 1321 bool Debug::IsDebugBreak(Address addr) { | 1327 bool Debug::IsDebugBreak(Address addr) { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1402 if (break_point_info->GetBreakPointCount() > 0) { | 1408 if (break_point_info->GetBreakPointCount() > 0) { |
| 1403 locations->set(count++, break_point_info->statement_position()); | 1409 locations->set(count++, break_point_info->statement_position()); |
| 1404 } | 1410 } |
| 1405 } | 1411 } |
| 1406 } | 1412 } |
| 1407 return locations; | 1413 return locations; |
| 1408 } | 1414 } |
| 1409 | 1415 |
| 1410 | 1416 |
| 1411 void Debug::NewBreak(StackFrame::Id break_frame_id) { | 1417 void Debug::NewBreak(StackFrame::Id break_frame_id) { |
| 1412 thread_local_.break_frame_id_ = break_frame_id; | 1418 ThreadLocal& thread_local = v8_context()->debug_data_.thread_local_; |
| 1413 thread_local_.break_id_ = ++thread_local_.break_count_; | 1419 thread_local.break_frame_id_ = break_frame_id; |
| 1420 thread_local.break_id_ = ++thread_local.break_count_; |
| 1414 } | 1421 } |
| 1415 | 1422 |
| 1416 | 1423 |
| 1417 void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) { | 1424 void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) { |
| 1418 thread_local_.break_frame_id_ = break_frame_id; | 1425 ThreadLocal& thread_local = v8_context()->debug_data_.thread_local_; |
| 1419 thread_local_.break_id_ = break_id; | 1426 thread_local.break_frame_id_ = break_frame_id; |
| 1427 thread_local.break_id_ = break_id; |
| 1420 } | 1428 } |
| 1421 | 1429 |
| 1422 | 1430 |
| 1423 // Handle stepping into a function. | 1431 // Handle stepping into a function. |
| 1424 void Debug::HandleStepIn(Handle<JSFunction> function, | 1432 void Debug::HandleStepIn(Handle<JSFunction> function, |
| 1425 Handle<Object> holder, | 1433 Handle<Object> holder, |
| 1426 Address fp, | 1434 Address fp, |
| 1427 bool is_constructor) { | 1435 bool is_constructor) { |
| 1428 // If the frame pointer is not supplied by the caller find it. | 1436 // If the frame pointer is not supplied by the caller find it. |
| 1429 if (fp == 0) { | 1437 if (fp == 0) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1465 | 1473 |
| 1466 | 1474 |
| 1467 void Debug::ClearStepping() { | 1475 void Debug::ClearStepping() { |
| 1468 // Clear the various stepping setup. | 1476 // Clear the various stepping setup. |
| 1469 ClearOneShot(); | 1477 ClearOneShot(); |
| 1470 ClearStepIn(); | 1478 ClearStepIn(); |
| 1471 ClearStepOut(); | 1479 ClearStepOut(); |
| 1472 ClearStepNext(); | 1480 ClearStepNext(); |
| 1473 | 1481 |
| 1474 // Clear multiple step counter. | 1482 // Clear multiple step counter. |
| 1475 thread_local_.step_count_ = 0; | 1483 v8_context()->debug_data_.thread_local_.step_count_ = 0; |
| 1476 } | 1484 } |
| 1477 | 1485 |
| 1478 // Clears all the one-shot break points that are currently set. Normally this | 1486 // Clears all the one-shot break points that are currently set. Normally this |
| 1479 // function is called each time a break point is hit as one shot break points | 1487 // function is called each time a break point is hit as one shot break points |
| 1480 // are used to support stepping. | 1488 // are used to support stepping. |
| 1481 void Debug::ClearOneShot() { | 1489 void Debug::ClearOneShot() { |
| 1482 // The current implementation just runs through all the breakpoints. When the | 1490 // The current implementation just runs through all the breakpoints. When the |
| 1483 // last break point for a function is removed that function is automatically | 1491 // last break point for a function is removed that function is automatically |
| 1484 // removed from the list. | 1492 // removed from the list. |
| 1485 | 1493 |
| 1486 DebugInfoListNode* node = debug_info_list_; | 1494 DebugInfoListNode* node = v8_context()->debug_data_.debug_info_list_; |
| 1487 while (node != NULL) { | 1495 while (node != NULL) { |
| 1488 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS); | 1496 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS); |
| 1489 while (!it.Done()) { | 1497 while (!it.Done()) { |
| 1490 it.ClearOneShot(); | 1498 it.ClearOneShot(); |
| 1491 it.Next(); | 1499 it.Next(); |
| 1492 } | 1500 } |
| 1493 node = node->next(); | 1501 node = node->next(); |
| 1494 } | 1502 } |
| 1495 } | 1503 } |
| 1496 | 1504 |
| 1497 | 1505 |
| 1498 void Debug::ActivateStepIn(StackFrame* frame) { | 1506 void Debug::ActivateStepIn(StackFrame* frame) { |
| 1499 ASSERT(!StepOutActive()); | 1507 ASSERT(!StepOutActive()); |
| 1500 thread_local_.step_into_fp_ = frame->fp(); | 1508 v8_context()->debug_data_.thread_local_.step_into_fp_ = frame->fp(); |
| 1501 } | 1509 } |
| 1502 | 1510 |
| 1503 | 1511 |
| 1504 void Debug::ClearStepIn() { | 1512 void Debug::ClearStepIn() { |
| 1505 thread_local_.step_into_fp_ = 0; | 1513 v8_context()->debug_data_.thread_local_.step_into_fp_ = 0; |
| 1506 } | 1514 } |
| 1507 | 1515 |
| 1508 | 1516 |
| 1509 void Debug::ActivateStepOut(StackFrame* frame) { | 1517 void Debug::ActivateStepOut(StackFrame* frame) { |
| 1510 ASSERT(!StepInActive()); | 1518 ASSERT(!StepInActive()); |
| 1511 thread_local_.step_out_fp_ = frame->fp(); | 1519 v8_context()->debug_data_.thread_local_.step_out_fp_ = frame->fp(); |
| 1512 } | 1520 } |
| 1513 | 1521 |
| 1514 | 1522 |
| 1515 void Debug::ClearStepOut() { | 1523 void Debug::ClearStepOut() { |
| 1516 thread_local_.step_out_fp_ = 0; | 1524 v8_context()->debug_data_.thread_local_.step_out_fp_ = 0; |
| 1517 } | 1525 } |
| 1518 | 1526 |
| 1519 | 1527 |
| 1520 void Debug::ClearStepNext() { | 1528 void Debug::ClearStepNext() { |
| 1521 thread_local_.last_step_action_ = StepNone; | 1529 ThreadLocal& thread_local = v8_context()->debug_data_.thread_local_; |
| 1522 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; | 1530 thread_local.last_step_action_ = StepNone; |
| 1523 thread_local_.last_fp_ = 0; | 1531 thread_local.last_statement_position_ = RelocInfo::kNoPosition; |
| 1532 thread_local.last_fp_ = 0; |
| 1524 } | 1533 } |
| 1525 | 1534 |
| 1526 | 1535 |
| 1527 bool Debug::EnsureCompiled(Handle<SharedFunctionInfo> shared) { | 1536 bool Debug::EnsureCompiled(Handle<SharedFunctionInfo> shared) { |
| 1528 if (shared->is_compiled()) return true; | 1537 if (shared->is_compiled()) return true; |
| 1529 return CompileLazyShared(shared, CLEAR_EXCEPTION, 0); | 1538 return CompileLazyShared(shared, CLEAR_EXCEPTION, 0); |
| 1530 } | 1539 } |
| 1531 | 1540 |
| 1532 | 1541 |
| 1533 // Ensures the debug information is present for shared. | 1542 // Ensures the debug information is present for shared. |
| 1534 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { | 1543 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { |
| 1535 // Return if we already have the debug info for shared. | 1544 // Return if we already have the debug info for shared. |
| 1536 if (HasDebugInfo(shared)) return true; | 1545 if (HasDebugInfo(shared)) return true; |
| 1537 | 1546 |
| 1538 // Ensure shared in compiled. Return false if this failed. | 1547 // Ensure shared in compiled. Return false if this failed. |
| 1539 if (!EnsureCompiled(shared)) return false; | 1548 if (!EnsureCompiled(shared)) return false; |
| 1540 | 1549 |
| 1541 // Create the debug info object. | 1550 // Create the debug info object. |
| 1542 Handle<DebugInfo> debug_info = Factory::NewDebugInfo(shared); | 1551 Handle<DebugInfo> debug_info = Factory::NewDebugInfo(shared); |
| 1543 | 1552 |
| 1544 // Add debug info to the list. | 1553 // Add debug info to the list. |
| 1545 DebugInfoListNode* node = new DebugInfoListNode(*debug_info); | 1554 DebugInfoListNode* node = new DebugInfoListNode(*debug_info); |
| 1546 node->set_next(debug_info_list_); | 1555 DebugData& data = v8_context()->debug_data_; |
| 1547 debug_info_list_ = node; | 1556 node->set_next(data.debug_info_list_); |
| 1557 data.debug_info_list_ = node; |
| 1548 | 1558 |
| 1549 // Now there is at least one break point. | 1559 // Now there is at least one break point. |
| 1550 has_break_points_ = true; | 1560 data.has_break_points_ = true; |
| 1551 | 1561 |
| 1552 return true; | 1562 return true; |
| 1553 } | 1563 } |
| 1554 | 1564 |
| 1555 | 1565 |
| 1556 void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) { | 1566 void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) { |
| 1557 ASSERT(debug_info_list_ != NULL); | 1567 DebugData& data = v8_context()->debug_data_; |
| 1568 ASSERT(data.debug_info_list_ != NULL); |
| 1558 // Run through the debug info objects to find this one and remove it. | 1569 // Run through the debug info objects to find this one and remove it. |
| 1559 DebugInfoListNode* prev = NULL; | 1570 DebugInfoListNode* prev = NULL; |
| 1560 DebugInfoListNode* current = debug_info_list_; | 1571 DebugInfoListNode* current = data.debug_info_list_; |
| 1561 while (current != NULL) { | 1572 while (current != NULL) { |
| 1562 if (*current->debug_info() == *debug_info) { | 1573 if (*current->debug_info() == *debug_info) { |
| 1563 // Unlink from list. If prev is NULL we are looking at the first element. | 1574 // Unlink from list. If prev is NULL we are looking at the first element. |
| 1564 if (prev == NULL) { | 1575 if (prev == NULL) { |
| 1565 debug_info_list_ = current->next(); | 1576 data.debug_info_list_ = current->next(); |
| 1566 } else { | 1577 } else { |
| 1567 prev->set_next(current->next()); | 1578 prev->set_next(current->next()); |
| 1568 } | 1579 } |
| 1569 current->debug_info()->shared()->set_debug_info(Heap::undefined_value()); | 1580 current->debug_info()->shared()->set_debug_info(Heap::undefined_value()); |
| 1570 delete current; | 1581 delete current; |
| 1571 | 1582 |
| 1572 // If there are no more debug info objects there are not more break | 1583 // If there are no more debug info objects there are not more break |
| 1573 // points. | 1584 // points. |
| 1574 has_break_points_ = debug_info_list_ != NULL; | 1585 data.has_break_points_ = data.debug_info_list_ != NULL; |
| 1575 | 1586 |
| 1576 return; | 1587 return; |
| 1577 } | 1588 } |
| 1578 // Move to next in list. | 1589 // Move to next in list. |
| 1579 prev = current; | 1590 prev = current; |
| 1580 current = current->next(); | 1591 current = current->next(); |
| 1581 } | 1592 } |
| 1582 UNREACHABLE(); | 1593 UNREACHABLE(); |
| 1583 } | 1594 } |
| 1584 | 1595 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1613 RelocIterator it(debug_info->code()); | 1624 RelocIterator it(debug_info->code()); |
| 1614 while (!it.done()) { | 1625 while (!it.done()) { |
| 1615 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) { | 1626 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) { |
| 1616 at_js_return = (it.rinfo()->pc() == | 1627 at_js_return = (it.rinfo()->pc() == |
| 1617 addr - Assembler::kPatchReturnSequenceAddressOffset); | 1628 addr - Assembler::kPatchReturnSequenceAddressOffset); |
| 1618 break_at_js_return_active = it.rinfo()->IsPatchedReturnSequence(); | 1629 break_at_js_return_active = it.rinfo()->IsPatchedReturnSequence(); |
| 1619 } | 1630 } |
| 1620 it.next(); | 1631 it.next(); |
| 1621 } | 1632 } |
| 1622 | 1633 |
| 1634 ThreadLocal& thread_local = v8_context()->debug_data_.thread_local_; |
| 1623 // Handle the jump to continue execution after break point depending on the | 1635 // Handle the jump to continue execution after break point depending on the |
| 1624 // break location. | 1636 // break location. |
| 1625 if (at_js_return) { | 1637 if (at_js_return) { |
| 1626 // If the break point as return is still active jump to the corresponding | 1638 // If the break point as return is still active jump to the corresponding |
| 1627 // place in the original code. If not the break point was removed during | 1639 // place in the original code. If not the break point was removed during |
| 1628 // break point processing. | 1640 // break point processing. |
| 1629 if (break_at_js_return_active) { | 1641 if (break_at_js_return_active) { |
| 1630 addr += original_code->instruction_start() - code->instruction_start(); | 1642 addr += original_code->instruction_start() - code->instruction_start(); |
| 1631 } | 1643 } |
| 1632 | 1644 |
| 1633 // Move back to where the call instruction sequence started. | 1645 // Move back to where the call instruction sequence started. |
| 1634 thread_local_.after_break_target_ = | 1646 thread_local.after_break_target_ = |
| 1635 addr - Assembler::kPatchReturnSequenceAddressOffset; | 1647 addr - Assembler::kPatchReturnSequenceAddressOffset; |
| 1636 } else { | 1648 } else { |
| 1637 // Check if there still is a debug break call at the target address. If the | 1649 // Check if there still is a debug break call at the target address. If the |
| 1638 // break point has been removed it will have disappeared. If it have | 1650 // break point has been removed it will have disappeared. If it have |
| 1639 // disappeared don't try to look in the original code as the running code | 1651 // disappeared don't try to look in the original code as the running code |
| 1640 // will have the right address. This takes care of the case where the last | 1652 // will have the right address. This takes care of the case where the last |
| 1641 // break point is removed from the function and therefore no "original code" | 1653 // break point is removed from the function and therefore no "original code" |
| 1642 // is available. If the debug break call is still there find the address in | 1654 // is available. If the debug break call is still there find the address in |
| 1643 // the original code. | 1655 // the original code. |
| 1644 if (IsDebugBreak(Assembler::target_address_at(addr))) { | 1656 if (IsDebugBreak(Assembler::target_address_at(addr))) { |
| 1645 // If the break point is still there find the call address which was | 1657 // If the break point is still there find the call address which was |
| 1646 // overwritten in the original code by the call to DebugBreakXXX. | 1658 // overwritten in the original code by the call to DebugBreakXXX. |
| 1647 | 1659 |
| 1648 // Find the corresponding address in the original code. | 1660 // Find the corresponding address in the original code. |
| 1649 addr += original_code->instruction_start() - code->instruction_start(); | 1661 addr += original_code->instruction_start() - code->instruction_start(); |
| 1650 } | 1662 } |
| 1651 | 1663 |
| 1652 // Install jump to the call address in the original code. This will be the | 1664 // Install jump to the call address in the original code. This will be the |
| 1653 // call which was overwritten by the call to DebugBreakXXX. | 1665 // call which was overwritten by the call to DebugBreakXXX. |
| 1654 thread_local_.after_break_target_ = Assembler::target_address_at(addr); | 1666 thread_local.after_break_target_ = Assembler::target_address_at(addr); |
| 1655 } | 1667 } |
| 1656 } | 1668 } |
| 1657 | 1669 |
| 1658 | 1670 |
| 1659 bool Debug::IsDebugGlobal(GlobalObject* global) { | 1671 bool Debug::IsDebugGlobal(GlobalObject* global) { |
| 1660 return IsLoaded() && global == Debug::debug_context()->global(); | 1672 return IsLoaded() && global == Debug::debug_context()->global(); |
| 1661 } | 1673 } |
| 1662 | 1674 |
| 1663 | 1675 |
| 1664 void Debug::ClearMirrorCache() { | 1676 void Debug::ClearMirrorCache() { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1680 | 1692 |
| 1681 void Debug::CreateScriptCache() { | 1693 void Debug::CreateScriptCache() { |
| 1682 HandleScope scope; | 1694 HandleScope scope; |
| 1683 | 1695 |
| 1684 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets | 1696 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets |
| 1685 // rid of all the cached script wrappers and the second gets rid of the | 1697 // rid of all the cached script wrappers and the second gets rid of the |
| 1686 // scripts which is no longer referenced. | 1698 // scripts which is no longer referenced. |
| 1687 Heap::CollectAllGarbage(false); | 1699 Heap::CollectAllGarbage(false); |
| 1688 Heap::CollectAllGarbage(false); | 1700 Heap::CollectAllGarbage(false); |
| 1689 | 1701 |
| 1690 ASSERT(script_cache_ == NULL); | 1702 DebugData& data = v8_context()->debug_data_; |
| 1691 script_cache_ = new ScriptCache(); | 1703 ASSERT(data.script_cache_ == NULL); |
| 1704 data.script_cache_ = new ScriptCache(); |
| 1692 | 1705 |
| 1693 // Scan heap for Script objects. | 1706 // Scan heap for Script objects. |
| 1694 int count = 0; | 1707 int count = 0; |
| 1695 HeapIterator iterator; | 1708 HeapIterator iterator; |
| 1696 while (iterator.has_next()) { | 1709 while (iterator.has_next()) { |
| 1697 HeapObject* obj = iterator.next(); | 1710 HeapObject* obj = iterator.next(); |
| 1698 ASSERT(obj != NULL); | 1711 ASSERT(obj != NULL); |
| 1699 if (obj->IsScript() && Script::cast(obj)->HasValidSource()) { | 1712 if (obj->IsScript() && Script::cast(obj)->HasValidSource()) { |
| 1700 script_cache_->Add(Handle<Script>(Script::cast(obj))); | 1713 data.script_cache_->Add(Handle<Script>(Script::cast(obj))); |
| 1701 count++; | 1714 count++; |
| 1702 } | 1715 } |
| 1703 } | 1716 } |
| 1704 } | 1717 } |
| 1705 | 1718 |
| 1706 | 1719 |
| 1707 void Debug::DestroyScriptCache() { | 1720 void Debug::DestroyScriptCache() { |
| 1721 DebugData& data = v8_context()->debug_data_; |
| 1708 // Get rid of the script cache if it was created. | 1722 // Get rid of the script cache if it was created. |
| 1709 if (script_cache_ != NULL) { | 1723 if (data.script_cache_ != NULL) { |
| 1710 delete script_cache_; | 1724 delete data.script_cache_; |
| 1711 script_cache_ = NULL; | 1725 data.script_cache_ = NULL; |
| 1712 } | 1726 } |
| 1713 } | 1727 } |
| 1714 | 1728 |
| 1715 | 1729 |
| 1716 void Debug::AddScriptToScriptCache(Handle<Script> script) { | 1730 void Debug::AddScriptToScriptCache(Handle<Script> script) { |
| 1717 if (script_cache_ != NULL) { | 1731 DebugData& data = v8_context()->debug_data_; |
| 1718 script_cache_->Add(script); | 1732 if (data.script_cache_ != NULL) { |
| 1733 data.script_cache_->Add(script); |
| 1719 } | 1734 } |
| 1720 } | 1735 } |
| 1721 | 1736 |
| 1722 | 1737 |
| 1723 Handle<FixedArray> Debug::GetLoadedScripts() { | 1738 Handle<FixedArray> Debug::GetLoadedScripts() { |
| 1739 DebugData& data = v8_context()->debug_data_; |
| 1724 // Create and fill the script cache when the loaded scripts is requested for | 1740 // Create and fill the script cache when the loaded scripts is requested for |
| 1725 // the first time. | 1741 // the first time. |
| 1726 if (script_cache_ == NULL) { | 1742 if (data.script_cache_ == NULL) { |
| 1727 CreateScriptCache(); | 1743 CreateScriptCache(); |
| 1728 } | 1744 } |
| 1729 | 1745 |
| 1730 // If the script cache is not active just return an empty array. | 1746 // If the script cache is not active just return an empty array. |
| 1731 ASSERT(script_cache_ != NULL); | 1747 ASSERT(data.script_cache_ != NULL); |
| 1732 if (script_cache_ == NULL) { | 1748 if (data.script_cache_ == NULL) { |
| 1733 Factory::NewFixedArray(0); | 1749 Factory::NewFixedArray(0); |
| 1734 } | 1750 } |
| 1735 | 1751 |
| 1736 // Perform GC to get unreferenced scripts evicted from the cache before | 1752 // Perform GC to get unreferenced scripts evicted from the cache before |
| 1737 // returning the content. | 1753 // returning the content. |
| 1738 Heap::CollectAllGarbage(false); | 1754 Heap::CollectAllGarbage(false); |
| 1739 | 1755 |
| 1740 // Get the scripts from the cache. | 1756 // Get the scripts from the cache. |
| 1741 return script_cache_->GetScripts(); | 1757 return data.script_cache_->GetScripts(); |
| 1742 } | 1758 } |
| 1743 | 1759 |
| 1744 | 1760 |
| 1745 void Debug::AfterGarbageCollection() { | 1761 void Debug::AfterGarbageCollection() { |
| 1762 DebugData& data = v8_context()->debug_data_; |
| 1746 // Generate events for collected scripts. | 1763 // Generate events for collected scripts. |
| 1747 if (script_cache_ != NULL) { | 1764 if (data.script_cache_ != NULL) { |
| 1748 script_cache_->ProcessCollectedScripts(); | 1765 data.script_cache_->ProcessCollectedScripts(); |
| 1749 } | 1766 } |
| 1750 } | 1767 } |
| 1751 | 1768 |
| 1752 | 1769 DebuggerData::DebuggerData() |
| 1753 Mutex* Debugger::debugger_access_ = OS::CreateMutex(); | 1770 :debugger_access_(OS::CreateMutex()), |
| 1754 Handle<Object> Debugger::event_listener_ = Handle<Object>(); | 1771 event_listener_(Handle<Object>()), |
| 1755 Handle<Object> Debugger::event_listener_data_ = Handle<Object>(); | 1772 event_listener_data_(Handle<Object>()), |
| 1756 bool Debugger::compiling_natives_ = false; | 1773 compiling_natives_(false), |
| 1757 bool Debugger::is_loading_debugger_ = false; | 1774 is_loading_debugger_(false), |
| 1758 bool Debugger::never_unload_debugger_ = false; | 1775 never_unload_debugger_(false), |
| 1759 v8::Debug::MessageHandler2 Debugger::message_handler_ = NULL; | 1776 message_handler_(NULL), |
| 1760 bool Debugger::debugger_unload_pending_ = false; | 1777 debugger_unload_pending_(false), |
| 1761 v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL; | 1778 host_dispatch_handler_(NULL), |
| 1762 v8::Debug::DebugMessageDispatchHandler | 1779 host_dispatch_micros_(100 * 1000), |
| 1763 Debugger::debug_message_dispatch_handler_ = NULL; | 1780 agent_(NULL), |
| 1764 int Debugger::host_dispatch_micros_ = 100 * 1000; | 1781 command_queue_(kQueueInitialSize), |
| 1765 DebuggerAgent* Debugger::agent_ = NULL; | 1782 command_received_(OS::CreateSemaphore(0)) { |
| 1766 LockingCommandMessageQueue Debugger::command_queue_(kQueueInitialSize); | 1783 } |
| 1767 Semaphore* Debugger::command_received_ = OS::CreateSemaphore(0); | |
| 1768 | |
| 1769 | 1784 |
| 1770 Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name, | 1785 Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name, |
| 1771 int argc, Object*** argv, | 1786 int argc, Object*** argv, |
| 1772 bool* caught_exception) { | 1787 bool* caught_exception) { |
| 1773 ASSERT(Top::context() == *Debug::debug_context()); | 1788 ASSERT(Top::context() == *Debug::debug_context()); |
| 1774 | 1789 |
| 1775 // Create the execution state object. | 1790 // Create the execution state object. |
| 1776 Handle<String> constructor_str = Factory::LookupSymbol(constructor_name); | 1791 Handle<String> constructor_str = Factory::LookupSymbol(constructor_name); |
| 1777 Handle<Object> constructor(Top::global()->GetProperty(*constructor_str)); | 1792 Handle<Object> constructor(Top::global()->GetProperty(*constructor_str)); |
| 1778 ASSERT(constructor->IsJSFunction()); | 1793 ASSERT(constructor->IsJSFunction()); |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2100 if (!auto_continue) { | 2115 if (!auto_continue) { |
| 2101 Debug::clear_interrupt_pending(DEBUGBREAK); | 2116 Debug::clear_interrupt_pending(DEBUGBREAK); |
| 2102 } | 2117 } |
| 2103 | 2118 |
| 2104 // Create the execution state. | 2119 // Create the execution state. |
| 2105 bool caught_exception = false; | 2120 bool caught_exception = false; |
| 2106 Handle<Object> exec_state = MakeExecutionState(&caught_exception); | 2121 Handle<Object> exec_state = MakeExecutionState(&caught_exception); |
| 2107 if (caught_exception) { | 2122 if (caught_exception) { |
| 2108 return; | 2123 return; |
| 2109 } | 2124 } |
| 2125 |
| 2126 DebuggerData& data = v8_context()->debugger_data_; |
| 2110 // First notify the message handler if any. | 2127 // First notify the message handler if any. |
| 2111 if (message_handler_ != NULL) { | 2128 if (data.message_handler_ != NULL) { |
| 2112 NotifyMessageHandler(event, | 2129 NotifyMessageHandler(event, |
| 2113 Handle<JSObject>::cast(exec_state), | 2130 Handle<JSObject>::cast(exec_state), |
| 2114 event_data, | 2131 event_data, |
| 2115 auto_continue); | 2132 auto_continue); |
| 2116 } | 2133 } |
| 2117 // Notify registered debug event listener. This can be either a C or a | 2134 // Notify registered debug event listener. This can be either a C or a |
| 2118 // JavaScript function. | 2135 // JavaScript function. |
| 2119 if (!event_listener_.is_null()) { | 2136 if (!data.event_listener_.is_null()) { |
| 2120 if (event_listener_->IsProxy()) { | 2137 if (data.event_listener_->IsProxy()) { |
| 2121 // C debug event listener. | 2138 // C debug event listener. |
| 2122 Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_)); | 2139 Handle<Proxy> callback_obj(Handle<Proxy>::cast(data.event_listener_)); |
| 2123 v8::Debug::EventCallback callback = | 2140 v8::Debug::EventCallback callback = |
| 2124 FUNCTION_CAST<v8::Debug::EventCallback>(callback_obj->proxy()); | 2141 FUNCTION_CAST<v8::Debug::EventCallback>(callback_obj->proxy()); |
| 2125 callback(event, | 2142 callback(event, |
| 2126 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), | 2143 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), |
| 2127 v8::Utils::ToLocal(event_data), | 2144 v8::Utils::ToLocal(event_data), |
| 2128 v8::Utils::ToLocal(Handle<Object>::cast(event_listener_data_))); | 2145 v8::Utils::ToLocal(Handle<Object>::cast( |
| 2146 data.event_listener_data_))); |
| 2129 } else { | 2147 } else { |
| 2130 // JavaScript debug event listener. | 2148 // JavaScript debug event listener. |
| 2131 ASSERT(event_listener_->IsJSFunction()); | 2149 ASSERT(data.event_listener_->IsJSFunction()); |
| 2132 Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_)); | 2150 Handle<JSFunction> fun(Handle<JSFunction>::cast(data.event_listener_)); |
| 2133 | 2151 |
| 2134 // Invoke the JavaScript debug event listener. | 2152 // Invoke the JavaScript debug event listener. |
| 2135 const int argc = 4; | 2153 const int argc = 4; |
| 2136 Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(), | 2154 Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(), |
| 2137 exec_state.location(), | 2155 exec_state.location(), |
| 2138 Handle<Object>::cast(event_data).location(), | 2156 Handle<Object>::cast(event_data).location(), |
| 2139 event_listener_data_.location() }; | 2157 data.event_listener_data_.location() }; |
| 2140 Handle<Object> result = Execution::TryCall(fun, Top::global(), | 2158 Handle<Object> result = Execution::TryCall(fun, Top::global(), |
| 2141 argc, argv, &caught_exception); | 2159 argc, argv, &caught_exception); |
| 2142 // Silently ignore exceptions from debug event listeners. | 2160 // Silently ignore exceptions from debug event listeners. |
| 2143 } | 2161 } |
| 2144 } | 2162 } |
| 2145 } | 2163 } |
| 2146 | 2164 |
| 2147 | 2165 |
| 2148 void Debugger::UnloadDebugger() { | 2166 void Debugger::UnloadDebugger() { |
| 2149 // Make sure that there are no breakpoints left. | 2167 // Make sure that there are no breakpoints left. |
| 2150 Debug::ClearAllBreakPoints(); | 2168 Debug::ClearAllBreakPoints(); |
| 2151 | 2169 |
| 2170 DebuggerData& data = v8_context()->debugger_data_; |
| 2152 // Unload the debugger if feasible. | 2171 // Unload the debugger if feasible. |
| 2153 if (!never_unload_debugger_) { | 2172 if (!data.never_unload_debugger_) { |
| 2154 Debug::Unload(); | 2173 Debug::Unload(); |
| 2155 } | 2174 } |
| 2156 | 2175 |
| 2157 // Clear the flag indicating that the debugger should be unloaded. | 2176 // Clear the flag indicating that the debugger should be unloaded. |
| 2158 debugger_unload_pending_ = false; | 2177 data.debugger_unload_pending_ = false; |
| 2159 } | 2178 } |
| 2160 | 2179 |
| 2161 | 2180 |
| 2162 void Debugger::NotifyMessageHandler(v8::DebugEvent event, | 2181 void Debugger::NotifyMessageHandler(v8::DebugEvent event, |
| 2163 Handle<JSObject> exec_state, | 2182 Handle<JSObject> exec_state, |
| 2164 Handle<JSObject> event_data, | 2183 Handle<JSObject> event_data, |
| 2165 bool auto_continue) { | 2184 bool auto_continue) { |
| 2166 HandleScope scope; | 2185 HandleScope scope; |
| 2167 | 2186 |
| 2168 if (!Debug::Load()) return; | 2187 if (!Debug::Load()) return; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2232 static const int kArgc = 1; | 2251 static const int kArgc = 1; |
| 2233 v8::Handle<Value> argv[kArgc] = { running }; | 2252 v8::Handle<Value> argv[kArgc] = { running }; |
| 2234 cmd_processor = v8::Object::Cast(*fun->Call(api_exec_state, kArgc, argv)); | 2253 cmd_processor = v8::Object::Cast(*fun->Call(api_exec_state, kArgc, argv)); |
| 2235 if (try_catch.HasCaught()) { | 2254 if (try_catch.HasCaught()) { |
| 2236 PrintLn(try_catch.Exception()); | 2255 PrintLn(try_catch.Exception()); |
| 2237 return; | 2256 return; |
| 2238 } | 2257 } |
| 2239 } | 2258 } |
| 2240 | 2259 |
| 2241 bool running = auto_continue; | 2260 bool running = auto_continue; |
| 2261 DebuggerData& data = v8_context()->debugger_data_; |
| 2242 | 2262 |
| 2243 // Process requests from the debugger. | 2263 // Process requests from the debugger. |
| 2244 while (true) { | 2264 while (true) { |
| 2245 // Wait for new command in the queue. | 2265 // Wait for new command in the queue. |
| 2246 if (Debugger::host_dispatch_handler_) { | 2266 if (data.host_dispatch_handler_) { |
| 2247 // In case there is a host dispatch - do periodic dispatches. | 2267 // In case there is a host dispatch - do periodic dispatches. |
| 2248 if (!command_received_->Wait(host_dispatch_micros_)) { | 2268 if (!data.command_received_->Wait(data.host_dispatch_micros_)) { |
| 2249 // Timout expired, do the dispatch. | 2269 // Timout expired, do the dispatch. |
| 2250 Debugger::host_dispatch_handler_(); | 2270 data.host_dispatch_handler_(); |
| 2251 continue; | 2271 continue; |
| 2252 } | 2272 } |
| 2253 } else { | 2273 } else { |
| 2254 // In case there is no host dispatch - just wait. | 2274 // In case there is no host dispatch - just wait. |
| 2255 command_received_->Wait(); | 2275 data.command_received_->Wait(); |
| 2256 } | 2276 } |
| 2257 | 2277 |
| 2258 // Get the command from the queue. | 2278 // Get the command from the queue. |
| 2259 CommandMessage command = command_queue_.Get(); | 2279 CommandMessage command = data.command_queue_.Get(); |
| 2260 Logger::DebugTag("Got request from command queue, in interactive loop."); | 2280 Logger::DebugTag("Got request from command queue, in interactive loop."); |
| 2261 if (!Debugger::IsDebuggerActive()) { | 2281 if (!Debugger::IsDebuggerActive()) { |
| 2262 // Delete command text and user data. | 2282 // Delete command text and user data. |
| 2263 command.Dispose(); | 2283 command.Dispose(); |
| 2264 return; | 2284 return; |
| 2265 } | 2285 } |
| 2266 | 2286 |
| 2267 // Invoke JavaScript to process the debug request. | 2287 // Invoke JavaScript to process the debug request. |
| 2268 v8::Local<v8::String> fun_name; | 2288 v8::Local<v8::String> fun_name; |
| 2269 v8::Local<v8::Function> fun; | 2289 v8::Local<v8::Function> fun; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2326 return; | 2346 return; |
| 2327 } | 2347 } |
| 2328 } | 2348 } |
| 2329 } | 2349 } |
| 2330 | 2350 |
| 2331 | 2351 |
| 2332 void Debugger::SetEventListener(Handle<Object> callback, | 2352 void Debugger::SetEventListener(Handle<Object> callback, |
| 2333 Handle<Object> data) { | 2353 Handle<Object> data) { |
| 2334 HandleScope scope; | 2354 HandleScope scope; |
| 2335 | 2355 |
| 2356 DebuggerData& debugger_data = v8_context()->debugger_data_; |
| 2357 |
| 2336 // Clear the global handles for the event listener and the event listener data | 2358 // Clear the global handles for the event listener and the event listener data |
| 2337 // object. | 2359 // object. |
| 2338 if (!event_listener_.is_null()) { | 2360 if (!debugger_data.event_listener_.is_null()) { |
| 2339 GlobalHandles::Destroy( | 2361 GlobalHandles::Destroy( |
| 2340 reinterpret_cast<Object**>(event_listener_.location())); | 2362 reinterpret_cast<Object**>(debugger_data.event_listener_.location())); |
| 2341 event_listener_ = Handle<Object>(); | 2363 debugger_data.event_listener_ = Handle<Object>(); |
| 2342 } | 2364 } |
| 2343 if (!event_listener_data_.is_null()) { | 2365 if (!debugger_data.event_listener_data_.is_null()) { |
| 2344 GlobalHandles::Destroy( | 2366 GlobalHandles::Destroy(reinterpret_cast<Object**>( |
| 2345 reinterpret_cast<Object**>(event_listener_data_.location())); | 2367 debugger_data.event_listener_data_.location())); |
| 2346 event_listener_data_ = Handle<Object>(); | 2368 debugger_data.event_listener_data_ = Handle<Object>(); |
| 2347 } | 2369 } |
| 2348 | 2370 |
| 2349 // If there is a new debug event listener register it together with its data | 2371 // If there is a new debug event listener register it together with its data |
| 2350 // object. | 2372 // object. |
| 2351 if (!callback->IsUndefined() && !callback->IsNull()) { | 2373 if (!callback->IsUndefined() && !callback->IsNull()) { |
| 2352 event_listener_ = Handle<Object>::cast(GlobalHandles::Create(*callback)); | 2374 debugger_data.event_listener_ = |
| 2375 Handle<Object>::cast(GlobalHandles::Create(*callback)); |
| 2353 if (data.is_null()) { | 2376 if (data.is_null()) { |
| 2354 data = Factory::undefined_value(); | 2377 data = Factory::undefined_value(); |
| 2355 } | 2378 } |
| 2356 event_listener_data_ = Handle<Object>::cast(GlobalHandles::Create(*data)); | 2379 debugger_data.event_listener_data_ = |
| 2380 Handle<Object>::cast(GlobalHandles::Create(*data)); |
| 2357 } | 2381 } |
| 2358 | 2382 |
| 2359 ListenersChanged(); | 2383 ListenersChanged(); |
| 2360 } | 2384 } |
| 2361 | 2385 |
| 2362 | 2386 |
| 2363 void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) { | 2387 void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) { |
| 2364 ScopedLock with(debugger_access_); | 2388 DebuggerData& data = v8_context()->debugger_data_; |
| 2389 ScopedLock with(data.debugger_access_); |
| 2365 | 2390 |
| 2366 message_handler_ = handler; | 2391 data.message_handler_ = handler; |
| 2367 ListenersChanged(); | 2392 ListenersChanged(); |
| 2368 if (handler == NULL) { | 2393 if (handler == NULL) { |
| 2369 // Send an empty command to the debugger if in a break to make JavaScript | 2394 // Send an empty command to the debugger if in a break to make JavaScript |
| 2370 // run again if the debugger is closed. | 2395 // run again if the debugger is closed. |
| 2371 if (Debug::InDebugger()) { | 2396 if (Debug::InDebugger()) { |
| 2372 ProcessCommand(Vector<const uint16_t>::empty()); | 2397 ProcessCommand(Vector<const uint16_t>::empty()); |
| 2373 } | 2398 } |
| 2374 } | 2399 } |
| 2375 } | 2400 } |
| 2376 | 2401 |
| 2377 | 2402 |
| 2378 void Debugger::ListenersChanged() { | 2403 void Debugger::ListenersChanged() { |
| 2379 if (IsDebuggerActive()) { | 2404 if (IsDebuggerActive()) { |
| 2380 // Disable the compilation cache when the debugger is active. | 2405 // Disable the compilation cache when the debugger is active. |
| 2381 CompilationCache::Disable(); | 2406 CompilationCache::Disable(); |
| 2382 } else { | 2407 } else { |
| 2383 CompilationCache::Enable(); | 2408 CompilationCache::Enable(); |
| 2384 | 2409 |
| 2385 // Unload the debugger if event listener and message handler cleared. | 2410 // Unload the debugger if event listener and message handler cleared. |
| 2386 if (Debug::InDebugger()) { | 2411 if (Debug::InDebugger()) { |
| 2387 // If we are in debugger set the flag to unload the debugger when last | 2412 // If we are in debugger set the flag to unload the debugger when last |
| 2388 // EnterDebugger on the current stack is destroyed. | 2413 // EnterDebugger on the current stack is destroyed. |
| 2389 debugger_unload_pending_ = true; | 2414 v8_context()->debugger_data_.debugger_unload_pending_ = true; |
| 2390 } else { | 2415 } else { |
| 2391 UnloadDebugger(); | 2416 UnloadDebugger(); |
| 2392 } | 2417 } |
| 2393 } | 2418 } |
| 2394 } | 2419 } |
| 2395 | 2420 |
| 2396 | 2421 |
| 2397 void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler, | 2422 void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler, |
| 2398 int period) { | 2423 int period) { |
| 2399 host_dispatch_handler_ = handler; | 2424 DebuggerData& data = v8_context()->debugger_data_; |
| 2400 host_dispatch_micros_ = period * 1000; | 2425 data.host_dispatch_handler_ = handler; |
| 2426 data.host_dispatch_micros_ = period * 1000; |
| 2401 } | 2427 } |
| 2402 | 2428 |
| 2403 | 2429 |
| 2404 void Debugger::SetDebugMessageDispatchHandler( | 2430 void Debugger::SetDebugMessageDispatchHandler( |
| 2405 v8::Debug::DebugMessageDispatchHandler handler) { | 2431 v8::Debug::DebugMessageDispatchHandler handler) { |
| 2406 debug_message_dispatch_handler_ = handler; | 2432 v8_context()->debugger_data_.debug_message_dispatch_handler_ = handler; |
| 2407 } | 2433 } |
| 2408 | 2434 |
| 2409 | 2435 |
| 2410 // Calls the registered debug message handler. This callback is part of the | 2436 // Calls the registered debug message handler. This callback is part of the |
| 2411 // public API. | 2437 // public API. |
| 2412 void Debugger::InvokeMessageHandler(MessageImpl message) { | 2438 void Debugger::InvokeMessageHandler(MessageImpl message) { |
| 2413 ScopedLock with(debugger_access_); | 2439 DebuggerData& data = v8_context()->debugger_data_; |
| 2440 ScopedLock with(data.debugger_access_); |
| 2414 | 2441 |
| 2415 if (message_handler_ != NULL) { | 2442 if (data.message_handler_ != NULL) { |
| 2416 message_handler_(message); | 2443 data.message_handler_(message); |
| 2417 } | 2444 } |
| 2418 } | 2445 } |
| 2419 | 2446 |
| 2420 | 2447 |
| 2421 // Puts a command coming from the public API on the queue. Creates | 2448 // Puts a command coming from the public API on the queue. Creates |
| 2422 // a copy of the command string managed by the debugger. Up to this | 2449 // a copy of the command string managed by the debugger. Up to this |
| 2423 // point, the command data was managed by the API client. Called | 2450 // point, the command data was managed by the API client. Called |
| 2424 // by the API client thread. | 2451 // by the API client thread. |
| 2425 void Debugger::ProcessCommand(Vector<const uint16_t> command, | 2452 void Debugger::ProcessCommand(Vector<const uint16_t> command, |
| 2426 v8::Debug::ClientData* client_data) { | 2453 v8::Debug::ClientData* client_data) { |
| 2427 // Need to cast away const. | 2454 // Need to cast away const. |
| 2428 CommandMessage message = CommandMessage::New( | 2455 CommandMessage message = CommandMessage::New( |
| 2429 Vector<uint16_t>(const_cast<uint16_t*>(command.start()), | 2456 Vector<uint16_t>(const_cast<uint16_t*>(command.start()), |
| 2430 command.length()), | 2457 command.length()), |
| 2431 client_data); | 2458 client_data); |
| 2432 Logger::DebugTag("Put command on command_queue."); | 2459 Logger::DebugTag("Put command on command_queue."); |
| 2433 command_queue_.Put(message); | 2460 DebuggerData& data = v8_context()->debugger_data_; |
| 2434 command_received_->Signal(); | 2461 data.command_queue_.Put(message); |
| 2462 data.command_received_->Signal(); |
| 2435 | 2463 |
| 2436 // Set the debug command break flag to have the command processed. | 2464 // Set the debug command break flag to have the command processed. |
| 2437 if (!Debug::InDebugger()) { | 2465 if (!Debug::InDebugger()) { |
| 2438 StackGuard::DebugCommand(); | 2466 StackGuard::DebugCommand(); |
| 2439 } | 2467 } |
| 2440 | 2468 |
| 2441 if (Debugger::debug_message_dispatch_handler_ != NULL) { | 2469 if (data.debug_message_dispatch_handler_ != NULL) { |
| 2442 Debugger::debug_message_dispatch_handler_(); | 2470 data.debug_message_dispatch_handler_(); |
| 2443 } | 2471 } |
| 2444 } | 2472 } |
| 2445 | 2473 |
| 2446 | 2474 |
| 2447 bool Debugger::HasCommands() { | 2475 bool Debugger::HasCommands() { |
| 2448 return !command_queue_.IsEmpty(); | 2476 return !v8_context()->debugger_data_.command_queue_.IsEmpty(); |
| 2449 } | 2477 } |
| 2450 | 2478 |
| 2451 | 2479 |
| 2452 bool Debugger::IsDebuggerActive() { | 2480 bool Debugger::IsDebuggerActive() { |
| 2453 ScopedLock with(debugger_access_); | 2481 DebuggerData& data = v8_context()->debugger_data_; |
| 2482 ScopedLock with(data.debugger_access_); |
| 2454 | 2483 |
| 2455 return message_handler_ != NULL || !event_listener_.is_null(); | 2484 return data.message_handler_ != NULL || !data.event_listener_.is_null(); |
| 2456 } | 2485 } |
| 2457 | 2486 |
| 2458 | 2487 |
| 2459 Handle<Object> Debugger::Call(Handle<JSFunction> fun, | 2488 Handle<Object> Debugger::Call(Handle<JSFunction> fun, |
| 2460 Handle<Object> data, | 2489 Handle<Object> data, |
| 2461 bool* pending_exception) { | 2490 bool* pending_exception) { |
| 2462 // When calling functions in the debugger prevent it from beeing unloaded. | 2491 // When calling functions in the debugger prevent it from beeing unloaded. |
| 2463 Debugger::never_unload_debugger_ = true; | 2492 v8_context()->debugger_data_.never_unload_debugger_ = true; |
| 2464 | 2493 |
| 2465 // Enter the debugger. | 2494 // Enter the debugger. |
| 2466 EnterDebugger debugger; | 2495 EnterDebugger debugger; |
| 2467 if (debugger.FailedToEnter() || !debugger.HasJavaScriptFrames()) { | 2496 if (debugger.FailedToEnter() || !debugger.HasJavaScriptFrames()) { |
| 2468 return Factory::undefined_value(); | 2497 return Factory::undefined_value(); |
| 2469 } | 2498 } |
| 2470 | 2499 |
| 2471 // Create the execution state. | 2500 // Create the execution state. |
| 2472 bool caught_exception = false; | 2501 bool caught_exception = false; |
| 2473 Handle<Object> exec_state = MakeExecutionState(&caught_exception); | 2502 Handle<Object> exec_state = MakeExecutionState(&caught_exception); |
| 2474 if (caught_exception) { | 2503 if (caught_exception) { |
| 2475 return Factory::undefined_value(); | 2504 return Factory::undefined_value(); |
| 2476 } | 2505 } |
| 2477 | 2506 |
| 2478 static const int kArgc = 2; | 2507 static const int kArgc = 2; |
| 2479 Object** argv[kArgc] = { exec_state.location(), data.location() }; | 2508 Object** argv[kArgc] = { exec_state.location(), data.location() }; |
| 2480 Handle<Object> result = Execution::Call(fun, Factory::undefined_value(), | 2509 Handle<Object> result = Execution::Call(fun, Factory::undefined_value(), |
| 2481 kArgc, argv, pending_exception); | 2510 kArgc, argv, pending_exception); |
| 2482 return result; | 2511 return result; |
| 2483 } | 2512 } |
| 2484 | 2513 |
| 2485 | 2514 |
| 2486 bool Debugger::StartAgent(const char* name, int port) { | 2515 bool Debugger::StartAgent(const char* name, int port) { |
| 2487 if (Socket::Setup()) { | 2516 if (Socket::Setup()) { |
| 2488 agent_ = new DebuggerAgent(name, port); | 2517 DebuggerData& data = v8_context()->debugger_data_; |
| 2489 agent_->Start(); | 2518 data.agent_ = new DebuggerAgent(name, port); |
| 2519 data.agent_->Start(); |
| 2490 return true; | 2520 return true; |
| 2491 } | 2521 } |
| 2492 | 2522 |
| 2493 return false; | 2523 return false; |
| 2494 } | 2524 } |
| 2495 | 2525 |
| 2496 | 2526 |
| 2497 void Debugger::StopAgent() { | 2527 void Debugger::StopAgent() { |
| 2498 if (agent_ != NULL) { | 2528 DebuggerData& data = v8_context()->debugger_data_; |
| 2499 agent_->Shutdown(); | 2529 if (data.agent_ != NULL) { |
| 2500 agent_->Join(); | 2530 data.agent_->Shutdown(); |
| 2501 delete agent_; | 2531 data.agent_->Join(); |
| 2502 agent_ = NULL; | 2532 delete data.agent_; |
| 2533 data.agent_ = NULL; |
| 2503 } | 2534 } |
| 2504 } | 2535 } |
| 2505 | 2536 |
| 2506 | 2537 |
| 2507 void Debugger::WaitForAgent() { | 2538 void Debugger::WaitForAgent() { |
| 2508 if (agent_ != NULL) | 2539 DebuggerData& data = v8_context()->debugger_data_; |
| 2509 agent_->WaitUntilListening(); | 2540 if (data.agent_ != NULL) |
| 2541 data.agent_->WaitUntilListening(); |
| 2510 } | 2542 } |
| 2511 | 2543 |
| 2512 MessageImpl MessageImpl::NewEvent(DebugEvent event, | 2544 MessageImpl MessageImpl::NewEvent(DebugEvent event, |
| 2513 bool running, | 2545 bool running, |
| 2514 Handle<JSObject> exec_state, | 2546 Handle<JSObject> exec_state, |
| 2515 Handle<JSObject> event_data) { | 2547 Handle<JSObject> event_data) { |
| 2516 MessageImpl message(true, event, running, | 2548 MessageImpl message(true, event, running, |
| 2517 exec_state, event_data, Handle<String>(), NULL); | 2549 exec_state, event_data, Handle<String>(), NULL); |
| 2518 return message; | 2550 return message; |
| 2519 } | 2551 } |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2725 | 2757 |
| 2726 | 2758 |
| 2727 void LockingCommandMessageQueue::Clear() { | 2759 void LockingCommandMessageQueue::Clear() { |
| 2728 ScopedLock sl(lock_); | 2760 ScopedLock sl(lock_); |
| 2729 queue_.Clear(); | 2761 queue_.Clear(); |
| 2730 } | 2762 } |
| 2731 | 2763 |
| 2732 #endif // ENABLE_DEBUGGER_SUPPORT | 2764 #endif // ENABLE_DEBUGGER_SUPPORT |
| 2733 | 2765 |
| 2734 } } // namespace v8::internal | 2766 } } // namespace v8::internal |
| OLD | NEW |