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 {
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.
if (IsInternalReference(rmode_)) {
// Jump table entry
......@@ -61,7 +61,7 @@ void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
DCHECK(IsInternalReferenceEncoded(rmode_));
Address target = Assembler::target_address_at(pc_, host_);
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,
}
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) {
// Returns the address of the call target from the return address that will
// be returned to after a call.
......@@ -297,19 +292,14 @@ void RelocInfo::set_code_age_stub(Code* stub,
}
Address RelocInfo::call_address() {
DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
// The pc_ offset of 0 assumes patched return sequence per
// BreakLocation::SetDebugBreakAtReturn(), or debug break
// slot per BreakLocation::SetDebugBreakAtSlot().
Address RelocInfo::debug_call_address() {
DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
return Assembler::target_address_at(pc_, host_);
}
void RelocInfo::set_call_address(Address target) {
DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
void RelocInfo::set_debug_call_address(Address target) {
DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
Assembler::set_target_address_at(pc_, host_, target);
if (host() != NULL) {
Object* target_code = Code::GetCodeFromTargetAddress(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() {
DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
......@@ -399,9 +374,8 @@ void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
visitor->VisitInternalReference(this);
} else if (RelocInfo::IsCodeAgeSequence(mode)) {
visitor->VisitCodeAgeSequence(this);
} else if (((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(mode) &&
IsPatchedDebugBreakSlotSequence())) &&
} else if (RelocInfo::IsDebugBreakSlot(mode) &&
IsPatchedDebugBreakSlotSequence() &&
isolate->debug()->has_break_points()) {
visitor->VisitDebugTarget(this);
} else if (IsRuntimeEntry(mode)) {
......@@ -427,9 +401,8 @@ void RelocInfo::Visit(Heap* heap) {
} else if (RelocInfo::IsCodeAgeSequence(mode)) {
StaticVisitor::VisitCodeAgeSequence(heap, this);
} else if (heap->isolate()->debug()->has_break_points() &&
((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(mode) &&
IsPatchedDebugBreakSlotSequence()))) {
RelocInfo::IsDebugBreakSlot(mode) &&
IsPatchedDebugBreakSlotSequence()) {
StaticVisitor::VisitDebugTarget(heap, this);
} else if (IsRuntimeEntry(mode)) {
StaticVisitor::VisitRuntimeEntry(this);
......
......@@ -643,9 +643,6 @@ class Assembler : public AssemblerBase {
// in the instruction stream that the call will return to.
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 is for calls and branches within generated code.
inline static void deserialization_set_special_target_at(
......@@ -696,14 +693,6 @@ class Assembler : public AssemblerBase {
static const int kCallTargetAddressOffset =
(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
// to jump to.
// Patched debug break slot code is a FIXED_SEQUENCE:
......@@ -712,13 +701,6 @@ class Assembler : public AssemblerBase {
// blrl
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()
// FIXED_SEQUENCE
static const int kDebugBreakSlotInstructions =
......@@ -1297,16 +1279,11 @@ class Assembler : public AssemblerBase {
// Debugging
// Mark address of the ExitJSFrame code.
void RecordJSReturn();
// Mark generator continuation.
void RecordGeneratorContinuation();
// Mark address of a debug break slot.
void RecordDebugBreakSlot();
void RecordDebugBreakSlotForCall(int argc);
void RecordDebugBreakSlotForConstructCall();
void RecordDebugBreakSlot(RelocInfo::Mode mode, int argc = 0);
// Record the AST id of the CallIC being compiled, so that it can be placed
// in the relocation information.
......
......@@ -12,36 +12,39 @@
namespace v8 {
namespace internal {
void BreakLocation::SetDebugBreakAtReturn() {
// Patch the code changing the return from JS function sequence from
//
// LeaveFrame
// blr
//
// to a call to the debug break return code.
// this uses a FIXED_SEQUENCE to load an address constant
//
// mov r0, <address>
// mtlr r0
// 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);
#define __ ACCESS_MASM(masm)
void EmitDebugBreakSlot(MacroAssembler* masm) {
Label check_size;
__ bind(&check_size);
for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
__ nop(MacroAssembler::DEBUG_BREAK_NOP);
}
DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
masm->InstructionsGeneratedSince(&check_size));
}
void BreakLocation::SetDebugBreakAtSlot() {
DCHECK(IsDebugBreakSlot());
void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode,
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
//
// ori r3, r3, 0
......@@ -56,22 +59,17 @@ void BreakLocation::SetDebugBreakAtSlot() {
// mtlr r0
// blrl
//
CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions);
Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm());
patcher.masm()->mov(
v8::internal::r0,
Operand(reinterpret_cast<intptr_t>(
debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())));
patcher.masm()->mov(v8::internal::r0,
Operand(reinterpret_cast<intptr_t>(code->entry())));
patcher.masm()->mtctr(v8::internal::r0);
patcher.masm()->bctrl();
}
#define __ ACCESS_MASM(masm)
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
RegList object_regs) {
void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
DebugBreakCallHelperMode mode) {
__ RecordComment("Debug break");
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
......@@ -83,36 +81,23 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
__ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
__ push(ip);
// Store the registers containing live values on the expression stack to
// 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);
}
if (mode == SAVE_RESULT_REGISTER) __ push(r3);
#ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
__ mov(r3, Operand::Zero()); // no arguments
__ mov(r4, Operand(ExternalReference::debug_break(masm->isolate())));
CEntryStub ceb(masm->isolate(), 1);
__ CallStub(&ceb);
// Restore the register values from the expression stack.
if (object_regs != 0) {
__ MultiPop(object_regs);
}
for (int i = 0; i < kNumJSCallerSaved; i++) {
int r = JSCallerSavedCode(i);
Register reg = {r};
if (FLAG_debug_code && ((object_regs & (1 << r)) == 0)) {
if (FLAG_debug_code) {
for (int i = 0; i < kNumJSCallerSaved; i++) {
Register reg = {JSCallerSavedCode(i)};
__ mov(reg, Operand(kDebugZapValue));
}
}
if (mode == SAVE_RESULT_REGISTER) __ pop(r3);
// Don't bother removing padding bytes pushed on the stack
// as the frame is going to be restored right away.
......@@ -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) {
__ Ret();
}
......
......@@ -491,11 +491,6 @@ void FullCodeGenerator::EmitReturnSequence() {
EmitProfilingCounterReset();
__ 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
// sequence.
{
......@@ -503,26 +498,10 @@ void FullCodeGenerator::EmitReturnSequence() {
int32_t arg_count = info_->scope()->num_parameters() + 1;
int32_t sp_delta = arg_count * kPointerSize;
SetReturnPosition(function());
__ RecordJSReturn();
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();
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 {
enum FlushICache { FLUSH, DONT_FLUSH };
CodePatcher(byte* address, int instructions, FlushICache flush_cache = FLUSH);
virtual ~CodePatcher();
~CodePatcher();
// Macro assembler to emit code.
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