OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_DEBUG_DEBUG_H_ | 5 #ifndef V8_DEBUG_DEBUG_H_ |
6 #define V8_DEBUG_DEBUG_H_ | 6 #define V8_DEBUG_DEBUG_H_ |
7 | 7 |
8 #include "src/allocation.h" | 8 #include "src/allocation.h" |
9 #include "src/arguments.h" | 9 #include "src/arguments.h" |
10 #include "src/assembler.h" | 10 #include "src/assembler.h" |
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
511 void Iterate(ObjectVisitor* v); | 511 void Iterate(ObjectVisitor* v); |
512 | 512 |
513 bool CheckExecutionState(int id) { | 513 bool CheckExecutionState(int id) { |
514 return CheckExecutionState() && break_id() == id; | 514 return CheckExecutionState() && break_id() == id; |
515 } | 515 } |
516 | 516 |
517 bool CheckExecutionState() { | 517 bool CheckExecutionState() { |
518 return is_active() && !debug_context().is_null() && break_id() != 0; | 518 return is_active() && !debug_context().is_null() && break_id() != 0; |
519 } | 519 } |
520 | 520 |
| 521 bool PerformSideEffectCheck(Handle<JSFunction> function); |
| 522 |
521 // Flags and states. | 523 // Flags and states. |
522 DebugScope* debugger_entry() { | 524 DebugScope* debugger_entry() { |
523 return reinterpret_cast<DebugScope*>( | 525 return reinterpret_cast<DebugScope*>( |
524 base::NoBarrier_Load(&thread_local_.current_debug_scope_)); | 526 base::NoBarrier_Load(&thread_local_.current_debug_scope_)); |
525 } | 527 } |
526 inline Handle<Context> debug_context() { return debug_context_; } | 528 inline Handle<Context> debug_context() { return debug_context_; } |
527 | 529 |
528 void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; } | 530 void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; } |
529 bool live_edit_enabled() const { | 531 bool live_edit_enabled() const { |
530 return FLAG_enable_liveedit && live_edit_enabled_; | 532 return FLAG_enable_liveedit && live_edit_enabled_; |
531 } | 533 } |
532 | 534 |
533 inline bool is_active() const { return is_active_; } | 535 inline bool is_active() const { return is_active_; } |
534 inline bool is_loaded() const { return !debug_context_.is_null(); } | 536 inline bool is_loaded() const { return !debug_context_.is_null(); } |
535 inline bool in_debug_scope() const { | 537 inline bool in_debug_scope() const { |
536 return !!base::NoBarrier_Load(&thread_local_.current_debug_scope_); | 538 return !!base::NoBarrier_Load(&thread_local_.current_debug_scope_); |
537 } | 539 } |
538 void set_break_points_active(bool v) { break_points_active_ = v; } | 540 void set_break_points_active(bool v) { break_points_active_ = v; } |
539 bool break_points_active() const { return break_points_active_; } | 541 bool break_points_active() const { return break_points_active_; } |
| 542 bool needs_side_effect_check() const { return needs_side_effect_check_; } |
540 | 543 |
541 StackFrame::Id break_frame_id() { return thread_local_.break_frame_id_; } | 544 StackFrame::Id break_frame_id() { return thread_local_.break_frame_id_; } |
542 int break_id() { return thread_local_.break_id_; } | 545 int break_id() { return thread_local_.break_id_; } |
543 | 546 |
544 Handle<Object> return_value() { return thread_local_.return_value_; } | 547 Handle<Object> return_value() { return thread_local_.return_value_; } |
545 void set_return_value(Handle<Object> value) { | 548 void set_return_value(Handle<Object> value) { |
546 thread_local_.return_value_ = value; | 549 thread_local_.return_value_ = value; |
547 } | 550 } |
548 | 551 |
549 // Support for embedding into generated code. | 552 // Support for embedding into generated code. |
550 Address is_active_address() { | 553 Address is_active_address() { |
551 return reinterpret_cast<Address>(&is_active_); | 554 return reinterpret_cast<Address>(&is_active_); |
552 } | 555 } |
553 | 556 |
| 557 Address hook_on_function_call_address() { |
| 558 return reinterpret_cast<Address>(&hook_on_function_call_); |
| 559 } |
| 560 |
554 Address after_break_target_address() { | 561 Address after_break_target_address() { |
555 return reinterpret_cast<Address>(&after_break_target_); | 562 return reinterpret_cast<Address>(&after_break_target_); |
556 } | 563 } |
557 | 564 |
558 Address last_step_action_address() { | 565 Address last_step_action_address() { |
559 return reinterpret_cast<Address>(&thread_local_.last_step_action_); | 566 return reinterpret_cast<Address>(&thread_local_.last_step_action_); |
560 } | 567 } |
561 | 568 |
562 Address suspended_generator_address() { | 569 Address suspended_generator_address() { |
563 return reinterpret_cast<Address>(&thread_local_.suspended_generator_); | 570 return reinterpret_cast<Address>(&thread_local_.suspended_generator_); |
564 } | 571 } |
565 | 572 |
566 StepAction last_step_action() { return thread_local_.last_step_action_; } | 573 StepAction last_step_action() { return thread_local_.last_step_action_; } |
567 | 574 |
568 DebugFeatureTracker* feature_tracker() { return &feature_tracker_; } | 575 DebugFeatureTracker* feature_tracker() { return &feature_tracker_; } |
569 | 576 |
570 private: | 577 private: |
571 explicit Debug(Isolate* isolate); | 578 explicit Debug(Isolate* isolate); |
572 | 579 |
573 void UpdateState(); | 580 void UpdateState(); |
| 581 void UpdateHookOnFunctionCall(); |
574 void Unload(); | 582 void Unload(); |
575 void SetNextBreakId() { | 583 void SetNextBreakId() { |
576 thread_local_.break_id_ = ++thread_local_.break_count_; | 584 thread_local_.break_id_ = ++thread_local_.break_count_; |
577 } | 585 } |
578 | 586 |
579 // Check whether there are commands in the command queue. | 587 // Check whether there are commands in the command queue. |
580 inline bool has_commands() const { return !command_queue_.IsEmpty(); } | 588 inline bool has_commands() const { return !command_queue_.IsEmpty(); } |
581 inline bool ignore_events() const { return is_suppressed_ || !is_active_; } | 589 inline bool ignore_events() const { return is_suppressed_ || !is_active_; } |
582 inline bool break_disabled() const { | 590 inline bool break_disabled() const { |
583 return break_disabled_ || in_debug_event_listener_; | 591 return break_disabled_ || in_debug_event_listener_; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
659 Handle<Context> debug_context_; | 667 Handle<Context> debug_context_; |
660 Handle<Object> event_listener_; | 668 Handle<Object> event_listener_; |
661 Handle<Object> event_listener_data_; | 669 Handle<Object> event_listener_data_; |
662 | 670 |
663 v8::Debug::MessageHandler message_handler_; | 671 v8::Debug::MessageHandler message_handler_; |
664 | 672 |
665 static const int kQueueInitialSize = 4; | 673 static const int kQueueInitialSize = 4; |
666 base::Semaphore command_received_; // Signaled for each command received. | 674 base::Semaphore command_received_; // Signaled for each command received. |
667 LockingCommandMessageQueue command_queue_; | 675 LockingCommandMessageQueue command_queue_; |
668 | 676 |
| 677 // Debugger is active, i.e. there is a debug event listener attached. |
669 bool is_active_; | 678 bool is_active_; |
| 679 // Debugger needs to be notified on every new function call. |
| 680 // Used for stepping and read-only checks |
| 681 bool hook_on_function_call_; |
| 682 // Suppress debug events. |
670 bool is_suppressed_; | 683 bool is_suppressed_; |
| 684 // LiveEdit is enabled. |
671 bool live_edit_enabled_; | 685 bool live_edit_enabled_; |
| 686 // Do not trigger debug break events. |
672 bool break_disabled_; | 687 bool break_disabled_; |
| 688 // Do not break on break points. |
673 bool break_points_active_; | 689 bool break_points_active_; |
| 690 // Nested inside a debug event listener. |
674 bool in_debug_event_listener_; | 691 bool in_debug_event_listener_; |
| 692 // Trigger debug break events for all exceptions. |
675 bool break_on_exception_; | 693 bool break_on_exception_; |
| 694 // Trigger debug break events for uncaught exceptions. |
676 bool break_on_uncaught_exception_; | 695 bool break_on_uncaught_exception_; |
| 696 // Perform side effect checks on function call. |
| 697 bool needs_side_effect_check_; |
| 698 // Termination exception because side effect check has failed. |
| 699 bool side_effect_check_failed_; |
677 | 700 |
678 DebugInfoListNode* debug_info_list_; // List of active debug info objects. | 701 // List of active debug info objects. |
| 702 DebugInfoListNode* debug_info_list_; |
679 | 703 |
680 // Storage location for jump when exiting debug break calls. | 704 // Storage location for jump when exiting debug break calls. |
681 // Note that this address is not GC safe. It should be computed immediately | 705 // Note that this address is not GC safe. It should be computed immediately |
682 // before returning to the DebugBreakCallHelper. | 706 // before returning to the DebugBreakCallHelper. |
683 Address after_break_target_; | 707 Address after_break_target_; |
684 | 708 |
685 // Used to collect histogram data on debugger feature usage. | 709 // Used to collect histogram data on debugger feature usage. |
686 DebugFeatureTracker feature_tracker_; | 710 DebugFeatureTracker feature_tracker_; |
687 | 711 |
688 // Per-thread data. | 712 // Per-thread data. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 // Storage location for registers when handling debug break calls | 750 // Storage location for registers when handling debug break calls |
727 ThreadLocal thread_local_; | 751 ThreadLocal thread_local_; |
728 | 752 |
729 Isolate* isolate_; | 753 Isolate* isolate_; |
730 | 754 |
731 friend class Isolate; | 755 friend class Isolate; |
732 friend class DebugScope; | 756 friend class DebugScope; |
733 friend class DisableBreak; | 757 friend class DisableBreak; |
734 friend class LiveEdit; | 758 friend class LiveEdit; |
735 friend class SuppressDebug; | 759 friend class SuppressDebug; |
| 760 friend class NoSideEffectScope; |
736 | 761 |
737 friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc | 762 friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc |
738 friend void CheckDebuggerUnloaded(bool check_functions); // In test-debug.cc | 763 friend void CheckDebuggerUnloaded(bool check_functions); // In test-debug.cc |
739 | 764 |
740 DISALLOW_COPY_AND_ASSIGN(Debug); | 765 DISALLOW_COPY_AND_ASSIGN(Debug); |
741 }; | 766 }; |
742 | 767 |
743 | 768 |
744 // This scope is used to load and enter the debug context and create a new | 769 // This scope is used to load and enter the debug context and create a new |
745 // break state. Leaving the scope will restore the previous state. | 770 // break state. Leaving the scope will restore the previous state. |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
799 debug_->is_suppressed_ = true; | 824 debug_->is_suppressed_ = true; |
800 } | 825 } |
801 ~SuppressDebug() { debug_->is_suppressed_ = old_state_; } | 826 ~SuppressDebug() { debug_->is_suppressed_ = old_state_; } |
802 | 827 |
803 private: | 828 private: |
804 Debug* debug_; | 829 Debug* debug_; |
805 bool old_state_; | 830 bool old_state_; |
806 DISALLOW_COPY_AND_ASSIGN(SuppressDebug); | 831 DISALLOW_COPY_AND_ASSIGN(SuppressDebug); |
807 }; | 832 }; |
808 | 833 |
| 834 class NoSideEffectScope { |
| 835 public: |
| 836 NoSideEffectScope(Debug* debug, bool disallow_side_effects) |
| 837 : debug_(debug), |
| 838 old_needs_side_effect_check_(debug->needs_side_effect_check_) { |
| 839 debug_->needs_side_effect_check_ |= disallow_side_effects; |
| 840 debug_->UpdateHookOnFunctionCall(); |
| 841 debug_->side_effect_check_failed_ = false; |
| 842 } |
| 843 ~NoSideEffectScope(); |
| 844 |
| 845 private: |
| 846 Debug* debug_; |
| 847 bool old_needs_side_effect_check_; |
| 848 DISALLOW_COPY_AND_ASSIGN(NoSideEffectScope); |
| 849 }; |
809 | 850 |
810 // Code generator routines. | 851 // Code generator routines. |
811 class DebugCodegen : public AllStatic { | 852 class DebugCodegen : public AllStatic { |
812 public: | 853 public: |
813 enum DebugBreakCallHelperMode { | 854 enum DebugBreakCallHelperMode { |
814 SAVE_RESULT_REGISTER, | 855 SAVE_RESULT_REGISTER, |
815 IGNORE_RESULT_REGISTER | 856 IGNORE_RESULT_REGISTER |
816 }; | 857 }; |
817 | 858 |
818 static void GenerateDebugBreakStub(MacroAssembler* masm, | 859 static void GenerateDebugBreakStub(MacroAssembler* masm, |
(...skipping 12 matching lines...) Expand all Loading... |
831 Handle<Code> code); | 872 Handle<Code> code); |
832 static bool DebugBreakSlotIsPatched(Address pc); | 873 static bool DebugBreakSlotIsPatched(Address pc); |
833 static void ClearDebugBreakSlot(Isolate* isolate, Address pc); | 874 static void ClearDebugBreakSlot(Isolate* isolate, Address pc); |
834 }; | 875 }; |
835 | 876 |
836 | 877 |
837 } // namespace internal | 878 } // namespace internal |
838 } // namespace v8 | 879 } // namespace v8 |
839 | 880 |
840 #endif // V8_DEBUG_DEBUG_H_ | 881 #endif // V8_DEBUG_DEBUG_H_ |
OLD | NEW |