From fb65527b75754bcf3b173f16f5d0b04a1c6d9b99 Mon Sep 17 00:00:00 2001 From: mythria Date: Thu, 24 Mar 2016 10:13:39 -0700 Subject: [PATCH] [Interpreter] Adds support to fetch return value on break at return. Debugger fetches the return value of a function when we break at return. Interpreter holds the return value in accumulator. This is not stored in a specified location on stack and hence it is not possible to look it up from stack similar to full-codegen or optimized frames. This cl adds support to store the value of accumulator on debug breaks. The value of accumulator is passed to the runtime function and is then stored in thread local data. Also changes full-codegen implementation to match that of ignition. The return value from full-codegen is also stored in thread local data. The return value is fetched directly thread local data instead of finding it by iterating over frames. BUG=v8:4280, v8:4690 LOG=N Review URL: https://codereview.chromium.org/1818873003 Cr-Commit-Position: refs/heads/master@{#35060} --- src/debug/arm/debug-arm.cc | 20 +++++++--- src/debug/arm64/debug-arm64.cc | 21 +++++++---- src/debug/debug.cc | 34 +++++------------ src/debug/debug.h | 14 ++++++- src/debug/ia32/debug-ia32.cc | 20 +++++++--- src/debug/mips/debug-mips.cc | 20 +++++++--- src/debug/mips64/debug-mips64.cc | 20 +++++++--- src/debug/ppc/debug-ppc.cc | 20 +++++++--- src/debug/s390/debug-s390.cc | 20 +++++++--- src/debug/x64/debug-x64.cc | 20 +++++++--- src/debug/x87/debug-x87.cc | 20 +++++++--- src/interpreter/interpreter.cc | 12 +++--- src/runtime/runtime-debug.cc | 64 +++++++++++++++++--------------- src/runtime/runtime.h | 5 +-- test/mjsunit/mjsunit.status | 1 - 15 files changed, 192 insertions(+), 119 deletions(-) diff --git a/src/debug/arm/debug-arm.cc b/src/debug/arm/debug-arm.cc index 99a555de9c..05c33f36d0 100644 --- a/src/debug/arm/debug-arm.cc +++ b/src/debug/arm/debug-arm.cc @@ -81,9 +81,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); __ push(ip); - if (mode == SAVE_RESULT_REGISTER) __ push(r0); - - __ mov(r0, Operand::Zero()); // no arguments + // Push arguments for DebugBreak call. + if (mode == SAVE_RESULT_REGISTER) { + // Break on return. + __ push(r0); + } else { + // Non-return breaks. + __ Push(masm->isolate()->factory()->the_hole_value()); + } + __ mov(r0, Operand(1)); __ mov(r1, Operand(ExternalReference( Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); @@ -94,12 +100,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, if (FLAG_debug_code) { for (int i = 0; i < kNumJSCallerSaved; i++) { Register reg = {JSCallerSavedCode(i)}; - __ mov(reg, Operand(kDebugZapValue)); + // Do not clobber r0 if SAVE_RESULT_REGISTER is set. It will + // contain return value of the function. + if (!(reg.is(r0) && SAVE_RESULT_REGISTER)) { + __ mov(reg, Operand(kDebugZapValue)); + } } } - if (mode == SAVE_RESULT_REGISTER) __ pop(r0); - // Don't bother removing padding bytes pushed on the stack // as the frame is going to be restored right away. diff --git a/src/debug/arm64/debug-arm64.cc b/src/debug/arm64/debug-arm64.cc index a2a6b73380..f12dd29ec1 100644 --- a/src/debug/arm64/debug-arm64.cc +++ b/src/debug/arm64/debug-arm64.cc @@ -92,9 +92,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); __ Push(scratch); - if (mode == SAVE_RESULT_REGISTER) __ Push(x0); - - __ Mov(x0, 0); // No arguments. + // Push arguments for DebugBreak call. + if (mode == SAVE_RESULT_REGISTER) { + // Break on return. + __ Push(x0); + } else { + // Non-return breaks. + __ Push(masm->isolate()->factory()->the_hole_value()); + } + __ Mov(x0, 1); __ Mov(x1, ExternalReference(Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())); @@ -104,13 +110,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, if (FLAG_debug_code) { for (int i = 0; i < kNumJSCallerSaved; i++) { Register reg = Register::XRegFromCode(JSCallerSavedCode(i)); - __ Mov(reg, Operand(kDebugZapValue)); + // Do not clobber x0 if SAVE_RESULT_REGISTER is set. It will + // contain return value of the function. + if (!(reg.is(x0) && SAVE_RESULT_REGISTER)) { + __ Mov(reg, Operand(kDebugZapValue)); + } } } - // Restore the register values from the expression stack. - if (mode == SAVE_RESULT_REGISTER) __ Pop(x0); - // Don't bother removing padding bytes pushed on the stack // as the frame is going to be restored right away. diff --git a/src/debug/debug.cc b/src/debug/debug.cc index 2efbd87c6a..3a6e0ac0de 100644 --- a/src/debug/debug.cc +++ b/src/debug/debug.cc @@ -16,7 +16,6 @@ #include "src/frames-inl.h" #include "src/full-codegen/full-codegen.h" #include "src/global-handles.h" -#include "src/interpreter/bytecodes.h" #include "src/interpreter/interpreter.h" #include "src/isolate-inl.h" #include "src/list.h" @@ -474,6 +473,7 @@ void Debug::ThreadInit() { thread_local_.last_fp_ = 0; thread_local_.target_fp_ = 0; thread_local_.step_in_enabled_ = false; + thread_local_.return_value_ = Handle(); // TODO(isolates): frames_are_dropped_? base::NoBarrier_Store(&thread_local_.current_debug_scope_, static_cast(0)); @@ -560,10 +560,8 @@ void Debug::Unload() { debug_context_ = Handle(); } - -void Debug::Break(Arguments args, JavaScriptFrame* frame) { +void Debug::Break(JavaScriptFrame* frame) { HandleScope scope(isolate_); - DCHECK(args.length() == 0); // Initialize LiveEdit. LiveEdit::InitializeThreadLocal(this); @@ -1569,25 +1567,11 @@ void Debug::RemoveDebugInfoAndClearFromShared(Handle debug_info) { UNREACHABLE(); } -Object* Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { - if (frame->is_interpreted()) { - // Find the handler from the original bytecode array. - InterpretedFrame* interpreted_frame = - reinterpret_cast(frame); - SharedFunctionInfo* shared = interpreted_frame->function()->shared(); - BytecodeArray* bytecode_array = shared->bytecode_array(); - int bytecode_offset = interpreted_frame->GetBytecodeOffset(); - interpreter::Bytecode bytecode = - interpreter::Bytecodes::FromByte(bytecode_array->get(bytecode_offset)); - return isolate_->interpreter()->GetBytecodeHandler( - bytecode, interpreter::OperandScale::kSingle); - } else { - after_break_target_ = NULL; - if (!LiveEdit::SetAfterBreakTarget(this)) { - // Continue just after the slot. - after_break_target_ = frame->pc(); - } - return isolate_->heap()->undefined_value(); +void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { + after_break_target_ = NULL; + if (!LiveEdit::SetAfterBreakTarget(this)) { + // Continue just after the slot. + after_break_target_ = frame->pc(); } } @@ -2328,9 +2312,10 @@ DebugScope::DebugScope(Debug* debug) base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_, reinterpret_cast(this)); - // Store the previous break id and frame id. + // Store the previous break id, frame id and return value. break_id_ = debug_->break_id(); break_frame_id_ = debug_->break_frame_id(); + return_value_ = debug_->return_value(); // Create the new break info. If there is no JavaScript frames there is no // break frame id. @@ -2368,6 +2353,7 @@ DebugScope::~DebugScope() { // Restore to the previous break state. debug_->thread_local_.break_frame_id_ = break_frame_id_; debug_->thread_local_.break_id_ = break_id_; + debug_->thread_local_.return_value_ = return_value_; debug_->UpdateState(); } diff --git a/src/debug/debug.h b/src/debug/debug.h index 600bc1a605..3e59adea1d 100644 --- a/src/debug/debug.h +++ b/src/debug/debug.h @@ -427,8 +427,8 @@ class Debug { // Internal logic bool Load(); - void Break(Arguments args, JavaScriptFrame*); - Object* SetAfterBreakTarget(JavaScriptFrame* frame); + void Break(JavaScriptFrame* frame); + void SetAfterBreakTarget(JavaScriptFrame* frame); // Scripts handling. Handle GetLoadedScripts(); @@ -524,6 +524,11 @@ class Debug { StackFrame::Id break_frame_id() { return thread_local_.break_frame_id_; } int break_id() { return thread_local_.break_id_; } + Handle return_value() { return thread_local_.return_value_; } + void set_return_value(Handle value) { + thread_local_.return_value_ = value; + } + // Support for embedding into generated code. Address is_active_address() { return reinterpret_cast
(&is_active_); @@ -678,6 +683,10 @@ class Debug { // Stores the way how LiveEdit has patched the stack. It is used when // debugger returns control back to user script. LiveEdit::FrameDropMode frame_drop_mode_; + + // Value of accumulator in interpreter frames. In non-interpreter frames + // this value will be the hole. + Handle return_value_; }; // Storage location for registers when handling debug break calls @@ -719,6 +728,7 @@ class DebugScope BASE_EMBEDDED { DebugScope* prev_; // Previous scope if entered recursively. StackFrame::Id break_frame_id_; // Previous break frame id. int break_id_; // Previous break id. + Handle return_value_; // Previous result. bool failed_; // Did the debug context fail to load? SaveContext save_; // Saves previous context. PostponeInterruptsScope no_termination_exceptons_; diff --git a/src/debug/ia32/debug-ia32.cc b/src/debug/ia32/debug-ia32.cc index 7df18c7eb8..4f25767f37 100644 --- a/src/debug/ia32/debug-ia32.cc +++ b/src/debug/ia32/debug-ia32.cc @@ -68,9 +68,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, } __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); - if (mode == SAVE_RESULT_REGISTER) __ push(eax); - - __ Move(eax, Immediate(0)); // No arguments. + // Push arguments for DebugBreak call. + if (mode == SAVE_RESULT_REGISTER) { + // Break on return. + __ push(eax); + } else { + // Non-return breaks. + __ Push(masm->isolate()->factory()->the_hole_value()); + } + __ Move(eax, Immediate(1)); __ mov(ebx, Immediate(ExternalReference( Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); @@ -81,12 +87,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, if (FLAG_debug_code) { for (int i = 0; i < kNumJSCallerSaved; ++i) { Register reg = {JSCallerSavedCode(i)}; - __ Move(reg, Immediate(kDebugZapValue)); + // Do not clobber eax if SAVE_RESULT_REGISTER is set. It will + // contain return value of the function. + if (!(reg.is(eax) && SAVE_RESULT_REGISTER)) { + __ Move(reg, Immediate(kDebugZapValue)); + } } } - if (mode == SAVE_RESULT_REGISTER) __ pop(eax); - __ pop(ebx); // We divide stored value by 2 (untagging) and multiply it by word's size. STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0); diff --git a/src/debug/mips/debug-mips.cc b/src/debug/mips/debug-mips.cc index 2da326c285..0b628aeda0 100644 --- a/src/debug/mips/debug-mips.cc +++ b/src/debug/mips/debug-mips.cc @@ -77,9 +77,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); __ push(at); - if (mode == SAVE_RESULT_REGISTER) __ push(v0); - - __ PrepareCEntryArgs(0); // No arguments. + // Push arguments for DebugBreak call. + if (mode == SAVE_RESULT_REGISTER) { + // Break on return. + __ push(v0); + } else { + // Non-return breaks. + __ Push(masm->isolate()->factory()->the_hole_value()); + } + __ PrepareCEntryArgs(1); __ PrepareCEntryFunction(ExternalReference( Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())); @@ -89,12 +95,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, if (FLAG_debug_code) { for (int i = 0; i < kNumJSCallerSaved; i++) { Register reg = {JSCallerSavedCode(i)}; - __ li(reg, kDebugZapValue); + // Do not clobber v0 if SAVE_RESULT_REGISTER is set. It will + // contain return value of the function returned by DebugBreak. + if (!(reg.is(v0) && SAVE_RESULT_REGISTER)) { + __ li(reg, kDebugZapValue); + } } } - if (mode == SAVE_RESULT_REGISTER) __ pop(v0); - // Don't bother removing padding bytes pushed on the stack // as the frame is going to be restored right away. diff --git a/src/debug/mips64/debug-mips64.cc b/src/debug/mips64/debug-mips64.cc index 1288d43b00..fb42ca3845 100644 --- a/src/debug/mips64/debug-mips64.cc +++ b/src/debug/mips64/debug-mips64.cc @@ -79,9 +79,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); __ push(at); - if (mode == SAVE_RESULT_REGISTER) __ push(v0); - - __ PrepareCEntryArgs(0); // No arguments. + // Push arguments for DebugBreak call. + if (mode == SAVE_RESULT_REGISTER) { + // Break on return. + __ push(v0); + } else { + // Non-return breaks. + __ Push(masm->isolate()->factory()->the_hole_value()); + } + __ PrepareCEntryArgs(1); __ PrepareCEntryFunction(ExternalReference( Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())); @@ -91,12 +97,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, if (FLAG_debug_code) { for (int i = 0; i < kNumJSCallerSaved; i++) { Register reg = {JSCallerSavedCode(i)}; - __ li(reg, kDebugZapValue); + // Do not clobber v0 if SAVE_RESULT_REGISTER is set. It will + // contain return value of the function returned by DebugBreak. + if (!(reg.is(v0) && SAVE_RESULT_REGISTER)) { + __ li(reg, kDebugZapValue); + } } } - if (mode == SAVE_RESULT_REGISTER) __ pop(v0); - // Don't bother removing padding bytes pushed on the stack // as the frame is going to be restored right away. diff --git a/src/debug/ppc/debug-ppc.cc b/src/debug/ppc/debug-ppc.cc index cd213d8f67..dd7073af6b 100644 --- a/src/debug/ppc/debug-ppc.cc +++ b/src/debug/ppc/debug-ppc.cc @@ -83,9 +83,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, __ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); __ push(ip); - if (mode == SAVE_RESULT_REGISTER) __ push(r3); - - __ mov(r3, Operand::Zero()); // no arguments + // Push arguments for DebugBreak call. + if (mode == SAVE_RESULT_REGISTER) { + // Break on return. + __ push(r3); + } else { + // Non-return breaks. + __ Push(masm->isolate()->factory()->the_hole_value()); + } + __ mov(r3, Operand(1)); __ mov(r4, Operand(ExternalReference( Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); @@ -96,12 +102,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, if (FLAG_debug_code) { for (int i = 0; i < kNumJSCallerSaved; i++) { Register reg = {JSCallerSavedCode(i)}; - __ mov(reg, Operand(kDebugZapValue)); + // Do not clobber r3 if SAVE_RESULT_REGISTER is set. It will + // contain return value of the function. + if (!(reg.is(r3) && SAVE_RESULT_REGISTER)) { + __ mov(reg, Operand(kDebugZapValue)); + } } } - if (mode == SAVE_RESULT_REGISTER) __ pop(r3); - // Don't bother removing padding bytes pushed on the stack // as the frame is going to be restored right away. diff --git a/src/debug/s390/debug-s390.cc b/src/debug/s390/debug-s390.cc index 8165bf9874..ab262630c4 100644 --- a/src/debug/s390/debug-s390.cc +++ b/src/debug/s390/debug-s390.cc @@ -88,9 +88,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, __ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); __ push(ip); - if (mode == SAVE_RESULT_REGISTER) __ push(r2); - - __ mov(r2, Operand::Zero()); // no arguments + // Push arguments for DebugBreak call. + if (mode == SAVE_RESULT_REGISTER) { + // Break on return. + __ push(r2); + } else { + // Non-return breaks. + __ Push(masm->isolate()->factory()->the_hole_value()); + } + __ mov(r2, Operand(1)); __ mov(r3, Operand(ExternalReference( Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); @@ -101,12 +107,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, if (FLAG_debug_code) { for (int i = 0; i < kNumJSCallerSaved; i++) { Register reg = {JSCallerSavedCode(i)}; - __ mov(reg, Operand(kDebugZapValue)); + // Do not clobber r2 if SAVE_RESULT_REGISTER is set. It will + // contain return value of the function. + if (!(reg.is(r2) && SAVE_RESULT_REGISTER)) { + __ mov(reg, Operand(kDebugZapValue)); + } } } - if (mode == SAVE_RESULT_REGISTER) __ pop(r2); - // Don't bother removing padding bytes pushed on the stack // as the frame is going to be restored right away. diff --git a/src/debug/x64/debug-x64.cc b/src/debug/x64/debug-x64.cc index 094e7b608e..4680596322 100644 --- a/src/debug/x64/debug-x64.cc +++ b/src/debug/x64/debug-x64.cc @@ -69,9 +69,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, } __ Push(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); - if (mode == SAVE_RESULT_REGISTER) __ Push(rax); - - __ Set(rax, 0); // No arguments (argc == 0). + // Push arguments for DebugBreak call. + if (mode == SAVE_RESULT_REGISTER) { + // Break on return. + __ Push(rax); + } else { + // Non-return breaks. + __ Push(masm->isolate()->factory()->the_hole_value()); + } + __ Set(rax, 1); __ Move(rbx, ExternalReference(Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())); @@ -81,12 +87,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, if (FLAG_debug_code) { for (int i = 0; i < kNumJSCallerSaved; ++i) { Register reg = {JSCallerSavedCode(i)}; - __ Set(reg, kDebugZapValue); + // Do not clobber rax if SAVE_RESULT_REGISTER is set. It will + // contain return value of the function. + if (!(reg.is(rax) && SAVE_RESULT_REGISTER)) { + __ Set(reg, kDebugZapValue); + } } } - if (mode == SAVE_RESULT_REGISTER) __ Pop(rax); - // Read current padding counter and skip corresponding number of words. __ Pop(kScratchRegister); __ SmiToInteger32(kScratchRegister, kScratchRegister); diff --git a/src/debug/x87/debug-x87.cc b/src/debug/x87/debug-x87.cc index 28b635b326..b4dbfc9bb9 100644 --- a/src/debug/x87/debug-x87.cc +++ b/src/debug/x87/debug-x87.cc @@ -68,9 +68,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, } __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); - if (mode == SAVE_RESULT_REGISTER) __ push(eax); - - __ Move(eax, Immediate(0)); // No arguments. + // Push arguments for DebugBreak call. + if (mode == SAVE_RESULT_REGISTER) { + // Break on return. + __ push(eax); + } else { + // Non-return breaks. + __ Push(masm->isolate()->factory()->the_hole_value()); + } + __ Move(eax, Immediate(1)); __ mov(ebx, Immediate(ExternalReference( Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); @@ -81,12 +87,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, if (FLAG_debug_code) { for (int i = 0; i < kNumJSCallerSaved; ++i) { Register reg = {JSCallerSavedCode(i)}; - __ Move(reg, Immediate(kDebugZapValue)); + // Do not clobber eax if SAVE_RESULT_REGISTER is set. It will + // contain return value of the function. + if (!(reg.is(eax) && SAVE_RESULT_REGISTER)) { + __ Move(reg, Immediate(kDebugZapValue)); + } } } - if (mode == SAVE_RESULT_REGISTER) __ pop(eax); - __ pop(ebx); // We divide stored value by 2 (untagging) and multiply it by word's size. STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0); diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc index 1ff57a7ca2..70bf311ee1 100644 --- a/src/interpreter/interpreter.cc +++ b/src/interpreter/interpreter.cc @@ -1485,11 +1485,13 @@ void Interpreter::DoDebugger(InterpreterAssembler* assembler) { // DebugBreak // // Call runtime to handle a debug break. -#define DEBUG_BREAK(Name, ...) \ - void Interpreter::Do##Name(InterpreterAssembler* assembler) { \ - Node* context = __ GetContext(); \ - Node* original_handler = __ CallRuntime(Runtime::kDebugBreak, context); \ - __ DispatchToBytecodeHandler(original_handler); \ +#define DEBUG_BREAK(Name, ...) \ + void Interpreter::Do##Name(InterpreterAssembler* assembler) { \ + Node* context = __ GetContext(); \ + Node* accumulator = __ GetAccumulator(); \ + Node* original_handler = \ + __ CallRuntime(Runtime::kDebugBreakOnBytecode, context, accumulator); \ + __ DispatchToBytecodeHandler(original_handler); \ } DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK); #undef DEBUG_BREAK diff --git a/src/runtime/runtime-debug.cc b/src/runtime/runtime-debug.cc index 631f5e8153..3263a89809 100644 --- a/src/runtime/runtime-debug.cc +++ b/src/runtime/runtime-debug.cc @@ -5,11 +5,13 @@ #include "src/runtime/runtime-utils.h" #include "src/arguments.h" -#include "src/debug/debug.h" #include "src/debug/debug-evaluate.h" #include "src/debug/debug-frames.h" #include "src/debug/debug-scopes.h" +#include "src/debug/debug.h" #include "src/frames-inl.h" +#include "src/interpreter/bytecodes.h" +#include "src/interpreter/interpreter.h" #include "src/isolate-inl.h" #include "src/runtime/runtime.h" @@ -18,11 +20,39 @@ namespace internal { RUNTIME_FUNCTION(Runtime_DebugBreak) { SealHandleScope shs(isolate); - DCHECK(args.length() == 0); + DCHECK(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); + isolate->debug()->set_return_value(value); + // Get the top-most JavaScript frame. JavaScriptFrameIterator it(isolate); - isolate->debug()->Break(args, it.frame()); - return isolate->debug()->SetAfterBreakTarget(it.frame()); + isolate->debug()->Break(it.frame()); + + isolate->debug()->SetAfterBreakTarget(it.frame()); + return *isolate->debug()->return_value(); +} + +RUNTIME_FUNCTION(Runtime_DebugBreakOnBytecode) { + SealHandleScope shs(isolate); + DCHECK(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); + isolate->debug()->set_return_value(value); + + // Get the top-most JavaScript frame. + JavaScriptFrameIterator it(isolate); + isolate->debug()->Break(it.frame()); + + // Return the handler from the original bytecode array. + DCHECK(it.frame()->is_interpreted()); + InterpretedFrame* interpreted_frame = + reinterpret_cast(it.frame()); + SharedFunctionInfo* shared = interpreted_frame->function()->shared(); + BytecodeArray* bytecode_array = shared->bytecode_array(); + int bytecode_offset = interpreted_frame->GetBytecodeOffset(); + interpreter::Bytecode bytecode = + interpreter::Bytecodes::FromByte(bytecode_array->get(bytecode_offset)); + return isolate->interpreter()->GetBytecodeHandler( + bytecode, interpreter::OperandScale::kSingle); } @@ -591,31 +621,7 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) { // to the frame information. Handle return_value = isolate->factory()->undefined_value(); if (at_return) { - StackFrameIterator it2(isolate); - Address internal_frame_sp = NULL; - while (!it2.done()) { - if (it2.frame()->is_internal()) { - internal_frame_sp = it2.frame()->sp(); - } else { - if (it2.frame()->is_java_script()) { - if (it2.frame()->id() == it.frame()->id()) { - // The internal frame just before the JavaScript frame contains the - // value to return on top. A debug break at return will create an - // internal frame to store the return value (eax/rax/r0) before - // entering the debug break exit frame. - if (internal_frame_sp != NULL) { - return_value = - Handle(Memory::Object_at(internal_frame_sp), isolate); - break; - } - } - } - - // Indicate that the previous frame was not an internal frame. - internal_frame_sp = NULL; - } - it2.Advance(); - } + return_value = isolate->debug()->return_value(); } // Now advance to the arguments adapter frame (if any). It contains all diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 1028f1d7d8..bd4b74ea42 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -137,10 +137,10 @@ namespace internal { F(DateCurrentTime, 0, 1) \ F(ThrowNotDateError, 0, 1) - #define FOR_EACH_INTRINSIC_DEBUG(F) \ F(HandleDebuggerStatement, 0, 1) \ - F(DebugBreak, 0, 1) \ + F(DebugBreak, 1, 1) \ + F(DebugBreakOnBytecode, 1, 1) \ F(SetDebugEventListener, 2, 1) \ F(ScheduleBreak, 0, 1) \ F(DebugGetInternalProperties, 1, 1) \ @@ -195,7 +195,6 @@ namespace internal { F(DebugIsActive, 0, 1) \ F(DebugBreakInOptimizedCode, 0, 1) - #define FOR_EACH_INTRINSIC_FORIN(F) \ F(ForInDone, 2, 1) \ F(ForInEnumerate, 1, 1) \ diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status index 09e2d82bbf..ea15c458db 100644 --- a/test/mjsunit/mjsunit.status +++ b/test/mjsunit/mjsunit.status @@ -755,7 +755,6 @@ ['ignition == True', { # TODO(yangguo,4690): assertion failures in debugger tests. 'debug-allscopes-on-debugger': [FAIL], - 'debug-return-value': [FAIL], 'es6/debug-stepnext-for': [FAIL], 'es6/debug-stepin-string-template': [FAIL], 'es6/debug-promises/stepin-constructor': [FAIL],