| Index: src/debug/debug.cc
|
| diff --git a/src/debug/debug.cc b/src/debug/debug.cc
|
| index e6e579baaf214f2ffe528956638c0a57cf786f05..06da2f8cbe2f0ed9f32c4ab5f84dacffc077b288 100644
|
| --- a/src/debug/debug.cc
|
| +++ b/src/debug/debug.cc
|
| @@ -17,6 +17,7 @@
|
| #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"
|
| #include "src/log.h"
|
| @@ -193,10 +194,12 @@ void BreakLocation::BytecodeArrayIterator::Next() {
|
| DCHECK(statement_position_ >= 0);
|
| break_index_++;
|
|
|
| + enum DebugBreakType type = GetDebugBreakType();
|
| + if (type == NOT_DEBUG_BREAK) continue;
|
| +
|
| if (break_locator_type_ == ALL_BREAK_LOCATIONS) break;
|
|
|
| DCHECK_EQ(CALLS_AND_RETURNS, break_locator_type_);
|
| - enum DebugBreakType type = GetDebugBreakType();
|
| if (type == DEBUG_BREAK_SLOT_AT_CALL ||
|
| type == DEBUG_BREAK_SLOT_AT_RETURN) {
|
| break;
|
| @@ -206,10 +209,9 @@ void BreakLocation::BytecodeArrayIterator::Next() {
|
|
|
| BreakLocation::DebugBreakType
|
| BreakLocation::BytecodeArrayIterator::GetDebugBreakType() {
|
| - BytecodeArray* bytecode_array =
|
| - debug_info_->abstract_code()->GetBytecodeArray();
|
| + BytecodeArray* bytecode_array = debug_info_->original_bytecode_array();
|
| interpreter::Bytecode bytecode =
|
| - static_cast<interpreter::Bytecode>(bytecode_array->get(code_offset()));
|
| + interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
|
|
|
| if (bytecode == interpreter::Bytecode::kDebugger) {
|
| return DEBUGGER_STATEMENT;
|
| @@ -238,20 +240,25 @@ BreakLocation BreakLocation::FromCodeOffset(Handle<DebugInfo> debug_info,
|
| return it->GetBreakLocation();
|
| }
|
|
|
| -// Move GetFirstFrameSummary Definition to here as FromFrame use it.
|
| FrameSummary GetFirstFrameSummary(JavaScriptFrame* frame) {
|
| List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
|
| frame->Summarize(&frames);
|
| return frames.first();
|
| }
|
|
|
| +int CallOffsetFromCodeOffset(int code_offset, bool is_interpreted) {
|
| + // Code offset points to the instruction after the call. Subtract 1 to
|
| + // exclude that instruction from the search. For bytecode, the code offset
|
| + // still points to the call.
|
| + return is_interpreted ? code_offset : code_offset - 1;
|
| +}
|
| +
|
| BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info,
|
| JavaScriptFrame* frame) {
|
| - // Code offset to the instruction after the current one, possibly a break
|
| - // location as well. So the "- 1" to exclude it from the search.
|
| - // Get code offset from the unoptimized code.
|
| FrameSummary summary = GetFirstFrameSummary(frame);
|
| - return FromCodeOffset(debug_info, summary.code_offset() - 1);
|
| + int call_offset =
|
| + CallOffsetFromCodeOffset(summary.code_offset(), frame->is_interpreted());
|
| + return FromCodeOffset(debug_info, call_offset);
|
| }
|
|
|
| // Find the break point at the supplied address, or the closest one before
|
| @@ -400,10 +407,16 @@ void BreakLocation::SetDebugBreak() {
|
| : builtins->Slot_DebugBreak();
|
| Address pc = code->instruction_start() + code_offset();
|
| DebugCodegen::PatchDebugBreakSlot(isolate(), pc, target);
|
| - DCHECK(IsDebugBreak());
|
| } else {
|
| - // TODO(yangguo): implement this once we have a way to record break points.
|
| + BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray();
|
| + interpreter::Bytecode bytecode =
|
| + interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
|
| + interpreter::Bytecode debugbreak =
|
| + interpreter::Bytecodes::GetDebugBreak(bytecode);
|
| + bytecode_array->set(code_offset(),
|
| + interpreter::Bytecodes::ToByte(debugbreak));
|
| }
|
| + DCHECK(IsDebugBreak());
|
| }
|
|
|
|
|
| @@ -417,10 +430,12 @@ void BreakLocation::ClearDebugBreak() {
|
| DCHECK(code->kind() == Code::FUNCTION);
|
| Address pc = code->instruction_start() + code_offset();
|
| DebugCodegen::ClearDebugBreakSlot(isolate(), pc);
|
| - DCHECK(!IsDebugBreak());
|
| } else {
|
| - // TODO(yangguo): implement this once we have a way to record break points.
|
| + BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray();
|
| + BytecodeArray* original = debug_info_->original_bytecode_array();
|
| + bytecode_array->set(code_offset(), original->get(code_offset()));
|
| }
|
| + DCHECK(!IsDebugBreak());
|
| }
|
|
|
|
|
| @@ -433,8 +448,10 @@ bool BreakLocation::IsDebugBreak() const {
|
| Address pc = code->instruction_start() + code_offset();
|
| return DebugCodegen::DebugBreakSlotIsPatched(pc);
|
| } else {
|
| - // TODO(yangguo): implement this once we have a way to record break points.
|
| - return false;
|
| + BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray();
|
| + interpreter::Bytecode bytecode =
|
| + interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
|
| + return interpreter::Bytecodes::IsDebugBreak(bytecode);
|
| }
|
| }
|
|
|
| @@ -999,10 +1016,10 @@ void Debug::PrepareStep(StepAction step_action) {
|
| summary = GetFirstFrameSummary(frame);
|
| }
|
|
|
| - // PC points to the instruction after the current one, possibly a break
|
| - // location as well. So the "- 1" to exclude it from the search.
|
| + int call_offset =
|
| + CallOffsetFromCodeOffset(summary.code_offset(), frame->is_interpreted());
|
| BreakLocation location =
|
| - BreakLocation::FromCodeOffset(debug_info, summary.code_offset() - 1);
|
| + BreakLocation::FromCodeOffset(debug_info, call_offset);
|
|
|
| // At a return statement we will step out either way.
|
| if (location.IsReturn()) step_action = StepOut;
|
| @@ -1523,7 +1540,7 @@ void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) {
|
| prev->set_next(current->next());
|
| }
|
| delete current;
|
| - shared->set_debug_info(isolate_->heap()->undefined_value());
|
| + shared->set_debug_info(DebugInfo::uninitialized());
|
| return;
|
| }
|
| // Move to next in list.
|
| @@ -1534,14 +1551,25 @@ void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) {
|
| UNREACHABLE();
|
| }
|
|
|
| -
|
| -void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
|
| - after_break_target_ = NULL;
|
| -
|
| - if (LiveEdit::SetAfterBreakTarget(this)) return; // LiveEdit did the job.
|
| -
|
| - // 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);
|
| + } else {
|
| + after_break_target_ = NULL;
|
| + if (!LiveEdit::SetAfterBreakTarget(this)) {
|
| + // Continue just after the slot.
|
| + after_break_target_ = frame->pc();
|
| + }
|
| + return isolate_->heap()->undefined_value();
|
| + }
|
| }
|
|
|
|
|
| @@ -1623,10 +1651,8 @@ void Debug::GetStepinPositions(JavaScriptFrame* frame, StackFrame::Id frame_id,
|
| summary = GetFirstFrameSummary(frame);
|
| }
|
|
|
| - // Find range of break points starting from the break point where execution
|
| - // has stopped. The code offset points to the instruction after the current
|
| - // possibly a break location, too. Subtract one to exclude it from the search.
|
| - int call_offset = summary.code_offset() - 1;
|
| + int call_offset =
|
| + CallOffsetFromCodeOffset(summary.code_offset(), frame->is_interpreted());
|
| List<BreakLocation> locations;
|
| BreakLocation::FromCodeOffsetSameStatement(debug_info, call_offset,
|
| &locations);
|
|
|