diff --git a/src/builtins/arm/builtins-arm.cc b/src/builtins/arm/builtins-arm.cc index f535ae785a..69339b86b0 100644 --- a/src/builtins/arm/builtins-arm.cc +++ b/src/builtins/arm/builtins-arm.cc @@ -1296,7 +1296,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray( } } -void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { +static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) { // Set the return address to the correct point in the interpreter entry // trampoline. Smi* interpreter_entry_return_pc_offset( @@ -1337,6 +1337,29 @@ void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { __ mov(pc, ip); } +void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) { + // Advance the current bytecode offset stored within the given interpreter + // stack frame. This simulates what all bytecode handlers do upon completion + // of the underlying operation. + __ ldr(r1, MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp)); + __ ldr(r2, MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); + __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ Push(kInterpreterAccumulatorRegister, r1, r2); + __ CallRuntime(Runtime::kInterpreterAdvanceBytecodeOffset); + __ mov(r2, r0); // Result is the new bytecode offset. + __ Pop(kInterpreterAccumulatorRegister); + } + __ str(r2, MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); + + Generate_InterpreterEnterBytecode(masm); +} + +void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { + Generate_InterpreterEnterBytecode(masm); +} + void Builtins::Generate_CompileLazy(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0 : argument count (preserved for callee) diff --git a/src/builtins/arm64/builtins-arm64.cc b/src/builtins/arm64/builtins-arm64.cc index 7327be2fc4..aeb0508a20 100644 --- a/src/builtins/arm64/builtins-arm64.cc +++ b/src/builtins/arm64/builtins-arm64.cc @@ -1306,7 +1306,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray( } } -void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { +static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) { // Set the return address to the correct point in the interpreter entry // trampoline. Smi* interpreter_entry_return_pc_offset( @@ -1347,6 +1347,29 @@ void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { __ Jump(ip0); } +void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) { + // Advance the current bytecode offset stored within the given interpreter + // stack frame. This simulates what all bytecode handlers do upon completion + // of the underlying operation. + __ Ldr(x1, MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp)); + __ Ldr(x2, MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); + __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ Push(kInterpreterAccumulatorRegister, x1, x2); + __ CallRuntime(Runtime::kInterpreterAdvanceBytecodeOffset); + __ Mov(x2, x0); // Result is the new bytecode offset. + __ Pop(kInterpreterAccumulatorRegister); + } + __ Str(x2, MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); + + Generate_InterpreterEnterBytecode(masm); +} + +void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { + Generate_InterpreterEnterBytecode(masm); +} + void Builtins::Generate_CompileLazy(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- x0 : argument count (preserved for callee) diff --git a/src/builtins/builtins.h b/src/builtins/builtins.h index cb62e4f62a..0e27e21eea 100644 --- a/src/builtins/builtins.h +++ b/src/builtins/builtins.h @@ -116,6 +116,7 @@ namespace internal { ASM(InterpreterPushArgsAndConstruct) \ ASM(InterpreterPushArgsAndConstructFunction) \ ASM(InterpreterPushArgsAndConstructArray) \ + ASM(InterpreterEnterBytecodeAdvance) \ ASM(InterpreterEnterBytecodeDispatch) \ ASM(InterpreterOnStackReplacement) \ \ diff --git a/src/builtins/ia32/builtins-ia32.cc b/src/builtins/ia32/builtins-ia32.cc index 1ae8cffad3..4287333d3f 100644 --- a/src/builtins/ia32/builtins-ia32.cc +++ b/src/builtins/ia32/builtins-ia32.cc @@ -980,7 +980,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray( } } -void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { +static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) { // Set the return address to the correct point in the interpreter entry // trampoline. Smi* interpreter_entry_return_pc_offset( @@ -1022,6 +1022,31 @@ void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { __ jmp(ebx); } +void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) { + // Advance the current bytecode offset stored within the given interpreter + // stack frame. This simulates what all bytecode handlers do upon completion + // of the underlying operation. + __ mov(ebx, Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp)); + __ mov(edx, Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ Push(kInterpreterAccumulatorRegister); + __ Push(ebx); // First argument is the bytecode array. + __ Push(edx); // Second argument is the bytecode offset. + __ CallRuntime(Runtime::kInterpreterAdvanceBytecodeOffset); + __ Move(edx, eax); // Result is the new bytecode offset. + __ Pop(kInterpreterAccumulatorRegister); + } + __ mov(Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp), edx); + + Generate_InterpreterEnterBytecode(masm); +} + +void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { + Generate_InterpreterEnterBytecode(masm); +} + void Builtins::Generate_CompileLazy(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- eax : argument count (preserved for callee) diff --git a/src/builtins/mips/builtins-mips.cc b/src/builtins/mips/builtins-mips.cc index b686b476d2..b9c4a72dd0 100644 --- a/src/builtins/mips/builtins-mips.cc +++ b/src/builtins/mips/builtins-mips.cc @@ -1296,7 +1296,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray( } } -void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { +static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) { // Set the return address to the correct point in the interpreter entry // trampoline. Smi* interpreter_entry_return_pc_offset( @@ -1339,6 +1339,29 @@ void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { __ Jump(a1); } +void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) { + // Advance the current bytecode offset stored within the given interpreter + // stack frame. This simulates what all bytecode handlers do upon completion + // of the underlying operation. + __ lw(a1, MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp)); + __ lw(a2, MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); + __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ Push(kInterpreterAccumulatorRegister, a1, a2); + __ CallRuntime(Runtime::kInterpreterAdvanceBytecodeOffset); + __ mov(a2, v0); // Result is the new bytecode offset. + __ Pop(kInterpreterAccumulatorRegister); + } + __ sw(a2, MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); + + Generate_InterpreterEnterBytecode(masm); +} + +void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { + Generate_InterpreterEnterBytecode(masm); +} + void Builtins::Generate_CompileLazy(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- a0 : argument count (preserved for callee) diff --git a/src/builtins/mips64/builtins-mips64.cc b/src/builtins/mips64/builtins-mips64.cc index dcd1d40dec..a6abb55c46 100644 --- a/src/builtins/mips64/builtins-mips64.cc +++ b/src/builtins/mips64/builtins-mips64.cc @@ -1288,7 +1288,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray( } } -void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { +static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) { // Set the return address to the correct point in the interpreter entry // trampoline. Smi* interpreter_entry_return_pc_offset( @@ -1331,6 +1331,29 @@ void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { __ Jump(a1); } +void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) { + // Advance the current bytecode offset stored within the given interpreter + // stack frame. This simulates what all bytecode handlers do upon completion + // of the underlying operation. + __ ld(a1, MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp)); + __ ld(a2, MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); + __ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ Push(kInterpreterAccumulatorRegister, a1, a2); + __ CallRuntime(Runtime::kInterpreterAdvanceBytecodeOffset); + __ mov(a2, v0); // Result is the new bytecode offset. + __ Pop(kInterpreterAccumulatorRegister); + } + __ sd(a2, MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); + + Generate_InterpreterEnterBytecode(masm); +} + +void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { + Generate_InterpreterEnterBytecode(masm); +} + void Builtins::Generate_CompileLazy(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- a0 : argument count (preserved for callee) diff --git a/src/builtins/x64/builtins-x64.cc b/src/builtins/x64/builtins-x64.cc index f4367871b7..cde02647ac 100644 --- a/src/builtins/x64/builtins-x64.cc +++ b/src/builtins/x64/builtins-x64.cc @@ -956,7 +956,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray( } } -void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { +static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) { // Set the return address to the correct point in the interpreter entry // trampoline. Smi* interpreter_entry_return_pc_offset( @@ -998,6 +998,31 @@ void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { __ jmp(rbx); } +void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) { + // Advance the current bytecode offset stored within the given interpreter + // stack frame. This simulates what all bytecode handlers do upon completion + // of the underlying operation. + __ movp(rbx, Operand(rbp, InterpreterFrameConstants::kBytecodeArrayFromFp)); + __ movp(rdx, Operand(rbp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); + __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); + { + FrameScope scope(masm, StackFrame::INTERNAL); + __ Push(kInterpreterAccumulatorRegister); + __ Push(rbx); // First argument is the bytecode array. + __ Push(rdx); // Second argument is the bytecode offset. + __ CallRuntime(Runtime::kInterpreterAdvanceBytecodeOffset); + __ Move(rdx, rax); // Result is the new bytecode offset. + __ Pop(kInterpreterAccumulatorRegister); + } + __ movp(Operand(rbp, InterpreterFrameConstants::kBytecodeOffsetFromFp), rdx); + + Generate_InterpreterEnterBytecode(masm); +} + +void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { + Generate_InterpreterEnterBytecode(masm); +} + void Builtins::Generate_CompileLazy(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- rax : argument count (preserved for callee) diff --git a/src/compiler/bytecode-graph-builder.cc b/src/compiler/bytecode-graph-builder.cc index 2c8c095da5..e76b541800 100644 --- a/src/compiler/bytecode-graph-builder.cc +++ b/src/compiler/bytecode-graph-builder.cc @@ -603,9 +603,9 @@ void BytecodeGraphBuilder::PrepareEagerCheckpoint() { DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); DCHECK_EQ(IrOpcode::kDead, NodeProperties::GetFrameStateInput(node)->opcode()); - BailoutId bailout_id_before(bytecode_iterator().current_offset()); + BailoutId bailout_id(bytecode_iterator().current_offset()); Node* frame_state_before = environment()->Checkpoint( - bailout_id_before, OutputFrameStateCombine::Ignore(), false); + bailout_id, OutputFrameStateCombine::Ignore(), false); NodeProperties::ReplaceFrameStateInput(node, frame_state_before); } } @@ -618,11 +618,10 @@ void BytecodeGraphBuilder::PrepareFrameState(Node* node, DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); DCHECK_EQ(IrOpcode::kDead, NodeProperties::GetFrameStateInput(node)->opcode()); - BailoutId bailout_id_after(bytecode_iterator().current_offset() + - bytecode_iterator().current_bytecode_size()); + BailoutId bailout_id(bytecode_iterator().current_offset()); bool has_exception = NodeProperties::IsExceptionalCall(node); Node* frame_state_after = - environment()->Checkpoint(bailout_id_after, combine, has_exception); + environment()->Checkpoint(bailout_id, combine, has_exception); NodeProperties::ReplaceFrameStateInput(node, frame_state_after); } } diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc index 2b32804f9f..d029fd4ff8 100644 --- a/src/deoptimizer.cc +++ b/src/deoptimizer.cc @@ -1001,7 +1001,7 @@ void Deoptimizer::DoComputeJSFrame(TranslatedFrame* translated_frame, } } - // Compute this frame's PC, state, and continuation. + // Compute this frame's PC and state. FixedArray* raw_data = non_optimized_code->deoptimization_data(); DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data); Address start = non_optimized_code->instruction_start(); @@ -1243,7 +1243,7 @@ void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame, // Translate the accumulator register (depending on frame position). if (is_topmost) { - // For topmost frmae, p ut the accumulator on the stack. The bailout state + // For topmost frame, put the accumulator on the stack. The bailout state // for interpreted frames is always set to {BailoutState::TOS_REGISTER} and // the {NotifyDeoptimized} builtin pops it off the topmost frame (possibly // after materialization). @@ -1268,9 +1268,15 @@ void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame, } CHECK_EQ(0u, output_offset); + // Compute this frame's PC and state. The PC will be a special builtin that + // continues the bytecode dispatch. Note that non-topmost and lazy-style + // bailout handlers also advance the bytecode offset before dispatch, hence + // simulating what normal handlers do upon completion of the operation. Builtins* builtins = isolate_->builtins(); Code* dispatch_builtin = - builtins->builtin(Builtins::kInterpreterEnterBytecodeDispatch); + (!is_topmost || (bailout_type_ == LAZY)) && !goto_catch_handler + ? builtins->builtin(Builtins::kInterpreterEnterBytecodeAdvance) + : builtins->builtin(Builtins::kInterpreterEnterBytecodeDispatch); output_frame->SetPc(reinterpret_cast(dispatch_builtin->entry())); // Restore accumulator (TOS) register. output_frame->SetState( @@ -2758,11 +2764,8 @@ int Deoptimizer::ComputeSourcePositionFromBaselineCode( int Deoptimizer::ComputeSourcePositionFromBytecodeArray( SharedFunctionInfo* shared, BailoutId node_id) { DCHECK(shared->HasBytecodeArray()); - // BailoutId points to the next bytecode in the bytecode aray. Subtract - // 1 to get the end of current bytecode. - int code_offset = node_id.ToInt() - 1; return AbstractCode::cast(shared->bytecode_array()) - ->SourcePosition(code_offset); + ->SourcePosition(node_id.ToInt()); } // static diff --git a/src/frames.cc b/src/frames.cc index 3df2763232..7190478991 100644 --- a/src/frames.cc +++ b/src/frames.cc @@ -404,11 +404,15 @@ void StackFrame::SetReturnAddressLocationResolver( static bool IsInterpreterFramePc(Isolate* isolate, Address pc) { Code* interpreter_entry_trampoline = isolate->builtins()->builtin(Builtins::kInterpreterEntryTrampoline); + Code* interpreter_bytecode_advance = + isolate->builtins()->builtin(Builtins::kInterpreterEnterBytecodeAdvance); Code* interpreter_bytecode_dispatch = isolate->builtins()->builtin(Builtins::kInterpreterEnterBytecodeDispatch); return (pc >= interpreter_entry_trampoline->instruction_start() && pc < interpreter_entry_trampoline->instruction_end()) || + (pc >= interpreter_bytecode_advance->instruction_start() && + pc < interpreter_bytecode_advance->instruction_end()) || (pc >= interpreter_bytecode_dispatch->instruction_start() && pc < interpreter_bytecode_dispatch->instruction_end()); } @@ -1219,9 +1223,7 @@ void OptimizedFrame::Summarize(List* frames, abstract_code = AbstractCode::cast(code); } else { DCHECK_EQ(frame_opcode, Translation::INTERPRETED_FRAME); - // BailoutId points to the next bytecode in the bytecode aray. Subtract - // 1 to get the end of current bytecode. - code_offset = bailout_id.ToInt() - 1; + code_offset = bailout_id.ToInt(); // Points to current bytecode. abstract_code = AbstractCode::cast(shared_info->bytecode_array()); } FrameSummary summary(receiver, function, abstract_code, code_offset, diff --git a/src/objects-inl.h b/src/objects-inl.h index 8a1433767c..016b3b0e0d 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -5055,6 +5055,7 @@ inline bool Code::is_hydrogen_stub() { inline bool Code::is_interpreter_trampoline_builtin() { Builtins* builtins = GetIsolate()->builtins(); return this == *builtins->InterpreterEntryTrampoline() || + this == *builtins->InterpreterEnterBytecodeAdvance() || this == *builtins->InterpreterEnterBytecodeDispatch(); } diff --git a/src/runtime/runtime-interpreter.cc b/src/runtime/runtime-interpreter.cc index ce71e2c52d..62eee1744f 100644 --- a/src/runtime/runtime-interpreter.cc +++ b/src/runtime/runtime-interpreter.cc @@ -171,5 +171,19 @@ RUNTIME_FUNCTION(Runtime_InterpreterSetPendingMessage) { return isolate->heap()->undefined_value(); } +RUNTIME_FUNCTION(Runtime_InterpreterAdvanceBytecodeOffset) { + SealHandleScope shs(isolate); + DCHECK_EQ(2, args.length()); + CONVERT_ARG_HANDLE_CHECKED(BytecodeArray, bytecode_array, 0); + CONVERT_SMI_ARG_CHECKED(bytecode_offset, 1); + interpreter::BytecodeArrayIterator it(bytecode_array); + int offset = bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag; + while (it.current_offset() < offset) it.Advance(); + DCHECK_EQ(offset, it.current_offset()); + it.Advance(); // Advance by one bytecode. + offset = it.current_offset() + BytecodeArray::kHeaderSize - kHeapObjectTag; + return Smi::FromInt(offset); +} + } // namespace internal } // namespace v8 diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 491e0e9e3f..0b0fd62dd3 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -215,7 +215,8 @@ namespace internal { F(InterpreterTraceBytecodeEntry, 3, 1) \ F(InterpreterTraceBytecodeExit, 3, 1) \ F(InterpreterClearPendingMessage, 0, 1) \ - F(InterpreterSetPendingMessage, 1, 1) + F(InterpreterSetPendingMessage, 1, 1) \ + F(InterpreterAdvanceBytecodeOffset, 2, 1) #define FOR_EACH_INTRINSIC_FUNCTION(F) \ F(FunctionGetName, 1, 1) \ diff --git a/test/debugger/debugger.status b/test/debugger/debugger.status index 4eca6f1c2e..7d7b714b22 100644 --- a/test/debugger/debugger.status +++ b/test/debugger/debugger.status @@ -22,11 +22,4 @@ 'debug/debug-stepout-scope-part7': [SKIP], 'debug/debug-stepout-scope-part8': [SKIP], }], # 'gc_stress == True' - -############################################################################## -['variant == turbofan_opt', { - - # TODO(jarin/mstarzinger): Investigate debugger issues with TurboFan. - 'debug/ignition/debug-break-on-stack': [FAIL], -}], # variant == turbofan_opt ] diff --git a/test/mjsunit/regress/regress-crbug-660379.js b/test/mjsunit/regress/regress-crbug-660379.js new file mode 100644 index 0000000000..84634628d6 --- /dev/null +++ b/test/mjsunit/regress/regress-crbug-660379.js @@ -0,0 +1,42 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +(function InlinedThrowAtEndOfTry() { + function g() { + %DeoptimizeFunction(f); + throw "boom"; + } + function f() { + try { + g(); // Right at the end of try. + } catch (e) { + assertEquals("boom", e) + } + } + assertDoesNotThrow(f); + assertDoesNotThrow(f); + %OptimizeFunctionOnNextCall(f); + assertDoesNotThrow(f); +})(); + +(function InlinedThrowInFrontOfTry() { + function g() { + %DeoptimizeFunction(f); + throw "boom"; + } + function f() { + g(); // Right in front of try. + try { + Math.random(); + } catch (e) { + assertUnreachable(); + } + } + assertThrows(f); + assertThrows(f); + %OptimizeFunctionOnNextCall(f); + assertThrows(f); +})();