Index: src/debug.cc |
=================================================================== |
--- src/debug.cc (revision 2839) |
+++ src/debug.cc (working copy) |
@@ -518,6 +518,7 @@ |
thread_local_.step_count_ = 0; |
thread_local_.last_fp_ = 0; |
thread_local_.step_into_fp_ = 0; |
+ thread_local_.step_out_fp_ = 0; |
thread_local_.after_break_target_ = 0; |
thread_local_.debugger_entry_ = NULL; |
thread_local_.pending_interrupts_ = 0; |
@@ -864,11 +865,18 @@ |
break_points_hit = CheckBreakPoints(break_point_objects); |
} |
- // Notify debugger if a real break point is triggered or if performing single |
- // stepping with no more steps to perform. Otherwise do another step. |
- if (!break_points_hit->IsUndefined() || |
- (thread_local_.last_step_action_ != StepNone && |
- thread_local_.step_count_ == 0)) { |
+ // If step out is active skip everything until the frame where we need to step |
+ // out to is reached, unless real breakpoint is hit. |
+ if (Debug::StepOutActive() && frame->fp() != Debug::step_out_fp() && |
+ break_points_hit->IsUndefined() ) { |
+ // Step count should always be 0 for StepOut. |
+ ASSERT(thread_local_.step_count_ == 0); |
+ } else if (!break_points_hit->IsUndefined() || |
+ (thread_local_.last_step_action_ != StepNone && |
+ thread_local_.step_count_ == 0)) { |
+ // Notify debugger if a real break point is triggered or if performing |
+ // single stepping with no more steps to perform. Otherwise do another step. |
+ |
// Clear all current stepping setup. |
ClearStepping(); |
@@ -1104,7 +1112,13 @@ |
// Remember this step action and count. |
thread_local_.last_step_action_ = step_action; |
- thread_local_.step_count_ = step_count; |
+ if (step_action == StepOut) { |
+ // For step out target frame will be found on the stack so there is no need |
+ // to set step counter for it. It's expected to always be 0 for StepOut. |
+ thread_local_.step_count_ = 0; |
+ } else { |
+ thread_local_.step_count_ = step_count; |
+ } |
// Get the frame where the execution has stopped and skip the debug frame if |
// any. The debug frame will only be present if execution was stopped due to |
@@ -1183,13 +1197,28 @@ |
// If this is the last break code target step out is the only possibility. |
if (it.IsExit() || step_action == StepOut) { |
+ if (step_action == StepOut) { |
+ // Skip step_count frames starting with the current one. |
+ while(step_count-- > 0 && !frames_it.done()) { |
+ frames_it.Advance(); |
+ } |
+ } else { |
+ ASSERT(it.IsExit()); |
+ frames_it.Advance(); |
+ } |
+ // Skip builtin functions on the stack. |
+ while(!frames_it.done() && |
+ JSFunction::cast(frames_it.frame()->function())->IsBuiltin()) { |
+ frames_it.Advance(); |
+ } |
// Step out: If there is a JavaScript caller frame, we need to |
// flood it with breakpoints. |
- frames_it.Advance(); |
if (!frames_it.done()) { |
// Fill the function to return to with one-shot break points. |
JSFunction* function = JSFunction::cast(frames_it.frame()->function()); |
FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared())); |
+ // Set target frame pointer. |
+ ActivateStepOut(frames_it.frame()); |
} |
} else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) || |
!call_function_stub.is_null()) |
@@ -1445,6 +1474,7 @@ |
// Clear the various stepping setup. |
ClearOneShot(); |
ClearStepIn(); |
+ ClearStepOut(); |
ClearStepNext(); |
// Clear multiple step counter. |
@@ -1472,6 +1502,7 @@ |
void Debug::ActivateStepIn(StackFrame* frame) { |
+ ASSERT(!StepOutActive()); |
thread_local_.step_into_fp_ = frame->fp(); |
} |
@@ -1481,6 +1512,17 @@ |
} |
+void Debug::ActivateStepOut(StackFrame* frame) { |
+ ASSERT(!StepInActive()); |
+ thread_local_.step_out_fp_ = frame->fp(); |
+} |
+ |
+ |
+void Debug::ClearStepOut() { |
+ thread_local_.step_out_fp_ = 0; |
+} |
+ |
+ |
void Debug::ClearStepNext() { |
thread_local_.last_step_action_ = StepNone; |
thread_local_.last_statement_position_ = RelocInfo::kNoPosition; |