Chromium Code Reviews| Index: src/debug/debug.cc |
| diff --git a/src/debug/debug.cc b/src/debug/debug.cc |
| index 733ea9b02dbb0c9c1dd362645abbd20941a0a401..3d239129315e5730cf5bbc2a0fdf935264ff7449 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,133 @@ 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()) { |
| + CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); |
| + it.SkipToPosition(position_, BREAK_POSITION_ALIGNED); |
| + return it.code_offset() == code_offset_; |
| + } else { |
|
jgruber
2016/08/11 14:28:13
Is abstract_code_->IsByteCodeArray() at this point
Yang
2016/08/12 05:33:46
Done. Not sure what kind of DCHECKs you had in min
|
| + 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 +194,7 @@ int BreakLocation::CodeIterator::GetModeMask(BreakLocatorType type) { |
| return mask; |
| } |
| -void BreakLocation::CodeIterator::Next() { |
| +void CodeBreakIterator::Next() { |
| DisallowHeapAllocation no_gc; |
| DCHECK(!Done()); |
| @@ -151,40 +220,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 +299,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 +311,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 +333,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 +517,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 +553,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 +576,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 +629,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 +697,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 +742,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 +847,6 @@ void Debug::ClearAllBreakPoints() { |
| } |
| } |
| - |
| void Debug::FloodWithOneShot(Handle<JSFunction> function, |
| BreakLocatorType type) { |
| // Debug utility functions are not subject to debugging. |
| @@ -892,14 +868,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 +995,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 +1003,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 +1048,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 +1071,17 @@ 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 { |
|
jgruber
2016/08/11 14:28:13
Same here.
Yang
2016/08/12 05:33:46
Done.
|
| + 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 +1092,6 @@ Handle<Object> Debug::GetSourceBreakLocations( |
| return locations; |
| } |
| - |
| void Debug::ClearStepping() { |
| // Clear the various stepping setup. |
| ClearOneShot(); |
| @@ -1135,11 +1112,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); |
|
jgruber
2016/08/11 14:28:13
Why are breakpoints reapplied here?
Yang
2016/08/12 05:33:46
Because having a function flooded with one-shots m
|
| } |
| } |
| @@ -1243,7 +1218,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 +1571,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 +2403,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(); |