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(); |