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}
This commit is contained in:
yangguo 2015-03-04 05:15:07 -08:00 committed by Commit bot
parent efe828e699
commit 1a608493e5
34 changed files with 583 additions and 969 deletions

View File

@ -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<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

View File

@ -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;

View File

@ -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
// <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(
@ -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
// <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(
@ -77,13 +50,6 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
}
void BreakLocationIterator::ClearDebugBreakAtSlot() {
DCHECK(IsDebugBreakSlot());
rinfo()->PatchCode(original_rinfo()->pc(),
Assembler::kDebugBreakSlotInstructions);
}
#define __ ACCESS_MASM(masm)

View File

@ -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<Instruction*>(pc_);
Instruction* i2 = i1->following();
return i1->IsLdrLiteralX() && (i1->Rt() == ip0.code()) &&

View File

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

View File

@ -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;

View File

@ -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<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();
@ -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<Instruction*>(rinfo()->pc()), 4);
PatchingAssembler patcher(reinterpret_cast<Instruction*>(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,

View File

@ -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

View File

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

View File

@ -60,47 +60,29 @@ static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) {
}
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.
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();
}
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<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);
}
@ -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 (type_ == ALL_BREAK_LOCATIONS) {
if (IsBreakStub(code)) {
break_point_++;
} else if (CodeStub::GetMajorKey(code) == CodeStub::CallFunction) {
break_index_++;
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.
void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
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 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,
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();
@ -298,7 +253,7 @@ void BreakLocationIterator::ClearBreakPoint(Handle<Object> 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())) {
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;
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());
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());
}
}
@ -457,70 +401,53 @@ static Handle<Code> DebugBreakForIC(Handle<Code> 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<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
}
@ -854,14 +781,14 @@ void Debug::Break(Arguments args, JavaScriptFrame* frame) {
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_--;
@ -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<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);
}
@ -1058,11 +984,10 @@ bool Debug::SetBreakPoint(Handle<JSFunction> 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<Script> script,
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;
@ -1102,12 +1028,12 @@ bool Debug::SetBreakPointForScript(Handle<Script> script,
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();
@ -1122,18 +1048,21 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
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.
@ -1148,15 +1077,17 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
}
// 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());
@ -1179,10 +1110,9 @@ void Debug::FloodWithOneShot(Handle<JSFunction> function,
}
// 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();
}
}
@ -1341,64 +1271,49 @@ void Debug::PrepareStep(StepAction step_action,
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
// 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());
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 (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;
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.
Code* maybe_call_function_stub = code;
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 (it.IsDebugBreak()) {
Address original_target = it.original_rinfo()->target_address();
maybe_call_function_stub =
Code::GetCodeFromTargetAddress(original_target);
if (location.IsDebugBreak()) {
maybe_call_function_stub = location.OriginalCodeTarget();
}
if ((maybe_call_function_stub->kind() == Code::STUB &&
CodeStub::GetMajorKey(maybe_call_function_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);
call_function_stub = maybe_call_function_stub;
}
}
} 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.
@ -1415,7 +1330,7 @@ void Debug::PrepareStep(StepAction step_action,
// 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.
@ -1511,7 +1426,7 @@ void Debug::PrepareStep(StepAction step_action,
// 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);
}
@ -1524,7 +1439,7 @@ void Debug::PrepareStep(StepAction step_action,
// 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.
@ -1543,11 +1458,11 @@ bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
// 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;
}
@ -1565,9 +1480,6 @@ bool Debug::IsDebugBreak(Address addr) {
}
// Simple function for returning the source positions for active break points.
Handle<Object> Debug::GetSourceBreakLocations(
Handle<SharedFunctionInfo> shared,
@ -1655,15 +1567,12 @@ void Debug::ClearOneShot() {
// 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();
}
}
@ -2080,7 +1989,7 @@ void Debug::PrepareForBreakPoints() {
}
Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
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
@ -2164,7 +2073,7 @@ Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
} // 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;
@ -2180,11 +2089,11 @@ Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
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;
}

View File

@ -66,83 +66,161 @@ enum BreakPositionAlignment {
};
// 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();
// 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);
void Next();
void Next(int count);
void FindBreakLocationFromAddress(Address pc);
void FindBreakLocationFromPosition(int position,
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);
void Reset();
bool Done() const;
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 RelocInfo rinfo() const {
return RelocInfo(pc(), rmode(), data_, code());
}
inline int code_position() {
return static_cast<int>(pc() - debug_info_->code()->entry());
inline RelocInfo original_rinfo() const {
return RelocInfo(original_pc(), original_rmode(), original_data_,
original_code());
}
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 int position() const { return position_; }
inline int statement_position() const { return statement_position_; }
inline Address pc() const { return code()->entry() + pc_offset_; }
inline Address original_pc() const {
return original_code()->entry() + original_pc_offset_;
}
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:
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);
BreakLocation GetBreakLocation() {
return BreakLocation(debug_info_, rinfo(), original_rinfo(), position(),
statement_position());
}
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();
}
inline RelocInfo* rinfo() { return reloc_iterator_.rinfo(); }
inline RelocInfo* original_rinfo() {
return reloc_iterator_original_->rinfo();
}
inline RelocInfo::Mode original_rmode() const {
return reloc_iterator_original_->rinfo()->rmode();
return reloc_iterator_original_.rinfo();
}
bool IsDebuggerStatement();
inline Address pc() { return rinfo()->pc(); }
inline Address original_pc() { return original_rinfo()->pc(); }
protected:
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_;
int break_point_;
RelocIterator reloc_iterator_;
RelocIterator reloc_iterator_original_;
int break_index_;
int position_;
int statement_position_;
Handle<DebugInfo> debug_info_;
RelocIterator* reloc_iterator_;
RelocIterator* reloc_iterator_original_;
private:
void SetDebugBreak();
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 SetDebugBreakAtIC();
void ClearDebugBreakAtIC();
bool IsDebugBreakAtReturn();
void SetDebugBreak();
void SetDebugBreakAtReturn();
void ClearDebugBreakAtReturn();
bool IsDebugBreakSlot();
bool IsDebugBreakAtSlot();
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_;
};
@ -403,8 +481,7 @@ class Debug {
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);
@ -422,13 +499,11 @@ class Debug {
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,

View File

@ -179,17 +179,6 @@ bool RelocInfo::IsInConstantPool() {
}
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) {

View File

@ -13,60 +13,61 @@
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;
// 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();
}
CpuFeatures::FlushICache(pc, code_size);
}
// 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() {
void BreakLocation::SetDebugBreakAtReturn() {
DCHECK(Assembler::kJSReturnSequenceLength >=
Assembler::kCallInstructionLength);
rinfo()->PatchCodeWithCall(
debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
PatchCodeWithCall(
pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
}
// Restore the JS frame exit code.
void BreakLocationIterator::ClearDebugBreakAtReturn() {
rinfo()->PatchCode(original_rinfo()->pc(),
Assembler::kJSReturnSequenceLength);
}
// 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());
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,

View File

@ -307,8 +307,8 @@ Address RelocInfo::call_address() {
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_);
}
@ -317,8 +317,8 @@ void RelocInfo::set_call_address(Address target) {
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);

View File

@ -214,27 +214,6 @@ bool RelocInfo::IsInConstantPool() {
}
// 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.

View File

@ -591,6 +591,8 @@ class Assembler : public AssemblerBase {
// 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;

View File

@ -14,12 +14,7 @@
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)
@ -31,7 +26,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
// 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())));
@ -45,29 +40,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 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)
@ -77,20 +50,13 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
// 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)

View File

@ -301,8 +301,8 @@ Address RelocInfo::call_address() {
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_);
}
@ -311,8 +311,8 @@ void RelocInfo::set_call_address(Address target) {
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);

View File

@ -191,27 +191,6 @@ bool RelocInfo::IsInConstantPool() {
}
// 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.

View File

@ -585,6 +585,8 @@ class Assembler : public AssemblerBase {
// 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;

View File

@ -14,12 +14,7 @@
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)
@ -31,7 +26,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
// 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())),
@ -44,29 +39,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 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)
@ -78,7 +51,7 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
// 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())),
@ -87,13 +60,6 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
}
void BreakLocationIterator::ClearDebugBreakAtSlot() {
DCHECK(IsDebugBreakSlot());
rinfo()->PatchCode(original_rinfo()->pc(),
Assembler::kDebugBreakSlotInstructions);
}
#define __ ACCESS_MASM(masm)

View File

@ -16726,12 +16726,14 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
// 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());
}
@ -16750,22 +16752,22 @@ int DebugInfo::GetBreakPointCount() {
}
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();
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)));
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 break_point_info;
}
}
}
return heap->undefined_value();
}
return isolate->factory()->undefined_value();
}

View File

@ -10773,9 +10773,9 @@ class DebugInfo: public Struct {
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,
static Handle<Object> FindBreakPointInfo(Handle<DebugInfo> debug_info,
Handle<Object> break_point_object);
// Get the number of break points for this function.
int GetBreakPointCount();

View File

@ -242,8 +242,8 @@ Address RelocInfo::call_address() {
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_);
}
@ -285,7 +285,7 @@ void RelocInfo::WipeOut() {
bool RelocInfo::IsPatchedReturnSequence() {
//
// The patched return sequence is defined by
// BreakLocationIterator::SetDebugBreakAtReturn()
// BreakLocation::SetDebugBreakAtReturn()
// FIXED_SEQUENCE
Instr instr0 = Assembler::instr_at(pc_);

View File

@ -160,27 +160,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<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

View File

@ -659,9 +659,11 @@ class Assembler : public AssemblerBase {
// 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

View File

@ -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
//
// LeaveFrame
@ -31,7 +26,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
// 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,
@ -45,29 +40,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
//
@ -83,7 +56,7 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
// 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,
@ -94,13 +67,6 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
}
void BreakLocationIterator::ClearDebugBreakAtSlot() {
DCHECK(IsDebugBreakSlot());
rinfo()->PatchCode(original_rinfo()->pc(),
Assembler::kDebugBreakSlotInstructions);
}
#define __ ACCESS_MASM(masm)

View File

@ -1164,18 +1164,19 @@ class ScopeIterator {
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) {
@ -1559,18 +1560,19 @@ RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
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();
@ -1587,20 +1589,15 @@ RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
}
}
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;
}

View File

@ -107,50 +107,6 @@ void CpuFeatures::PrintFeatures() {
}
// -----------------------------------------------------------------------------
// 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.

View File

@ -14,58 +14,57 @@
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);
// 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();
}
CpuFeatures::FlushICache(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() {
void BreakLocation::SetDebugBreakAtReturn() {
DCHECK(Assembler::kJSReturnSequenceLength >= Assembler::kCallSequenceLength);
rinfo()->PatchCodeWithCall(
debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
PatchCodeWithCall(
pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
Assembler::kJSReturnSequenceLength - Assembler::kCallSequenceLength);
}
// Restore the JS frame exit code.
void BreakLocationIterator::ClearDebugBreakAtReturn() {
rinfo()->PatchCode(original_rinfo()->pc(),
Assembler::kJSReturnSequenceLength);
}
// 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();
}
bool BreakLocationIterator::IsDebugBreakAtSlot() {
void BreakLocation::SetDebugBreakAtSlot() {
DCHECK(IsDebugBreakSlot());
// Check whether the debug break slot instructions have been patched.
return rinfo()->IsPatchedDebugBreakSlotSequence();
}
void BreakLocationIterator::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)

View File

@ -102,48 +102,6 @@ bool RelocInfo::IsInConstantPool() {
}
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

View File

@ -13,60 +13,60 @@
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);
// 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();
}
CpuFeatures::FlushICache(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() {
void BreakLocation::SetDebugBreakAtReturn() {
DCHECK(Assembler::kJSReturnSequenceLength >=
Assembler::kCallInstructionLength);
rinfo()->PatchCodeWithCall(
debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
PatchCodeWithCall(
pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
}
// Restore the JS frame exit code.
void BreakLocationIterator::ClearDebugBreakAtReturn() {
rinfo()->PatchCode(original_rinfo()->pc(),
Assembler::kJSReturnSequenceLength);
}
// 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() {
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,

View File

@ -416,7 +416,7 @@ void CheckDebuggerUnloaded(bool check_functions) {
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());
}
}
}
@ -437,47 +437,36 @@ static void CheckDebuggerUnloaded(bool check_functions = false) {
}
// 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
@ -485,15 +474,17 @@ void CheckDebugBreakFunction(DebugLocalContext* env,
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());
}
}

View File

@ -81,11 +81,9 @@ static void CheckFunctionName(v8::Handle<v8::Script> script,
// 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 =