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 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 static Address step_in_fp() { return thread_local_.step_into_fp_; } | 275 static Address step_in_fp() { return thread_local_.step_into_fp_; } |
276 static Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; } | 276 static Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; } |
277 | 277 |
278 static EnterDebugger* debugger_entry() { | 278 static EnterDebugger* debugger_entry() { |
279 return thread_local_.debugger_entry_; | 279 return thread_local_.debugger_entry_; |
280 } | 280 } |
281 static void set_debugger_entry(EnterDebugger* entry) { | 281 static void set_debugger_entry(EnterDebugger* entry) { |
282 thread_local_.debugger_entry_ = entry; | 282 thread_local_.debugger_entry_ = entry; |
283 } | 283 } |
284 | 284 |
285 static bool preemption_pending() { | 285 // Check whether any of the specified interrupts are pending. |
286 return thread_local_.preemption_pending_; | 286 static bool is_interrupt_pending(InterruptFlag what) { |
| 287 return (thread_local_.pending_interrupts_ & what) != 0; |
287 } | 288 } |
288 static void set_preemption_pending(bool preemption_pending) { | 289 |
289 thread_local_.preemption_pending_ = preemption_pending; | 290 // Set specified interrupts as pending. |
| 291 static void set_interrupts_pending(InterruptFlag what) { |
| 292 thread_local_.pending_interrupts_ |= what; |
| 293 } |
| 294 |
| 295 // Clear specified interrupts from pending. |
| 296 static void clear_interrupt_pending(InterruptFlag what) { |
| 297 thread_local_.pending_interrupts_ &= ~static_cast<int>(what); |
290 } | 298 } |
291 | 299 |
292 // Getter and setter for the disable break state. | 300 // Getter and setter for the disable break state. |
293 static bool disable_break() { return disable_break_; } | 301 static bool disable_break() { return disable_break_; } |
294 static void set_disable_break(bool disable_break) { | 302 static void set_disable_break(bool disable_break) { |
295 disable_break_ = disable_break; | 303 disable_break_ = disable_break; |
296 } | 304 } |
297 | 305 |
298 // Getters for the current exception break state. | 306 // Getters for the current exception break state. |
299 static bool break_on_exception() { return break_on_exception_; } | 307 static bool break_on_exception() { return break_on_exception_; } |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
424 | 432 |
425 // Frame pointer for frame from which step in was performed. | 433 // Frame pointer for frame from which step in was performed. |
426 Address step_into_fp_; | 434 Address step_into_fp_; |
427 | 435 |
428 // Storage location for jump when exiting debug break calls. | 436 // Storage location for jump when exiting debug break calls. |
429 Address after_break_target_; | 437 Address after_break_target_; |
430 | 438 |
431 // Top debugger entry. | 439 // Top debugger entry. |
432 EnterDebugger* debugger_entry_; | 440 EnterDebugger* debugger_entry_; |
433 | 441 |
434 // Preemption happened while debugging. | 442 // Pending interrupts scheduled while debugging. |
435 bool preemption_pending_; | 443 int pending_interrupts_; |
436 }; | 444 }; |
437 | 445 |
438 // Storage location for registers when handling debug break calls | 446 // Storage location for registers when handling debug break calls |
439 static JSCallerSavedBuffer registers_; | 447 static JSCallerSavedBuffer registers_; |
440 static ThreadLocal thread_local_; | 448 static ThreadLocal thread_local_; |
441 static void ThreadInit(); | 449 static void ThreadInit(); |
442 | 450 |
443 // Code object for debug break return entry code. | 451 // Code object for debug break return entry code. |
444 static Code* debug_break_return_entry_; | 452 static Code* debug_break_return_entry_; |
445 | 453 |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
672 | 680 |
673 // This class is used for entering the debugger. Create an instance in the stack | 681 // This class is used for entering the debugger. Create an instance in the stack |
674 // to enter the debugger. This will set the current break state, make sure the | 682 // to enter the debugger. This will set the current break state, make sure the |
675 // debugger is loaded and switch to the debugger context. If the debugger for | 683 // debugger is loaded and switch to the debugger context. If the debugger for |
676 // some reason could not be entered FailedToEnter will return true. | 684 // some reason could not be entered FailedToEnter will return true. |
677 class EnterDebugger BASE_EMBEDDED { | 685 class EnterDebugger BASE_EMBEDDED { |
678 public: | 686 public: |
679 EnterDebugger() | 687 EnterDebugger() |
680 : prev_(Debug::debugger_entry()), | 688 : prev_(Debug::debugger_entry()), |
681 has_js_frames_(!it_.done()) { | 689 has_js_frames_(!it_.done()) { |
682 ASSERT(prev_ == NULL ? !Debug::preemption_pending() : true); | 690 ASSERT(prev_ != NULL || !Debug::is_interrupt_pending(PREEMPT)); |
| 691 ASSERT(prev_ != NULL || !Debug::is_interrupt_pending(DEBUGBREAK)); |
683 | 692 |
684 // Link recursive debugger entry. | 693 // Link recursive debugger entry. |
685 Debug::set_debugger_entry(this); | 694 Debug::set_debugger_entry(this); |
686 | 695 |
687 // Store the previous break id and frame id. | 696 // Store the previous break id and frame id. |
688 break_id_ = Debug::break_id(); | 697 break_id_ = Debug::break_id(); |
689 break_frame_id_ = Debug::break_frame_id(); | 698 break_frame_id_ = Debug::break_frame_id(); |
690 | 699 |
691 // Create the new break info. If there is no JavaScript frames there is no | 700 // Create the new break info. If there is no JavaScript frames there is no |
692 // break frame id. | 701 // break frame id. |
693 if (has_js_frames_) { | 702 if (has_js_frames_) { |
694 Debug::NewBreak(it_.frame()->id()); | 703 Debug::NewBreak(it_.frame()->id()); |
695 } else { | 704 } else { |
696 Debug::NewBreak(StackFrame::NO_ID); | 705 Debug::NewBreak(StackFrame::NO_ID); |
697 } | 706 } |
698 | 707 |
699 // Make sure that debugger is loaded and enter the debugger context. | 708 // Make sure that debugger is loaded and enter the debugger context. |
700 load_failed_ = !Debug::Load(); | 709 load_failed_ = !Debug::Load(); |
701 if (!load_failed_) { | 710 if (!load_failed_) { |
702 // NOTE the member variable save which saves the previous context before | 711 // NOTE the member variable save which saves the previous context before |
703 // this change. | 712 // this change. |
704 Top::set_context(*Debug::debug_context()); | 713 Top::set_context(*Debug::debug_context()); |
705 } | 714 } |
706 } | 715 } |
707 | 716 |
708 ~EnterDebugger() { | 717 ~EnterDebugger() { |
709 // Restore to the previous break state. | 718 // Restore to the previous break state. |
710 Debug::SetBreak(break_frame_id_, break_id_); | 719 Debug::SetBreak(break_frame_id_, break_id_); |
711 | 720 |
712 // Request preemption when leaving the last debugger entry and a preemption | 721 // Check for leaving the debugger. |
713 // had been recorded while debugging. This is to avoid starvation in some | |
714 // debugging scenarios. | |
715 if (prev_ == NULL && Debug::preemption_pending()) { | |
716 StackGuard::Preempt(); | |
717 Debug::set_preemption_pending(false); | |
718 } | |
719 | |
720 // If there are commands in the queue when leaving the debugger request that | |
721 // these commands are processed. | |
722 if (prev_ == NULL && Debugger::HasCommands()) { | |
723 StackGuard::DebugCommand(); | |
724 } | |
725 | |
726 if (prev_ == NULL) { | 722 if (prev_ == NULL) { |
727 // Clear mirror cache when leaving the debugger. Skip this if there is a | 723 // Clear mirror cache when leaving the debugger. Skip this if there is a |
728 // pending exception as clearing the mirror cache calls back into | 724 // pending exception as clearing the mirror cache calls back into |
729 // JavaScript. This can happen if the v8::Debug::Call is used in which | 725 // JavaScript. This can happen if the v8::Debug::Call is used in which |
730 // case the exception should end up in the calling code. | 726 // case the exception should end up in the calling code. |
731 if (!Top::has_pending_exception()) { | 727 if (!Top::has_pending_exception()) { |
| 728 // Try to avoid any pending debug break breaking in the clear mirror |
| 729 // cache JavaScript code. |
| 730 if (StackGuard::IsDebugBreak()) { |
| 731 Debug::set_interrupts_pending(DEBUGBREAK); |
| 732 StackGuard::Continue(DEBUGBREAK); |
| 733 } |
732 Debug::ClearMirrorCache(); | 734 Debug::ClearMirrorCache(); |
733 } | 735 } |
| 736 |
| 737 // Request preemption and debug break when leaving the last debugger entry |
| 738 // if any of these where recorded while debugging. |
| 739 if (Debug::is_interrupt_pending(PREEMPT)) { |
| 740 // This re-scheduling of preemption is to avoid starvation in some |
| 741 // debugging scenarios. |
| 742 Debug::clear_interrupt_pending(PREEMPT); |
| 743 StackGuard::Preempt(); |
| 744 } |
| 745 if (Debug::is_interrupt_pending(DEBUGBREAK)) { |
| 746 Debug::clear_interrupt_pending(DEBUGBREAK); |
| 747 StackGuard::DebugBreak(); |
| 748 } |
| 749 |
| 750 // If there are commands in the queue when leaving the debugger request |
| 751 // that these commands are processed. |
| 752 if (Debugger::HasCommands()) { |
| 753 StackGuard::DebugCommand(); |
| 754 } |
| 755 |
734 // If leaving the debugger with the debugger no longer active unload it. | 756 // If leaving the debugger with the debugger no longer active unload it. |
735 if (!Debugger::IsDebuggerActive()) { | 757 if (!Debugger::IsDebuggerActive()) { |
736 Debugger::UnloadDebugger(); | 758 Debugger::UnloadDebugger(); |
737 } | 759 } |
738 } | 760 } |
739 | 761 |
740 // Leaving this debugger entry. | 762 // Leaving this debugger entry. |
741 Debug::set_debugger_entry(prev_); | 763 Debug::set_debugger_entry(prev_); |
742 } | 764 } |
743 | 765 |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
819 Debug::AddressId id_; | 841 Debug::AddressId id_; |
820 int reg_; | 842 int reg_; |
821 }; | 843 }; |
822 | 844 |
823 | 845 |
824 } } // namespace v8::internal | 846 } } // namespace v8::internal |
825 | 847 |
826 #endif // ENABLE_DEBUGGER_SUPPORT | 848 #endif // ENABLE_DEBUGGER_SUPPORT |
827 | 849 |
828 #endif // V8_DEBUG_H_ | 850 #endif // V8_DEBUG_H_ |
OLD | NEW |