From 1a608493e55eacf5c7569e2b1213da42eb0e6207 Mon Sep 17 00:00:00 2001 From: yangguo Date: Wed, 4 Mar 2015 05:15:07 -0800 Subject: [PATCH] Refactor BreakLocationIterator. We now have BreakLocation::Iterator to iterate via RelocIterator, and create a BreakLocation when we are done iterating. The reloc info is stored in BreakLocation in a GC-safe way and instantiated on demand. R=ulan@chromium.org BUG=v8:3924 LOG=N Review URL: https://codereview.chromium.org/967323002 Cr-Commit-Position: refs/heads/master@{#26983} --- src/arm/assembler-arm.cc | 21 - src/arm/assembler-arm.h | 2 + src/arm/debug-arm.cc | 42 +- src/arm64/assembler-arm64-inl.h | 2 +- src/arm64/assembler-arm64.cc | 20 - src/arm64/assembler-arm64.h | 6 +- src/arm64/debug-arm64.cc | 41 +- src/arm64/full-codegen-arm64.cc | 4 +- src/assembler.h | 6 +- src/debug.cc | 521 ++++++++++-------------- src/debug.h | 205 +++++++--- src/ia32/assembler-ia32.cc | 11 - src/ia32/debug-ia32.cc | 73 ++-- src/mips/assembler-mips-inl.h | 8 +- src/mips/assembler-mips.cc | 21 - src/mips/assembler-mips.h | 2 + src/mips/debug-mips.cc | 42 +- src/mips64/assembler-mips64-inl.h | 8 +- src/mips64/assembler-mips64.cc | 21 - src/mips64/assembler-mips64.h | 2 + src/mips64/debug-mips64.cc | 42 +- src/objects.cc | 34 +- src/objects.h | 6 +- src/ppc/assembler-ppc-inl.h | 6 +- src/ppc/assembler-ppc.cc | 21 - src/ppc/assembler-ppc.h | 4 +- src/ppc/debug-ppc.cc | 42 +- src/runtime/runtime-debug.cc | 45 +- src/x64/assembler-x64.cc | 44 -- src/x64/debug-x64.cc | 71 ++-- src/x87/assembler-x87.cc | 42 -- src/x87/debug-x87.cc | 70 ++-- test/cctest/test-debug.cc | 59 ++- test/cctest/test-func-name-inference.cc | 8 +- 34 files changed, 583 insertions(+), 969 deletions(-) diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc index bbc766bed3..b1e664ac26 100644 --- a/src/arm/assembler-arm.cc +++ b/src/arm/assembler-arm.cc @@ -246,27 +246,6 @@ bool RelocInfo::IsInConstantPool() { } -void RelocInfo::PatchCode(byte* instructions, int instruction_count) { - // Patch the code at the current address with the supplied instructions. - Instr* pc = reinterpret_cast(pc_); - Instr* instr = reinterpret_cast(instructions); - for (int i = 0; i < instruction_count; i++) { - *(pc + i) = *(instr + i); - } - - // Indicate that code has changed. - CpuFeatures::FlushICache(pc_, instruction_count * Assembler::kInstrSize); -} - - -// Patch the code at the current PC with a call to the target address. -// Additional guard instructions can be added if required. -void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) { - // Patch the code at the current address with a call to the target. - UNIMPLEMENTED(); -} - - // ----------------------------------------------------------------------------- // Implementation of Operand and MemOperand // See assembler-arm-inl.h for inlined constructors diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h index 721b0bce41..fc143e1741 100644 --- a/src/arm/assembler-arm.h +++ b/src/arm/assembler-arm.h @@ -824,6 +824,8 @@ class Assembler : public AssemblerBase { static const int kPcLoadDelta = 8; static const int kJSReturnSequenceInstructions = 4; + static const int kJSReturnSequenceLength = + kJSReturnSequenceInstructions * kInstrSize; static const int kDebugBreakSlotInstructions = 3; static const int kDebugBreakSlotLength = kDebugBreakSlotInstructions * kInstrSize; diff --git a/src/arm/debug-arm.cc b/src/arm/debug-arm.cc index c9100576d2..d9c25c6588 100644 --- a/src/arm/debug-arm.cc +++ b/src/arm/debug-arm.cc @@ -12,12 +12,7 @@ namespace v8 { namespace internal { -bool BreakLocationIterator::IsDebugBreakAtReturn() { - return Debug::IsDebugBreakAtReturn(rinfo()); -} - - -void BreakLocationIterator::SetDebugBreakAtReturn() { +void BreakLocation::SetDebugBreakAtReturn() { // Patch the code changing the return from JS function sequence from // mov sp, fp // ldmia sp!, {fp, lr} @@ -28,7 +23,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() { // blx ip // // bkpt 0 - CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions); + CodePatcher patcher(pc(), Assembler::kJSReturnSequenceInstructions); patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0)); patcher.masm()->blx(v8::internal::ip); patcher.Emit( @@ -37,29 +32,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() { } -// Restore the JS frame exit code. -void BreakLocationIterator::ClearDebugBreakAtReturn() { - rinfo()->PatchCode(original_rinfo()->pc(), - Assembler::kJSReturnSequenceInstructions); -} - - -// A debug break in the frame exit code is identified by the JS frame exit code -// having been patched with a call instruction. -bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) { - DCHECK(RelocInfo::IsJSReturn(rinfo->rmode())); - return rinfo->IsPatchedReturnSequence(); -} - - -bool BreakLocationIterator::IsDebugBreakAtSlot() { - DCHECK(IsDebugBreakSlot()); - // Check whether the debug break slot instructions have been patched. - return rinfo()->IsPatchedDebugBreakSlotSequence(); -} - - -void BreakLocationIterator::SetDebugBreakAtSlot() { +void BreakLocation::SetDebugBreakAtSlot() { DCHECK(IsDebugBreakSlot()); // Patch the code changing the debug break slot code from // mov r2, r2 @@ -69,7 +42,7 @@ void BreakLocationIterator::SetDebugBreakAtSlot() { // ldr ip, [pc, #0] // blx ip // - CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions); + CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions); patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0)); patcher.masm()->blx(v8::internal::ip); patcher.Emit( @@ -77,13 +50,6 @@ void BreakLocationIterator::SetDebugBreakAtSlot() { } -void BreakLocationIterator::ClearDebugBreakAtSlot() { - DCHECK(IsDebugBreakSlot()); - rinfo()->PatchCode(original_rinfo()->pc(), - Assembler::kDebugBreakSlotInstructions); -} - - #define __ ACCESS_MASM(masm) diff --git a/src/arm64/assembler-arm64-inl.h b/src/arm64/assembler-arm64-inl.h index 4547efef0c..b13635f28e 100644 --- a/src/arm64/assembler-arm64-inl.h +++ b/src/arm64/assembler-arm64-inl.h @@ -838,7 +838,7 @@ bool RelocInfo::IsPatchedReturnSequence() { // The sequence must be: // ldr ip0, [pc, #offset] // blr ip0 - // See arm64/debug-arm64.cc BreakLocationIterator::SetDebugBreakAtReturn(). + // See arm64/debug-arm64.cc BreakLocation::SetDebugBreakAtReturn(). Instruction* i1 = reinterpret_cast(pc_); Instruction* i2 = i1->following(); return i1->IsLdrLiteralX() && (i1->Rt() == ip0.code()) && diff --git a/src/arm64/assembler-arm64.cc b/src/arm64/assembler-arm64.cc index bba78c89e4..93d1d25a6c 100644 --- a/src/arm64/assembler-arm64.cc +++ b/src/arm64/assembler-arm64.cc @@ -188,26 +188,6 @@ bool RelocInfo::IsInConstantPool() { } -void RelocInfo::PatchCode(byte* instructions, int instruction_count) { - // Patch the code at the current address with the supplied instructions. - Instr* pc = reinterpret_cast(pc_); - Instr* instr = reinterpret_cast(instructions); - for (int i = 0; i < instruction_count; i++) { - *(pc + i) = *(instr + i); - } - - // Indicate that code has changed. - CpuFeatures::FlushICache(pc_, instruction_count * kInstructionSize); -} - - -// Patch the code at the current PC with a call to the target address. -// Additional guard instructions can be added if required. -void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) { - UNIMPLEMENTED(); -} - - Register GetAllocatableRegisterThatIsNotOneOf(Register reg1, Register reg2, Register reg3, Register reg4) { CPURegList regs(reg1, reg2, reg3, reg4); diff --git a/src/arm64/assembler-arm64.h b/src/arm64/assembler-arm64.h index 16d027065f..23662ad7a0 100644 --- a/src/arm64/assembler-arm64.h +++ b/src/arm64/assembler-arm64.h @@ -952,7 +952,9 @@ class Assembler : public AssemblerBase { // Number of instructions generated for the return sequence in // FullCodeGenerator::EmitReturnSequence. - static const int kJSRetSequenceInstructions = 7; + static const int kJSReturnSequenceInstructions = 7; + static const int kJSReturnSequenceLength = + kJSReturnSequenceInstructions * kInstructionSize; // Distance between start of patched return sequence and the emitted address // to jump to. static const int kPatchReturnSequenceAddressOffset = 0; @@ -960,7 +962,7 @@ class Assembler : public AssemblerBase { // Number of instructions necessary to be able to later patch it to a call. // See DebugCodegen::GenerateSlot() and - // BreakLocationIterator::SetDebugBreakAtSlot(). + // BreakLocation::SetDebugBreakAtSlot(). static const int kDebugBreakSlotInstructions = 4; static const int kDebugBreakSlotLength = kDebugBreakSlotInstructions * kInstructionSize; diff --git a/src/arm64/debug-arm64.cc b/src/arm64/debug-arm64.cc index dae5a28434..56e3c031ed 100644 --- a/src/arm64/debug-arm64.cc +++ b/src/arm64/debug-arm64.cc @@ -15,12 +15,8 @@ namespace internal { #define __ ACCESS_MASM(masm) -bool BreakLocationIterator::IsDebugBreakAtReturn() { - return Debug::IsDebugBreakAtReturn(rinfo()); -} - -void BreakLocationIterator::SetDebugBreakAtReturn() { +void BreakLocation::SetDebugBreakAtReturn() { // Patch the code emitted by FullCodeGenerator::EmitReturnSequence, changing // the return from JS function sequence from // mov sp, fp @@ -39,8 +35,8 @@ void BreakLocationIterator::SetDebugBreakAtReturn() { // The patching code must not overflow the space occupied by the return // sequence. - STATIC_ASSERT(Assembler::kJSRetSequenceInstructions >= 5); - PatchingAssembler patcher(reinterpret_cast(rinfo()->pc()), 5); + STATIC_ASSERT(Assembler::kJSReturnSequenceInstructions >= 5); + PatchingAssembler patcher(reinterpret_cast(pc()), 5); byte* entry = debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(); @@ -59,27 +55,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() { } -void BreakLocationIterator::ClearDebugBreakAtReturn() { - // Reset the code emitted by EmitReturnSequence to its original state. - rinfo()->PatchCode(original_rinfo()->pc(), - Assembler::kJSRetSequenceInstructions); -} - - -bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) { - DCHECK(RelocInfo::IsJSReturn(rinfo->rmode())); - return rinfo->IsPatchedReturnSequence(); -} - - -bool BreakLocationIterator::IsDebugBreakAtSlot() { - DCHECK(IsDebugBreakSlot()); - // Check whether the debug break slot instructions have been patched. - return rinfo()->IsPatchedDebugBreakSlotSequence(); -} - - -void BreakLocationIterator::SetDebugBreakAtSlot() { +void BreakLocation::SetDebugBreakAtSlot() { // Patch the code emitted by DebugCodegen::GenerateSlots, changing the debug // break slot code from // mov x0, x0 @ nop DEBUG_BREAK_NOP @@ -99,7 +75,7 @@ void BreakLocationIterator::SetDebugBreakAtSlot() { // The patching code must not overflow the space occupied by the return // sequence. STATIC_ASSERT(Assembler::kDebugBreakSlotInstructions >= 4); - PatchingAssembler patcher(reinterpret_cast(rinfo()->pc()), 4); + PatchingAssembler patcher(reinterpret_cast(pc()), 4); byte* entry = debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry(); @@ -117,13 +93,6 @@ void BreakLocationIterator::SetDebugBreakAtSlot() { } -void BreakLocationIterator::ClearDebugBreakAtSlot() { - DCHECK(IsDebugBreakSlot()); - rinfo()->PatchCode(original_rinfo()->pc(), - Assembler::kDebugBreakSlotInstructions); -} - - static void Generate_DebugBreakCallHelper(MacroAssembler* masm, RegList object_regs, RegList non_object_regs, diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index e168028b48..97bfb80ae0 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -456,10 +456,10 @@ void FullCodeGenerator::EmitReturnSequence() { // Make sure that the constant pool is not emitted inside of the return // sequence. This sequence can get patched when the debugger is used. See - // debug-arm64.cc:BreakLocationIterator::SetDebugBreakAtReturn(). + // debug-arm64.cc:BreakLocation::SetDebugBreakAtReturn(). { InstructionAccurateScope scope(masm_, - Assembler::kJSRetSequenceInstructions); + Assembler::kJSReturnSequenceInstructions); CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); __ RecordJSReturn(); // This code is generated using Assembler methods rather than Macro diff --git a/src/assembler.h b/src/assembler.h index eb00f8a7e6..9e6311dafd 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -476,6 +476,9 @@ class RelocInfo { static inline bool IsDebugBreakSlot(Mode mode) { return mode == DEBUG_BREAK_SLOT; } + static inline bool IsDebuggerStatement(Mode mode) { + return mode == DEBUG_BREAK; + } static inline bool IsNone(Mode mode) { return mode == NONE32 || mode == NONE64; } @@ -595,9 +598,6 @@ class RelocInfo { template inline void Visit(Heap* heap); inline void Visit(Isolate* isolate, ObjectVisitor* v); - // Patch the code with some other code. - void PatchCode(byte* instructions, int instruction_count); - // Patch the code with a call. void PatchCodeWithCall(Address target, int guard_bytes); diff --git a/src/debug.cc b/src/debug.cc index ea402ffa3d..0cd20ad5b1 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -60,47 +60,29 @@ static v8::Handle GetDebugEventContext(Isolate* isolate) { } -BreakLocationIterator::BreakLocationIterator(Handle debug_info, - BreakLocatorType type) { - debug_info_ = debug_info; - type_ = type; - reloc_iterator_ = NULL; - reloc_iterator_original_ = NULL; - Reset(); // Initialize the rest of the member variables. +BreakLocation::Iterator::Iterator(Handle debug_info, + BreakLocatorType type) + : debug_info_(debug_info), + type_(type), + reloc_iterator_(debug_info->code(), + ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)), + reloc_iterator_original_( + debug_info->original_code(), + ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)), + break_index_(-1), + position_(1), + statement_position_(1) { + Next(); } -BreakLocationIterator::~BreakLocationIterator() { - DCHECK(reloc_iterator_ != NULL); - DCHECK(reloc_iterator_original_ != NULL); - delete reloc_iterator_; - delete reloc_iterator_original_; -} - - -// Check whether a code stub with the specified major key is a possible break -// point location when looking for source break locations. -static bool IsSourceBreakStub(Code* code) { - CodeStub::Major major_key = CodeStub::GetMajorKey(code); - return major_key == CodeStub::CallFunction; -} - - -// Check whether a code stub with the specified major key is a possible break -// location. -static bool IsBreakStub(Code* code) { - CodeStub::Major major_key = CodeStub::GetMajorKey(code); - return major_key == CodeStub::CallFunction; -} - - -void BreakLocationIterator::Next() { +void BreakLocation::Iterator::Next() { DisallowHeapAllocation no_gc; DCHECK(!RinfoDone()); // Iterate through reloc info for code and original code stopping at each // breakable code target. - bool first = break_point_ == -1; + bool first = break_index_ == -1; while (!RinfoDone()) { if (!first) RinfoNext(); first = false; @@ -115,8 +97,8 @@ void BreakLocationIterator::Next() { } // Always update the position as we don't want that to be before the // statement position. - position_ = static_cast( - rinfo()->data() - debug_info_->shared()->start_position()); + position_ = static_cast(rinfo()->data() - + debug_info_->shared()->start_position()); DCHECK(position_ >= 0); DCHECK(statement_position_ >= 0); } @@ -131,7 +113,7 @@ void BreakLocationIterator::Next() { position_ = 0; } statement_position_ = position_; - break_point_++; + break_index_++; return; } @@ -143,7 +125,7 @@ void BreakLocationIterator::Next() { Code* code = Code::GetCodeFromTargetAddress(target); if (RelocInfo::IsConstructCall(rmode()) || code->is_call_stub()) { - break_point_++; + break_index_++; return; } @@ -152,144 +134,117 @@ void BreakLocationIterator::Next() { if ((code->is_inline_cache_stub() && !code->is_binary_op_stub() && !code->is_compare_ic_stub() && !code->is_to_boolean_ic_stub())) { - break_point_++; + break_index_++; return; } if (code->kind() == Code::STUB) { - if (IsDebuggerStatement()) { - break_point_++; + if (RelocInfo::IsDebuggerStatement(rmode())) { + break_index_++; + return; + } else if (CodeStub::GetMajorKey(code) == CodeStub::CallFunction) { + break_index_++; return; - } else if (type_ == ALL_BREAK_LOCATIONS) { - if (IsBreakStub(code)) { - break_point_++; - return; - } - } else { - DCHECK(type_ == SOURCE_BREAK_LOCATIONS); - if (IsSourceBreakStub(code)) { - break_point_++; - return; - } } } } - if (IsDebugBreakSlot() && type_ != CALLS_AND_RETURNS) { + if (RelocInfo::IsDebugBreakSlot(rmode()) && type_ != CALLS_AND_RETURNS) { // There is always a possible break point at a debug break slot. - break_point_++; + break_index_++; return; } } } -void BreakLocationIterator::Next(int count) { - while (count > 0) { - Next(); - count--; - } +// Find the break point at the supplied address, or the closest one before +// the address. +BreakLocation BreakLocation::FromAddress(Handle debug_info, + BreakLocatorType type, Address pc) { + Iterator it(debug_info, type); + it.SkipTo(BreakIndexFromAddress(debug_info, type, pc)); + return it.GetBreakLocation(); } // Find the break point at the supplied address, or the closest one before // the address. -void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) { - // Run through all break points to locate the one closest to the address. - int closest_break_point = 0; - int distance = kMaxInt; - while (!Done()) { - // Check if this break point is closer that what was previously found. - if (this->pc() <= pc && pc - this->pc() < distance) { - closest_break_point = break_point(); - distance = static_cast(pc - this->pc()); - // Check whether we can't get any closer. - if (distance == 0) break; - } - Next(); +void BreakLocation::FromAddressSameStatement(Handle debug_info, + BreakLocatorType type, Address pc, + List* result_out) { + int break_index = BreakIndexFromAddress(debug_info, type, pc); + Iterator it(debug_info, type); + it.SkipTo(break_index); + int statement_position = it.statement_position(); + while (!it.Done() && it.statement_position() == statement_position) { + result_out->Add(it.GetBreakLocation()); + it.Next(); } - - // Move to the break point found. - Reset(); - Next(closest_break_point); } -// Find the break point closest to the supplied source position. -void BreakLocationIterator::FindBreakLocationFromPosition(int position, - BreakPositionAlignment alignment) { +int BreakLocation::BreakIndexFromAddress(Handle debug_info, + BreakLocatorType type, Address pc) { + // Run through all break points to locate the one closest to the address. + int closest_break = 0; + int distance = kMaxInt; + for (Iterator it(debug_info, type); !it.Done(); it.Next()) { + // Check if this break point is closer that what was previously found. + if (it.pc() <= pc && pc - it.pc() < distance) { + closest_break = it.break_index(); + distance = static_cast(pc - it.pc()); + // Check whether we can't get any closer. + if (distance == 0) break; + } + } + return closest_break; +} + + +BreakLocation BreakLocation::FromPosition(Handle debug_info, + BreakLocatorType type, int position, + BreakPositionAlignment alignment) { // Run through all break points to locate the one closest to the source // position. - int closest_break_point = 0; + int closest_break = 0; int distance = kMaxInt; - while (!Done()) { + for (Iterator it(debug_info, type); !it.Done(); it.Next()) { int next_position; - switch (alignment) { - case STATEMENT_ALIGNED: - next_position = this->statement_position(); - break; - case BREAK_POSITION_ALIGNED: - next_position = this->position(); - break; - default: - UNREACHABLE(); - next_position = this->statement_position(); + if (alignment == STATEMENT_ALIGNED) { + next_position = it.statement_position(); + } else { + DCHECK(alignment == BREAK_POSITION_ALIGNED); + next_position = it.position(); } - // Check if this break point is closer that what was previously found. if (position <= next_position && next_position - position < distance) { - closest_break_point = break_point(); + closest_break = it.break_index(); distance = next_position - position; // Check whether we can't get any closer. if (distance == 0) break; } - Next(); } - // Move to the break point found. - Reset(); - Next(closest_break_point); + Iterator it(debug_info, type); + it.SkipTo(closest_break); + return it.GetBreakLocation(); } -void BreakLocationIterator::Reset() { - // Create relocation iterators for the two code objects. - if (reloc_iterator_ != NULL) delete reloc_iterator_; - if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_; - reloc_iterator_ = new RelocIterator( - debug_info_->code(), - ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)); - reloc_iterator_original_ = new RelocIterator( - debug_info_->original_code(), - ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)); - - // Position at the first break point. - break_point_ = -1; - position_ = 1; - statement_position_ = 1; - Next(); -} - - -bool BreakLocationIterator::Done() const { - return RinfoDone(); -} - - -void BreakLocationIterator::SetBreakPoint(Handle break_point_object) { +void BreakLocation::SetBreakPoint(Handle 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_, code_position(), - position(), statement_position(), - break_point_object); + DebugInfo::SetBreakPoint(debug_info_, pc_offset_, position_, + statement_position_, break_point_object); } -void BreakLocationIterator::ClearBreakPoint(Handle break_point_object) { +void BreakLocation::ClearBreakPoint(Handle break_point_object) { // Clear the break point information. - DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object); + DebugInfo::ClearBreakPoint(debug_info_, pc_offset_, break_point_object); // If there are no more break points here remove the debug break. if (!HasBreakPoint()) { ClearDebugBreak(); @@ -298,7 +253,7 @@ void BreakLocationIterator::ClearBreakPoint(Handle break_point_object) { } -void BreakLocationIterator::SetOneShot() { +void BreakLocation::SetOneShot() { // Debugger statement always calls debugger. No need to modify it. if (IsDebuggerStatement()) return; @@ -313,7 +268,7 @@ void BreakLocationIterator::SetOneShot() { } -void BreakLocationIterator::ClearOneShot() { +void BreakLocation::ClearOneShot() { // Debugger statement always calls debugger. No need to modify it. if (IsDebuggerStatement()) return; @@ -329,7 +284,7 @@ void BreakLocationIterator::ClearOneShot() { } -void BreakLocationIterator::SetDebugBreak() { +void BreakLocation::SetDebugBreak() { // Debugger statement always calls debugger. No need to modify it. if (IsDebuggerStatement()) return; @@ -339,7 +294,7 @@ void BreakLocationIterator::SetDebugBreak() { // handler as the handler and the function is the same. if (IsDebugBreak()) return; - if (RelocInfo::IsJSReturn(rmode())) { + if (IsExit()) { // Patch the frame exit code with a break point. SetDebugBreakAtReturn(); } else if (IsDebugBreakSlot()) { @@ -353,59 +308,48 @@ void BreakLocationIterator::SetDebugBreak() { } -void BreakLocationIterator::ClearDebugBreak() { +void BreakLocation::ClearDebugBreak() { // Debugger statement always calls debugger. No need to modify it. if (IsDebuggerStatement()) return; - if (RelocInfo::IsJSReturn(rmode())) { - // Restore the frame exit code. - ClearDebugBreakAtReturn(); + if (IsExit()) { + // Restore the frame exit code with a break point. + RestoreFromOriginal(Assembler::kJSReturnSequenceLength); } else if (IsDebugBreakSlot()) { // Restore the code in the break slot. - ClearDebugBreakAtSlot(); + RestoreFromOriginal(Assembler::kDebugBreakSlotLength); } else { - // Patch the IC call. - ClearDebugBreakAtIC(); + // Restore the IC call. + rinfo().set_target_address(original_rinfo().target_address()); } DCHECK(!IsDebugBreak()); } -bool BreakLocationIterator::IsStepInLocation(Isolate* isolate) { - if (RelocInfo::IsConstructCall(original_rmode())) { - return true; - } else if (RelocInfo::IsCodeTarget(rmode())) { +void BreakLocation::RestoreFromOriginal(int length_in_bytes) { + memcpy(pc(), original_pc(), length_in_bytes); + CpuFeatures::FlushICache(pc(), length_in_bytes); +} + + +bool BreakLocation::IsStepInLocation() const { + if (IsConstructCall()) return true; + if (RelocInfo::IsCodeTarget(rmode())) { HandleScope scope(debug_info_->GetIsolate()); - Address target = original_rinfo()->target_address(); - Handle target_code(Code::GetCodeFromTargetAddress(target)); - if (target_code->kind() == Code::STUB) { - return CodeStub::GetMajorKey(*target_code) == CodeStub::CallFunction; - } + Handle target_code = CodeTarget(); return target_code->is_call_stub(); } return false; } -// Check whether the break point is at a position which will exit the function. -bool BreakLocationIterator::IsExit() const { - return (RelocInfo::IsJSReturn(rmode())); -} - - -bool BreakLocationIterator::HasBreakPoint() { - return debug_info_->HasBreakPoint(code_position()); -} - - -// Check whether there is a debug break at the current position. -bool BreakLocationIterator::IsDebugBreak() { - if (RelocInfo::IsJSReturn(rmode())) { - return IsDebugBreakAtReturn(); +bool BreakLocation::IsDebugBreak() const { + if (IsExit()) { + return rinfo().IsPatchedReturnSequence(); } else if (IsDebugBreakSlot()) { - return IsDebugBreakAtSlot(); + return rinfo().IsPatchedDebugBreakSlotSequence(); } else { - return Debug::IsDebugBreak(rinfo()->target_address()); + return Debug::IsDebugBreak(rinfo().target_address()); } } @@ -457,70 +401,53 @@ static Handle DebugBreakForIC(Handle code, RelocInfo::Mode mode) { } -void BreakLocationIterator::SetDebugBreakAtIC() { +void BreakLocation::SetDebugBreakAtIC() { // Patch the original code with the current address as the current address // might have changed by the inline caching since the code was copied. - original_rinfo()->set_target_address(rinfo()->target_address()); + original_rinfo().set_target_address(rinfo().target_address()); - RelocInfo::Mode mode = rmode(); - if (RelocInfo::IsCodeTarget(mode)) { - Address target = rinfo()->target_address(); - Handle target_code(Code::GetCodeFromTargetAddress(target)); + if (RelocInfo::IsCodeTarget(rmode_)) { + Handle target_code = CodeTarget(); // Patch the code to invoke the builtin debug break function matching the // calling convention used by the call site. - Handle dbgbrk_code = DebugBreakForIC(target_code, mode); - rinfo()->set_target_address(dbgbrk_code->entry()); + Handle debug_break_code = DebugBreakForIC(target_code, rmode_); + rinfo().set_target_address(debug_break_code->entry()); } } -void BreakLocationIterator::ClearDebugBreakAtIC() { - // Patch the code to the original invoke. - rinfo()->set_target_address(original_rinfo()->target_address()); +Handle BreakLocation::BreakPointObjects() const { + return debug_info_->GetBreakPointObjects(pc_offset_); } -bool BreakLocationIterator::IsDebuggerStatement() { - return RelocInfo::DEBUG_BREAK == rmode(); +Handle BreakLocation::CodeTarget() const { + DCHECK(IsCodeTarget()); + Address target = rinfo().target_address(); + return Handle(Code::GetCodeFromTargetAddress(target)); } -bool BreakLocationIterator::IsDebugBreakSlot() { - return RelocInfo::DEBUG_BREAK_SLOT == rmode(); +Handle BreakLocation::OriginalCodeTarget() const { + DCHECK(IsCodeTarget()); + Address target = original_rinfo().target_address(); + return Handle(Code::GetCodeFromTargetAddress(target)); } -Object* BreakLocationIterator::BreakPointObjects() { - return debug_info_->GetBreakPointObjects(code_position()); +bool BreakLocation::Iterator::RinfoDone() const { + DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done()); + return reloc_iterator_.done(); } -// 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 BreakLocationIterator::ClearAllDebugBreak() { - while (!Done()) { - ClearDebugBreak(); - Next(); - } -} - - -bool BreakLocationIterator::RinfoDone() const { - DCHECK(reloc_iterator_->done() == reloc_iterator_original_->done()); - return reloc_iterator_->done(); -} - - -void BreakLocationIterator::RinfoNext() { - reloc_iterator_->next(); - reloc_iterator_original_->next(); +void BreakLocation::Iterator::RinfoNext() { + reloc_iterator_.next(); + reloc_iterator_original_.next(); #ifdef DEBUG - DCHECK(reloc_iterator_->done() == reloc_iterator_original_->done()); - if (!reloc_iterator_->done()) { - DCHECK(rmode() == original_rmode()); - } + DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done()); + DCHECK(reloc_iterator_.done() || rmode() == original_rmode()); #endif } @@ -854,14 +781,14 @@ void Debug::Break(Arguments args, JavaScriptFrame* frame) { Handle debug_info = GetDebugInfo(shared); // Find the break point where execution has stopped. - BreakLocationIterator break_location_iterator(debug_info, - ALL_BREAK_LOCATIONS); - // pc points to the instruction after the current one, possibly a break + // PC points to the instruction after the current one, possibly a break // location as well. So the "- 1" to exclude it from the search. - break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); + Address call_pc = frame->pc() - 1; + BreakLocation break_location = + BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); // Check whether step next reached a new statement. - if (!StepNextContinue(&break_location_iterator, frame)) { + if (!StepNextContinue(&break_location, frame)) { // Decrease steps left if performing multiple steps. if (thread_local_.step_count_ > 0) { thread_local_.step_count_--; @@ -871,9 +798,8 @@ void Debug::Break(Arguments args, JavaScriptFrame* frame) { // If there is one or more real break points check whether any of these are // triggered. Handle break_points_hit(heap->undefined_value(), isolate_); - if (break_location_iterator.HasBreakPoint()) { - Handle break_point_objects = - Handle(break_location_iterator.BreakPointObjects(), isolate_); + if (break_location.HasBreakPoint()) { + Handle break_point_objects = break_location.BreakPointObjects(); break_points_hit = CheckBreakPoints(break_point_objects); } @@ -1058,11 +984,10 @@ bool Debug::SetBreakPoint(Handle function, DCHECK(*source_position >= 0); // Find the break point and change it. - BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS); - it.FindBreakLocationFromPosition(*source_position, STATEMENT_ALIGNED); - it.SetBreakPoint(break_point_object); - - *source_position = it.statement_position(); + BreakLocation location = BreakLocation::FromPosition( + debug_info, SOURCE_BREAK_LOCATIONS, *source_position, STATEMENT_ALIGNED); + *source_position = location.statement_position(); + location.SetBreakPoint(break_point_object); // At least one active break point now. return debug_info->GetBreakPointCount() > 0; @@ -1078,11 +1003,12 @@ bool Debug::SetBreakPointForScript(Handle