Revert of [Interpreter] Adds support to fetch return value on break at return. (patchset #9 id:160001 of https://codereview.chromium.org/1818873003/ )
Reason for revert: [Sheriff] Seems to break nosnap debug: https://build.chromium.org/p/client.v8/builders/V8%20Linux%20-%20nosnap%20-%20debug/builds/6019 Original issue's description: > [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 > > Committed: https://crrev.com/fb65527b75754bcf3b173f16f5d0b04a1c6d9b99 > Cr-Commit-Position: refs/heads/master@{#35060} TBR=rmcilroy@chromium.org,yangguo@chromium.org,weiliang.lin@intel.com,balazs.kilvady@imgtec.com,jyan@ca.ibm.com,mythria@chromium.org # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=v8:4280, v8:4690 Review URL: https://codereview.chromium.org/1834733002 Cr-Commit-Position: refs/heads/master@{#35065}
This commit is contained in:
parent
2e87c7f5ae
commit
25d2b24771
@ -81,15 +81,9 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
__ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
|
||||
__ push(ip);
|
||||
|
||||
// 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));
|
||||
if (mode == SAVE_RESULT_REGISTER) __ push(r0);
|
||||
|
||||
__ mov(r0, Operand::Zero()); // no arguments
|
||||
__ mov(r1,
|
||||
Operand(ExternalReference(
|
||||
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
|
||||
@ -100,14 +94,12 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
if (FLAG_debug_code) {
|
||||
for (int i = 0; i < kNumJSCallerSaved; i++) {
|
||||
Register reg = {JSCallerSavedCode(i)};
|
||||
// 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));
|
||||
}
|
||||
__ 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.
|
||||
|
||||
|
@ -92,15 +92,9 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
__ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
|
||||
__ Push(scratch);
|
||||
|
||||
// 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);
|
||||
if (mode == SAVE_RESULT_REGISTER) __ Push(x0);
|
||||
|
||||
__ Mov(x0, 0); // No arguments.
|
||||
__ Mov(x1, ExternalReference(Runtime::FunctionForId(Runtime::kDebugBreak),
|
||||
masm->isolate()));
|
||||
|
||||
@ -110,14 +104,13 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
if (FLAG_debug_code) {
|
||||
for (int i = 0; i < kNumJSCallerSaved; i++) {
|
||||
Register reg = Register::XRegFromCode(JSCallerSavedCode(i));
|
||||
// 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));
|
||||
}
|
||||
__ 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.
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#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"
|
||||
@ -473,7 +474,6 @@ void Debug::ThreadInit() {
|
||||
thread_local_.last_fp_ = 0;
|
||||
thread_local_.target_fp_ = 0;
|
||||
thread_local_.step_in_enabled_ = false;
|
||||
thread_local_.return_value_ = Handle<Object>();
|
||||
// TODO(isolates): frames_are_dropped_?
|
||||
base::NoBarrier_Store(&thread_local_.current_debug_scope_,
|
||||
static_cast<base::AtomicWord>(0));
|
||||
@ -560,8 +560,10 @@ void Debug::Unload() {
|
||||
debug_context_ = Handle<Context>();
|
||||
}
|
||||
|
||||
void Debug::Break(JavaScriptFrame* frame) {
|
||||
|
||||
void Debug::Break(Arguments args, JavaScriptFrame* frame) {
|
||||
HandleScope scope(isolate_);
|
||||
DCHECK(args.length() == 0);
|
||||
|
||||
// Initialize LiveEdit.
|
||||
LiveEdit::InitializeThreadLocal(this);
|
||||
@ -1567,11 +1569,25 @@ void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
|
||||
after_break_target_ = NULL;
|
||||
if (!LiveEdit::SetAfterBreakTarget(this)) {
|
||||
// Continue just after the slot.
|
||||
after_break_target_ = frame->pc();
|
||||
Object* Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
|
||||
if (frame->is_interpreted()) {
|
||||
// Find the handler from the original bytecode array.
|
||||
InterpretedFrame* interpreted_frame =
|
||||
reinterpret_cast<InterpretedFrame*>(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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2312,10 +2328,9 @@ DebugScope::DebugScope(Debug* debug)
|
||||
base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
|
||||
reinterpret_cast<base::AtomicWord>(this));
|
||||
|
||||
// Store the previous break id, frame id and return value.
|
||||
// Store the previous break id and frame id.
|
||||
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.
|
||||
@ -2353,7 +2368,6 @@ 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();
|
||||
}
|
||||
|
@ -427,8 +427,8 @@ class Debug {
|
||||
|
||||
// Internal logic
|
||||
bool Load();
|
||||
void Break(JavaScriptFrame* frame);
|
||||
void SetAfterBreakTarget(JavaScriptFrame* frame);
|
||||
void Break(Arguments args, JavaScriptFrame*);
|
||||
Object* SetAfterBreakTarget(JavaScriptFrame* frame);
|
||||
|
||||
// Scripts handling.
|
||||
Handle<FixedArray> GetLoadedScripts();
|
||||
@ -524,11 +524,6 @@ class Debug {
|
||||
StackFrame::Id break_frame_id() { return thread_local_.break_frame_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.
|
||||
Address is_active_address() {
|
||||
return reinterpret_cast<Address>(&is_active_);
|
||||
@ -683,10 +678,6 @@ 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<Object> return_value_;
|
||||
};
|
||||
|
||||
// Storage location for registers when handling debug break calls
|
||||
@ -728,7 +719,6 @@ 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<Object> return_value_; // Previous result.
|
||||
bool failed_; // Did the debug context fail to load?
|
||||
SaveContext save_; // Saves previous context.
|
||||
PostponeInterruptsScope no_termination_exceptons_;
|
||||
|
@ -68,15 +68,9 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
}
|
||||
__ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
|
||||
|
||||
// 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));
|
||||
if (mode == SAVE_RESULT_REGISTER) __ push(eax);
|
||||
|
||||
__ Move(eax, Immediate(0)); // No arguments.
|
||||
__ mov(ebx,
|
||||
Immediate(ExternalReference(
|
||||
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
|
||||
@ -87,14 +81,12 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
if (FLAG_debug_code) {
|
||||
for (int i = 0; i < kNumJSCallerSaved; ++i) {
|
||||
Register reg = {JSCallerSavedCode(i)};
|
||||
// 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));
|
||||
}
|
||||
__ 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);
|
||||
|
@ -77,15 +77,9 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
__ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
|
||||
__ push(at);
|
||||
|
||||
// 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);
|
||||
if (mode == SAVE_RESULT_REGISTER) __ push(v0);
|
||||
|
||||
__ PrepareCEntryArgs(0); // No arguments.
|
||||
__ PrepareCEntryFunction(ExternalReference(
|
||||
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()));
|
||||
|
||||
@ -95,14 +89,12 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
if (FLAG_debug_code) {
|
||||
for (int i = 0; i < kNumJSCallerSaved; i++) {
|
||||
Register reg = {JSCallerSavedCode(i)};
|
||||
// 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);
|
||||
}
|
||||
__ 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.
|
||||
|
||||
|
@ -79,15 +79,9 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
__ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
|
||||
__ push(at);
|
||||
|
||||
// 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);
|
||||
if (mode == SAVE_RESULT_REGISTER) __ push(v0);
|
||||
|
||||
__ PrepareCEntryArgs(0); // No arguments.
|
||||
__ PrepareCEntryFunction(ExternalReference(
|
||||
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()));
|
||||
|
||||
@ -97,14 +91,12 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
if (FLAG_debug_code) {
|
||||
for (int i = 0; i < kNumJSCallerSaved; i++) {
|
||||
Register reg = {JSCallerSavedCode(i)};
|
||||
// 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);
|
||||
}
|
||||
__ 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.
|
||||
|
||||
|
@ -83,15 +83,9 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
__ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
|
||||
__ push(ip);
|
||||
|
||||
// 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));
|
||||
if (mode == SAVE_RESULT_REGISTER) __ push(r3);
|
||||
|
||||
__ mov(r3, Operand::Zero()); // no arguments
|
||||
__ mov(r4,
|
||||
Operand(ExternalReference(
|
||||
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
|
||||
@ -102,14 +96,12 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
if (FLAG_debug_code) {
|
||||
for (int i = 0; i < kNumJSCallerSaved; i++) {
|
||||
Register reg = {JSCallerSavedCode(i)};
|
||||
// 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));
|
||||
}
|
||||
__ 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.
|
||||
|
||||
|
@ -88,15 +88,9 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
__ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
|
||||
__ push(ip);
|
||||
|
||||
// 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));
|
||||
if (mode == SAVE_RESULT_REGISTER) __ push(r2);
|
||||
|
||||
__ mov(r2, Operand::Zero()); // no arguments
|
||||
__ mov(r3,
|
||||
Operand(ExternalReference(
|
||||
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
|
||||
@ -107,14 +101,12 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
if (FLAG_debug_code) {
|
||||
for (int i = 0; i < kNumJSCallerSaved; i++) {
|
||||
Register reg = {JSCallerSavedCode(i)};
|
||||
// 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));
|
||||
}
|
||||
__ 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.
|
||||
|
||||
|
@ -69,15 +69,9 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
}
|
||||
__ Push(Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
|
||||
|
||||
// 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);
|
||||
if (mode == SAVE_RESULT_REGISTER) __ Push(rax);
|
||||
|
||||
__ Set(rax, 0); // No arguments (argc == 0).
|
||||
__ Move(rbx, ExternalReference(Runtime::FunctionForId(Runtime::kDebugBreak),
|
||||
masm->isolate()));
|
||||
|
||||
@ -87,14 +81,12 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
if (FLAG_debug_code) {
|
||||
for (int i = 0; i < kNumJSCallerSaved; ++i) {
|
||||
Register reg = {JSCallerSavedCode(i)};
|
||||
// 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);
|
||||
}
|
||||
__ 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);
|
||||
|
@ -68,15 +68,9 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
}
|
||||
__ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
|
||||
|
||||
// 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));
|
||||
if (mode == SAVE_RESULT_REGISTER) __ push(eax);
|
||||
|
||||
__ Move(eax, Immediate(0)); // No arguments.
|
||||
__ mov(ebx,
|
||||
Immediate(ExternalReference(
|
||||
Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
|
||||
@ -87,14 +81,12 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
|
||||
if (FLAG_debug_code) {
|
||||
for (int i = 0; i < kNumJSCallerSaved; ++i) {
|
||||
Register reg = {JSCallerSavedCode(i)};
|
||||
// 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));
|
||||
}
|
||||
__ 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);
|
||||
|
@ -1485,13 +1485,11 @@ 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* accumulator = __ GetAccumulator(); \
|
||||
Node* original_handler = \
|
||||
__ CallRuntime(Runtime::kDebugBreakOnBytecode, context, accumulator); \
|
||||
__ DispatchToBytecodeHandler(original_handler); \
|
||||
#define DEBUG_BREAK(Name, ...) \
|
||||
void Interpreter::Do##Name(InterpreterAssembler* assembler) { \
|
||||
Node* context = __ GetContext(); \
|
||||
Node* original_handler = __ CallRuntime(Runtime::kDebugBreak, context); \
|
||||
__ DispatchToBytecodeHandler(original_handler); \
|
||||
}
|
||||
DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK);
|
||||
#undef DEBUG_BREAK
|
||||
|
@ -5,13 +5,11 @@
|
||||
#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"
|
||||
|
||||
@ -20,39 +18,11 @@ namespace internal {
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DebugBreak) {
|
||||
SealHandleScope shs(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
|
||||
isolate->debug()->set_return_value(value);
|
||||
|
||||
DCHECK(args.length() == 0);
|
||||
// Get the top-most JavaScript frame.
|
||||
JavaScriptFrameIterator it(isolate);
|
||||
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<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);
|
||||
isolate->debug()->Break(args, it.frame());
|
||||
return isolate->debug()->SetAfterBreakTarget(it.frame());
|
||||
}
|
||||
|
||||
|
||||
@ -621,7 +591,31 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
|
||||
// to the frame information.
|
||||
Handle<Object> return_value = isolate->factory()->undefined_value();
|
||||
if (at_return) {
|
||||
return_value = isolate->debug()->return_value();
|
||||
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<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
|
||||
|
@ -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, 1, 1) \
|
||||
F(DebugBreakOnBytecode, 1, 1) \
|
||||
F(DebugBreak, 0, 1) \
|
||||
F(SetDebugEventListener, 2, 1) \
|
||||
F(ScheduleBreak, 0, 1) \
|
||||
F(DebugGetInternalProperties, 1, 1) \
|
||||
@ -195,6 +195,7 @@ namespace internal {
|
||||
F(DebugIsActive, 0, 1) \
|
||||
F(DebugBreakInOptimizedCode, 0, 1)
|
||||
|
||||
|
||||
#define FOR_EACH_INTRINSIC_FORIN(F) \
|
||||
F(ForInDone, 2, 1) \
|
||||
F(ForInEnumerate, 1, 1) \
|
||||
|
@ -756,6 +756,7 @@
|
||||
['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],
|
||||
|
Loading…
Reference in New Issue
Block a user