Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(174)

Unified Diff: src/debug/debug.cc

Issue 1539483002: [debugger] simplify stepping logic. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/debug/debug.h ('k') | src/debug/debug-scopes.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/debug/debug.cc
diff --git a/src/debug/debug.cc b/src/debug/debug.cc
index b212aad033eb50470073d6c4f4f21ca2cdcca1de..955f86618213482fcee80aa69fc321ddf69ef27a 100644
--- a/src/debug/debug.cc
+++ b/src/debug/debug.cc
@@ -145,9 +145,9 @@ void BreakLocation::Iterator::Next() {
// Find the break point at the supplied address, or the closest one before
// the address.
BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info,
- BreakLocatorType type, Address pc) {
- Iterator it(debug_info, type);
- it.SkipTo(BreakIndexFromAddress(debug_info, type, pc));
+ Address pc) {
+ Iterator it(debug_info, ALL_BREAK_LOCATIONS);
+ it.SkipTo(BreakIndexFromAddress(debug_info, pc));
return it.GetBreakLocation();
}
@@ -155,10 +155,10 @@ BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info,
// Find the break point at the supplied address, or the closest one before
// the address.
void BreakLocation::FromAddressSameStatement(Handle<DebugInfo> debug_info,
- BreakLocatorType type, Address pc,
+ Address pc,
List<BreakLocation>* result_out) {
- int break_index = BreakIndexFromAddress(debug_info, type, pc);
- Iterator it(debug_info, type);
+ int break_index = BreakIndexFromAddress(debug_info, pc);
+ Iterator it(debug_info, ALL_BREAK_LOCATIONS);
it.SkipTo(break_index);
int statement_position = it.statement_position();
while (!it.Done() && it.statement_position() == statement_position) {
@@ -169,11 +169,11 @@ void BreakLocation::FromAddressSameStatement(Handle<DebugInfo> debug_info,
int BreakLocation::BreakIndexFromAddress(Handle<DebugInfo> debug_info,
- BreakLocatorType type, Address pc) {
+ Address pc) {
// Run through all break points to locate the one closest to the address.
int closest_break = 0;
int distance = kMaxInt;
- for (Iterator it(debug_info, type); !it.Done(); it.Next()) {
+ for (Iterator it(debug_info, ALL_BREAK_LOCATIONS); !it.Done(); it.Next()) {
// Check if this break point is closer that what was previously found.
if (it.pc() <= pc && pc - it.pc() < distance) {
closest_break = it.break_index();
@@ -187,14 +187,14 @@ int BreakLocation::BreakIndexFromAddress(Handle<DebugInfo> debug_info,
BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info,
- BreakLocatorType type, int position,
+ int position,
BreakPositionAlignment alignment) {
// Run through all break points to locate the one closest to the source
// position.
int closest_break = 0;
int distance = kMaxInt;
- for (Iterator it(debug_info, type); !it.Done(); it.Next()) {
+ for (Iterator it(debug_info, ALL_BREAK_LOCATIONS); !it.Done(); it.Next()) {
int next_position;
if (alignment == STATEMENT_ALIGNED) {
next_position = it.statement_position();
@@ -210,7 +210,7 @@ BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info,
}
}
- Iterator it(debug_info, type);
+ Iterator it(debug_info, ALL_BREAK_LOCATIONS);
it.SkipTo(closest_break);
return it.GetBreakLocation();
}
@@ -327,9 +327,8 @@ void Debug::ThreadInit() {
thread_local_.break_frame_id_ = StackFrame::NO_ID;
thread_local_.last_step_action_ = StepNone;
thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
- thread_local_.step_count_ = 0;
thread_local_.last_fp_ = 0;
- thread_local_.step_out_fp_ = 0;
+ thread_local_.target_fp_ = 0;
thread_local_.step_in_enabled_ = false;
// TODO(isolates): frames_are_dropped_?
base::NoBarrier_Store(&thread_local_.current_debug_scope_,
@@ -419,7 +418,6 @@ void Debug::Unload() {
void Debug::Break(Arguments args, JavaScriptFrame* frame) {
- Heap* heap = isolate_->heap();
HandleScope scope(isolate_);
DCHECK(args.length() == 0);
@@ -445,61 +443,62 @@ void Debug::Break(Arguments args, JavaScriptFrame* frame) {
}
Handle<DebugInfo> debug_info(shared->GetDebugInfo());
- // Find the break point where execution has stopped.
+ // Find the break location where execution has stopped.
// PC points to the instruction after the current one, possibly a break
// location as well. So the "- 1" to exclude it from the search.
Address call_pc = frame->pc() - 1;
- BreakLocation break_location =
- BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc);
-
- // Check whether step next reached a new statement.
- if (!StepNextContinue(&break_location, frame)) {
- // Decrease steps left if performing multiple steps.
- if (thread_local_.step_count_ > 0) {
- thread_local_.step_count_--;
+ BreakLocation location = BreakLocation::FromAddress(debug_info, call_pc);
+
+ // Find actual break points, if any, and trigger debug break event.
+ if (break_points_active_ && location.HasBreakPoint()) {
+ Handle<Object> break_point_objects = location.BreakPointObjects();
+ Handle<Object> break_points_hit = CheckBreakPoints(break_point_objects);
+ if (!break_points_hit->IsUndefined()) {
+ // Clear all current stepping setup.
+ ClearStepping();
+ // Notify the debug event listeners.
+ OnDebugBreak(break_points_hit, false);
+ return;
}
}
- // If there is one or more real break points check whether any of these are
- // triggered.
- Handle<Object> break_points_hit(heap->undefined_value(), isolate_);
- if (break_points_active_ && break_location.HasBreakPoint()) {
- Handle<Object> break_point_objects = break_location.BreakPointObjects();
- break_points_hit = CheckBreakPoints(break_point_objects);
- }
-
- // 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 (StepOutActive() &&
- frame->fp() != thread_local_.step_out_fp_ &&
- break_points_hit->IsUndefined() ) {
- // Step count should always be 0 for StepOut.
- DCHECK(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();
- // Notify the debug event listeners.
- OnDebugBreak(break_points_hit, false);
- } else if (thread_local_.last_step_action_ != StepNone) {
- // Hold on to last step action as it is cleared by the call to
- // ClearStepping.
- StepAction step_action = thread_local_.last_step_action_;
- int step_count = thread_local_.step_count_;
+ // No break point. Check for stepping.
+ StepAction step_action = last_step_action();
+ Address current_fp = frame->UnpaddedFP();
+ Address target_fp = thread_local_.target_fp_;
+ Address last_fp = thread_local_.last_fp_;
- // If StepNext goes deeper into code, just return. The functions we need
- // to have flooded with one-shots are already flooded.
- if (step_action == StepNext && frame->fp() < thread_local_.last_fp_) return;
+ bool step_break = true;
+ switch (step_action) {
+ case StepNone:
+ return;
+ case StepOut:
+ // Step out has not reached the target frame yet.
+ if (current_fp < target_fp) return;
+ break;
+ case StepNext:
+ // Step next should not break in a deeper frame.
+ if (current_fp < target_fp) return;
+ // Fall through.
+ case StepIn:
+ step_break = location.IsReturn() || (current_fp != last_fp) ||
+ (thread_local_.last_statement_position_ !=
+ location.code()->SourceStatementPosition(frame->pc()));
+ break;
+ case StepFrame:
+ step_break = current_fp != last_fp;
+ break;
+ }
- // Clear all current stepping setup.
- ClearStepping();
+ // Clear all current stepping setup.
+ ClearStepping();
- // Set up for the remaining steps.
- PrepareStep(step_action, step_count);
+ if (step_break) {
+ // Notify the debug event listeners.
+ OnDebugBreak(isolate_->factory()->undefined_value(), false);
+ } else {
+ // Re-prepare to continue.
+ PrepareStep(step_action);
}
}
@@ -596,7 +595,7 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function,
// Find the break point and change it.
BreakLocation location = BreakLocation::FromPosition(
- debug_info, ALL_BREAK_LOCATIONS, *source_position, STATEMENT_ALIGNED);
+ debug_info, *source_position, STATEMENT_ALIGNED);
*source_position = location.statement_position();
location.SetBreakPoint(break_point_object);
@@ -639,8 +638,8 @@ bool Debug::SetBreakPointForScript(Handle<Script> script,
DCHECK(position >= 0);
// Find the break point and change it.
- BreakLocation location = BreakLocation::FromPosition(
- debug_info, ALL_BREAK_LOCATIONS, position, alignment);
+ BreakLocation location =
+ BreakLocation::FromPosition(debug_info, position, alignment);
location.SetBreakPoint(break_point_object);
feature_tracker()->Track(DebugFeatureTracker::kBreakPoint);
@@ -673,8 +672,7 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
Address pc =
debug_info->code()->entry() + break_point_info->code_position();
- BreakLocation location =
- BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, pc);
+ BreakLocation location = BreakLocation::FromAddress(debug_info, pc);
location.ClearBreakPoint(break_point_object);
// If there are no more break points left remove the debug info for this
@@ -762,11 +760,9 @@ FrameSummary GetFirstFrameSummary(JavaScriptFrame* frame) {
void Debug::PrepareStepIn(Handle<JSFunction> function) {
if (!is_active()) return;
- if (!IsStepping()) return;
if (last_step_action() < StepIn) return;
if (in_debug_scope()) return;
if (thread_local_.step_in_enabled_) {
- ClearStepOut();
FloodWithOneShot(function);
}
}
@@ -774,7 +770,6 @@ void Debug::PrepareStepIn(Handle<JSFunction> function) {
void Debug::PrepareStepOnThrow() {
if (!is_active()) return;
- if (!IsStepping()) return;
if (last_step_action() == StepNone) return;
if (in_debug_scope()) return;
@@ -801,7 +796,7 @@ void Debug::PrepareStepOnThrow() {
}
-void Debug::PrepareStep(StepAction step_action, int step_count) {
+void Debug::PrepareStep(StepAction step_action) {
HandleScope scope(isolate_);
DCHECK(in_debug_scope());
@@ -823,13 +818,6 @@ void Debug::PrepareStep(StepAction step_action, int step_count) {
thread_local_.last_step_action_ = step_action;
STATIC_ASSERT(StepFrame > StepIn);
thread_local_.step_in_enabled_ = (step_action >= StepIn);
- 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;
- }
// If the function on the top frame is unresolved perform step out. This will
// be the case when calling unknown function and having the debugger stopped
@@ -860,98 +848,57 @@ void Debug::PrepareStep(StepAction step_action, int step_count) {
// PC points to the instruction after the current one, possibly a break
// location as well. So the "- 1" to exclude it from the search.
Address call_pc = summary.pc() - 1;
- BreakLocation location =
- BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc);
+ BreakLocation location = BreakLocation::FromAddress(debug_info, call_pc);
- // If this is the last break code target step out is the only possibility.
- if (location.IsReturn() || 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 {
- DCHECK(location.IsReturn());
- frames_it.Advance();
- }
- // Skip native and extension functions on the stack.
- while (!frames_it.done() &&
- !frames_it.frame()->function()->shared()->IsSubjectToDebugging()) {
- if (step_action >= StepIn) {
- // Builtin functions are not subject to stepping, but need to be
- // deoptimized, because optimized code does not check for debug
- // step in at call sites.
- Deoptimizer::DeoptimizeFunction(frames_it.frame()->function());
- }
- frames_it.Advance();
- }
- // Step out: If there is a JavaScript caller frame, we need to
- // flood it with breakpoints.
- if (!frames_it.done()) {
- // Fill the function to return to with one-shot break points.
- JSFunction* function = frames_it.frame()->function();
- FloodWithOneShot(Handle<JSFunction>(function));
- // Set target frame pointer.
- ActivateStepOut(frames_it.frame());
- } else {
- // Stepping out to the embedder. Disable step-in to avoid stepping into
- // the next (unrelated) call that the embedder makes.
- thread_local_.step_in_enabled_ = false;
- }
- return;
- }
+ // At a return statement we will step out either way.
+ if (location.IsReturn()) step_action = StepOut;
- // Fill the current function with one-shot break points even for step in on
- // a call target as the function called might be a native function for
- // which step in will not stop. It also prepares for stepping in
- // getters/setters.
- // If we are stepping into another frame, only fill calls and returns.
- FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS
- : ALL_BREAK_LOCATIONS);
-
- // Remember source position and frame to handle step next.
thread_local_.last_statement_position_ =
debug_info->code()->SourceStatementPosition(summary.pc());
thread_local_.last_fp_ = frame->UnpaddedFP();
-}
-
-
-// Check whether the current debug break should be reported to the debugger. It
-// is used to have step next and step in only report break back to the debugger
-// if on a different frame or in a different statement. In some situations
-// there will be several break points in the same statement when the code is
-// flooded with one-shot break points. This function helps to perform several
-// steps before reporting break back to the debugger.
-bool Debug::StepNextContinue(BreakLocation* break_location,
- JavaScriptFrame* frame) {
- // StepNext and StepOut shouldn't bring us deeper in code, so last frame
- // shouldn't be a parent of current frame.
- StepAction step_action = thread_local_.last_step_action_;
-
- if (step_action == StepNext || step_action == StepOut) {
- if (frame->fp() < thread_local_.last_fp_) return true;
- }
-
- // We stepped into a new frame if the frame pointer changed.
- if (step_action == StepFrame) {
- return frame->UnpaddedFP() == thread_local_.last_fp_;
- }
-
- // If the step last action was step next or step in make sure that a new
- // statement is hit.
- if (step_action == StepNext || step_action == StepIn) {
- // Never continue if returning from function.
- if (break_location->IsReturn()) return false;
- // Continue if we are still on the same frame and in the same statement.
- int current_statement_position =
- break_location->code()->SourceStatementPosition(frame->pc());
- return thread_local_.last_fp_ == frame->UnpaddedFP() &&
- thread_local_.last_statement_position_ == current_statement_position;
+ switch (step_action) {
+ case StepNone:
+ UNREACHABLE();
+ break;
+ case StepOut:
+ // Advance to caller frame.
+ frames_it.Advance();
+ // Skip native and extension functions on the stack.
+ while (!frames_it.done() &&
+ !frames_it.frame()->function()->shared()->IsSubjectToDebugging()) {
+ // Builtin functions are not subject to stepping, but need to be
+ // deoptimized to include checks for step-in at call sites.
+ Deoptimizer::DeoptimizeFunction(frames_it.frame()->function());
+ frames_it.Advance();
+ }
+ if (frames_it.done()) {
+ // Stepping out to the embedder. Disable step-in to avoid stepping into
+ // the next (unrelated) call that the embedder makes.
+ thread_local_.step_in_enabled_ = false;
+ } else {
+ // Fill the caller function to return to with one-shot break points.
+ Handle<JSFunction> caller_function(frames_it.frame()->function());
+ FloodWithOneShot(caller_function);
+ thread_local_.target_fp_ = frames_it.frame()->UnpaddedFP();
+ }
+ // Clear last position info. For stepping out it does not matter.
+ thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
+ thread_local_.last_fp_ = 0;
+ break;
+ case StepNext:
+ thread_local_.target_fp_ = frame->UnpaddedFP();
+ FloodWithOneShot(function);
+ break;
+ case StepIn:
+ FloodWithOneShot(function);
+ break;
+ case StepFrame:
+ // No point in setting one-shot breaks at places where we are not about
+ // to leave the current frame.
+ FloodWithOneShot(function, CALLS_AND_RETURNS);
+ break;
}
-
- // No step next action - don't continue.
- return false;
}
@@ -996,13 +943,12 @@ Handle<Object> Debug::GetSourceBreakLocations(
void Debug::ClearStepping() {
// Clear the various stepping setup.
ClearOneShot();
- ClearStepOut();
- thread_local_.step_count_ = 0;
thread_local_.last_step_action_ = StepNone;
thread_local_.step_in_enabled_ = false;
thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
thread_local_.last_fp_ = 0;
+ thread_local_.target_fp_ = 0;
}
@@ -1023,20 +969,12 @@ void Debug::ClearOneShot() {
}
-void Debug::ActivateStepOut(StackFrame* frame) {
- thread_local_.step_out_fp_ = frame->UnpaddedFP();
-}
-
-
void Debug::EnableStepIn() {
STATIC_ASSERT(StepFrame > StepIn);
thread_local_.step_in_enabled_ = (last_step_action() >= StepIn);
}
-void Debug::ClearStepOut() { thread_local_.step_out_fp_ = 0; }
-
-
bool MatchingCodeTargets(Code* target1, Code* target2) {
if (target1 == target2) return true;
if (target1->kind() != target2->kind()) return false;
@@ -1533,8 +1471,7 @@ void Debug::GetStepinPositions(JavaScriptFrame* frame, StackFrame::Id frame_id,
// has stopped.
Address call_pc = summary.pc() - 1;
List<BreakLocation> locations;
- BreakLocation::FromAddressSameStatement(debug_info, ALL_BREAK_LOCATIONS,
- call_pc, &locations);
+ BreakLocation::FromAddressSameStatement(debug_info, call_pc, &locations);
for (BreakLocation location : locations) {
if (location.pc() <= summary.pc()) {
« no previous file with comments | « src/debug/debug.h ('k') | src/debug/debug-scopes.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698