Index: src/debug/debug.cc |
diff --git a/src/debug/debug.cc b/src/debug/debug.cc |
index 3a6e0ac0de86cc3ae4d9929eb8323da7bc9aa495..7c76742bb973cb3fa6fc605ea1fe4316ad608fde 100644 |
--- a/src/debug/debug.cc |
+++ b/src/debug/debug.cc |
@@ -108,6 +108,9 @@ int BreakLocation::CodeIterator::GetModeMask(BreakLocatorType type) { |
mask |= RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION); |
mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN); |
mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_CALL); |
+ if (isolate()->is_tail_call_elimination_enabled()) { |
+ mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL); |
+ } |
if (type == ALL_BREAK_LOCATIONS) { |
mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION); |
mask |= RelocInfo::ModeMask(RelocInfo::DEBUGGER_STATEMENT); |
@@ -161,6 +164,10 @@ BreakLocation BreakLocation::CodeIterator::GetBreakLocation() { |
type = DEBUG_BREAK_SLOT_AT_RETURN; |
} else if (RelocInfo::IsDebugBreakSlotAtCall(rmode())) { |
type = DEBUG_BREAK_SLOT_AT_CALL; |
+ } else if (RelocInfo::IsDebugBreakSlotAtTailCall(rmode())) { |
+ type = isolate()->is_tail_call_elimination_enabled() |
+ ? DEBUG_BREAK_SLOT_AT_TAIL_CALL |
+ : DEBUG_BREAK_SLOT_AT_CALL; |
} else if (RelocInfo::IsDebuggerStatement(rmode())) { |
type = DEBUGGER_STATEMENT; |
} else if (RelocInfo::IsDebugBreakSlot(rmode())) { |
@@ -226,6 +233,10 @@ BreakLocation::BytecodeArrayIterator::GetDebugBreakType() { |
return DEBUGGER_STATEMENT; |
} else if (bytecode == interpreter::Bytecode::kReturn) { |
return DEBUG_BREAK_SLOT_AT_RETURN; |
+ } else if (bytecode == interpreter::Bytecode::kTailCall) { |
+ return isolate()->is_tail_call_elimination_enabled() |
+ ? DEBUG_BREAK_SLOT_AT_TAIL_CALL |
+ : DEBUG_BREAK_SLOT_AT_CALL; |
} else if (interpreter::Bytecodes::IsCallOrNew(bytecode)) { |
return DEBUG_BREAK_SLOT_AT_CALL; |
} else if (source_position_iterator_.is_statement()) { |
@@ -604,22 +615,26 @@ void Debug::Break(JavaScriptFrame* frame) { |
Address target_fp = thread_local_.target_fp_; |
Address last_fp = thread_local_.last_fp_; |
- bool step_break = true; |
+ bool step_break = false; |
switch (step_action) { |
case StepNone: |
return; |
case StepOut: |
// Step out has not reached the target frame yet. |
if (current_fp < target_fp) return; |
+ step_break = true; |
break; |
case StepNext: |
// Step next should not break in a deeper frame. |
if (current_fp < target_fp) return; |
+ // For step-next, a tail call is like a return and should break. |
+ step_break = location.IsTailCall(); |
// Fall through. |
case StepIn: { |
FrameSummary summary = GetFirstFrameSummary(frame); |
int offset = summary.code_offset(); |
- step_break = location.IsReturn() || (current_fp != last_fp) || |
+ step_break = step_break || location.IsReturn() || |
+ (current_fp != last_fp) || |
(thread_local_.last_statement_position_ != |
location.abstract_code()->SourceStatementPosition(offset)); |
break; |
@@ -1015,8 +1030,10 @@ void Debug::PrepareStep(StepAction step_action) { |
BreakLocation location = |
BreakLocation::FromCodeOffset(debug_info, call_offset); |
- // At a return statement we will step out either way. |
+ // Any step at a return is a step-out. |
if (location.IsReturn()) step_action = StepOut; |
+ // A step-next at a tail call is a step-out. |
+ if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; |
thread_local_.last_statement_position_ = |
debug_info->abstract_code()->SourceStatementPosition( |
@@ -1592,7 +1609,7 @@ bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { |
Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
BreakLocation location = |
BreakLocation::FromCodeOffset(debug_info, summary.code_offset()); |
- return location.IsReturn(); |
+ return location.IsReturn() || location.IsTailCall(); |
} |