| 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();
|
| }
|
|
|
|
|
|
|