Commit b82720df authored by mythria's avatar mythria Committed by Commit bot

[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/1842683002

Cr-Commit-Position: refs/heads/master@{#35127}
parent 682df6dd
...@@ -81,9 +81,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -81,9 +81,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
__ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
__ push(ip); __ push(ip);
if (mode == SAVE_RESULT_REGISTER) __ push(r0); // Push arguments for DebugBreak call.
if (mode == SAVE_RESULT_REGISTER) {
__ mov(r0, Operand::Zero()); // no arguments // Break on return.
__ push(r0);
} else {
// Non-return breaks.
__ Push(masm->isolate()->factory()->the_hole_value());
}
__ mov(r0, Operand(1));
__ mov(r1, __ mov(r1,
Operand(ExternalReference( Operand(ExternalReference(
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
...@@ -94,12 +100,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -94,12 +100,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
if (FLAG_debug_code) { if (FLAG_debug_code) {
for (int i = 0; i < kNumJSCallerSaved; i++) { for (int i = 0; i < kNumJSCallerSaved; i++) {
Register reg = {JSCallerSavedCode(i)}; Register reg = {JSCallerSavedCode(i)};
__ mov(reg, Operand(kDebugZapValue)); // Do not clobber r0 if mode is SAVE_RESULT_REGISTER. It will
// contain return value of the function.
if (!(reg.is(r0) && (mode == SAVE_RESULT_REGISTER))) {
__ mov(reg, Operand(kDebugZapValue));
}
} }
} }
if (mode == SAVE_RESULT_REGISTER) __ pop(r0);
// Don't bother removing padding bytes pushed on the stack // Don't bother removing padding bytes pushed on the stack
// as the frame is going to be restored right away. // as the frame is going to be restored right away.
......
...@@ -92,9 +92,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -92,9 +92,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
__ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
__ Push(scratch); __ Push(scratch);
if (mode == SAVE_RESULT_REGISTER) __ Push(x0); // Push arguments for DebugBreak call.
if (mode == SAVE_RESULT_REGISTER) {
__ Mov(x0, 0); // No arguments. // 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), __ Mov(x1, ExternalReference(Runtime::FunctionForId(Runtime::kDebugBreak),
masm->isolate())); masm->isolate()));
...@@ -104,13 +110,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -104,13 +110,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
if (FLAG_debug_code) { if (FLAG_debug_code) {
for (int i = 0; i < kNumJSCallerSaved; i++) { for (int i = 0; i < kNumJSCallerSaved; i++) {
Register reg = Register::XRegFromCode(JSCallerSavedCode(i)); Register reg = Register::XRegFromCode(JSCallerSavedCode(i));
__ Mov(reg, Operand(kDebugZapValue)); // Do not clobber x0 if mode is SAVE_RESULT_REGISTER. It will
// contain return value of the function.
if (!(reg.is(x0) && (mode == 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 // Don't bother removing padding bytes pushed on the stack
// as the frame is going to be restored right away. // as the frame is going to be restored right away.
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include "src/frames-inl.h" #include "src/frames-inl.h"
#include "src/full-codegen/full-codegen.h" #include "src/full-codegen/full-codegen.h"
#include "src/global-handles.h" #include "src/global-handles.h"
#include "src/interpreter/bytecodes.h"
#include "src/interpreter/interpreter.h" #include "src/interpreter/interpreter.h"
#include "src/isolate-inl.h" #include "src/isolate-inl.h"
#include "src/list.h" #include "src/list.h"
...@@ -474,6 +473,7 @@ void Debug::ThreadInit() { ...@@ -474,6 +473,7 @@ void Debug::ThreadInit() {
thread_local_.last_fp_ = 0; thread_local_.last_fp_ = 0;
thread_local_.target_fp_ = 0; thread_local_.target_fp_ = 0;
thread_local_.step_in_enabled_ = false; thread_local_.step_in_enabled_ = false;
thread_local_.return_value_ = Handle<Object>();
// TODO(isolates): frames_are_dropped_? // TODO(isolates): frames_are_dropped_?
base::NoBarrier_Store(&thread_local_.current_debug_scope_, base::NoBarrier_Store(&thread_local_.current_debug_scope_,
static_cast<base::AtomicWord>(0)); static_cast<base::AtomicWord>(0));
...@@ -560,10 +560,8 @@ void Debug::Unload() { ...@@ -560,10 +560,8 @@ void Debug::Unload() {
debug_context_ = Handle<Context>(); debug_context_ = Handle<Context>();
} }
void Debug::Break(JavaScriptFrame* frame) {
void Debug::Break(Arguments args, JavaScriptFrame* frame) {
HandleScope scope(isolate_); HandleScope scope(isolate_);
DCHECK(args.length() == 0);
// Initialize LiveEdit. // Initialize LiveEdit.
LiveEdit::InitializeThreadLocal(this); LiveEdit::InitializeThreadLocal(this);
...@@ -1569,25 +1567,11 @@ void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) { ...@@ -1569,25 +1567,11 @@ void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) {
UNREACHABLE(); UNREACHABLE();
} }
Object* Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
if (frame->is_interpreted()) { after_break_target_ = NULL;
// Find the handler from the original bytecode array. if (!LiveEdit::SetAfterBreakTarget(this)) {
InterpretedFrame* interpreted_frame = // Continue just after the slot.
reinterpret_cast<InterpretedFrame*>(frame); after_break_target_ = frame->pc();
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();
} }
} }
...@@ -2328,9 +2312,10 @@ DebugScope::DebugScope(Debug* debug) ...@@ -2328,9 +2312,10 @@ DebugScope::DebugScope(Debug* debug)
base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_, base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
reinterpret_cast<base::AtomicWord>(this)); reinterpret_cast<base::AtomicWord>(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_id_ = debug_->break_id();
break_frame_id_ = debug_->break_frame_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 // Create the new break info. If there is no JavaScript frames there is no
// break frame id. // break frame id.
...@@ -2368,6 +2353,7 @@ DebugScope::~DebugScope() { ...@@ -2368,6 +2353,7 @@ DebugScope::~DebugScope() {
// Restore to the previous break state. // Restore to the previous break state.
debug_->thread_local_.break_frame_id_ = break_frame_id_; debug_->thread_local_.break_frame_id_ = break_frame_id_;
debug_->thread_local_.break_id_ = break_id_; debug_->thread_local_.break_id_ = break_id_;
debug_->thread_local_.return_value_ = return_value_;
debug_->UpdateState(); debug_->UpdateState();
} }
......
...@@ -427,8 +427,8 @@ class Debug { ...@@ -427,8 +427,8 @@ class Debug {
// Internal logic // Internal logic
bool Load(); bool Load();
void Break(Arguments args, JavaScriptFrame*); void Break(JavaScriptFrame* frame);
Object* SetAfterBreakTarget(JavaScriptFrame* frame); void SetAfterBreakTarget(JavaScriptFrame* frame);
// Scripts handling. // Scripts handling.
Handle<FixedArray> GetLoadedScripts(); Handle<FixedArray> GetLoadedScripts();
...@@ -524,6 +524,11 @@ class Debug { ...@@ -524,6 +524,11 @@ class Debug {
StackFrame::Id break_frame_id() { return thread_local_.break_frame_id_; } StackFrame::Id break_frame_id() { return thread_local_.break_frame_id_; }
int break_id() { return thread_local_.break_id_; } int break_id() { return thread_local_.break_id_; }
Handle<Object> return_value() { return thread_local_.return_value_; }
void set_return_value(Handle<Object> value) {
thread_local_.return_value_ = value;
}
// Support for embedding into generated code. // Support for embedding into generated code.
Address is_active_address() { Address is_active_address() {
return reinterpret_cast<Address>(&is_active_); return reinterpret_cast<Address>(&is_active_);
...@@ -678,6 +683,10 @@ class Debug { ...@@ -678,6 +683,10 @@ class Debug {
// Stores the way how LiveEdit has patched the stack. It is used when // Stores the way how LiveEdit has patched the stack. It is used when
// debugger returns control back to user script. // debugger returns control back to user script.
LiveEdit::FrameDropMode frame_drop_mode_; LiveEdit::FrameDropMode frame_drop_mode_;
// Value of accumulator in interpreter frames. In non-interpreter frames
// this value will be the hole.
Handle<Object> return_value_;
}; };
// Storage location for registers when handling debug break calls // Storage location for registers when handling debug break calls
...@@ -719,6 +728,7 @@ class DebugScope BASE_EMBEDDED { ...@@ -719,6 +728,7 @@ class DebugScope BASE_EMBEDDED {
DebugScope* prev_; // Previous scope if entered recursively. DebugScope* prev_; // Previous scope if entered recursively.
StackFrame::Id break_frame_id_; // Previous break frame id. StackFrame::Id break_frame_id_; // Previous break frame id.
int break_id_; // Previous break id. int break_id_; // Previous break id.
Handle<Object> return_value_; // Previous result.
bool failed_; // Did the debug context fail to load? bool failed_; // Did the debug context fail to load?
SaveContext save_; // Saves previous context. SaveContext save_; // Saves previous context.
PostponeInterruptsScope no_termination_exceptons_; PostponeInterruptsScope no_termination_exceptons_;
......
...@@ -68,9 +68,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -68,9 +68,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
} }
__ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
if (mode == SAVE_RESULT_REGISTER) __ push(eax); // Push arguments for DebugBreak call.
if (mode == SAVE_RESULT_REGISTER) {
__ Move(eax, Immediate(0)); // No arguments. // Break on return.
__ push(eax);
} else {
// Non-return breaks.
__ Push(masm->isolate()->factory()->the_hole_value());
}
__ Move(eax, Immediate(1));
__ mov(ebx, __ mov(ebx,
Immediate(ExternalReference( Immediate(ExternalReference(
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
...@@ -81,12 +87,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -81,12 +87,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
if (FLAG_debug_code) { if (FLAG_debug_code) {
for (int i = 0; i < kNumJSCallerSaved; ++i) { for (int i = 0; i < kNumJSCallerSaved; ++i) {
Register reg = {JSCallerSavedCode(i)}; Register reg = {JSCallerSavedCode(i)};
__ Move(reg, Immediate(kDebugZapValue)); // Do not clobber eax if mode is SAVE_RESULT_REGISTER. It will
// contain return value of the function.
if (!(reg.is(eax) && (mode == SAVE_RESULT_REGISTER))) {
__ Move(reg, Immediate(kDebugZapValue));
}
} }
} }
if (mode == SAVE_RESULT_REGISTER) __ pop(eax);
__ pop(ebx); __ pop(ebx);
// We divide stored value by 2 (untagging) and multiply it by word's size. // We divide stored value by 2 (untagging) and multiply it by word's size.
STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0); STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0);
......
...@@ -77,9 +77,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -77,9 +77,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
__ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
__ push(at); __ push(at);
if (mode == SAVE_RESULT_REGISTER) __ push(v0); // Push arguments for DebugBreak call.
if (mode == SAVE_RESULT_REGISTER) {
__ PrepareCEntryArgs(0); // No arguments. // Break on return.
__ push(v0);
} else {
// Non-return breaks.
__ Push(masm->isolate()->factory()->the_hole_value());
}
__ PrepareCEntryArgs(1);
__ PrepareCEntryFunction(ExternalReference( __ PrepareCEntryFunction(ExternalReference(
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())); Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()));
...@@ -89,12 +95,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -89,12 +95,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
if (FLAG_debug_code) { if (FLAG_debug_code) {
for (int i = 0; i < kNumJSCallerSaved; i++) { for (int i = 0; i < kNumJSCallerSaved; i++) {
Register reg = {JSCallerSavedCode(i)}; Register reg = {JSCallerSavedCode(i)};
__ li(reg, kDebugZapValue); // Do not clobber v0 if mode is SAVE_RESULT_REGISTER. It will
// contain return value of the function returned by DebugBreak.
if (!(reg.is(v0) && (mode == SAVE_RESULT_REGISTER))) {
__ li(reg, kDebugZapValue);
}
} }
} }
if (mode == SAVE_RESULT_REGISTER) __ pop(v0);
// Don't bother removing padding bytes pushed on the stack // Don't bother removing padding bytes pushed on the stack
// as the frame is going to be restored right away. // as the frame is going to be restored right away.
......
...@@ -79,9 +79,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -79,9 +79,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
__ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
__ push(at); __ push(at);
if (mode == SAVE_RESULT_REGISTER) __ push(v0); // Push arguments for DebugBreak call.
if (mode == SAVE_RESULT_REGISTER) {
__ PrepareCEntryArgs(0); // No arguments. // Break on return.
__ push(v0);
} else {
// Non-return breaks.
__ Push(masm->isolate()->factory()->the_hole_value());
}
__ PrepareCEntryArgs(1);
__ PrepareCEntryFunction(ExternalReference( __ PrepareCEntryFunction(ExternalReference(
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())); Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()));
...@@ -91,12 +97,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -91,12 +97,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
if (FLAG_debug_code) { if (FLAG_debug_code) {
for (int i = 0; i < kNumJSCallerSaved; i++) { for (int i = 0; i < kNumJSCallerSaved; i++) {
Register reg = {JSCallerSavedCode(i)}; Register reg = {JSCallerSavedCode(i)};
__ li(reg, kDebugZapValue); // Do not clobber v0 if mode is SAVE_RESULT_REGISTER. It will
// contain return value of the function returned by DebugBreak.
if (!(reg.is(v0) && (mode == SAVE_RESULT_REGISTER))) {
__ li(reg, kDebugZapValue);
}
} }
} }
if (mode == SAVE_RESULT_REGISTER) __ pop(v0);
// Don't bother removing padding bytes pushed on the stack // Don't bother removing padding bytes pushed on the stack
// as the frame is going to be restored right away. // as the frame is going to be restored right away.
......
...@@ -83,9 +83,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -83,9 +83,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
__ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); __ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
__ push(ip); __ push(ip);
if (mode == SAVE_RESULT_REGISTER) __ push(r3); // Push arguments for DebugBreak call.
if (mode == SAVE_RESULT_REGISTER) {
__ mov(r3, Operand::Zero()); // no arguments // Break on return.
__ push(r3);
} else {
// Non-return breaks.
__ Push(masm->isolate()->factory()->the_hole_value());
}
__ mov(r3, Operand(1));
__ mov(r4, __ mov(r4,
Operand(ExternalReference( Operand(ExternalReference(
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
...@@ -96,12 +102,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -96,12 +102,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
if (FLAG_debug_code) { if (FLAG_debug_code) {
for (int i = 0; i < kNumJSCallerSaved; i++) { for (int i = 0; i < kNumJSCallerSaved; i++) {
Register reg = {JSCallerSavedCode(i)}; Register reg = {JSCallerSavedCode(i)};
__ mov(reg, Operand(kDebugZapValue)); // Do not clobber r3 if mode is SAVE_RESULT_REGISTER. It will
// contain return value of the function.
if (!(reg.is(r3) && (mode == SAVE_RESULT_REGISTER))) {
__ mov(reg, Operand(kDebugZapValue));
}
} }
} }
if (mode == SAVE_RESULT_REGISTER) __ pop(r3);
// Don't bother removing padding bytes pushed on the stack // Don't bother removing padding bytes pushed on the stack
// as the frame is going to be restored right away. // as the frame is going to be restored right away.
......
...@@ -88,9 +88,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -88,9 +88,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
__ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); __ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
__ push(ip); __ push(ip);
if (mode == SAVE_RESULT_REGISTER) __ push(r2); // Push arguments for DebugBreak call.
if (mode == SAVE_RESULT_REGISTER) {
__ mov(r2, Operand::Zero()); // no arguments // Break on return.
__ push(r2);
} else {
// Non-return breaks.
__ Push(masm->isolate()->factory()->the_hole_value());
}
__ mov(r2, Operand(1));
__ mov(r3, __ mov(r3,
Operand(ExternalReference( Operand(ExternalReference(
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
...@@ -101,12 +107,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -101,12 +107,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
if (FLAG_debug_code) { if (FLAG_debug_code) {
for (int i = 0; i < kNumJSCallerSaved; i++) { for (int i = 0; i < kNumJSCallerSaved; i++) {
Register reg = {JSCallerSavedCode(i)}; Register reg = {JSCallerSavedCode(i)};
__ mov(reg, Operand(kDebugZapValue)); // Do not clobber r2 if mode is SAVE_RESULT_REGISTER. It will
// contain return value of the function.
if (!(reg.is(r2) && (mode == SAVE_RESULT_REGISTER))) {
__ mov(reg, Operand(kDebugZapValue));
}
} }
} }
if (mode == SAVE_RESULT_REGISTER) __ pop(r2);
// Don't bother removing padding bytes pushed on the stack // Don't bother removing padding bytes pushed on the stack
// as the frame is going to be restored right away. // as the frame is going to be restored right away.
......
...@@ -69,9 +69,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -69,9 +69,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
} }
__ Push(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); __ Push(Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
if (mode == SAVE_RESULT_REGISTER) __ Push(rax); // Push arguments for DebugBreak call.
if (mode == SAVE_RESULT_REGISTER) {
__ Set(rax, 0); // No arguments (argc == 0). // 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), __ Move(rbx, ExternalReference(Runtime::FunctionForId(Runtime::kDebugBreak),
masm->isolate())); masm->isolate()));
...@@ -81,12 +87,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -81,12 +87,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
if (FLAG_debug_code) { if (FLAG_debug_code) {
for (int i = 0; i < kNumJSCallerSaved; ++i) { for (int i = 0; i < kNumJSCallerSaved; ++i) {
Register reg = {JSCallerSavedCode(i)}; Register reg = {JSCallerSavedCode(i)};
__ Set(reg, kDebugZapValue); // Do not clobber rax if mode is SAVE_RESULT_REGISTER. It will
// contain return value of the function.
if (!(reg.is(rax) && (mode == SAVE_RESULT_REGISTER))) {
__ Set(reg, kDebugZapValue);
}
} }
} }
if (mode == SAVE_RESULT_REGISTER) __ Pop(rax);
// Read current padding counter and skip corresponding number of words. // Read current padding counter and skip corresponding number of words.
__ Pop(kScratchRegister); __ Pop(kScratchRegister);
__ SmiToInteger32(kScratchRegister, kScratchRegister); __ SmiToInteger32(kScratchRegister, kScratchRegister);
......
...@@ -68,9 +68,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -68,9 +68,15 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
} }
__ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
if (mode == SAVE_RESULT_REGISTER) __ push(eax); // Push arguments for DebugBreak call.
if (mode == SAVE_RESULT_REGISTER) {
__ Move(eax, Immediate(0)); // No arguments. // Break on return.
__ push(eax);
} else {
// Non-return breaks.
__ Push(masm->isolate()->factory()->the_hole_value());
}
__ Move(eax, Immediate(1));
__ mov(ebx, __ mov(ebx,
Immediate(ExternalReference( Immediate(ExternalReference(
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
...@@ -81,12 +87,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ...@@ -81,12 +87,14 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
if (FLAG_debug_code) { if (FLAG_debug_code) {
for (int i = 0; i < kNumJSCallerSaved; ++i) { for (int i = 0; i < kNumJSCallerSaved; ++i) {
Register reg = {JSCallerSavedCode(i)}; Register reg = {JSCallerSavedCode(i)};
__ Move(reg, Immediate(kDebugZapValue)); // Do not clobber eax if mode is SAVE_RESULT_REGISTER. It will
// contain return value of the function.
if (!(reg.is(eax) && (mode == SAVE_RESULT_REGISTER))) {
__ Move(reg, Immediate(kDebugZapValue));
}
} }
} }
if (mode == SAVE_RESULT_REGISTER) __ pop(eax);
__ pop(ebx); __ pop(ebx);
// We divide stored value by 2 (untagging) and multiply it by word's size. // We divide stored value by 2 (untagging) and multiply it by word's size.
STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0); STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0);
......
...@@ -1485,11 +1485,13 @@ void Interpreter::DoDebugger(InterpreterAssembler* assembler) { ...@@ -1485,11 +1485,13 @@ void Interpreter::DoDebugger(InterpreterAssembler* assembler) {
// DebugBreak // DebugBreak
// //
// Call runtime to handle a debug break. // Call runtime to handle a debug break.
#define DEBUG_BREAK(Name, ...) \ #define DEBUG_BREAK(Name, ...) \
void Interpreter::Do##Name(InterpreterAssembler* assembler) { \ void Interpreter::Do##Name(InterpreterAssembler* assembler) { \
Node* context = __ GetContext(); \ Node* context = __ GetContext(); \
Node* original_handler = __ CallRuntime(Runtime::kDebugBreak, context); \ Node* accumulator = __ GetAccumulator(); \
__ DispatchToBytecodeHandler(original_handler); \ Node* original_handler = \
__ CallRuntime(Runtime::kDebugBreakOnBytecode, context, accumulator); \
__ DispatchToBytecodeHandler(original_handler); \
} }
DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK); DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK);
#undef DEBUG_BREAK #undef DEBUG_BREAK
......
...@@ -5,11 +5,13 @@ ...@@ -5,11 +5,13 @@
#include "src/runtime/runtime-utils.h" #include "src/runtime/runtime-utils.h"
#include "src/arguments.h" #include "src/arguments.h"
#include "src/debug/debug.h"
#include "src/debug/debug-evaluate.h" #include "src/debug/debug-evaluate.h"
#include "src/debug/debug-frames.h" #include "src/debug/debug-frames.h"
#include "src/debug/debug-scopes.h" #include "src/debug/debug-scopes.h"
#include "src/debug/debug.h"
#include "src/frames-inl.h" #include "src/frames-inl.h"
#include "src/interpreter/bytecodes.h"
#include "src/interpreter/interpreter.h"
#include "src/isolate-inl.h" #include "src/isolate-inl.h"
#include "src/runtime/runtime.h" #include "src/runtime/runtime.h"
...@@ -18,11 +20,39 @@ namespace internal { ...@@ -18,11 +20,39 @@ namespace internal {
RUNTIME_FUNCTION(Runtime_DebugBreak) { RUNTIME_FUNCTION(Runtime_DebugBreak) {
SealHandleScope shs(isolate); 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. // Get the top-most JavaScript frame.
JavaScriptFrameIterator it(isolate); JavaScriptFrameIterator it(isolate);
isolate->debug()->Break(args, it.frame()); isolate->debug()->Break(it.frame());
return isolate->debug()->SetAfterBreakTarget(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<InterpretedFrame*>(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) { ...@@ -591,31 +621,7 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
// to the frame information. // to the frame information.
Handle<Object> return_value = isolate->factory()->undefined_value(); Handle<Object> return_value = isolate->factory()->undefined_value();
if (at_return) { if (at_return) {
StackFrameIterator it2(isolate); return_value = isolate->debug()->return_value();
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<Object>(Memory::Object_at(internal_frame_sp), isolate);
break;
}
}
}
// Indicate that the previous frame was not an internal frame.
internal_frame_sp = NULL;
}
it2.Advance();
}
} }
// Now advance to the arguments adapter frame (if any). It contains all // Now advance to the arguments adapter frame (if any). It contains all
......
...@@ -137,10 +137,10 @@ namespace internal { ...@@ -137,10 +137,10 @@ namespace internal {
F(DateCurrentTime, 0, 1) \ F(DateCurrentTime, 0, 1) \
F(ThrowNotDateError, 0, 1) F(ThrowNotDateError, 0, 1)
#define FOR_EACH_INTRINSIC_DEBUG(F) \ #define FOR_EACH_INTRINSIC_DEBUG(F) \
F(HandleDebuggerStatement, 0, 1) \ F(HandleDebuggerStatement, 0, 1) \
F(DebugBreak, 0, 1) \ F(DebugBreak, 1, 1) \
F(DebugBreakOnBytecode, 1, 1) \
F(SetDebugEventListener, 2, 1) \ F(SetDebugEventListener, 2, 1) \
F(ScheduleBreak, 0, 1) \ F(ScheduleBreak, 0, 1) \
F(DebugGetInternalProperties, 1, 1) \ F(DebugGetInternalProperties, 1, 1) \
...@@ -195,7 +195,6 @@ namespace internal { ...@@ -195,7 +195,6 @@ namespace internal {
F(DebugIsActive, 0, 1) \ F(DebugIsActive, 0, 1) \
F(DebugBreakInOptimizedCode, 0, 1) F(DebugBreakInOptimizedCode, 0, 1)
#define FOR_EACH_INTRINSIC_FORIN(F) \ #define FOR_EACH_INTRINSIC_FORIN(F) \
F(ForInDone, 2, 1) \ F(ForInDone, 2, 1) \
F(ForInEnumerate, 1, 1) \ F(ForInEnumerate, 1, 1) \
......
...@@ -758,7 +758,6 @@ ...@@ -758,7 +758,6 @@
['ignition == True', { ['ignition == True', {
# TODO(yangguo,4690): assertion failures in debugger tests. # TODO(yangguo,4690): assertion failures in debugger tests.
'debug-allscopes-on-debugger': [FAIL], 'debug-allscopes-on-debugger': [FAIL],
'debug-return-value': [FAIL],
'es6/debug-stepnext-for': [FAIL], 'es6/debug-stepnext-for': [FAIL],
'es6/debug-stepin-string-template': [FAIL], 'es6/debug-stepin-string-template': [FAIL],
'es6/debug-promises/stepin-constructor': [FAIL], 'es6/debug-promises/stepin-constructor': [FAIL],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment