Commit 4689f800 authored by mbrandy's avatar mbrandy Committed by Commit bot

PPC: Debugger: use debug break slots to break at function exit.

Port fc9c5275

Original commit message:
    By not having to patch the return sequence (we patch the debug
    break slot right before it), we don't overwrite it and therefore
    don't have to keep the original copy of the code around.

R=yangguo@chromium.org, dstence@us.ibm.com, michael_dawson@ca.ibm.com
BUG=

Review URL: https://codereview.chromium.org/1238503003

Cr-Commit-Position: refs/heads/master@{#29703}
parent a02f7e6f
...@@ -50,7 +50,7 @@ namespace internal { ...@@ -50,7 +50,7 @@ namespace internal {
bool CpuFeatures::SupportsCrankshaft() { return true; } bool CpuFeatures::SupportsCrankshaft() { return true; }
void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) { void RelocInfo::apply(intptr_t delta) {
// absolute code pointer inside code object moves with the code object. // absolute code pointer inside code object moves with the code object.
if (IsInternalReference(rmode_)) { if (IsInternalReference(rmode_)) {
// Jump table entry // Jump table entry
...@@ -61,7 +61,7 @@ void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) { ...@@ -61,7 +61,7 @@ void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
DCHECK(IsInternalReferenceEncoded(rmode_)); DCHECK(IsInternalReferenceEncoded(rmode_));
Address target = Assembler::target_address_at(pc_, host_); Address target = Assembler::target_address_at(pc_, host_);
Assembler::set_target_address_at(pc_, host_, target + delta, Assembler::set_target_address_at(pc_, host_, target + delta,
icache_flush_mode); SKIP_ICACHE_FLUSH);
} }
} }
...@@ -146,11 +146,6 @@ void RelocInfo::set_target_address(Address target, ...@@ -146,11 +146,6 @@ void RelocInfo::set_target_address(Address target,
} }
Address Assembler::break_address_from_return_address(Address pc) {
return target_address_from_return_address(pc);
}
Address Assembler::target_address_from_return_address(Address pc) { Address Assembler::target_address_from_return_address(Address pc) {
// Returns the address of the call target from the return address that will // Returns the address of the call target from the return address that will
// be returned to after a call. // be returned to after a call.
...@@ -297,19 +292,14 @@ void RelocInfo::set_code_age_stub(Code* stub, ...@@ -297,19 +292,14 @@ void RelocInfo::set_code_age_stub(Code* stub,
} }
Address RelocInfo::call_address() { Address RelocInfo::debug_call_address() {
DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) || DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
// The pc_ offset of 0 assumes patched return sequence per
// BreakLocation::SetDebugBreakAtReturn(), or debug break
// slot per BreakLocation::SetDebugBreakAtSlot().
return Assembler::target_address_at(pc_, host_); return Assembler::target_address_at(pc_, host_);
} }
void RelocInfo::set_call_address(Address target) { void RelocInfo::set_debug_call_address(Address target) {
DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) || DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
Assembler::set_target_address_at(pc_, host_, target); Assembler::set_target_address_at(pc_, host_, target);
if (host() != NULL) { if (host() != NULL) {
Object* target_code = Code::GetCodeFromTargetAddress(target); Object* target_code = Code::GetCodeFromTargetAddress(target);
...@@ -319,21 +309,6 @@ void RelocInfo::set_call_address(Address target) { ...@@ -319,21 +309,6 @@ void RelocInfo::set_call_address(Address target) {
} }
Object* RelocInfo::call_object() { return *call_object_address(); }
void RelocInfo::set_call_object(Object* target) {
*call_object_address() = target;
}
Object** RelocInfo::call_object_address() {
DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
}
void RelocInfo::WipeOut() { void RelocInfo::WipeOut() {
DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) || DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) || IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
...@@ -399,9 +374,8 @@ void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) { ...@@ -399,9 +374,8 @@ void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
visitor->VisitInternalReference(this); visitor->VisitInternalReference(this);
} else if (RelocInfo::IsCodeAgeSequence(mode)) { } else if (RelocInfo::IsCodeAgeSequence(mode)) {
visitor->VisitCodeAgeSequence(this); visitor->VisitCodeAgeSequence(this);
} else if (((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) || } else if (RelocInfo::IsDebugBreakSlot(mode) &&
(RelocInfo::IsDebugBreakSlot(mode) && IsPatchedDebugBreakSlotSequence() &&
IsPatchedDebugBreakSlotSequence())) &&
isolate->debug()->has_break_points()) { isolate->debug()->has_break_points()) {
visitor->VisitDebugTarget(this); visitor->VisitDebugTarget(this);
} else if (IsRuntimeEntry(mode)) { } else if (IsRuntimeEntry(mode)) {
...@@ -427,9 +401,8 @@ void RelocInfo::Visit(Heap* heap) { ...@@ -427,9 +401,8 @@ void RelocInfo::Visit(Heap* heap) {
} else if (RelocInfo::IsCodeAgeSequence(mode)) { } else if (RelocInfo::IsCodeAgeSequence(mode)) {
StaticVisitor::VisitCodeAgeSequence(heap, this); StaticVisitor::VisitCodeAgeSequence(heap, this);
} else if (heap->isolate()->debug()->has_break_points() && } else if (heap->isolate()->debug()->has_break_points() &&
((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) || RelocInfo::IsDebugBreakSlot(mode) &&
(RelocInfo::IsDebugBreakSlot(mode) && IsPatchedDebugBreakSlotSequence()) {
IsPatchedDebugBreakSlotSequence()))) {
StaticVisitor::VisitDebugTarget(heap, this); StaticVisitor::VisitDebugTarget(heap, this);
} else if (IsRuntimeEntry(mode)) { } else if (IsRuntimeEntry(mode)) {
StaticVisitor::VisitRuntimeEntry(this); StaticVisitor::VisitRuntimeEntry(this);
......
...@@ -643,9 +643,6 @@ class Assembler : public AssemblerBase { ...@@ -643,9 +643,6 @@ class Assembler : public AssemblerBase {
// in the instruction stream that the call will return to. // in the instruction stream that the call will return to.
INLINE(static Address return_address_from_call_start(Address pc)); INLINE(static Address return_address_from_call_start(Address pc));
// Return the code target address of the patch debug break slot
INLINE(static Address break_address_from_return_address(Address pc));
// This sets the branch destination. // This sets the branch destination.
// This is for calls and branches within generated code. // This is for calls and branches within generated code.
inline static void deserialization_set_special_target_at( inline static void deserialization_set_special_target_at(
...@@ -696,14 +693,6 @@ class Assembler : public AssemblerBase { ...@@ -696,14 +693,6 @@ class Assembler : public AssemblerBase {
static const int kCallTargetAddressOffset = static const int kCallTargetAddressOffset =
(kMovInstructions + 2) * kInstrSize; (kMovInstructions + 2) * kInstrSize;
// Distance between start of patched return sequence and the emitted address
// to jump to.
// Patched return sequence is a FIXED_SEQUENCE:
// mov r0, <address>
// mtlr r0
// blrl
static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
// Distance between start of patched debug break slot and the emitted address // Distance between start of patched debug break slot and the emitted address
// to jump to. // to jump to.
// Patched debug break slot code is a FIXED_SEQUENCE: // Patched debug break slot code is a FIXED_SEQUENCE:
...@@ -712,13 +701,6 @@ class Assembler : public AssemblerBase { ...@@ -712,13 +701,6 @@ class Assembler : public AssemblerBase {
// blrl // blrl
static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize; static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
// This is the length of the BreakLocation::SetDebugBreakAtReturn()
// code patch FIXED_SEQUENCE
static const int kJSReturnSequenceInstructions =
kMovInstructionsNoConstantPool + 3;
static const int kJSReturnSequenceLength =
kJSReturnSequenceInstructions * kInstrSize;
// This is the length of the code sequence from SetDebugBreakAtSlot() // This is the length of the code sequence from SetDebugBreakAtSlot()
// FIXED_SEQUENCE // FIXED_SEQUENCE
static const int kDebugBreakSlotInstructions = static const int kDebugBreakSlotInstructions =
...@@ -1297,16 +1279,11 @@ class Assembler : public AssemblerBase { ...@@ -1297,16 +1279,11 @@ class Assembler : public AssemblerBase {
// Debugging // Debugging
// Mark address of the ExitJSFrame code.
void RecordJSReturn();
// Mark generator continuation. // Mark generator continuation.
void RecordGeneratorContinuation(); void RecordGeneratorContinuation();
// Mark address of a debug break slot. // Mark address of a debug break slot.
void RecordDebugBreakSlot(); void RecordDebugBreakSlot(RelocInfo::Mode mode, int argc = 0);
void RecordDebugBreakSlotForCall(int argc);
void RecordDebugBreakSlotForConstructCall();
// Record the AST id of the CallIC being compiled, so that it can be placed // Record the AST id of the CallIC being compiled, so that it can be placed
// in the relocation information. // in the relocation information.
......
...@@ -12,36 +12,39 @@ ...@@ -12,36 +12,39 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
void BreakLocation::SetDebugBreakAtReturn() { #define __ ACCESS_MASM(masm)
// Patch the code changing the return from JS function sequence from
//
// LeaveFrame void EmitDebugBreakSlot(MacroAssembler* masm) {
// blr Label check_size;
// __ bind(&check_size);
// to a call to the debug break return code. for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
// this uses a FIXED_SEQUENCE to load an address constant __ nop(MacroAssembler::DEBUG_BREAK_NOP);
// }
// mov r0, <address> DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
// mtlr r0 masm->InstructionsGeneratedSince(&check_size));
// blrl
// bkpt
//
CodePatcher patcher(pc(), Assembler::kJSReturnSequenceInstructions);
Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm());
patcher.masm()->mov(
v8::internal::r0,
Operand(reinterpret_cast<intptr_t>(debug_info_->GetIsolate()
->builtins()
->Return_DebugBreak()
->entry())));
patcher.masm()->mtctr(v8::internal::r0);
patcher.masm()->bctrl();
patcher.masm()->bkpt(0);
} }
void BreakLocation::SetDebugBreakAtSlot() { void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode,
DCHECK(IsDebugBreakSlot()); int call_argc) {
// Generate enough nop's to make space for a call instruction. Avoid emitting
// the trampoline pool in the debug break slot code.
Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
masm->RecordDebugBreakSlot(mode, call_argc);
EmitDebugBreakSlot(masm);
}
void DebugCodegen::ClearDebugBreakSlot(Address pc) {
CodePatcher patcher(pc, Assembler::kDebugBreakSlotInstructions);
EmitDebugBreakSlot(patcher.masm());
}
void DebugCodegen::PatchDebugBreakSlot(Address pc, Handle<Code> code) {
DCHECK_EQ(Code::BUILTIN, code->kind());
CodePatcher patcher(pc, Assembler::kDebugBreakSlotInstructions);
// Patch the code changing the debug break slot code from // Patch the code changing the debug break slot code from
// //
// ori r3, r3, 0 // ori r3, r3, 0
...@@ -56,22 +59,17 @@ void BreakLocation::SetDebugBreakAtSlot() { ...@@ -56,22 +59,17 @@ void BreakLocation::SetDebugBreakAtSlot() {
// mtlr r0 // mtlr r0
// blrl // blrl
// //
CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions);
Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm()); Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm());
patcher.masm()->mov( patcher.masm()->mov(v8::internal::r0,
v8::internal::r0, Operand(reinterpret_cast<intptr_t>(code->entry())));
Operand(reinterpret_cast<intptr_t>(
debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())));
patcher.masm()->mtctr(v8::internal::r0); patcher.masm()->mtctr(v8::internal::r0);
patcher.masm()->bctrl(); patcher.masm()->bctrl();
} }
#define __ ACCESS_MASM(masm) void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
DebugBreakCallHelperMode mode) {
__ RecordComment("Debug break");
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
RegList object_regs) {
{ {
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
...@@ -83,36 +81,23 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, ...@@ -83,36 +81,23 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
__ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); __ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
__ push(ip); __ push(ip);
// Store the registers containing live values on the expression stack to if (mode == SAVE_RESULT_REGISTER) __ push(r3);
// make sure that these are correctly updated during GC. Non object values
// are stored as a smi causing it to be untouched by GC.
DCHECK((object_regs & ~kJSCallerSaved) == 0);
if (object_regs != 0) {
__ MultiPush(object_regs);
}
#ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
__ mov(r3, Operand::Zero()); // no arguments __ mov(r3, Operand::Zero()); // no arguments
__ mov(r4, Operand(ExternalReference::debug_break(masm->isolate()))); __ mov(r4, Operand(ExternalReference::debug_break(masm->isolate())));
CEntryStub ceb(masm->isolate(), 1); CEntryStub ceb(masm->isolate(), 1);
__ CallStub(&ceb); __ CallStub(&ceb);
// Restore the register values from the expression stack. if (FLAG_debug_code) {
if (object_regs != 0) { for (int i = 0; i < kNumJSCallerSaved; i++) {
__ MultiPop(object_regs); Register reg = {JSCallerSavedCode(i)};
}
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
Register reg = {r};
if (FLAG_debug_code && ((object_regs & (1 << r)) == 0)) {
__ mov(reg, Operand(kDebugZapValue)); __ mov(reg, Operand(kDebugZapValue));
} }
} }
if (mode == SAVE_RESULT_REGISTER) __ pop(r3);
// Don't bother removing padding bytes pushed on the stack // Don't bother removing padding bytes pushed on the stack
// as the frame is going to be restored right away. // as the frame is going to be restored right away.
...@@ -130,38 +115,6 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, ...@@ -130,38 +115,6 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
} }
void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
// In places other than IC call sites it is expected that r3 is TOS which
// is an object - this is not generally the case so this should be used with
// care.
Generate_DebugBreakCallHelper(masm, r3.bit());
}
void DebugCodegen::GenerateSlot(MacroAssembler* masm,
DebugCodegen::SlotLocation location,
int call_argc) {
// Generate enough nop's to make space for a call instruction. Avoid emitting
// the trampoline pool in the debug break slot code.
Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
Label check_codesize;
__ bind(&check_codesize);
RecordRelocInfo(masm, location, call_argc);
for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
__ nop(MacroAssembler::DEBUG_BREAK_NOP);
}
DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
masm->InstructionsGeneratedSince(&check_codesize));
}
void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
// In the places where a debug break slot is inserted no registers can contain
// object pointers.
Generate_DebugBreakCallHelper(masm, 0);
}
void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
__ Ret(); __ Ret();
} }
......
...@@ -491,11 +491,6 @@ void FullCodeGenerator::EmitReturnSequence() { ...@@ -491,11 +491,6 @@ void FullCodeGenerator::EmitReturnSequence() {
EmitProfilingCounterReset(); EmitProfilingCounterReset();
__ bind(&ok); __ bind(&ok);
#ifdef DEBUG
// Add a label for checking the size of the code used for returning.
Label check_exit_codesize;
__ bind(&check_exit_codesize);
#endif
// Make sure that the constant pool is not emitted inside of the return // Make sure that the constant pool is not emitted inside of the return
// sequence. // sequence.
{ {
...@@ -503,26 +498,10 @@ void FullCodeGenerator::EmitReturnSequence() { ...@@ -503,26 +498,10 @@ void FullCodeGenerator::EmitReturnSequence() {
int32_t arg_count = info_->scope()->num_parameters() + 1; int32_t arg_count = info_->scope()->num_parameters() + 1;
int32_t sp_delta = arg_count * kPointerSize; int32_t sp_delta = arg_count * kPointerSize;
SetReturnPosition(function()); SetReturnPosition(function());
__ RecordJSReturn();
int no_frame_start = __ LeaveFrame(StackFrame::JAVA_SCRIPT, sp_delta); int no_frame_start = __ LeaveFrame(StackFrame::JAVA_SCRIPT, sp_delta);
#if V8_TARGET_ARCH_PPC64
// With 64bit we may need nop() instructions to ensure we have
// enough space to SetDebugBreakAtReturn()
if (is_int16(sp_delta)) {
if (!FLAG_enable_embedded_constant_pool) masm_->nop();
masm_->nop();
}
#endif
__ blr(); __ blr();
info_->AddNoFrameRange(no_frame_start, masm_->pc_offset()); info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
} }
#ifdef DEBUG
// Check that the size of the code used for returning is large enough
// for the debugger's requirements.
DCHECK(Assembler::kJSReturnSequenceInstructions <=
masm_->InstructionsGeneratedSince(&check_exit_codesize));
#endif
} }
} }
......
...@@ -1526,7 +1526,7 @@ class CodePatcher { ...@@ -1526,7 +1526,7 @@ class CodePatcher {
enum FlushICache { FLUSH, DONT_FLUSH }; enum FlushICache { FLUSH, DONT_FLUSH };
CodePatcher(byte* address, int instructions, FlushICache flush_cache = FLUSH); CodePatcher(byte* address, int instructions, FlushICache flush_cache = FLUSH);
virtual ~CodePatcher(); ~CodePatcher();
// Macro assembler to emit code. // Macro assembler to emit code.
MacroAssembler* masm() { return &masm_; } MacroAssembler* masm() { return &masm_; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment