| Index: src/debug/debug.cc
|
| diff --git a/src/debug/debug.cc b/src/debug/debug.cc
|
| index 733ea9b02dbb0c9c1dd362645abbd20941a0a401..22a8b49016132f07e9786a3f162d2f5b080cdfcc 100644
|
| --- a/src/debug/debug.cc
|
| +++ b/src/debug/debug.cc
|
| @@ -33,17 +33,6 @@
|
| namespace v8 {
|
| namespace internal {
|
|
|
| -namespace {
|
| -
|
| -inline 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;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| Debug::Debug(Isolate* isolate)
|
| : debug_context_(Handle<Context>()),
|
| event_listener_(Handle<Object>()),
|
| @@ -65,53 +54,135 @@ Debug::Debug(Isolate* isolate)
|
| ThreadInit();
|
| }
|
|
|
| +BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info,
|
| + JavaScriptFrame* frame) {
|
| + FrameSummary summary = FrameSummary::GetFirst(frame);
|
| + int offset = summary.code_offset();
|
| + Handle<AbstractCode> abstract_code = summary.abstract_code();
|
| + if (abstract_code->IsCode()) offset = offset - 1;
|
| + auto it = BreakIterator::GetIterator(debug_info, abstract_code);
|
| + it->SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset));
|
| + return it->GetBreakLocation();
|
| +}
|
|
|
| -static v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) {
|
| - Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
|
| - // Isolate::context() may have been NULL when "script collected" event
|
| - // occured.
|
| - if (context.is_null()) return v8::Local<v8::Context>();
|
| - Handle<Context> native_context(context->native_context());
|
| - return v8::Utils::ToLocal(native_context);
|
| +void BreakLocation::AllAtCurrentStatement(Handle<DebugInfo> debug_info,
|
| + JavaScriptFrame* frame,
|
| + List<BreakLocation>* result_out) {
|
| + FrameSummary summary = FrameSummary::GetFirst(frame);
|
| + int offset = summary.code_offset();
|
| + Handle<AbstractCode> abstract_code = summary.abstract_code();
|
| + if (abstract_code->IsCode()) offset = offset - 1;
|
| + int statement_position;
|
| + {
|
| + auto it = BreakIterator::GetIterator(debug_info, abstract_code);
|
| + it->SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset));
|
| + statement_position = it->statement_position();
|
| + }
|
| + for (auto it = BreakIterator::GetIterator(debug_info, abstract_code);
|
| + !it->Done(); it->Next()) {
|
| + if (it->statement_position() == statement_position) {
|
| + result_out->Add(it->GetBreakLocation());
|
| + }
|
| + }
|
| +}
|
| +
|
| +int BreakLocation::BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info,
|
| + Handle<AbstractCode> abstract_code,
|
| + int offset) {
|
| + // Run through all break points to locate the one closest to the address.
|
| + int closest_break = 0;
|
| + int distance = kMaxInt;
|
| + DCHECK(0 <= offset && offset < abstract_code->Size());
|
| + for (auto it = BreakIterator::GetIterator(debug_info, abstract_code);
|
| + !it->Done(); it->Next()) {
|
| + // Check if this break point is closer that what was previously found.
|
| + if (it->code_offset() <= offset && offset - it->code_offset() < distance) {
|
| + closest_break = it->break_index();
|
| + distance = offset - it->code_offset();
|
| + // Check whether we can't get any closer.
|
| + if (distance == 0) break;
|
| + }
|
| + }
|
| + return closest_break;
|
| }
|
|
|
| -BreakLocation::BreakLocation(Handle<DebugInfo> debug_info, DebugBreakType type,
|
| - int code_offset, int position,
|
| - int statement_position)
|
| - : debug_info_(debug_info),
|
| - code_offset_(code_offset),
|
| - type_(type),
|
| - position_(position),
|
| - statement_position_(statement_position) {}
|
| +bool BreakLocation::HasBreakPoint(Handle<DebugInfo> debug_info) const {
|
| + // First check whether there is a break point with the same source position.
|
| + if (!debug_info->HasBreakPoint(position_)) return false;
|
| + // Then check whether a break point at that source position would have
|
| + // the same code offset. Otherwise it's just a break location that we can
|
| + // step to, but not actually a location where we can put a break point.
|
| + if (abstract_code_->IsCode()) {
|
| + DCHECK_EQ(debug_info->DebugCode(), abstract_code_->GetCode());
|
| + CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS);
|
| + it.SkipToPosition(position_, BREAK_POSITION_ALIGNED);
|
| + return it.code_offset() == code_offset_;
|
| + } else {
|
| + DCHECK(abstract_code_->IsBytecodeArray());
|
| + BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS);
|
| + it.SkipToPosition(position_, BREAK_POSITION_ALIGNED);
|
| + return it.code_offset() == code_offset_;
|
| + }
|
| +}
|
|
|
| -BreakLocation::Iterator* BreakLocation::GetIterator(
|
| - Handle<DebugInfo> debug_info, BreakLocatorType type) {
|
| - if (debug_info->abstract_code()->IsBytecodeArray()) {
|
| - return new BytecodeArrayIterator(debug_info, type);
|
| +std::unique_ptr<BreakIterator> BreakIterator::GetIterator(
|
| + Handle<DebugInfo> debug_info, Handle<AbstractCode> abstract_code,
|
| + BreakLocatorType type) {
|
| + if (abstract_code->IsBytecodeArray()) {
|
| + DCHECK(debug_info->HasDebugBytecodeArray());
|
| + return std::unique_ptr<BreakIterator>(
|
| + new BytecodeArrayBreakIterator(debug_info, type));
|
| } else {
|
| - return new CodeIterator(debug_info, type);
|
| + DCHECK(abstract_code->IsCode());
|
| + DCHECK(debug_info->HasDebugCode());
|
| + return std::unique_ptr<BreakIterator>(
|
| + new CodeBreakIterator(debug_info, type));
|
| }
|
| }
|
|
|
| -BreakLocation::Iterator::Iterator(Handle<DebugInfo> debug_info)
|
| - : debug_info_(debug_info), break_index_(-1) {
|
| +BreakIterator::BreakIterator(Handle<DebugInfo> debug_info,
|
| + BreakLocatorType type)
|
| + : debug_info_(debug_info), break_index_(-1), break_locator_type_(type) {
|
| position_ = debug_info->shared()->start_position();
|
| statement_position_ = position_;
|
| }
|
|
|
| -BreakLocation::CodeIterator::CodeIterator(Handle<DebugInfo> debug_info,
|
| - BreakLocatorType type)
|
| - : Iterator(debug_info),
|
| - reloc_iterator_(debug_info->abstract_code()->GetCode(),
|
| - GetModeMask(type)),
|
| +int BreakIterator::BreakIndexFromPosition(int source_position,
|
| + BreakPositionAlignment alignment) {
|
| + int distance = kMaxInt;
|
| + int closest_break = break_index();
|
| + while (!Done()) {
|
| + int next_position;
|
| + if (alignment == STATEMENT_ALIGNED) {
|
| + next_position = statement_position();
|
| + } else {
|
| + DCHECK(alignment == BREAK_POSITION_ALIGNED);
|
| + next_position = position();
|
| + }
|
| + if (source_position <= next_position &&
|
| + next_position - source_position < distance) {
|
| + closest_break = break_index();
|
| + distance = next_position - source_position;
|
| + // Check whether we can't get any closer.
|
| + if (distance == 0) break;
|
| + }
|
| + Next();
|
| + }
|
| + return closest_break;
|
| +}
|
| +
|
| +CodeBreakIterator::CodeBreakIterator(Handle<DebugInfo> debug_info,
|
| + BreakLocatorType type)
|
| + : BreakIterator(debug_info, type),
|
| + reloc_iterator_(debug_info->DebugCode(), GetModeMask(type)),
|
| source_position_iterator_(
|
| - debug_info->abstract_code()->GetCode()->source_position_table()) {
|
| + debug_info->DebugCode()->source_position_table()) {
|
| // There is at least one break location.
|
| DCHECK(!Done());
|
| Next();
|
| }
|
|
|
| -int BreakLocation::CodeIterator::GetModeMask(BreakLocatorType type) {
|
| +int CodeBreakIterator::GetModeMask(BreakLocatorType type) {
|
| int mask = 0;
|
| mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN);
|
| mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_CALL);
|
| @@ -125,7 +196,7 @@ int BreakLocation::CodeIterator::GetModeMask(BreakLocatorType type) {
|
| return mask;
|
| }
|
|
|
| -void BreakLocation::CodeIterator::Next() {
|
| +void CodeBreakIterator::Next() {
|
| DisallowHeapAllocation no_gc;
|
| DCHECK(!Done());
|
|
|
| @@ -151,40 +222,71 @@ void BreakLocation::CodeIterator::Next() {
|
| break_index_++;
|
| }
|
|
|
| -BreakLocation BreakLocation::CodeIterator::GetBreakLocation() {
|
| - DebugBreakType type;
|
| +DebugBreakType CodeBreakIterator::GetDebugBreakType() {
|
| if (RelocInfo::IsDebugBreakSlotAtReturn(rmode())) {
|
| - type = DEBUG_BREAK_SLOT_AT_RETURN;
|
| + return DEBUG_BREAK_SLOT_AT_RETURN;
|
| } else if (RelocInfo::IsDebugBreakSlotAtCall(rmode())) {
|
| - type = DEBUG_BREAK_SLOT_AT_CALL;
|
| + return DEBUG_BREAK_SLOT_AT_CALL;
|
| } else if (RelocInfo::IsDebugBreakSlotAtTailCall(rmode())) {
|
| - type = isolate()->is_tail_call_elimination_enabled()
|
| + return isolate()->is_tail_call_elimination_enabled()
|
| ? DEBUG_BREAK_SLOT_AT_TAIL_CALL
|
| : DEBUG_BREAK_SLOT_AT_CALL;
|
| } else if (RelocInfo::IsDebuggerStatement(rmode())) {
|
| - type = DEBUGGER_STATEMENT;
|
| + return DEBUGGER_STATEMENT;
|
| } else if (RelocInfo::IsDebugBreakSlot(rmode())) {
|
| - type = DEBUG_BREAK_SLOT;
|
| + return DEBUG_BREAK_SLOT;
|
| } else {
|
| - type = NOT_DEBUG_BREAK;
|
| + return NOT_DEBUG_BREAK;
|
| }
|
| - return BreakLocation(debug_info_, type, code_offset(), position(),
|
| - statement_position());
|
| }
|
|
|
| -BreakLocation::BytecodeArrayIterator::BytecodeArrayIterator(
|
| +void CodeBreakIterator::SkipToPosition(int position,
|
| + BreakPositionAlignment alignment) {
|
| + CodeBreakIterator it(debug_info_, break_locator_type_);
|
| + SkipTo(it.BreakIndexFromPosition(position, alignment));
|
| +}
|
| +
|
| +void CodeBreakIterator::SetDebugBreak() {
|
| + DebugBreakType debug_break_type = GetDebugBreakType();
|
| + if (debug_break_type == DEBUGGER_STATEMENT) return;
|
| + DCHECK(debug_break_type >= DEBUG_BREAK_SLOT);
|
| + Builtins* builtins = isolate()->builtins();
|
| + Handle<Code> target = debug_break_type == DEBUG_BREAK_SLOT_AT_RETURN
|
| + ? builtins->Return_DebugBreak()
|
| + : builtins->Slot_DebugBreak();
|
| + DebugCodegen::PatchDebugBreakSlot(isolate(), rinfo()->pc(), target);
|
| +}
|
| +
|
| +void CodeBreakIterator::ClearDebugBreak() {
|
| + DebugBreakType debug_break_type = GetDebugBreakType();
|
| + if (debug_break_type == DEBUGGER_STATEMENT) return;
|
| + DCHECK(debug_break_type >= DEBUG_BREAK_SLOT);
|
| + DebugCodegen::ClearDebugBreakSlot(isolate(), rinfo()->pc());
|
| +}
|
| +
|
| +bool CodeBreakIterator::IsDebugBreak() {
|
| + DebugBreakType debug_break_type = GetDebugBreakType();
|
| + if (debug_break_type == DEBUGGER_STATEMENT) return false;
|
| + DCHECK(debug_break_type >= DEBUG_BREAK_SLOT);
|
| + return DebugCodegen::DebugBreakSlotIsPatched(rinfo()->pc());
|
| +}
|
| +
|
| +BreakLocation CodeBreakIterator::GetBreakLocation() {
|
| + Handle<AbstractCode> code(AbstractCode::cast(debug_info_->DebugCode()));
|
| + return BreakLocation(code, GetDebugBreakType(), code_offset(), position_);
|
| +}
|
| +
|
| +BytecodeArrayBreakIterator::BytecodeArrayBreakIterator(
|
| Handle<DebugInfo> debug_info, BreakLocatorType type)
|
| - : Iterator(debug_info),
|
| - source_position_iterator_(debug_info->abstract_code()
|
| - ->GetBytecodeArray()
|
| - ->source_position_table()),
|
| - break_locator_type_(type) {
|
| + : BreakIterator(debug_info, type),
|
| + source_position_iterator_(
|
| + debug_info->DebugBytecodeArray()->source_position_table()) {
|
| // There is at least one break location.
|
| DCHECK(!Done());
|
| Next();
|
| }
|
|
|
| -void BreakLocation::BytecodeArrayIterator::Next() {
|
| +void BytecodeArrayBreakIterator::Next() {
|
| DisallowHeapAllocation no_gc;
|
| DCHECK(!Done());
|
| bool first = break_index_ == -1;
|
| @@ -199,7 +301,7 @@ void BreakLocation::BytecodeArrayIterator::Next() {
|
| DCHECK(position_ >= 0);
|
| DCHECK(statement_position_ >= 0);
|
|
|
| - enum DebugBreakType type = GetDebugBreakType();
|
| + DebugBreakType type = GetDebugBreakType();
|
| if (type == NOT_DEBUG_BREAK) continue;
|
|
|
| if (break_locator_type_ == ALL_BREAK_LOCATIONS) break;
|
| @@ -211,9 +313,8 @@ void BreakLocation::BytecodeArrayIterator::Next() {
|
| break_index_++;
|
| }
|
|
|
| -BreakLocation::DebugBreakType
|
| -BreakLocation::BytecodeArrayIterator::GetDebugBreakType() {
|
| - BytecodeArray* bytecode_array = debug_info_->original_bytecode_array();
|
| +DebugBreakType BytecodeArrayBreakIterator::GetDebugBreakType() {
|
| + BytecodeArray* bytecode_array = debug_info_->OriginalBytecodeArray();
|
| interpreter::Bytecode bytecode =
|
| interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
|
|
|
| @@ -234,215 +335,51 @@ BreakLocation::BytecodeArrayIterator::GetDebugBreakType() {
|
| }
|
| }
|
|
|
| -BreakLocation BreakLocation::BytecodeArrayIterator::GetBreakLocation() {
|
| - return BreakLocation(debug_info_, GetDebugBreakType(), code_offset(),
|
| - position(), statement_position());
|
| -}
|
| -
|
| -// Find the break point at the supplied address, or the closest one before
|
| -// the address.
|
| -BreakLocation BreakLocation::FromCodeOffset(Handle<DebugInfo> debug_info,
|
| - int offset) {
|
| - std::unique_ptr<Iterator> it(GetIterator(debug_info));
|
| - it->SkipTo(BreakIndexFromCodeOffset(debug_info, offset));
|
| - return it->GetBreakLocation();
|
| -}
|
| -
|
| -BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info,
|
| - JavaScriptFrame* frame) {
|
| - int code_offset = FrameSummary::GetFirst(frame).code_offset();
|
| - int call_offset =
|
| - CallOffsetFromCodeOffset(code_offset, frame->is_interpreted());
|
| - return FromCodeOffset(debug_info, call_offset);
|
| -}
|
| -
|
| -void BreakLocation::AllForStatementPosition(Handle<DebugInfo> debug_info,
|
| - int statement_position,
|
| - List<BreakLocation>* result_out) {
|
| - for (std::unique_ptr<Iterator> it(GetIterator(debug_info)); !it->Done();
|
| - it->Next()) {
|
| - if (it->statement_position() == statement_position) {
|
| - result_out->Add(it->GetBreakLocation());
|
| - }
|
| - }
|
| -}
|
| -
|
| -int BreakLocation::BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info,
|
| - int offset) {
|
| - // Run through all break points to locate the one closest to the address.
|
| - int closest_break = 0;
|
| - int distance = kMaxInt;
|
| - DCHECK(0 <= offset && offset < debug_info->abstract_code()->Size());
|
| - for (std::unique_ptr<Iterator> it(GetIterator(debug_info)); !it->Done();
|
| - it->Next()) {
|
| - // Check if this break point is closer that what was previously found.
|
| - if (it->code_offset() <= offset && offset - it->code_offset() < distance) {
|
| - closest_break = it->break_index();
|
| - distance = offset - it->code_offset();
|
| - // Check whether we can't get any closer.
|
| - if (distance == 0) break;
|
| - }
|
| - }
|
| - return closest_break;
|
| -}
|
| -
|
| -
|
| -BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info,
|
| - int position,
|
| - BreakPositionAlignment alignment) {
|
| - // Run through all break points to locate the one closest to the source
|
| - // position.
|
| - int distance = kMaxInt;
|
| - std::unique_ptr<Iterator> it(GetIterator(debug_info));
|
| - BreakLocation closest_break = it->GetBreakLocation();
|
| - while (!it->Done()) {
|
| - int next_position;
|
| - if (alignment == STATEMENT_ALIGNED) {
|
| - next_position = it->statement_position();
|
| - } else {
|
| - DCHECK(alignment == BREAK_POSITION_ALIGNED);
|
| - next_position = it->position();
|
| - }
|
| - if (position <= next_position && next_position - position < distance) {
|
| - closest_break = it->GetBreakLocation();
|
| - distance = next_position - position;
|
| - // Check whether we can't get any closer.
|
| - if (distance == 0) break;
|
| - }
|
| - it->Next();
|
| - }
|
| - return closest_break;
|
| -}
|
| -
|
| -
|
| -void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) {
|
| - // If there is not already a real break point here patch code with debug
|
| - // break.
|
| - if (!HasBreakPoint()) SetDebugBreak();
|
| - DCHECK(IsDebugBreak() || IsDebuggerStatement());
|
| - // Set the break point information.
|
| - DebugInfo::SetBreakPoint(debug_info_, position_, statement_position_,
|
| - break_point_object);
|
| -}
|
| -
|
| -
|
| -void BreakLocation::ClearBreakPoint(Handle<Object> break_point_object) {
|
| - // Clear the break point information.
|
| - DebugInfo::ClearBreakPoint(debug_info_, position_, break_point_object);
|
| - // If there are no more break points here remove the debug break.
|
| - if (!HasBreakPoint()) {
|
| - ClearDebugBreak();
|
| - DCHECK(!IsDebugBreak());
|
| - }
|
| -}
|
| -
|
| -
|
| -void BreakLocation::SetOneShot() {
|
| - // Debugger statement always calls debugger. No need to modify it.
|
| - if (IsDebuggerStatement()) return;
|
| -
|
| - // Patch code with debug break.
|
| - SetDebugBreak();
|
| -}
|
| -
|
| -
|
| -void BreakLocation::ClearOneShot() {
|
| - // Debugger statement always calls debugger. No need to modify it.
|
| - if (IsDebuggerStatement()) return;
|
| -
|
| - // If there is a real break point here no more to do.
|
| - if (HasBreakPoint()) {
|
| - DCHECK(IsDebugBreak());
|
| - return;
|
| - }
|
| -
|
| - // Patch code removing debug break.
|
| - ClearDebugBreak();
|
| - DCHECK(!IsDebugBreak());
|
| -}
|
| -
|
| -
|
| -void BreakLocation::SetDebugBreak() {
|
| - // Debugger statement always calls debugger. No need to modify it.
|
| - if (IsDebuggerStatement()) return;
|
| -
|
| - // If there is already a break point here just return. This might happen if
|
| - // the same code is flooded with break points twice. Flooding the same
|
| - // function twice might happen when stepping in a function with an exception
|
| - // handler as the handler and the function is the same.
|
| - if (IsDebugBreak()) return;
|
| -
|
| - DCHECK(IsDebugBreakSlot());
|
| - if (abstract_code()->IsCode()) {
|
| - Code* code = abstract_code()->GetCode();
|
| - DCHECK(code->kind() == Code::FUNCTION);
|
| - Builtins* builtins = isolate()->builtins();
|
| - Handle<Code> target = IsReturn() ? builtins->Return_DebugBreak()
|
| - : builtins->Slot_DebugBreak();
|
| - Address pc = code->instruction_start() + code_offset();
|
| - DebugCodegen::PatchDebugBreakSlot(isolate(), pc, target);
|
| - } else {
|
| - 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());
|
| -}
|
| -
|
| -
|
| -void BreakLocation::ClearDebugBreak() {
|
| - // Debugger statement always calls debugger. No need to modify it.
|
| - if (IsDebuggerStatement()) return;
|
| -
|
| - DCHECK(IsDebugBreakSlot());
|
| - if (abstract_code()->IsCode()) {
|
| - Code* code = abstract_code()->GetCode();
|
| - DCHECK(code->kind() == Code::FUNCTION);
|
| - Address pc = code->instruction_start() + code_offset();
|
| - DebugCodegen::ClearDebugBreakSlot(isolate(), pc);
|
| - } else {
|
| - BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray();
|
| - BytecodeArray* original = debug_info_->original_bytecode_array();
|
| - bytecode_array->set(code_offset(), original->get(code_offset()));
|
| - }
|
| - DCHECK(!IsDebugBreak());
|
| +void BytecodeArrayBreakIterator::SkipToPosition(
|
| + int position, BreakPositionAlignment alignment) {
|
| + BytecodeArrayBreakIterator it(debug_info_, break_locator_type_);
|
| + SkipTo(it.BreakIndexFromPosition(position, alignment));
|
| }
|
|
|
| -
|
| -bool BreakLocation::IsDebugBreak() const {
|
| - if (IsDebuggerStatement()) return false;
|
| - DCHECK(IsDebugBreakSlot());
|
| - if (abstract_code()->IsCode()) {
|
| - Code* code = abstract_code()->GetCode();
|
| - DCHECK(code->kind() == Code::FUNCTION);
|
| - Address pc = code->instruction_start() + code_offset();
|
| - return DebugCodegen::DebugBreakSlotIsPatched(pc);
|
| - } else {
|
| - BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray();
|
| - interpreter::Bytecode bytecode =
|
| - interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
|
| - return interpreter::Bytecodes::IsDebugBreak(bytecode);
|
| - }
|
| +void BytecodeArrayBreakIterator::SetDebugBreak() {
|
| + DebugBreakType debug_break_type = GetDebugBreakType();
|
| + if (debug_break_type == DEBUGGER_STATEMENT) return;
|
| + DCHECK(debug_break_type >= DEBUG_BREAK_SLOT);
|
| + BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray();
|
| + interpreter::Bytecode bytecode =
|
| + interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
|
| + if (interpreter::Bytecodes::IsDebugBreak(bytecode)) return;
|
| + interpreter::Bytecode debugbreak =
|
| + interpreter::Bytecodes::GetDebugBreak(bytecode);
|
| + bytecode_array->set(code_offset(),
|
| + interpreter::Bytecodes::ToByte(debugbreak));
|
| +}
|
| +
|
| +void BytecodeArrayBreakIterator::ClearDebugBreak() {
|
| + DebugBreakType debug_break_type = GetDebugBreakType();
|
| + if (debug_break_type == DEBUGGER_STATEMENT) return;
|
| + DCHECK(debug_break_type >= DEBUG_BREAK_SLOT);
|
| + BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray();
|
| + BytecodeArray* original = debug_info_->OriginalBytecodeArray();
|
| + bytecode_array->set(code_offset(), original->get(code_offset()));
|
| +}
|
| +
|
| +bool BytecodeArrayBreakIterator::IsDebugBreak() {
|
| + DebugBreakType debug_break_type = GetDebugBreakType();
|
| + if (debug_break_type == DEBUGGER_STATEMENT) return false;
|
| + DCHECK(debug_break_type >= DEBUG_BREAK_SLOT);
|
| + BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray();
|
| + interpreter::Bytecode bytecode =
|
| + interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
|
| + return interpreter::Bytecodes::IsDebugBreak(bytecode);
|
| }
|
|
|
| -Handle<Object> BreakLocation::BreakPointObjects() const {
|
| - return debug_info_->GetBreakPointObjects(position_);
|
| +BreakLocation BytecodeArrayBreakIterator::GetBreakLocation() {
|
| + Handle<AbstractCode> code(
|
| + AbstractCode::cast(debug_info_->DebugBytecodeArray()));
|
| + return BreakLocation(code, GetDebugBreakType(), code_offset(), position_);
|
| }
|
|
|
| -bool BreakLocation::HasBreakPoint() const {
|
| - // First check whether there is a break point with the same source position.
|
| - if (!debug_info_->HasBreakPoint(position_)) return false;
|
| - // Then check whether a break point at that source position would have
|
| - // the same code offset. Otherwise it's just a break location that we can
|
| - // step to, but not actually a location where we can put a break point.
|
| - BreakLocation break_point_location = BreakLocation::FromPosition(
|
| - debug_info_, position_, BREAK_POSITION_ALIGNED);
|
| - return break_point_location.code_offset() == code_offset_;
|
| -}
|
|
|
| void DebugFeatureTracker::Track(DebugFeatureTracker::Feature feature) {
|
| uint32_t mask = 1 << feature;
|
| @@ -582,7 +519,7 @@ void Debug::Break(JavaScriptFrame* frame) {
|
| BreakLocation location = BreakLocation::FromFrame(debug_info, frame);
|
|
|
| // Find actual break points, if any, and trigger debug break event.
|
| - Handle<Object> break_points_hit = CheckBreakPoints(&location);
|
| + Handle<Object> break_points_hit = CheckBreakPoints(debug_info, &location);
|
| if (!break_points_hit->IsUndefined(isolate_)) {
|
| // Clear all current stepping setup.
|
| ClearStepping();
|
| @@ -618,7 +555,7 @@ void Debug::Break(JavaScriptFrame* frame) {
|
| step_break = step_break || location.IsReturn() ||
|
| (current_fp != last_fp) ||
|
| (thread_local_.last_statement_position_ !=
|
| - location.abstract_code()->SourceStatementPosition(offset));
|
| + summary.abstract_code()->SourceStatementPosition(offset));
|
| break;
|
| }
|
| case StepFrame:
|
| @@ -641,15 +578,17 @@ void Debug::Break(JavaScriptFrame* frame) {
|
|
|
| // Find break point objects for this location, if any, and evaluate them.
|
| // Return an array of break point objects that evaluated true.
|
| -Handle<Object> Debug::CheckBreakPoints(BreakLocation* location,
|
| +Handle<Object> Debug::CheckBreakPoints(Handle<DebugInfo> debug_info,
|
| + BreakLocation* location,
|
| bool* has_break_points) {
|
| Factory* factory = isolate_->factory();
|
| bool has_break_points_to_check =
|
| - break_points_active_ && location->HasBreakPoint();
|
| + break_points_active_ && location->HasBreakPoint(debug_info);
|
| if (has_break_points) *has_break_points = has_break_points_to_check;
|
| if (!has_break_points_to_check) return factory->undefined_value();
|
|
|
| - Handle<Object> break_point_objects = location->BreakPointObjects();
|
| + Handle<Object> break_point_objects =
|
| + debug_info->GetBreakPointObjects(location->position());
|
| // Count the number of break points hit. If there are multiple break points
|
| // they are in a FixedArray.
|
| Handle<FixedArray> break_points_hit;
|
| @@ -692,15 +631,13 @@ bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) {
|
| // Enter the debugger.
|
| DebugScope debug_scope(this);
|
| if (debug_scope.failed()) return false;
|
| - BreakLocation current_position = BreakLocation::FromFrame(debug_info, frame);
|
| List<BreakLocation> break_locations;
|
| - BreakLocation::AllForStatementPosition(
|
| - debug_info, current_position.statement_position(), &break_locations);
|
| + BreakLocation::AllAtCurrentStatement(debug_info, frame, &break_locations);
|
| bool has_break_points_at_all = false;
|
| for (int i = 0; i < break_locations.length(); i++) {
|
| bool has_break_points;
|
| Handle<Object> check_result =
|
| - CheckBreakPoints(&break_locations[i], &has_break_points);
|
| + CheckBreakPoints(debug_info, &break_locations[i], &has_break_points);
|
| has_break_points_at_all |= has_break_points;
|
| if (has_break_points && !check_result->IsUndefined(isolate_)) return false;
|
| }
|
| @@ -762,15 +699,17 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function,
|
| DCHECK(*source_position >= 0);
|
|
|
| // Find the break point and change it.
|
| - BreakLocation location = BreakLocation::FromPosition(
|
| - debug_info, *source_position, STATEMENT_ALIGNED);
|
| - *source_position = location.statement_position();
|
| - location.SetBreakPoint(break_point_object);
|
| + *source_position =
|
| + FindBreakablePosition(debug_info, *source_position, STATEMENT_ALIGNED);
|
| + DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object);
|
| + // At least one active break point now.
|
| + DCHECK(debug_info->GetBreakPointCount() > 0);
|
|
|
| - feature_tracker()->Track(DebugFeatureTracker::kBreakPoint);
|
| + ClearBreakPoints(debug_info);
|
| + ApplyBreakPoints(debug_info);
|
|
|
| - // At least one active break point now.
|
| - return debug_info->GetBreakPointCount() > 0;
|
| + feature_tracker()->Track(DebugFeatureTracker::kBreakPoint);
|
| + return true;
|
| }
|
|
|
|
|
| @@ -805,64 +744,104 @@ bool Debug::SetBreakPointForScript(Handle<Script> script,
|
| Handle<DebugInfo> debug_info(shared->GetDebugInfo());
|
|
|
| // Find the break point and change it.
|
| - BreakLocation location =
|
| - BreakLocation::FromPosition(debug_info, *source_position, alignment);
|
| - location.SetBreakPoint(break_point_object);
|
| + *source_position =
|
| + FindBreakablePosition(debug_info, *source_position, alignment);
|
| + DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object);
|
| + // At least one active break point now.
|
| + DCHECK(debug_info->GetBreakPointCount() > 0);
|
| +
|
| + ClearBreakPoints(debug_info);
|
| + ApplyBreakPoints(debug_info);
|
|
|
| feature_tracker()->Track(DebugFeatureTracker::kBreakPoint);
|
| + return true;
|
| +}
|
|
|
| - *source_position = (alignment == STATEMENT_ALIGNED)
|
| - ? location.statement_position()
|
| - : location.position();
|
| +int Debug::FindBreakablePosition(Handle<DebugInfo> debug_info,
|
| + int source_position,
|
| + BreakPositionAlignment alignment) {
|
| + int statement_position;
|
| + int position;
|
| + if (debug_info->HasDebugCode()) {
|
| + CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS);
|
| + it.SkipToPosition(source_position, alignment);
|
| + statement_position = it.statement_position();
|
| + position = it.position();
|
| + } else {
|
| + DCHECK(debug_info->HasDebugBytecodeArray());
|
| + BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS);
|
| + it.SkipToPosition(source_position, alignment);
|
| + statement_position = it.statement_position();
|
| + position = it.position();
|
| + }
|
| + return alignment == STATEMENT_ALIGNED ? statement_position : position;
|
| +}
|
|
|
| - // At least one active break point now.
|
| - DCHECK(debug_info->GetBreakPointCount() > 0);
|
| - return true;
|
| +void Debug::ApplyBreakPoints(Handle<DebugInfo> debug_info) {
|
| + DisallowHeapAllocation no_gc;
|
| + if (debug_info->break_points()->IsUndefined(isolate_)) return;
|
| + FixedArray* break_points = debug_info->break_points();
|
| + for (int i = 0; i < break_points->length(); i++) {
|
| + if (break_points->get(i)->IsUndefined(isolate_)) continue;
|
| + BreakPointInfo* info = BreakPointInfo::cast(break_points->get(i));
|
| + if (info->GetBreakPointCount() == 0) continue;
|
| + if (debug_info->HasDebugCode()) {
|
| + CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS);
|
| + it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED);
|
| + it.SetDebugBreak();
|
| + }
|
| + if (debug_info->HasDebugBytecodeArray()) {
|
| + BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS);
|
| + it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED);
|
| + it.SetDebugBreak();
|
| + }
|
| + }
|
| }
|
|
|
| +void Debug::ClearBreakPoints(Handle<DebugInfo> debug_info) {
|
| + DisallowHeapAllocation no_gc;
|
| + if (debug_info->HasDebugCode()) {
|
| + for (CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); !it.Done();
|
| + it.Next()) {
|
| + it.ClearDebugBreak();
|
| + }
|
| + }
|
| + if (debug_info->HasDebugBytecodeArray()) {
|
| + for (BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS);
|
| + !it.Done(); it.Next()) {
|
| + it.ClearDebugBreak();
|
| + }
|
| + }
|
| +}
|
|
|
| void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
|
| HandleScope scope(isolate_);
|
|
|
| - DebugInfoListNode* node = debug_info_list_;
|
| - while (node != NULL) {
|
| + for (DebugInfoListNode* node = debug_info_list_; node != NULL;
|
| + node = node->next()) {
|
| Handle<Object> result =
|
| DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object);
|
| - if (!result->IsUndefined(isolate_)) {
|
| - // Get information in the break point.
|
| - Handle<BreakPointInfo> break_point_info =
|
| - Handle<BreakPointInfo>::cast(result);
|
| - Handle<DebugInfo> debug_info = node->debug_info();
|
| -
|
| - BreakLocation location = BreakLocation::FromPosition(
|
| - debug_info, break_point_info->source_position(),
|
| - BREAK_POSITION_ALIGNED);
|
| - location.ClearBreakPoint(break_point_object);
|
| -
|
| - // If there are no more break points left remove the debug info for this
|
| - // function.
|
| + if (result->IsUndefined(isolate_)) continue;
|
| + Handle<DebugInfo> debug_info = node->debug_info();
|
| + if (DebugInfo::ClearBreakPoint(debug_info, break_point_object)) {
|
| + ClearBreakPoints(debug_info);
|
| if (debug_info->GetBreakPointCount() == 0) {
|
| RemoveDebugInfoAndClearFromShared(debug_info);
|
| + } else {
|
| + ApplyBreakPoints(debug_info);
|
| }
|
| -
|
| return;
|
| }
|
| - node = node->next();
|
| }
|
| }
|
|
|
| -
|
| // Clear out all the debug break code. This is ONLY supposed to be used when
|
| // shutting down the debugger as it will leave the break point information in
|
| // DebugInfo even though the code is patched back to the non break point state.
|
| void Debug::ClearAllBreakPoints() {
|
| for (DebugInfoListNode* node = debug_info_list_; node != NULL;
|
| node = node->next()) {
|
| - for (std::unique_ptr<BreakLocation::Iterator> it(
|
| - BreakLocation::GetIterator(node->debug_info()));
|
| - !it->Done(); it->Next()) {
|
| - it->GetBreakLocation().ClearDebugBreak();
|
| - }
|
| + ClearBreakPoints(node->debug_info());
|
| }
|
| // Remove all debug info.
|
| while (debug_info_list_ != NULL) {
|
| @@ -870,7 +849,6 @@ void Debug::ClearAllBreakPoints() {
|
| }
|
| }
|
|
|
| -
|
| void Debug::FloodWithOneShot(Handle<JSFunction> function,
|
| BreakLocatorType type) {
|
| // Debug utility functions are not subject to debugging.
|
| @@ -892,14 +870,19 @@ void Debug::FloodWithOneShot(Handle<JSFunction> function,
|
|
|
| // Flood the function with break points.
|
| Handle<DebugInfo> debug_info(shared->GetDebugInfo());
|
| - for (std::unique_ptr<BreakLocation::Iterator> it(
|
| - BreakLocation::GetIterator(debug_info, type));
|
| - !it->Done(); it->Next()) {
|
| - it->GetBreakLocation().SetOneShot();
|
| + if (debug_info->HasDebugCode()) {
|
| + for (CodeBreakIterator it(debug_info, type); !it.Done(); it.Next()) {
|
| + it.SetDebugBreak();
|
| + }
|
| + }
|
| + if (debug_info->HasDebugBytecodeArray()) {
|
| + for (BytecodeArrayBreakIterator it(debug_info, type); !it.Done();
|
| + it.Next()) {
|
| + it.SetDebugBreak();
|
| + }
|
| }
|
| }
|
|
|
| -
|
| void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
|
| if (type == BreakUncaughtException) {
|
| break_on_uncaught_exception_ = enable;
|
| @@ -1014,15 +997,7 @@ void Debug::PrepareStep(StepAction step_action) {
|
| }
|
|
|
| Handle<DebugInfo> debug_info(shared->GetDebugInfo());
|
| - // Refresh frame summary if the code has been recompiled for debugging.
|
| - if (AbstractCode::cast(shared->code()) != *summary.abstract_code()) {
|
| - summary = FrameSummary::GetFirst(frame);
|
| - }
|
| -
|
| - int call_offset =
|
| - CallOffsetFromCodeOffset(summary.code_offset(), frame->is_interpreted());
|
| - BreakLocation location =
|
| - BreakLocation::FromCodeOffset(debug_info, call_offset);
|
| + BreakLocation location = BreakLocation::FromFrame(debug_info, frame);
|
|
|
| // Any step at a return is a step-out.
|
| if (location.IsReturn()) step_action = StepOut;
|
| @@ -1030,8 +1005,7 @@ void Debug::PrepareStep(StepAction step_action) {
|
| if (location.IsTailCall() && step_action == StepNext) step_action = StepOut;
|
|
|
| thread_local_.last_statement_position_ =
|
| - debug_info->abstract_code()->SourceStatementPosition(
|
| - summary.code_offset());
|
| + summary.abstract_code()->SourceStatementPosition(summary.code_offset());
|
| thread_local_.last_fp_ = frame->UnpaddedFP();
|
| // No longer perform the current async step.
|
| clear_suspended_generator();
|
| @@ -1076,7 +1050,6 @@ void Debug::PrepareStep(StepAction step_action) {
|
| }
|
| }
|
|
|
| -
|
| // Simple function for returning the source positions for active break points.
|
| Handle<Object> Debug::GetSourceBreakLocations(
|
| Handle<SharedFunctionInfo> shared,
|
| @@ -1100,10 +1073,18 @@ Handle<Object> Debug::GetSourceBreakLocations(
|
| if (break_points == 0) continue;
|
| Smi* position = NULL;
|
| if (position_alignment == STATEMENT_ALIGNED) {
|
| - BreakLocation break_point_location = BreakLocation::FromPosition(
|
| - debug_info, break_point_info->source_position(),
|
| - BREAK_POSITION_ALIGNED);
|
| - position = Smi::FromInt(break_point_location.statement_position());
|
| + if (debug_info->HasDebugCode()) {
|
| + CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS);
|
| + it.SkipToPosition(break_point_info->source_position(),
|
| + BREAK_POSITION_ALIGNED);
|
| + position = Smi::FromInt(it.statement_position());
|
| + } else {
|
| + DCHECK(debug_info->HasDebugBytecodeArray());
|
| + BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS);
|
| + it.SkipToPosition(break_point_info->source_position(),
|
| + BREAK_POSITION_ALIGNED);
|
| + position = Smi::FromInt(it.statement_position());
|
| + }
|
| } else {
|
| DCHECK_EQ(BREAK_POSITION_ALIGNED, position_alignment);
|
| position = Smi::FromInt(break_point_info->source_position());
|
| @@ -1114,7 +1095,6 @@ Handle<Object> Debug::GetSourceBreakLocations(
|
| return locations;
|
| }
|
|
|
| -
|
| void Debug::ClearStepping() {
|
| // Clear the various stepping setup.
|
| ClearOneShot();
|
| @@ -1135,11 +1115,9 @@ void Debug::ClearOneShot() {
|
| // removed from the list.
|
| for (DebugInfoListNode* node = debug_info_list_; node != NULL;
|
| node = node->next()) {
|
| - for (std::unique_ptr<BreakLocation::Iterator> it(
|
| - BreakLocation::GetIterator(node->debug_info()));
|
| - !it->Done(); it->Next()) {
|
| - it->GetBreakLocation().ClearOneShot();
|
| - }
|
| + Handle<DebugInfo> debug_info = node->debug_info();
|
| + ClearBreakPoints(debug_info);
|
| + ApplyBreakPoints(debug_info);
|
| }
|
| }
|
|
|
| @@ -1243,7 +1221,7 @@ class RedirectActiveFunctions : public ThreadVisitor {
|
| InterpretedFrame* interpreted_frame =
|
| reinterpret_cast<InterpretedFrame*>(frame);
|
| BytecodeArray* debug_copy =
|
| - shared_->GetDebugInfo()->abstract_code()->GetBytecodeArray();
|
| + shared_->GetDebugInfo()->DebugBytecodeArray();
|
| interpreted_frame->PatchBytecodeArray(debug_copy);
|
| continue;
|
| }
|
| @@ -1596,10 +1574,8 @@ bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
|
| if (!shared->HasDebugInfo()) return false;
|
|
|
| DCHECK(!frame->is_optimized());
|
| - int code_offset = FrameSummary::GetFirst(frame).code_offset();
|
| Handle<DebugInfo> debug_info(shared->GetDebugInfo());
|
| - BreakLocation location =
|
| - BreakLocation::FromCodeOffset(debug_info, code_offset);
|
| + BreakLocation location = BreakLocation::FromFrame(debug_info, frame);
|
| return location.IsReturn() || location.IsTailCall();
|
| }
|
|
|
| @@ -2430,6 +2406,16 @@ v8::Local<v8::String> MessageImpl::GetJSON() const {
|
| }
|
| }
|
|
|
| +namespace {
|
| +v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) {
|
| + Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
|
| + // Isolate::context() may have been NULL when "script collected" event
|
| + // occured.
|
| + if (context.is_null()) return v8::Local<v8::Context>();
|
| + Handle<Context> native_context(context->native_context());
|
| + return v8::Utils::ToLocal(native_context);
|
| +}
|
| +} // anonymous namespace
|
|
|
| v8::Local<v8::Context> MessageImpl::GetEventContext() const {
|
| Isolate* isolate = event_data_->GetIsolate();
|
|
|