}
-void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
- // Patch the code at the current address with the supplied instructions.
- Instr* pc = reinterpret_cast<Instr*>(pc_);
- Instr* instr = reinterpret_cast<Instr*>(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
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;
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}
// blx ip
// <debug break return code entry point address>
// 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(
}
-// 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
// ldr ip, [pc, #0]
// blx ip
// <debug break slot code entry point address>
- 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(
}
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
- DCHECK(IsDebugBreakSlot());
- rinfo()->PatchCode(original_rinfo()->pc(),
- Assembler::kDebugBreakSlotInstructions);
-}
-
-
#define __ ACCESS_MASM(masm)
// 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<Instruction*>(pc_);
Instruction* i2 = i1->following();
return i1->IsLdrLiteralX() && (i1->Rt() == ip0.code()) &&
}
-void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
- // Patch the code at the current address with the supplied instructions.
- Instr* pc = reinterpret_cast<Instr*>(pc_);
- Instr* instr = reinterpret_cast<Instr*>(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);
// 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;
// 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;
#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
// The patching code must not overflow the space occupied by the return
// sequence.
- STATIC_ASSERT(Assembler::kJSRetSequenceInstructions >= 5);
- PatchingAssembler patcher(reinterpret_cast<Instruction*>(rinfo()->pc()), 5);
+ STATIC_ASSERT(Assembler::kJSReturnSequenceInstructions >= 5);
+ PatchingAssembler patcher(reinterpret_cast<Instruction*>(pc()), 5);
byte* entry =
debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry();
}
-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
// The patching code must not overflow the space occupied by the return
// sequence.
STATIC_ASSERT(Assembler::kDebugBreakSlotInstructions >= 4);
- PatchingAssembler patcher(reinterpret_cast<Instruction*>(rinfo()->pc()), 4);
+ PatchingAssembler patcher(reinterpret_cast<Instruction*>(pc()), 4);
byte* entry =
debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry();
}
-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,
// 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
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;
}
template<typename StaticVisitor> 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);
}
-BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> 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.
-}
-
-
-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;
+BreakLocation::Iterator::Iterator(Handle<DebugInfo> 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();
}
-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;
}
// Always update the position as we don't want that to be before the
// statement position.
- position_ = static_cast<int>(
- rinfo()->data() - debug_info_->shared()->start_position());
+ position_ = static_cast<int>(rinfo()->data() -
+ debug_info_->shared()->start_position());
DCHECK(position_ >= 0);
DCHECK(statement_position_ >= 0);
}
position_ = 0;
}
statement_position_ = position_;
- break_point_++;
+ break_index_++;
return;
}
Code* code = Code::GetCodeFromTargetAddress(target);
if (RelocInfo::IsConstructCall(rmode()) || code->is_call_stub()) {
- break_point_++;
+ break_index_++;
return;
}
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<DebugInfo> 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) {
+void BreakLocation::FromAddressSameStatement(Handle<DebugInfo> debug_info,
+ BreakLocatorType type, Address pc,
+ List<BreakLocation>* 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();
+ }
+}
+
+
+int BreakLocation::BreakIndexFromAddress(Handle<DebugInfo> debug_info,
+ BreakLocatorType type, Address pc) {
// Run through all break points to locate the one closest to the address.
- int closest_break_point = 0;
+ int closest_break = 0;
int distance = kMaxInt;
- while (!Done()) {
+ for (Iterator it(debug_info, type); !it.Done(); it.Next()) {
// 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<int>(pc - this->pc());
+ if (it.pc() <= pc && pc - it.pc() < distance) {
+ closest_break = it.break_index();
+ distance = static_cast<int>(pc - it.pc());
// Check whether we can't get any closer.
if (distance == 0) break;
}
- Next();
}
-
- // Move to the break point found.
- Reset();
- Next(closest_break_point);
+ return closest_break;
}
-// Find the break point closest to the supplied source position.
-void BreakLocationIterator::FindBreakLocationFromPosition(int position,
- BreakPositionAlignment alignment) {
+BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> 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<Object> break_point_object) {
+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_, code_position(),
- position(), statement_position(),
- break_point_object);
+ DebugInfo::SetBreakPoint(debug_info_, pc_offset_, position_,
+ statement_position_, break_point_object);
}
-void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
+void BreakLocation::ClearBreakPoint(Handle<Object> 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();
}
-void BreakLocationIterator::SetOneShot() {
+void BreakLocation::SetOneShot() {
// Debugger statement always calls debugger. No need to modify it.
if (IsDebuggerStatement()) return;
}
-void BreakLocationIterator::ClearOneShot() {
+void BreakLocation::ClearOneShot() {
// Debugger statement always calls debugger. No need to modify it.
if (IsDebuggerStatement()) return;
}
-void BreakLocationIterator::SetDebugBreak() {
+void BreakLocation::SetDebugBreak() {
// Debugger statement always calls debugger. No need to modify it.
if (IsDebuggerStatement()) return;
// 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()) {
}
-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<Code> target_code(Code::GetCodeFromTargetAddress(target));
- if (target_code->kind() == Code::STUB) {
- return CodeStub::GetMajorKey(*target_code) == CodeStub::CallFunction;
- }
+ Handle<Code> 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());
}
}
}
-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<Code> target_code(Code::GetCodeFromTargetAddress(target));
+ if (RelocInfo::IsCodeTarget(rmode_)) {
+ Handle<Code> target_code = CodeTarget();
// Patch the code to invoke the builtin debug break function matching the
// calling convention used by the call site.
- Handle<Code> dbgbrk_code = DebugBreakForIC(target_code, mode);
- rinfo()->set_target_address(dbgbrk_code->entry());
+ Handle<Code> 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<Object> BreakLocation::BreakPointObjects() const {
+ return debug_info_->GetBreakPointObjects(pc_offset_);
}
-bool BreakLocationIterator::IsDebuggerStatement() {
- return RelocInfo::DEBUG_BREAK == rmode();
+Handle<Code> BreakLocation::CodeTarget() const {
+ DCHECK(IsCodeTarget());
+ Address target = rinfo().target_address();
+ return Handle<Code>(Code::GetCodeFromTargetAddress(target));
}
-bool BreakLocationIterator::IsDebugBreakSlot() {
- return RelocInfo::DEBUG_BREAK_SLOT == rmode();
+Handle<Code> BreakLocation::OriginalCodeTarget() const {
+ DCHECK(IsCodeTarget());
+ Address target = original_rinfo().target_address();
+ return Handle<Code>(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
}
Handle<DebugInfo> 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_--;
// If there is one or more real break points check whether any of these are
// triggered.
Handle<Object> break_points_hit(heap->undefined_value(), isolate_);
- if (break_location_iterator.HasBreakPoint()) {
- Handle<Object> break_point_objects =
- Handle<Object>(break_location_iterator.BreakPointObjects(), isolate_);
+ if (break_location.HasBreakPoint()) {
+ Handle<Object> break_point_objects = break_location.BreakPointObjects();
break_points_hit = CheckBreakPoints(break_point_objects);
}
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;
PrepareForBreakPoints();
// Obtain shared function info for the function.
- Object* result = FindSharedFunctionInfoInScript(script, *source_position);
+ Handle<Object> result =
+ FindSharedFunctionInfoInScript(script, *source_position);
if (result->IsUndefined()) return false;
// Make sure the function has set up the debug info.
- Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
+ Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result);
if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) {
// Return if retrieving debug info failed.
return false;
DCHECK(position >= 0);
// Find the break point and change it.
- BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
- it.FindBreakLocationFromPosition(position, alignment);
- it.SetBreakPoint(break_point_object);
+ BreakLocation location = BreakLocation::FromPosition(
+ debug_info, SOURCE_BREAK_LOCATIONS, position, alignment);
+ location.SetBreakPoint(break_point_object);
- position = (alignment == STATEMENT_ALIGNED) ? it.statement_position()
- : it.position();
+ position = (alignment == STATEMENT_ALIGNED) ? location.statement_position()
+ : location.position();
*source_position = position + shared->start_position();
DebugInfoListNode* node = debug_info_list_;
while (node != NULL) {
- Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
- break_point_object);
+ Handle<Object> result =
+ DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object);
if (!result->IsUndefined()) {
// Get information in the break point.
- BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
+ Handle<BreakPointInfo> break_point_info =
+ Handle<BreakPointInfo>::cast(result);
Handle<DebugInfo> debug_info = node->debug_info();
// Find the break point and clear it.
- BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
- it.FindBreakLocationFromAddress(debug_info->code()->entry() +
- break_point_info->code_position()->value());
- it.ClearBreakPoint(break_point_object);
+ Address pc = debug_info->code()->entry() +
+ break_point_info->code_position()->value();
+
+ BreakLocation location =
+ BreakLocation::FromAddress(debug_info, SOURCE_BREAK_LOCATIONS, pc);
+ location.ClearBreakPoint(break_point_object);
// If there are no more break points left remove the debug info for this
// function.
}
+// 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() {
- DebugInfoListNode* node = debug_info_list_;
- while (node != NULL) {
- // Remove all debug break code.
- BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
- it.ClearAllDebugBreak();
- node = node->next();
+ for (DebugInfoListNode* node = debug_info_list_; node != NULL;
+ node = node->next()) {
+ for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
+ !it.Done(); it.Next()) {
+ it.GetBreakLocation().ClearDebugBreak();
+ }
}
-
// Remove all debug info.
while (debug_info_list_ != NULL) {
RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info());
}
// Flood the function with break points.
- BreakLocationIterator it(GetDebugInfo(shared), type);
- while (!it.Done()) {
- it.SetOneShot();
- it.Next();
+ for (BreakLocation::Iterator it(GetDebugInfo(shared), type); !it.Done();
+ it.Next()) {
+ it.GetBreakLocation().SetOneShot();
}
}
bool is_load_or_store = false;
bool is_inline_cache_stub = false;
bool is_at_restarted_function = false;
- bool is_exit = false;
- bool is_construct_call = false;
Handle<Code> call_function_stub;
- {
- // Find the break location where execution has stopped.
- DisallowHeapAllocation no_gc;
- BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
-
- // pc points to the instruction after the current one, possibly a break
- // location as well. So the "- 1" to exclude it from the search.
- it.FindBreakLocationFromAddress(frame->pc() - 1);
-
- is_exit = it.IsExit();
- is_construct_call = RelocInfo::IsConstructCall(it.rmode());
-
- if (thread_local_.restarter_frame_function_pointer_ == NULL) {
- if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
- bool is_call_target = false;
- Address target = it.rinfo()->target_address();
- Code* code = Code::GetCodeFromTargetAddress(target);
-
- is_call_target = code->is_call_stub();
- is_inline_cache_stub = code->is_inline_cache_stub();
- is_load_or_store = is_inline_cache_stub && !is_call_target;
-
- // Check if target code is CallFunction stub.
- Code* maybe_call_function_stub = code;
- // If there is a breakpoint at this line look at the original code to
- // check if it is a CallFunction stub.
- if (it.IsDebugBreak()) {
- Address original_target = it.original_rinfo()->target_address();
- maybe_call_function_stub =
- Code::GetCodeFromTargetAddress(original_target);
- }
- if ((maybe_call_function_stub->kind() == Code::STUB &&
- CodeStub::GetMajorKey(maybe_call_function_stub) ==
- CodeStub::CallFunction) ||
- maybe_call_function_stub->is_call_stub()) {
- // Save reference to the code as we may need it to find out arguments
- // count for 'step in' later.
- call_function_stub = Handle<Code>(maybe_call_function_stub);
- }
+ // PC points to the instruction after the current one, possibly a break
+ // location as well. So the "- 1" to exclude it from the search.
+ Address call_pc = frame->pc() - 1;
+ BreakLocation location =
+ BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc);
+
+ if (thread_local_.restarter_frame_function_pointer_ == NULL) {
+ if (location.IsCodeTarget()) {
+ Handle<Code> target_code = location.CodeTarget();
+ is_inline_cache_stub = target_code->is_inline_cache_stub();
+ is_load_or_store = is_inline_cache_stub && !target_code->is_call_stub();
+
+ // Check if target code is CallFunction stub.
+ Handle<Code> maybe_call_function_stub = target_code;
+ // If there is a breakpoint at this line look at the original code to
+ // check if it is a CallFunction stub.
+ if (location.IsDebugBreak()) {
+ maybe_call_function_stub = location.OriginalCodeTarget();
+ }
+ if ((maybe_call_function_stub->kind() == Code::STUB &&
+ CodeStub::GetMajorKey(*maybe_call_function_stub) ==
+ CodeStub::CallFunction) ||
+ maybe_call_function_stub->is_call_stub()) {
+ // Save reference to the code as we may need it to find out arguments
+ // count for 'step in' later.
+ call_function_stub = maybe_call_function_stub;
}
- } else {
- is_at_restarted_function = true;
}
+ } else {
+ is_at_restarted_function = true;
}
// If this is the last break code target step out is the only possibility.
- if (is_exit || step_action == StepOut) {
+ if (location.IsExit() || step_action == StepOut) {
if (step_action == StepOut) {
// Skip step_count frames starting with the current one.
while (step_count-- > 0 && !frames_it.done()) {
frames_it.Advance();
}
} else {
- DCHECK(is_exit);
+ DCHECK(location.IsExit());
frames_it.Advance();
}
// Skip builtin functions on the stack.
// Set target frame pointer.
ActivateStepOut(frames_it.frame());
}
- } else if (!(is_inline_cache_stub || is_construct_call ||
+ } else if (!(is_inline_cache_stub || location.IsConstructCall() ||
!call_function_stub.is_null() || is_at_restarted_function) ||
step_action == StepNext || step_action == StepMin) {
// Step next or step min.
// Step in through CallFunction stub should also be prepared by caller of
// this function (Debug::PrepareStep) which should flood target function
// with breakpoints.
- DCHECK(is_construct_call || is_inline_cache_stub ||
+ DCHECK(location.IsConstructCall() || is_inline_cache_stub ||
!call_function_stub.is_null() || is_at_restarted_function);
ActivateStepIn(frame);
}
// there will be several break points in the same statement when the code is
// flooded with one-shot break points. This function helps to perform several
// steps before reporting break back to the debugger.
-bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
+bool Debug::StepNextContinue(BreakLocation* break_location,
JavaScriptFrame* frame) {
// StepNext and StepOut shouldn't bring us deeper in code, so last frame
// shouldn't be a parent of current frame.
// statement is hit.
if (step_action == StepNext || step_action == StepIn) {
// Never continue if returning from function.
- if (break_location_iterator->IsExit()) return false;
+ if (break_location->IsExit()) return false;
// Continue if we are still on the same frame and in the same statement.
int current_statement_position =
- break_location_iterator->code()->SourceStatementPosition(frame->pc());
+ break_location->code()->SourceStatementPosition(frame->pc());
return thread_local_.last_fp_ == frame->UnpaddedFP() &&
thread_local_.last_statement_position_ == current_statement_position;
}
}
-
-
-
// Simple function for returning the source positions for active break points.
Handle<Object> Debug::GetSourceBreakLocations(
Handle<SharedFunctionInfo> shared,
// The current implementation just runs through all the breakpoints. When the
// last break point for a function is removed that function is automatically
// removed from the list.
-
- DebugInfoListNode* node = debug_info_list_;
- while (node != NULL) {
- BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
- while (!it.Done()) {
- it.ClearOneShot();
- it.Next();
+ for (DebugInfoListNode* node = debug_info_list_; node != NULL;
+ node = node->next()) {
+ for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
+ !it.Done(); it.Next()) {
+ it.GetBreakLocation().ClearOneShot();
}
- node = node->next();
}
}
}
-Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
- int position) {
+Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
+ int position) {
// Iterate the heap looking for SharedFunctionInfo generated from the
// script. The inner most SharedFunctionInfo containing the source position
// for the requested break point is found.
} // End for loop.
} // End no-allocation scope.
- if (target.is_null()) return heap->undefined_value();
+ if (target.is_null()) return isolate_->factory()->undefined_value();
// There will be at least one break point when we are done.
has_break_points_ = true;
MaybeHandle<Code> maybe_result = target_function.is_null()
? Compiler::GetUnoptimizedCode(target)
: Compiler::GetUnoptimizedCode(target_function);
- if (maybe_result.is_null()) return isolate_->heap()->undefined_value();
+ if (maybe_result.is_null()) return isolate_->factory()->undefined_value();
}
} // End while loop.
- return *target;
+ return target;
}
};
-// Class for iterating through the break points in a function and changing
-// them.
-class BreakLocationIterator {
+class BreakLocation {
public:
- explicit BreakLocationIterator(Handle<DebugInfo> debug_info,
- BreakLocatorType type);
- virtual ~BreakLocationIterator();
-
- void Next();
- void Next(int count);
- void FindBreakLocationFromAddress(Address pc);
- void FindBreakLocationFromPosition(int position,
- BreakPositionAlignment alignment);
- void Reset();
- bool Done() const;
+ // Find the break point at the supplied address, or the closest one before
+ // the address.
+ static BreakLocation FromAddress(Handle<DebugInfo> debug_info,
+ BreakLocatorType type, Address pc);
+
+ static void FromAddressSameStatement(Handle<DebugInfo> debug_info,
+ BreakLocatorType type, Address pc,
+ List<BreakLocation>* result_out);
+
+ static BreakLocation FromPosition(Handle<DebugInfo> debug_info,
+ BreakLocatorType type, int position,
+ BreakPositionAlignment alignment);
+
+ bool IsDebugBreak() const;
+ inline bool IsExit() const { return RelocInfo::IsJSReturn(rmode_); }
+ inline bool IsConstructCall() const {
+ return RelocInfo::IsConstructCall(rmode_);
+ }
+ inline bool IsCodeTarget() const { return RelocInfo::IsCodeTarget(rmode_); }
+
+ Handle<Code> CodeTarget() const;
+ Handle<Code> OriginalCodeTarget() const;
+
+ bool IsStepInLocation() const;
+ inline bool HasBreakPoint() const {
+ return debug_info_->HasBreakPoint(pc_offset_);
+ }
+
+ Handle<Object> BreakPointObjects() const;
+
void SetBreakPoint(Handle<Object> break_point_object);
void ClearBreakPoint(Handle<Object> break_point_object);
+
void SetOneShot();
void ClearOneShot();
- bool IsStepInLocation(Isolate* isolate);
- bool IsExit() const;
- bool HasBreakPoint();
- bool IsDebugBreak();
- Object* BreakPointObjects();
- void ClearAllDebugBreak();
-
- inline int code_position() {
- return static_cast<int>(pc() - debug_info_->code()->entry());
- }
- inline int break_point() { return break_point_; }
- inline int position() { return position_; }
- inline int statement_position() { return statement_position_; }
- inline Address pc() { return reloc_iterator_->rinfo()->pc(); }
- inline Code* code() { return debug_info_->code(); }
- inline RelocInfo* rinfo() { return reloc_iterator_->rinfo(); }
- inline RelocInfo::Mode rmode() const {
- return reloc_iterator_->rinfo()->rmode();
+ inline RelocInfo rinfo() const {
+ return RelocInfo(pc(), rmode(), data_, code());
}
- inline RelocInfo* original_rinfo() {
- return reloc_iterator_original_->rinfo();
- }
- inline RelocInfo::Mode original_rmode() const {
- return reloc_iterator_original_->rinfo()->rmode();
+
+ inline RelocInfo original_rinfo() const {
+ return RelocInfo(original_pc(), original_rmode(), original_data_,
+ original_code());
}
- bool IsDebuggerStatement();
+ inline int position() const { return position_; }
+ inline int statement_position() const { return statement_position_; }
- protected:
- bool RinfoDone() const;
- void RinfoNext();
+ inline Address pc() const { return code()->entry() + pc_offset_; }
+ inline Address original_pc() const {
+ return original_code()->entry() + original_pc_offset_;
+ }
- BreakLocatorType type_;
- int break_point_;
- int position_;
- int statement_position_;
- Handle<DebugInfo> debug_info_;
- RelocIterator* reloc_iterator_;
- RelocIterator* reloc_iterator_original_;
+ inline RelocInfo::Mode rmode() const { return rmode_; }
+ inline RelocInfo::Mode original_rmode() const { return original_rmode_; }
+
+ inline Code* code() const { return debug_info_->code(); }
+ inline Code* original_code() const { return debug_info_->original_code(); }
private:
- void SetDebugBreak();
- void ClearDebugBreak();
+ BreakLocation(Handle<DebugInfo> debug_info, RelocInfo* rinfo,
+ RelocInfo* original_rinfo, int position, int statement_position)
+ : debug_info_(debug_info),
+ pc_offset_(static_cast<int>(rinfo->pc() - debug_info->code()->entry())),
+ original_pc_offset_(static_cast<int>(
+ original_rinfo->pc() - debug_info->original_code()->entry())),
+ rmode_(rinfo->rmode()),
+ original_rmode_(original_rinfo->rmode()),
+ data_(rinfo->data()),
+ original_data_(original_rinfo->data()),
+ position_(position),
+ statement_position_(statement_position) {}
+
+ class Iterator {
+ public:
+ Iterator(Handle<DebugInfo> debug_info, BreakLocatorType type);
- void SetDebugBreakAtIC();
- void ClearDebugBreakAtIC();
+ BreakLocation GetBreakLocation() {
+ return BreakLocation(debug_info_, rinfo(), original_rinfo(), position(),
+ statement_position());
+ }
- bool IsDebugBreakAtReturn();
- void SetDebugBreakAtReturn();
- void ClearDebugBreakAtReturn();
+ inline bool Done() const { return RinfoDone(); }
+ void Next();
+
+ void SkipTo(int count) {
+ while (count-- > 0) Next();
+ }
+
+ inline RelocInfo::Mode rmode() { return reloc_iterator_.rinfo()->rmode(); }
+ inline RelocInfo::Mode original_rmode() {
+ return reloc_iterator_.rinfo()->rmode();
+ }
- bool IsDebugBreakSlot();
- bool IsDebugBreakAtSlot();
+ inline RelocInfo* rinfo() { return reloc_iterator_.rinfo(); }
+ inline RelocInfo* original_rinfo() {
+ return reloc_iterator_original_.rinfo();
+ }
+
+ inline Address pc() { return rinfo()->pc(); }
+ inline Address original_pc() { return original_rinfo()->pc(); }
+
+ int break_index() const { return break_index_; }
+
+ inline int position() const { return position_; }
+ inline int statement_position() const { return statement_position_; }
+
+ private:
+ bool RinfoDone() const;
+ void RinfoNext();
+
+ Handle<DebugInfo> debug_info_;
+ BreakLocatorType type_;
+ RelocIterator reloc_iterator_;
+ RelocIterator reloc_iterator_original_;
+ int break_index_;
+ int position_;
+ int statement_position_;
+
+ DisallowHeapAllocation no_gc_;
+
+ DISALLOW_COPY_AND_ASSIGN(Iterator);
+ };
+
+ friend class Debug;
+
+ static int BreakIndexFromAddress(Handle<DebugInfo> debug_info,
+ BreakLocatorType type, Address pc);
+
+ void ClearDebugBreak();
+ void RestoreFromOriginal(int length_in_bytes);
+
+ void SetDebugBreak();
+ void SetDebugBreakAtReturn();
void SetDebugBreakAtSlot();
- void ClearDebugBreakAtSlot();
+ void SetDebugBreakAtIC();
- DISALLOW_COPY_AND_ASSIGN(BreakLocationIterator);
+ inline bool IsDebuggerStatement() const {
+ return RelocInfo::IsDebuggerStatement(rmode_);
+ }
+ inline bool IsDebugBreakSlot() const {
+ return RelocInfo::IsDebugBreakSlot(rmode_);
+ }
+
+ Handle<DebugInfo> debug_info_;
+ int pc_offset_;
+ int original_pc_offset_;
+ RelocInfo::Mode rmode_;
+ RelocInfo::Mode original_rmode_;
+ intptr_t data_;
+ intptr_t original_data_;
+ int position_;
+ int statement_position_;
};
void ClearStepping();
void ClearStepOut();
bool IsStepping() { return thread_local_.step_count_ > 0; }
- bool StepNextContinue(BreakLocationIterator* break_location_iterator,
- JavaScriptFrame* frame);
+ bool StepNextContinue(BreakLocation* location, JavaScriptFrame* frame);
bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
void HandleStepIn(Handle<Object> function_obj, Handle<Object> holder,
Address fp, bool is_constructor);
static bool HasDebugInfo(Handle<SharedFunctionInfo> shared);
// This function is used in FunctionNameUsing* tests.
- Object* FindSharedFunctionInfoInScript(Handle<Script> script, int position);
+ Handle<Object> FindSharedFunctionInfoInScript(Handle<Script> script,
+ int position);
// Returns true if the current stub call is patched to call the debugger.
static bool IsDebugBreak(Address addr);
- // Returns true if the current return statement has been patched to be
- // a debugger breakpoint.
- static bool IsDebugBreakAtReturn(RelocInfo* rinfo);
static Handle<Object> GetSourceBreakLocations(
Handle<SharedFunctionInfo> shared,
}
-void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
- // Patch the code at the current address with the supplied instructions.
- for (int i = 0; i < instruction_count; i++) {
- *(pc_ + i) = *(instructions + i);
- }
-
- // Indicate that code has changed.
- CpuFeatures::FlushICache(pc_, instruction_count);
-}
-
-
// Patch the code at the current PC with a call to the target address.
// Additional guard int3 instructions can be added if required.
void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
namespace v8 {
namespace internal {
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
- return Debug::IsDebugBreakAtReturn(rinfo());
-}
+// Patch the code at the current PC with a call to the target address.
+// Additional guard int3 instructions can be added if required.
+void PatchCodeWithCall(Address pc, Address target, int guard_bytes) {
+ // Call instruction takes up 5 bytes and int3 takes up one byte.
+ static const int kCallCodeSize = 5;
+ int code_size = kCallCodeSize + guard_bytes;
-// Patch the JS frame exit code with a debug break call. See
-// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-ia32.cc
-// for the precise return instructions sequence.
-void BreakLocationIterator::SetDebugBreakAtReturn() {
- DCHECK(Assembler::kJSReturnSequenceLength >=
- Assembler::kCallInstructionLength);
- rinfo()->PatchCodeWithCall(
- debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
- Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
-}
+ // Create a code patcher.
+ CodePatcher patcher(pc, code_size);
+// Add a label for checking the size of the code used for returning.
+#ifdef DEBUG
+ Label check_codesize;
+ patcher.masm()->bind(&check_codesize);
+#endif
-// Restore the JS frame exit code.
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
- rinfo()->PatchCode(original_rinfo()->pc(),
- Assembler::kJSReturnSequenceLength);
-}
+ // Patch the code.
+ patcher.masm()->call(target, RelocInfo::NONE32);
+ // Check that the size of the code generated is as expected.
+ DCHECK_EQ(kCallCodeSize,
+ patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
-// 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();
+ // Add the requested number of int3 instructions after the call.
+ DCHECK_GE(guard_bytes, 0);
+ for (int i = 0; i < guard_bytes; i++) {
+ patcher.masm()->int3();
+ }
+
+ CpuFeatures::FlushICache(pc, code_size);
}
-bool BreakLocationIterator::IsDebugBreakAtSlot() {
- DCHECK(IsDebugBreakSlot());
- // Check whether the debug break slot instructions have been patched.
- return rinfo()->IsPatchedDebugBreakSlotSequence();
+// Patch the JS frame exit code with a debug break call. See
+// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-ia32.cc
+// for the precise return instructions sequence.
+void BreakLocation::SetDebugBreakAtReturn() {
+ DCHECK(Assembler::kJSReturnSequenceLength >=
+ Assembler::kCallInstructionLength);
+ PatchCodeWithCall(
+ pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
+ Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
}
-void BreakLocationIterator::SetDebugBreakAtSlot() {
+void BreakLocation::SetDebugBreakAtSlot() {
DCHECK(IsDebugBreakSlot());
Isolate* isolate = debug_info_->GetIsolate();
- rinfo()->PatchCodeWithCall(
- isolate->builtins()->Slot_DebugBreak()->entry(),
+ PatchCodeWithCall(
+ pc(), isolate->builtins()->Slot_DebugBreak()->entry(),
Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
}
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
- DCHECK(IsDebugBreakSlot());
- rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
-}
-
-
#define __ ACCESS_MASM(masm)
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
// The pc_ offset of 0 assumes mips patched return sequence per
- // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or
- // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot().
+ // debug-mips.cc BreakLocation::SetDebugBreakAtReturn(), or
+ // debug break slot per BreakLocation::SetDebugBreakAtSlot().
return Assembler::target_address_at(pc_, host_);
}
DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
// The pc_ offset of 0 assumes mips patched return sequence per
- // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or
- // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot().
+ // debug-mips.cc BreakLocation::SetDebugBreakAtReturn(), or
+ // debug break slot per BreakLocation::SetDebugBreakAtSlot().
Assembler::set_target_address_at(pc_, host_, target);
if (host() != NULL) {
Object* target_code = Code::GetCodeFromTargetAddress(target);
}
-// Patch the code at the current address with the supplied instructions.
-void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
- Instr* pc = reinterpret_cast<Instr*>(pc_);
- Instr* instr = reinterpret_cast<Instr*>(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_MIPS();
-}
-
-
// -----------------------------------------------------------------------------
// Implementation of Operand and MemOperand.
// See assembler-mips-inl.h for inlined constructors.
// Number of instructions used for the JS return sequence. The constant is
// used by the debugger to patch the JS return sequence.
static const int kJSReturnSequenceInstructions = 7;
+ static const int kJSReturnSequenceLength =
+ kJSReturnSequenceInstructions * kInstrSize;
static const int kDebugBreakSlotInstructions = 4;
static const int kDebugBreakSlotLength =
kDebugBreakSlotInstructions * kInstrSize;
namespace v8 {
namespace internal {
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
- return Debug::IsDebugBreakAtReturn(rinfo());
-}
-
-
-void BreakLocationIterator::SetDebugBreakAtReturn() {
+void BreakLocation::SetDebugBreakAtReturn() {
// Mips return sequence:
// mov sp, fp
// lw fp, sp(0)
// Make sure this constant matches the number if instrucntions we emit.
DCHECK(Assembler::kJSReturnSequenceInstructions == 7);
- CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
+ CodePatcher patcher(pc(), Assembler::kJSReturnSequenceInstructions);
// li and Call pseudo-instructions emit two instructions each.
patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>(
debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry())));
}
-// Restore the JS frame exit code.
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
- rinfo()->PatchCode(original_rinfo()->pc(),
- Assembler::kJSReturnSequenceInstructions);
-}
-
-
-// A debug break in the exit code is identified by the JS frame exit code
-// having been patched with li/call psuedo-instrunction (liu/ori/jalr).
-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:
// nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
// to a call to the debug break slot code.
// li t9, address (lui t9 / ori t9 instruction pair)
// call t9 (jalr t9 / nop instruction pair)
- CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
+ CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions);
patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>(
debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())));
patcher.masm()->Call(v8::internal::t9);
}
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
- DCHECK(IsDebugBreakSlot());
- rinfo()->PatchCode(original_rinfo()->pc(),
- Assembler::kDebugBreakSlotInstructions);
-}
-
-
#define __ ACCESS_MASM(masm)
DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
// The pc_ offset of 0 assumes mips patched return sequence per
- // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or
- // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot().
+ // debug-mips.cc BreakLocation::SetDebugBreakAtReturn(), or
+ // debug break slot per BreakLocation::SetDebugBreakAtSlot().
return Assembler::target_address_at(pc_, host_);
}
DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
// The pc_ offset of 0 assumes mips patched return sequence per
- // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or
- // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot().
+ // debug-mips.cc BreakLocation::SetDebugBreakAtReturn(), or
+ // debug break slot per BreakLocation::SetDebugBreakAtSlot().
Assembler::set_target_address_at(pc_, host_, target);
if (host() != NULL) {
Object* target_code = Code::GetCodeFromTargetAddress(target);
}
-// Patch the code at the current address with the supplied instructions.
-void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
- Instr* pc = reinterpret_cast<Instr*>(pc_);
- Instr* instr = reinterpret_cast<Instr*>(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_MIPS();
-}
-
-
// -----------------------------------------------------------------------------
// Implementation of Operand and MemOperand.
// See assembler-mips-inl.h for inlined constructors.
// Number of instructions used for the JS return sequence. The constant is
// used by the debugger to patch the JS return sequence.
static const int kJSReturnSequenceInstructions = 7;
+ static const int kJSReturnSequenceLength =
+ kJSReturnSequenceInstructions * kInstrSize;
static const int kDebugBreakSlotInstructions = 6;
static const int kDebugBreakSlotLength =
kDebugBreakSlotInstructions * kInstrSize;
namespace v8 {
namespace internal {
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
- return Debug::IsDebugBreakAtReturn(rinfo());
-}
-
-
-void BreakLocationIterator::SetDebugBreakAtReturn() {
+void BreakLocation::SetDebugBreakAtReturn() {
// Mips return sequence:
// mov sp, fp
// lw fp, sp(0)
// Make sure this constant matches the number if instructions we emit.
DCHECK(Assembler::kJSReturnSequenceInstructions == 7);
- CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
+ CodePatcher patcher(pc(), Assembler::kJSReturnSequenceInstructions);
// li and Call pseudo-instructions emit 6 + 2 instructions.
patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int64_t>(
debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry())),
}
-// Restore the JS frame exit code.
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
- rinfo()->PatchCode(original_rinfo()->pc(),
- Assembler::kJSReturnSequenceInstructions);
-}
-
-
-// A debug break in the exit code is identified by the JS frame exit code
-// having been patched with li/call psuedo-instrunction (liu/ori/jalr).
-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:
// nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
// to a call to the debug break slot code.
// li t9, address (4-instruction sequence on mips64)
// call t9 (jalr t9 / nop instruction pair)
- CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
+ CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions);
patcher.masm()->li(v8::internal::t9,
Operand(reinterpret_cast<int64_t>(
debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())),
}
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
- DCHECK(IsDebugBreakSlot());
- rinfo()->PatchCode(original_rinfo()->pc(),
- Assembler::kDebugBreakSlotInstructions);
-}
-
-
#define __ ACCESS_MASM(masm)
// Get the break point objects for a code position.
-Object* DebugInfo::GetBreakPointObjects(int code_position) {
+Handle<Object> DebugInfo::GetBreakPointObjects(int code_position) {
Object* break_point_info = GetBreakPointInfo(code_position);
if (break_point_info->IsUndefined()) {
- return GetHeap()->undefined_value();
+ return GetIsolate()->factory()->undefined_value();
}
- return BreakPointInfo::cast(break_point_info)->break_point_objects();
+ return Handle<Object>(
+ BreakPointInfo::cast(break_point_info)->break_point_objects(),
+ GetIsolate());
}
}
-Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
- Handle<Object> break_point_object) {
- Heap* heap = debug_info->GetHeap();
- if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
- for (int i = 0; i < debug_info->break_points()->length(); i++) {
- if (!debug_info->break_points()->get(i)->IsUndefined()) {
- Handle<BreakPointInfo> break_point_info =
- Handle<BreakPointInfo>(BreakPointInfo::cast(
- debug_info->break_points()->get(i)));
- if (BreakPointInfo::HasBreakPointObject(break_point_info,
- break_point_object)) {
- return *break_point_info;
+Handle<Object> DebugInfo::FindBreakPointInfo(
+ Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
+ Isolate* isolate = debug_info->GetIsolate();
+ if (!debug_info->break_points()->IsUndefined()) {
+ for (int i = 0; i < debug_info->break_points()->length(); i++) {
+ if (!debug_info->break_points()->get(i)->IsUndefined()) {
+ Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
+ BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
+ if (BreakPointInfo::HasBreakPointObject(break_point_info,
+ break_point_object)) {
+ return break_point_info;
+ }
}
}
}
- return heap->undefined_value();
+ return isolate->factory()->undefined_value();
}
int source_position, int statement_position,
Handle<Object> break_point_object);
// Get the break point objects for a code position.
- Object* GetBreakPointObjects(int code_position);
+ Handle<Object> GetBreakPointObjects(int code_position);
// Find the break point info holding this break point object.
- static Object* FindBreakPointInfo(Handle<DebugInfo> debug_info,
- Handle<Object> break_point_object);
+ static Handle<Object> FindBreakPointInfo(Handle<DebugInfo> debug_info,
+ Handle<Object> break_point_object);
// Get the number of break points for this function.
int GetBreakPointCount();
DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
// The pc_ offset of 0 assumes patched return sequence per
- // BreakLocationIterator::SetDebugBreakAtReturn(), or debug break
- // slot per BreakLocationIterator::SetDebugBreakAtSlot().
+ // BreakLocation::SetDebugBreakAtReturn(), or debug break
+ // slot per BreakLocation::SetDebugBreakAtSlot().
return Assembler::target_address_at(pc_, host_);
}
bool RelocInfo::IsPatchedReturnSequence() {
//
// The patched return sequence is defined by
- // BreakLocationIterator::SetDebugBreakAtReturn()
+ // BreakLocation::SetDebugBreakAtReturn()
// FIXED_SEQUENCE
Instr instr0 = Assembler::instr_at(pc_);
}
-void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
- // Patch the code at the current address with the supplied instructions.
- Instr* pc = reinterpret_cast<Instr*>(pc_);
- Instr* instr = reinterpret_cast<Instr*>(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-ppc-inl.h for inlined constructors
// blrl
static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
- // This is the length of the BreakLocationIterator::SetDebugBreakAtReturn()
+ // This is the length of the BreakLocation::SetDebugBreakAtReturn()
// code patch FIXED_SEQUENCE
static const int kJSReturnSequenceInstructions = kMovInstructions + 3;
+ static const int kJSReturnSequenceLength =
+ kJSReturnSequenceInstructions * kInstrSize;
// This is the length of the code sequence from SetDebugBreakAtSlot()
// FIXED_SEQUENCE
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
//
// LeaveFrame
// blrl
// bkpt
//
- CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
+ CodePatcher patcher(pc(), Assembler::kJSReturnSequenceInstructions);
Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm());
patcher.masm()->mov(
v8::internal::r0,
}
-// 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
//
// mtlr r0
// blrl
//
- CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
+ CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions);
Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm());
patcher.masm()->mov(
v8::internal::r0,
}
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
- DCHECK(IsDebugBreakSlot());
- rinfo()->PatchCode(original_rinfo()->pc(),
- Assembler::kDebugBreakSlotInstructions);
-}
-
-
#define __ ACCESS_MASM(masm)
if (!ignore_nested_scopes) {
Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
- // 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;
+
+ // Find the break point where execution has stopped.
+ BreakLocation location =
+ BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc);
// Within the return sequence at the moment it is not possible to
// get a source position which is consistent with the current scope chain.
// Thus all nested with, catch and block contexts are skipped and we only
// provide the function scope.
- ignore_nested_scopes = break_location_iterator.IsExit();
+ ignore_nested_scopes = location.IsExit();
}
if (ignore_nested_scopes) {
Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
- int len = 0;
- Handle<JSArray> array(isolate->factory()->NewJSArray(10));
- // Find the break point where execution has stopped.
- BreakLocationIterator break_location_iterator(debug_info,
- ALL_BREAK_LOCATIONS);
+ // Find range of break points starting from the break point where execution
+ // has stopped.
+ Address call_pc = frame->pc() - 1;
+ List<BreakLocation> locations;
+ BreakLocation::FromAddressSameStatement(debug_info, ALL_BREAK_LOCATIONS,
+ call_pc, &locations);
- break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
- int current_statement_pos = break_location_iterator.statement_position();
+ Handle<JSArray> array = isolate->factory()->NewJSArray(locations.length());
- while (!break_location_iterator.Done()) {
+ int index = 0;
+ for (BreakLocation location : locations) {
bool accept;
- if (break_location_iterator.pc() > frame->pc()) {
+ if (location.pc() > frame->pc()) {
accept = true;
} else {
StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
}
}
if (accept) {
- if (break_location_iterator.IsStepInLocation(isolate)) {
- Smi* position_value = Smi::FromInt(break_location_iterator.position());
+ if (location.IsStepInLocation()) {
+ Smi* position_value = Smi::FromInt(location.position());
RETURN_FAILURE_ON_EXCEPTION(
isolate, JSObject::SetElement(
- array, len, Handle<Object>(position_value, isolate),
+ array, index, Handle<Object>(position_value, isolate),
NONE, SLOPPY));
- len++;
+ index++;
}
}
- // Advance iterator.
- break_location_iterator.Next();
- if (current_statement_pos != break_location_iterator.statement_position()) {
- break;
- }
}
return *array;
}
}
-// -----------------------------------------------------------------------------
-// Implementation of RelocInfo
-
-// Patch the code at the current PC with a call to the target address.
-// Additional guard int3 instructions can be added if required.
-void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
- int code_size = Assembler::kCallSequenceLength + guard_bytes;
-
- // Create a code patcher.
- CodePatcher patcher(pc_, code_size);
-
- // Add a label for checking the size of the code used for returning.
-#ifdef DEBUG
- Label check_codesize;
- patcher.masm()->bind(&check_codesize);
-#endif
-
- // Patch the code.
- patcher.masm()->movp(kScratchRegister, reinterpret_cast<void*>(target),
- Assembler::RelocInfoNone());
- patcher.masm()->call(kScratchRegister);
-
- // Check that the size of the code generated is as expected.
- DCHECK_EQ(Assembler::kCallSequenceLength,
- patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
-
- // Add the requested number of int3 instructions after the call.
- for (int i = 0; i < guard_bytes; i++) {
- patcher.masm()->int3();
- }
-}
-
-
-void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
- // Patch the code at the current address with the supplied instructions.
- for (int i = 0; i < instruction_count; i++) {
- *(pc_ + i) = *(instructions + i);
- }
-
- // Indicate that code has changed.
- CpuFeatures::FlushICache(pc_, instruction_count);
-}
-
-
// -----------------------------------------------------------------------------
// Register constants.
namespace v8 {
namespace internal {
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
- return Debug::IsDebugBreakAtReturn(rinfo());
-}
+// Patch the code at the current PC with a call to the target address.
+// Additional guard int3 instructions can be added if required.
+void PatchCodeWithCall(Address pc, Address target, int guard_bytes) {
+ int code_size = Assembler::kCallSequenceLength + guard_bytes;
+ // Create a code patcher.
+ CodePatcher patcher(pc, code_size);
-// Patch the JS frame exit code with a debug break call. See
-// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x64.cc
-// for the precise return instructions sequence.
-void BreakLocationIterator::SetDebugBreakAtReturn() {
- DCHECK(Assembler::kJSReturnSequenceLength >= Assembler::kCallSequenceLength);
- rinfo()->PatchCodeWithCall(
- debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
- Assembler::kJSReturnSequenceLength - Assembler::kCallSequenceLength);
-}
+// Add a label for checking the size of the code used for returning.
+#ifdef DEBUG
+ Label check_codesize;
+ patcher.masm()->bind(&check_codesize);
+#endif
+ // Patch the code.
+ patcher.masm()->movp(kScratchRegister, reinterpret_cast<void*>(target),
+ Assembler::RelocInfoNone());
+ patcher.masm()->call(kScratchRegister);
-// Restore the JS frame exit code.
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
- rinfo()->PatchCode(original_rinfo()->pc(),
- Assembler::kJSReturnSequenceLength);
-}
+ // Check that the size of the code generated is as expected.
+ DCHECK_EQ(Assembler::kCallSequenceLength,
+ patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
+ // Add the requested number of int3 instructions after the call.
+ for (int i = 0; i < guard_bytes; i++) {
+ patcher.masm()->int3();
+ }
-// 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(v8::internal::RelocInfo* rinfo) {
- DCHECK(RelocInfo::IsJSReturn(rinfo->rmode()));
- return rinfo->IsPatchedReturnSequence();
+ CpuFeatures::FlushICache(pc, code_size);
}
-bool BreakLocationIterator::IsDebugBreakAtSlot() {
- DCHECK(IsDebugBreakSlot());
- // Check whether the debug break slot instructions have been patched.
- return rinfo()->IsPatchedDebugBreakSlotSequence();
+// Patch the JS frame exit code with a debug break call. See
+// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x64.cc
+// for the precise return instructions sequence.
+void BreakLocation::SetDebugBreakAtReturn() {
+ DCHECK(Assembler::kJSReturnSequenceLength >= Assembler::kCallSequenceLength);
+ PatchCodeWithCall(
+ pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
+ Assembler::kJSReturnSequenceLength - Assembler::kCallSequenceLength);
}
-void BreakLocationIterator::SetDebugBreakAtSlot() {
+void BreakLocation::SetDebugBreakAtSlot() {
DCHECK(IsDebugBreakSlot());
- rinfo()->PatchCodeWithCall(
- debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry(),
+ PatchCodeWithCall(
+ pc(), debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry(),
Assembler::kDebugBreakSlotLength - Assembler::kCallSequenceLength);
}
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
- DCHECK(IsDebugBreakSlot());
- rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
-}
-
-
#define __ ACCESS_MASM(masm)
}
-void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
- // Patch the code at the current address with the supplied instructions.
- for (int i = 0; i < instruction_count; i++) {
- *(pc_ + i) = *(instructions + i);
- }
-
- // Indicate that code has changed.
- CpuFeatures::FlushICache(pc_, instruction_count);
-}
-
-
-// Patch the code at the current PC with a call to the target address.
-// Additional guard int3 instructions can be added if required.
-void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
- // Call instruction takes up 5 bytes and int3 takes up one byte.
- static const int kCallCodeSize = 5;
- int code_size = kCallCodeSize + guard_bytes;
-
- // Create a code patcher.
- CodePatcher patcher(pc_, code_size);
-
- // Add a label for checking the size of the code used for returning.
-#ifdef DEBUG
- Label check_codesize;
- patcher.masm()->bind(&check_codesize);
-#endif
-
- // Patch the code.
- patcher.masm()->call(target, RelocInfo::NONE32);
-
- // Check that the size of the code generated is as expected.
- DCHECK_EQ(kCallCodeSize,
- patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
-
- // Add the requested number of int3 instructions after the call.
- DCHECK_GE(guard_bytes, 0);
- for (int i = 0; i < guard_bytes; i++) {
- patcher.masm()->int3();
- }
-}
-
-
// -----------------------------------------------------------------------------
// Implementation of Operand
namespace v8 {
namespace internal {
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
- return Debug::IsDebugBreakAtReturn(rinfo());
-}
+// Patch the code at the current PC with a call to the target address.
+// Additional guard int3 instructions can be added if required.
+void RelocInfo::PatchCodeWithCall(Address pc, Address target, int guard_bytes) {
+ // Call instruction takes up 5 bytes and int3 takes up one byte.
+ static const int kCallCodeSize = 5;
+ int code_size = kCallCodeSize + guard_bytes;
+ // Create a code patcher.
+ CodePatcher patcher(pc, code_size);
-// Patch the JS frame exit code with a debug break call. See
-// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x87.cc
-// for the precise return instructions sequence.
-void BreakLocationIterator::SetDebugBreakAtReturn() {
- DCHECK(Assembler::kJSReturnSequenceLength >=
- Assembler::kCallInstructionLength);
- rinfo()->PatchCodeWithCall(
- debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
- Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
-}
+// Add a label for checking the size of the code used for returning.
+#ifdef DEBUG
+ Label check_codesize;
+ patcher.masm()->bind(&check_codesize);
+#endif
+ // Patch the code.
+ patcher.masm()->call(target, RelocInfo::NONE32);
-// Restore the JS frame exit code.
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
- rinfo()->PatchCode(original_rinfo()->pc(),
- Assembler::kJSReturnSequenceLength);
-}
+ // Check that the size of the code generated is as expected.
+ DCHECK_EQ(kCallCodeSize,
+ patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
+ // Add the requested number of int3 instructions after the call.
+ DCHECK_GE(guard_bytes, 0);
+ for (int i = 0; i < guard_bytes; i++) {
+ patcher.masm()->int3();
+ }
-// 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();
+ CpuFeatures::FlushICache(pc, code_size);
}
-bool BreakLocationIterator::IsDebugBreakAtSlot() {
- DCHECK(IsDebugBreakSlot());
- // Check whether the debug break slot instructions have been patched.
- return rinfo()->IsPatchedDebugBreakSlotSequence();
+// Patch the JS frame exit code with a debug break call. See
+// CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x87.cc
+// for the precise return instructions sequence.
+void BreakLocation::SetDebugBreakAtReturn() {
+ DCHECK(Assembler::kJSReturnSequenceLength >=
+ Assembler::kCallInstructionLength);
+ PatchCodeWithCall(
+ pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
+ Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
}
void BreakLocationIterator::SetDebugBreakAtSlot() {
DCHECK(IsDebugBreakSlot());
Isolate* isolate = debug_info_->GetIsolate();
- rinfo()->PatchCodeWithCall(
- isolate->builtins()->Slot_DebugBreak()->entry(),
+ rinfo().PatchCodeWithCall(
+ pc(), isolate->builtins()->Slot_DebugBreak()->entry(),
Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
}
-void BreakLocationIterator::ClearDebugBreakAtSlot() {
- DCHECK(IsDebugBreakSlot());
- rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
-}
-
-
#define __ ACCESS_MASM(masm)
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
if (RelocInfo::IsCodeTarget(rmode)) {
CHECK(!Debug::IsDebugBreak(it.rinfo()->target_address()));
} else if (RelocInfo::IsJSReturn(rmode)) {
- CHECK(!Debug::IsDebugBreakAtReturn(it.rinfo()));
+ CHECK(!it.rinfo()->IsPatchedReturnSequence());
}
}
}
}
-// Inherit from BreakLocationIterator to get access to protected parts for
-// testing.
-class TestBreakLocationIterator: public v8::internal::BreakLocationIterator {
- public:
- explicit TestBreakLocationIterator(Handle<v8::internal::DebugInfo> debug_info)
- : BreakLocationIterator(debug_info, v8::internal::SOURCE_BREAK_LOCATIONS) {}
- v8::internal::RelocIterator* it() { return reloc_iterator_; }
- v8::internal::RelocIterator* it_original() {
- return reloc_iterator_original_;
- }
-};
-
-
// Compile a function, set a break point and check that the call at the break
// location in the code is the expected debug_break function.
void CheckDebugBreakFunction(DebugLocalContext* env,
const char* source, const char* name,
int position, v8::internal::RelocInfo::Mode mode,
Code* debug_break) {
- v8::internal::Debug* debug = CcTest::i_isolate()->debug();
+ i::Debug* debug = CcTest::i_isolate()->debug();
// Create function and set the break point.
- Handle<v8::internal::JSFunction> fun = v8::Utils::OpenHandle(
- *CompileFunction(env, source, name));
+ Handle<i::JSFunction> fun =
+ v8::Utils::OpenHandle(*CompileFunction(env, source, name));
int bp = SetBreakPoint(fun, position);
// Check that the debug break function is as expected.
- Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
+ Handle<i::SharedFunctionInfo> shared(fun->shared());
CHECK(Debug::HasDebugInfo(shared));
- TestBreakLocationIterator it1(Debug::GetDebugInfo(shared));
- it1.FindBreakLocationFromPosition(position, v8::internal::STATEMENT_ALIGNED);
- v8::internal::RelocInfo::Mode actual_mode = it1.it()->rinfo()->rmode();
- if (actual_mode == v8::internal::RelocInfo::CODE_TARGET_WITH_ID) {
- actual_mode = v8::internal::RelocInfo::CODE_TARGET;
+ i::BreakLocation location = i::BreakLocation::FromPosition(
+ Debug::GetDebugInfo(shared), i::SOURCE_BREAK_LOCATIONS, position,
+ i::STATEMENT_ALIGNED);
+ i::RelocInfo::Mode actual_mode = location.rmode();
+ if (actual_mode == i::RelocInfo::CODE_TARGET_WITH_ID) {
+ actual_mode = i::RelocInfo::CODE_TARGET;
}
CHECK_EQ(mode, actual_mode);
- if (mode != v8::internal::RelocInfo::JS_RETURN) {
- CHECK_EQ(debug_break,
- Code::GetCodeFromTargetAddress(it1.it()->rinfo()->target_address()));
+ if (mode != i::RelocInfo::JS_RETURN) {
+ CHECK_EQ(debug_break, *location.CodeTarget());
} else {
- CHECK(Debug::IsDebugBreakAtReturn(it1.it()->rinfo()));
+ i::RelocInfo rinfo = location.rinfo();
+ CHECK(i::RelocInfo::IsJSReturn(rinfo.rmode()));
+ CHECK(rinfo.IsPatchedReturnSequence());
}
// Clear the break point and check that the debug break function is no longer
ClearBreakPoint(bp);
CHECK(!debug->HasDebugInfo(shared));
CHECK(debug->EnsureDebugInfo(shared, fun));
- TestBreakLocationIterator it2(Debug::GetDebugInfo(shared));
- it2.FindBreakLocationFromPosition(position, v8::internal::STATEMENT_ALIGNED);
- actual_mode = it2.it()->rinfo()->rmode();
- if (actual_mode == v8::internal::RelocInfo::CODE_TARGET_WITH_ID) {
- actual_mode = v8::internal::RelocInfo::CODE_TARGET;
+ location = i::BreakLocation::FromPosition(Debug::GetDebugInfo(shared),
+ i::SOURCE_BREAK_LOCATIONS, position,
+ i::STATEMENT_ALIGNED);
+ actual_mode = location.rmode();
+ if (actual_mode == i::RelocInfo::CODE_TARGET_WITH_ID) {
+ actual_mode = i::RelocInfo::CODE_TARGET;
}
CHECK_EQ(mode, actual_mode);
- if (mode == v8::internal::RelocInfo::JS_RETURN) {
- CHECK(!Debug::IsDebugBreakAtReturn(it2.it()->rinfo()));
+ if (mode == i::RelocInfo::JS_RETURN) {
+ i::RelocInfo rinfo = location.rinfo();
+ CHECK(!rinfo.IsPatchedReturnSequence());
}
}
// Obtain SharedFunctionInfo for the function.
isolate->debug()->PrepareForBreakPoints();
- Object* shared_func_info_ptr =
- isolate->debug()->FindSharedFunctionInfoInScript(i_script, func_pos);
- CHECK(shared_func_info_ptr != CcTest::heap()->undefined_value());
- Handle<SharedFunctionInfo> shared_func_info(
- SharedFunctionInfo::cast(shared_func_info_ptr));
+ Handle<SharedFunctionInfo> shared_func_info =
+ Handle<SharedFunctionInfo>::cast(
+ isolate->debug()->FindSharedFunctionInfoInScript(i_script, func_pos));
// Verify inferred function name.
SmartArrayPointer<char> inferred_name =