PPC: Debugger: use debug break slots to break at function exit.
authormbrandy <mbrandy@us.ibm.com>
Thu, 16 Jul 2015 14:11:50 +0000 (07:11 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 16 Jul 2015 14:12:07 +0000 (14:12 +0000)
Port fc9c5275c3a747caca709b7d5745579f70e61301

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}

src/ppc/assembler-ppc-inl.h
src/ppc/assembler-ppc.h
src/ppc/debug-ppc.cc
src/ppc/full-codegen-ppc.cc
src/ppc/macro-assembler-ppc.h

index 74eb0c3ddd8a3e2daba7e5a050ae767b90ee815c..13607234e32fcfb64bf168779ca756eaea6961be 100644 (file)
@@ -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);
index f946c6dbce09150b30fb9ae5169427c5bc517fdf..3e3931a0a9520572898ded4e9d3cd4bdc3e96940 100644 (file)
@@ -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.
index 054dd2cc2d7a047ab21cf4751b658726a04b7cdd..d4c41f3bb7c3f2d37c4fb00c80ac50c64772facb 100644 (file)
 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();
 }
index 2f3d7eeb85d24890d413dc651babcf0ea4e029bd..a69f60a38f374d5a4ea723b86c33e541fd42d33a 100644 (file)
@@ -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
   }
 }
 
index 04c44315fdea7423ee5a131b80211a9fbc2a4055..e830be9111f2fd8c78ebecc2251149ae5e736edc 100644 (file)
@@ -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_; }