Index: src/debug.h |
=================================================================== |
--- src/debug.h (revision 1435) |
+++ src/debug.h (working copy) |
@@ -36,10 +36,16 @@ |
#include "factory.h" |
#include "platform.h" |
#include "string-stream.h" |
+#include "v8threads.h" |
namespace v8 { namespace internal { |
+ |
+// Forward declarations. |
+class EnterDebugger; |
+ |
+ |
// Step actions. NOTE: These values are in macros.py as well. |
enum StepAction { |
StepNone = -1, // Stepping not prepared. |
@@ -166,7 +172,8 @@ |
static bool Load(); |
static void Unload(); |
static bool IsLoaded() { return !debug_context_.is_null(); } |
- static bool InDebugger() { return Top::is_break(); } |
+ static bool InDebugger() { return thread_local_.debugger_entry_ != NULL; } |
+ static void PreemptionWhileInDebugger(); |
static void Iterate(ObjectVisitor* v); |
static Object* Break(Arguments args); |
@@ -211,6 +218,16 @@ |
// Fast check to see if any break points are active. |
inline static bool has_break_points() { return has_break_points_; } |
+ static void NewBreak(StackFrame::Id break_frame_id); |
+ static void SetBreak(StackFrame::Id break_frame_id, int break_id); |
+ static StackFrame::Id break_frame_id() { |
+ return thread_local_.break_frame_id_; |
+ } |
+ static int break_id() { return thread_local_.break_id_; } |
+ |
+ |
+ |
+ |
static bool StepInActive() { return thread_local_.step_into_fp_ != 0; } |
static void HandleStepIn(Handle<JSFunction> function, |
Address fp, |
@@ -218,6 +235,20 @@ |
static Address step_in_fp() { return thread_local_.step_into_fp_; } |
static Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; } |
+ static EnterDebugger* debugger_entry() { |
+ return thread_local_.debugger_entry_; |
+ } |
+ static void set_debugger_entry(EnterDebugger* entry) { |
+ thread_local_.debugger_entry_ = entry; |
+ } |
+ |
+ static bool preemption_pending() { |
+ return thread_local_.preemption_pending_; |
+ } |
+ static void set_preemption_pending(bool preemption_pending) { |
+ thread_local_.preemption_pending_ = preemption_pending; |
+ } |
+ |
// Getter and setter for the disable break state. |
static bool disable_break() { return disable_break_; } |
static void set_disable_break(bool disable_break) { |
@@ -313,9 +344,18 @@ |
static bool break_on_exception_; |
static bool break_on_uncaught_exception_; |
- // Per-thread: |
+ // Per-thread data. |
class ThreadLocal { |
public: |
+ // Counter for generating next break id. |
+ int break_count_; |
+ |
+ // Current break id. |
+ int break_id_; |
+ |
+ // Frame id for the frame of the current break. |
+ StackFrame::Id break_frame_id_; |
+ |
// Step action for last step performed. |
StepAction last_step_action_; |
@@ -333,6 +373,12 @@ |
// Storage location for jump when exiting debug break calls. |
Address after_break_target_; |
+ |
+ // Top debugger entry. |
+ EnterDebugger* debugger_entry_; |
+ |
+ // Preemption happened while debugging. |
+ bool preemption_pending_; |
}; |
// Storage location for registers when handling debug break calls |
@@ -519,17 +565,34 @@ |
// some reason could not be entered FailedToEnter will return true. |
class EnterDebugger BASE_EMBEDDED { |
public: |
- EnterDebugger() : has_js_frames_(!it_.done()) { |
+ EnterDebugger() |
+ : prev_(Debug::debugger_entry()), |
+ has_js_frames_(!it_.done()) { |
+ ASSERT(!Debug::preemption_pending()); |
+ |
+ // Link recursive debugger entry. |
+ Debug::set_debugger_entry(this); |
+ |
+ // If a preemption is pending when first entering the debugger clear it as |
+ // we don't want preemption happening while executing JavaScript in the |
+ // debugger. When recursively entering the debugger the preemption flag |
+ // cannot be set as this is disabled while in the debugger (see |
+ // RuntimePreempt). |
+ if (prev_ == NULL && StackGuard::IsPreempted()) { |
+ StackGuard::Continue(PREEMPT); |
+ } |
+ ASSERT(!StackGuard::IsPreempted()); |
+ |
// Store the previous break id and frame id. |
- break_id_ = Top::break_id(); |
- break_frame_id_ = Top::break_frame_id(); |
+ break_id_ = Debug::break_id(); |
+ break_frame_id_ = Debug::break_frame_id(); |
// Create the new break info. If there is no JavaScript frames there is no |
// break frame id. |
if (has_js_frames_) { |
- Top::new_break(it_.frame()->id()); |
+ Debug::NewBreak(it_.frame()->id()); |
} else { |
- Top::new_break(StackFrame::NO_ID); |
+ Debug::NewBreak(StackFrame::NO_ID); |
} |
// Make sure that debugger is loaded and enter the debugger context. |
@@ -543,7 +606,18 @@ |
~EnterDebugger() { |
// Restore to the previous break state. |
- Top::set_break(break_frame_id_, break_id_); |
+ Debug::SetBreak(break_frame_id_, break_id_); |
+ |
+ // Request preemption when leaving the last debugger entry and a preemption |
+ // had been recorded while debugging. This is to avoid starvation in some |
+ // debugging scenarios. |
+ if (prev_ == NULL && Debug::preemption_pending()) { |
+ StackGuard::Preempt(); |
+ Debug::set_preemption_pending(false); |
+ } |
+ |
+ // Leaving this debugger entry. |
+ Debug::set_debugger_entry(prev_); |
} |
// Check whether the debugger could be entered. |
@@ -553,6 +627,7 @@ |
inline bool HasJavaScriptFrames() { return has_js_frames_; } |
private: |
+ EnterDebugger* prev_; // Previous debugger entry if entered recursively. |
JavaScriptFrameIterator it_; |
const bool has_js_frames_; // Were there any JavaScript frames? |
StackFrame::Id break_frame_id_; // Previous break frame id. |