Cleanup the way the debugger stores live registers when entering at a break
authorsgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 27 Aug 2010 07:08:03 +0000 (07:08 +0000)
committersgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 27 Aug 2010 07:08:03 +0000 (07:08 +0000)
The live registers are now only stored to the expression stack with the non pointer values being stored as smis (on the 32-bit platforms these values are assumed to be 31-bit max).

This makes the CEntryStub entry/exit code much simpler, and there is no longer any need for a mode (debug or normal) on it.

Fix a missing live register when breaking at ARM keyed load.
Review URL: http://codereview.chromium.org/3141047

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5358 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

24 files changed:
src/arm/code-stubs-arm.cc
src/arm/debug-arm.cc
src/arm/frames-arm.cc
src/arm/frames-arm.h
src/arm/macro-assembler-arm.cc
src/arm/macro-assembler-arm.h
src/codegen.cc
src/codegen.h
src/debug.h
src/frames.h
src/ia32/code-stubs-ia32.cc
src/ia32/debug-ia32.cc
src/ia32/frames-ia32.cc
src/ia32/macro-assembler-ia32.cc
src/ia32/macro-assembler-ia32.h
src/serialize.cc
src/x64/code-stubs-x64.cc
src/x64/debug-x64.cc
src/x64/frames-x64.cc
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h
test/cctest/cctest.status
test/cctest/test-debug.cc
test/cctest/test-serialize.cc

index 0826e0a..5f9d729 100644 (file)
@@ -2702,7 +2702,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   // r0:r1: result
   // sp: stack pointer
   // fp: frame pointer
-  __ LeaveExitFrame(mode_);
+  __ LeaveExitFrame();
 
   // check if we should retry or throw exception
   Label retry;
@@ -2751,7 +2751,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // builtin once.
 
   // Enter the exit frame that transitions from JavaScript to C++.
-  __ EnterExitFrame(mode_);
+  __ EnterExitFrame();
 
   // r4: number of arguments (C callee-saved)
   // r5: pointer to builtin function (C callee-saved)
index 5c1c149..82f93b6 100644 (file)
@@ -130,21 +130,30 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() {
 
 
 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
-                                          RegList pointer_regs) {
-  // Save the content of all general purpose registers in memory. This copy in
-  // memory is later pushed onto the JS expression stack for the fake JS frame
-  // generated and also to the C frame generated on top of that. In the JS
-  // frame ONLY the registers containing pointers will be pushed on the
-  // expression stack. This causes the GC to update these  pointers so that
-  // they will have the correct value when returning from the debugger.
-  __ SaveRegistersToMemory(kJSCallerSaved);
-
+                                          RegList object_regs,
+                                          RegList non_object_regs) {
   __ EnterInternalFrame();
 
-  // Store the registers containing object pointers on the expression stack to
-  // make sure that these are correctly updated during GC.
-  // Use sp as base to push.
-  __ CopyRegistersFromMemoryToStack(sp, pointer_regs);
+  // 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.
+  ASSERT((object_regs & ~kJSCallerSaved) == 0);
+  ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
+  ASSERT((object_regs & non_object_regs) == 0);
+  if ((object_regs | non_object_regs) != 0) {
+    for (int i = 0; i < kNumJSCallerSaved; i++) {
+      int r = JSCallerSavedCode(i);
+      Register reg = { r };
+      if ((non_object_regs & (1 << r)) != 0) {
+        if (FLAG_debug_code) {
+          __ tst(reg, Operand(0xc0000000));
+          __ Assert(eq, "Unable to encode value as smi");
+        }
+        __ mov(reg, Operand(reg, LSL, kSmiTagSize));
+      }
+    }
+    __ stm(db_w, sp, object_regs | non_object_regs);
+  }
 
 #ifdef DEBUG
   __ RecordComment("// Calling from debug break to runtime - come in - over");
@@ -152,19 +161,27 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
   __ mov(r0, Operand(0));  // no arguments
   __ mov(r1, Operand(ExternalReference::debug_break()));
 
-  CEntryStub ceb(1, ExitFrame::MODE_DEBUG);
+  CEntryStub ceb(1);
   __ CallStub(&ceb);
 
-  // Restore the register values containing object pointers from the expression
-  // stack in the reverse order as they where pushed.
-  // Use sp as base to pop.
-  __ CopyRegistersFromStackToMemory(sp, r3, pointer_regs);
+  // Restore the register values from the expression stack.
+  if ((object_regs | non_object_regs) != 0) {
+    __ ldm(ia_w, sp, object_regs | non_object_regs);
+    for (int i = 0; i < kNumJSCallerSaved; i++) {
+      int r = JSCallerSavedCode(i);
+      Register reg = { r };
+      if ((non_object_regs & (1 << r)) != 0) {
+        __ mov(reg, Operand(reg, LSR, kSmiTagSize));
+      }
+      if (FLAG_debug_code &&
+          (((object_regs |non_object_regs) & (1 << r)) == 0)) {
+        __ mov(reg, Operand(kDebugZapValue));
+      }
+    }
+  }
 
   __ LeaveInternalFrame();
 
-  // Finally restore all registers.
-  __ RestoreRegistersFromMemory(kJSCallerSaved);
-
   // Now that the break point has been handled, resume normal execution by
   // jumping to the target address intended by the caller and that was
   // overwritten by the address of DebugBreakXXX.
@@ -184,7 +201,7 @@ void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
   // -----------------------------------
   // Registers r0 and r2 contain objects that need to be pushed on the
   // expression stack of the fake JS frame.
-  Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit());
+  Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit(), 0);
 }
 
 
@@ -198,7 +215,7 @@ void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
   // -----------------------------------
   // Registers r0, r1, and r2 contain objects that need to be pushed on the
   // expression stack of the fake JS frame.
-  Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit());
+  Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0);
 }
 
 
@@ -206,9 +223,8 @@ void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
   // ---------- S t a t e --------------
   //  -- lr     : return address
   //  -- r0     : key
-  //  -- sp[0]  : key
-  //  -- sp[4]  : receiver
-  Generate_DebugBreakCallHelper(masm, r0.bit());
+  //  -- r1     : receiver
+  Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit(), 0);
 }
 
 
@@ -218,24 +234,24 @@ void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
   //  -- r1     : key
   //  -- r2     : receiver
   //  -- lr     : return address
-  Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit());
+  Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0);
 }
 
 
 void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
   // Calling convention for IC call (from ic-arm.cc)
   // ----------- S t a t e -------------
-  //  -- r2: name
+  //  -- r2     : name
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, r2.bit());
+  Generate_DebugBreakCallHelper(masm, r2.bit(), 0);
 }
 
 
 void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) {
-  // In places other than IC call sites it is expected that r0 is TOS which
-  // is an object - this is not generally the case so this should be used with
-  // care.
-  Generate_DebugBreakCallHelper(masm, r0.bit());
+  // Calling convention for construct call (from builtins-arm.cc)
+  //  -- r0     : number of arguments (not smi)
+  //  -- r1     : constructor function
+  Generate_DebugBreakCallHelper(masm, r1.bit(), r0.bit());
 }
 
 
@@ -243,7 +259,7 @@ void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
   // In places other than IC call sites it is expected that r0 is TOS which
   // is an object - this is not generally the case so this should be used with
   // care.
-  Generate_DebugBreakCallHelper(masm, r0.bit());
+  Generate_DebugBreakCallHelper(masm, r0.bit(), 0);
 }
 
 
@@ -251,7 +267,7 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  No registers used on entry.
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, 0);
+  Generate_DebugBreakCallHelper(masm, 0, 0);
 }
 
 
@@ -273,7 +289,7 @@ void Debug::GenerateSlot(MacroAssembler* masm) {
 void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
   // In the places where a debug break slot is inserted no registers can contain
   // object pointers.
-  Generate_DebugBreakCallHelper(masm, 0);
+  Generate_DebugBreakCallHelper(masm, 0, 0);
 }
 
 
index 271e4a6..b7fb3d7 100644 (file)
@@ -55,17 +55,13 @@ StackFrame::Type StackFrame::ComputeType(State* state) {
 StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
   if (fp == 0) return NONE;
   // Compute frame type and stack pointer.
-  Address sp = fp + ExitFrameConstants::kSPDisplacement;
-  const int offset = ExitFrameConstants::kCodeOffset;
-  Object* code = Memory::Object_at(fp + offset);
-  bool is_debug_exit = code->IsSmi();
-  if (is_debug_exit) {
-    sp -= kNumJSCallerSaved * kPointerSize;
-  }
+  Address sp = fp + ExitFrameConstants::kSPOffset;
+
   // Fill in the state.
   state->sp = sp;
   state->fp = fp;
   state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
+  ASSERT(*state->pc_address != NULL);
   return EXIT;
 }
 
index 4924c1a..5847a6a 100644 (file)
@@ -96,11 +96,8 @@ class EntryFrameConstants : public AllStatic {
 
 class ExitFrameConstants : public AllStatic {
  public:
-  // Exit frames have a debug marker on the stack.
-  static const int kSPDisplacement = -1 * kPointerSize;
-
-  // The debug marker is just above the frame pointer.
   static const int kCodeOffset = -1 * kPointerSize;
+  static const int kSPOffset = -1 * kPointerSize;
 
   static const int kSavedRegistersOffset = 0 * kPointerSize;
 
index 0d04156..80da51e 100644 (file)
@@ -513,7 +513,7 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
 }
 
 
-void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) {
+void MacroAssembler::EnterExitFrame() {
   // Compute the argv pointer and keep it in a callee-saved register.
   // r0 is argc.
   add(r6, sp, Operand(r0, LSL, kPointerSizeLog2));
@@ -556,16 +556,6 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) {
   // Setup argc and the builtin function in callee-saved registers.
   mov(r4, Operand(r0));
   mov(r5, Operand(r1));
-
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
-  // Save the state of all registers to the stack from the memory
-  // location. This is needed to allow nested break points.
-  if (mode == ExitFrame::MODE_DEBUG) {
-    // Use sp as base to push.
-    CopyRegistersFromMemoryToStack(sp, kJSCallerSaved);
-  }
-#endif
 }
 
 
@@ -600,19 +590,7 @@ int MacroAssembler::ActivationFrameAlignment() {
 }
 
 
-void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode) {
-#ifdef ENABLE_DEBUGGER_SUPPORT
-  // Restore the memory copy of the registers by digging them out from
-  // the stack. This is needed to allow nested break points.
-  if (mode == ExitFrame::MODE_DEBUG) {
-    // This code intentionally clobbers r2 and r3.
-    const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
-    const int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize;
-    add(r3, fp, Operand(kOffset));
-    CopyRegistersFromStackToMemory(r3, r2, kJSCallerSaved);
-  }
-#endif
-
+void MacroAssembler::LeaveExitFrame() {
   // Clear top frame.
   mov(r3, Operand(0));
   mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
@@ -779,66 +757,8 @@ void MacroAssembler::InvokeFunction(JSFunction* function,
   InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag);
 }
 
-#ifdef ENABLE_DEBUGGER_SUPPORT
-void MacroAssembler::SaveRegistersToMemory(RegList regs) {
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Copy the content of registers to memory location.
-  for (int i = 0; i < kNumJSCallerSaved; i++) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      Register reg = { r };
-      mov(ip, Operand(ExternalReference(Debug_Address::Register(i))));
-      str(reg, MemOperand(ip));
-    }
-  }
-}
-
-
-void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Copy the content of memory location to registers.
-  for (int i = kNumJSCallerSaved; --i >= 0;) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      Register reg = { r };
-      mov(ip, Operand(ExternalReference(Debug_Address::Register(i))));
-      ldr(reg, MemOperand(ip));
-    }
-  }
-}
-
-
-void MacroAssembler::CopyRegistersFromMemoryToStack(Register base,
-                                                    RegList regs) {
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Copy the content of the memory location to the stack and adjust base.
-  for (int i = kNumJSCallerSaved; --i >= 0;) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      mov(ip, Operand(ExternalReference(Debug_Address::Register(i))));
-      ldr(ip, MemOperand(ip));
-      str(ip, MemOperand(base, 4, NegPreIndex));
-    }
-  }
-}
-
-
-void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
-                                                    Register scratch,
-                                                    RegList regs) {
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Copy the content of the stack to the memory location and adjust base.
-  for (int i = 0; i < kNumJSCallerSaved; i++) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      mov(ip, Operand(ExternalReference(Debug_Address::Register(i))));
-      ldr(scratch, MemOperand(base, 4, PostIndex));
-      str(scratch, MemOperand(ip));
-    }
-  }
-}
-
 
+#ifdef ENABLE_DEBUGGER_SUPPORT
 void MacroAssembler::DebugBreak() {
   ASSERT(allow_stub_calls());
   mov(r0, Operand(0));
index a1c5dbb..04d6dc2 100644 (file)
@@ -250,14 +250,14 @@ class MacroAssembler: public Assembler {
   void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
   void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
 
-  // Enter specific kind of exit frame; either normal or debug mode.
+  // Enter exit frame.
   // Expects the number of arguments in register r0 and
   // the builtin function to call in register r1. Exits with argc in
   // r4, argv in r6, and and the builtin function to call in r5.
-  void EnterExitFrame(ExitFrame::Mode mode);
+  void EnterExitFrame();
 
   // Leave the current exit frame. Expects the return value in r0.
-  void LeaveExitFrame(ExitFrame::Mode mode);
+  void LeaveExitFrame();
 
   // Get the actual activation frame alignment for target environment.
   static int ActivationFrameAlignment();
@@ -294,12 +294,6 @@ class MacroAssembler: public Assembler {
   // ---------------------------------------------------------------------------
   // Debugger Support
 
-  void SaveRegistersToMemory(RegList regs);
-  void RestoreRegistersFromMemory(RegList regs);
-  void CopyRegistersFromMemoryToStack(Register base, RegList regs);
-  void CopyRegistersFromStackToMemory(Register base,
-                                      Register scratch,
-                                      RegList regs);
   void DebugBreak();
 #endif
 
index 9c372fa..20fb310 100644 (file)
@@ -501,12 +501,11 @@ void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
 
 
 int CEntryStub::MinorKey() {
-  ASSERT(result_size_ <= 2);
+  ASSERT(result_size_ == 1 || result_size_ == 2);
 #ifdef _WIN64
-  return ExitFrameModeBits::encode(mode_)
-         | IndirectResultBits::encode(result_size_ > 1);
+  return result_size_ == 1 ? 0 : 1;
 #else
-  return ExitFrameModeBits::encode(mode_);
+  return 0;
 #endif
 }
 
index 56c175e..f1d2f72 100644 (file)
@@ -560,9 +560,7 @@ class CompareStub: public CodeStub {
 
 class CEntryStub : public CodeStub {
  public:
-  explicit CEntryStub(int result_size,
-                      ExitFrame::Mode mode = ExitFrame::MODE_NORMAL)
-      : result_size_(result_size), mode_(mode) { }
+  explicit CEntryStub(int result_size) : result_size_(result_size) { }
 
   void Generate(MacroAssembler* masm);
 
@@ -580,10 +578,8 @@ class CEntryStub : public CodeStub {
 
   // Number of pointers/values returned.
   const int result_size_;
-  const ExitFrame::Mode mode_;
 
   // Minor key encoding
-  class ExitFrameModeBits: public BitField<ExitFrame::Mode, 0, 1> {};
   class IndirectResultBits: public BitField<bool, 1, 1> {};
 
   Major MajorKey() { return CEntry; }
index 98d1919..f33394e 100644 (file)
@@ -332,8 +332,7 @@ class Debug {
     k_after_break_target_address,
     k_debug_break_return_address,
     k_debug_break_slot_address,
-    k_restarter_frame_function_pointer,
-    k_register_address
+    k_restarter_frame_function_pointer
   };
 
   // Support for setting the address to jump to when returning from break point.
@@ -953,10 +952,7 @@ class DisableBreak BASE_EMBEDDED {
 // code.
 class Debug_Address {
  public:
-  Debug_Address(Debug::AddressId id, int reg = 0)
-    : id_(id), reg_(reg) {
-    ASSERT(reg == 0 || id == Debug::k_register_address);
-  }
+  Debug_Address(Debug::AddressId id) : id_(id) { }
 
   static Debug_Address AfterBreakTarget() {
     return Debug_Address(Debug::k_after_break_target_address);
@@ -970,10 +966,6 @@ class Debug_Address {
     return Debug_Address(Debug::k_restarter_frame_function_pointer);
   }
 
-  static Debug_Address Register(int reg) {
-    return Debug_Address(Debug::k_register_address, reg);
-  }
-
   Address address() const {
     switch (id_) {
       case Debug::k_after_break_target_address:
@@ -985,8 +977,6 @@ class Debug_Address {
       case Debug::k_restarter_frame_function_pointer:
         return reinterpret_cast<Address>(
             Debug::restarter_frame_function_pointer_address());
-      case Debug::k_register_address:
-        return reinterpret_cast<Address>(Debug::register_address(reg_));
       default:
         UNREACHABLE();
         return NULL;
@@ -994,7 +984,6 @@ class Debug_Address {
   }
  private:
   Debug::AddressId id_;
-  int reg_;
 };
 
 // The optional thread that Debug Agent may use to temporary call V8 to process
index cb791d2..d1fdfb5 100644 (file)
@@ -280,7 +280,6 @@ class EntryConstructFrame: public EntryFrame {
 // Exit frames are used to exit JavaScript execution and go to C.
 class ExitFrame: public StackFrame {
  public:
-  enum Mode { MODE_NORMAL, MODE_DEBUG };
   virtual Type type() const { return EXIT; }
 
   virtual Code* unchecked_code() const;
index 3fbf18a..39bb424 100644 (file)
@@ -3054,7 +3054,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
   Label empty_handle;
   Label prologue;
   Label promote_scheduled_exception;
-  __ EnterApiExitFrame(ExitFrame::MODE_NORMAL, kStackSpace, kArgc);
+  __ EnterApiExitFrame(kStackSpace, kArgc);
   STATIC_ASSERT(kArgc == 4);
   if (kPassHandlesDirectly) {
     // When handles as passed directly we don't have to allocate extra
@@ -3100,7 +3100,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
   // It was non-zero.  Dereference to get the result value.
   __ mov(eax, Operand(eax, 0));
   __ bind(&prologue);
-  __ LeaveExitFrame(ExitFrame::MODE_NORMAL);
+  __ LeaveExitFrame();
   __ ret(0);
   __ bind(&promote_scheduled_exception);
   __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
@@ -3177,7 +3177,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   __ j(zero, &failure_returned, not_taken);
 
   // Exit the JavaScript to C++ exit frame.
-  __ LeaveExitFrame(mode_);
+  __ LeaveExitFrame();
   __ ret(0);
 
   // Handling of failure.
@@ -3277,7 +3277,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // a garbage collection and retrying the builtin (twice).
 
   // Enter the exit frame that transitions from JavaScript to C++.
-  __ EnterExitFrame(mode_);
+  __ EnterExitFrame();
 
   // eax: result parameter for PerformGC, if any (setup below)
   // ebx: pointer to builtin function  (C callee-saved)
index 3d3f511..ee94565 100644 (file)
@@ -94,22 +94,33 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() {
 
 
 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
-                                          RegList pointer_regs,
+                                          RegList object_regs,
+                                          RegList non_object_regs,
                                           bool convert_call_to_jmp) {
-  // Save the content of all general purpose registers in memory. This copy in
-  // memory is later pushed onto the JS expression stack for the fake JS frame
-  // generated and also to the C frame generated on top of that. In the JS
-  // frame ONLY the registers containing pointers will be pushed on the
-  // expression stack. This causes the GC to update these pointers so that
-  // they will have the correct value when returning from the debugger.
-  __ SaveRegistersToMemory(kJSCallerSaved);
-
   // Enter an internal frame.
   __ EnterInternalFrame();
 
-  // Store the registers containing object pointers on the expression stack to
-  // make sure that these are correctly updated during GC.
-  __ PushRegistersFromMemory(pointer_regs);
+  // 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.
+  ASSERT((object_regs & ~kJSCallerSaved) == 0);
+  ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
+  ASSERT((object_regs & non_object_regs) == 0);
+  for (int i = 0; i < kNumJSCallerSaved; i++) {
+    int r = JSCallerSavedCode(i);
+    Register reg = { r };
+    if ((object_regs & (1 << r)) != 0) {
+      __ push(reg);
+    }
+    if ((non_object_regs & (1 << r)) != 0) {
+      if (FLAG_debug_code) {
+        __ test(reg, Immediate(0xc0000000));
+        __ Assert(zero, "Unable to encode value as smi");
+      }
+      __ SmiTag(reg);
+      __ push(reg);
+    }
+  }
 
 #ifdef DEBUG
   __ RecordComment("// Calling from debug break to runtime - come in - over");
@@ -117,12 +128,25 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
   __ Set(eax, Immediate(0));  // no arguments
   __ mov(ebx, Immediate(ExternalReference::debug_break()));
 
-  CEntryStub ceb(1, ExitFrame::MODE_DEBUG);
+  CEntryStub ceb(1);
   __ CallStub(&ceb);
 
   // Restore the register values containing object pointers from the expression
-  // stack in the reverse order as they where pushed.
-  __ PopRegistersToMemory(pointer_regs);
+  // stack.
+  for (int i = kNumJSCallerSaved; --i >= 0;) {
+    int r = JSCallerSavedCode(i);
+    Register reg = { r };
+    if (FLAG_debug_code) {
+      __ Set(reg, Immediate(kDebugZapValue));
+    }
+    if ((object_regs & (1 << r)) != 0) {
+      __ pop(reg);
+    }
+    if ((non_object_regs & (1 << r)) != 0) {
+      __ pop(reg);
+      __ SmiUntag(reg);
+    }
+  }
 
   // Get rid of the internal frame.
   __ LeaveInternalFrame();
@@ -130,12 +154,9 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
   // If this call did not replace a call but patched other code then there will
   // be an unwanted return address left on the stack. Here we get rid of that.
   if (convert_call_to_jmp) {
-    __ pop(eax);
+    __ add(Operand(esp), Immediate(kPointerSize));
   }
 
-  // Finally restore all registers.
-  __ RestoreRegistersFromMemory(kJSCallerSaved);
-
   // Now that the break point has been handled, resume normal execution by
   // jumping to the target address intended by the caller and that was
   // overwritten by the address of DebugBreakXXX.
@@ -151,7 +172,7 @@ void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
   //  -- eax    : receiver
   //  -- ecx    : name
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit(), false);
+  Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit(), 0, false);
 }
 
 
@@ -162,7 +183,8 @@ void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
   //  -- ecx    : name
   //  -- edx    : receiver
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit() | edx.bit(), false);
+  Generate_DebugBreakCallHelper(
+      masm, eax.bit() | ecx.bit() | edx.bit(), 0, false);
 }
 
 
@@ -172,7 +194,7 @@ void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
   //  -- edx    : receiver
   //  -- eax    : key
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, eax.bit() | edx.bit(), false);
+  Generate_DebugBreakCallHelper(masm, eax.bit() | edx.bit(), 0, false);
 }
 
 
@@ -183,7 +205,8 @@ void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
   //  -- ecx    : key
   //  -- edx    : receiver
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit() | edx.bit(), false);
+  Generate_DebugBreakCallHelper(
+      masm, eax.bit() | ecx.bit() | edx.bit(), 0, false);
 }
 
 
@@ -192,7 +215,7 @@ void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- ecx: name
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, ecx.bit(), false);
+  Generate_DebugBreakCallHelper(masm, ecx.bit(), 0, false);
 }
 
 
@@ -201,10 +224,11 @@ void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) {
   // eax is the actual number of arguments not encoded as a smi see comment
   // above IC call.
   // ----------- S t a t e -------------
-  //  -- eax: number of arguments
+  //  -- eax: number of arguments (not smi)
+  //  -- edi: constructor function
   // -----------------------------------
   // The number of arguments in eax is not smi encoded.
-  Generate_DebugBreakCallHelper(masm, 0, false);
+  Generate_DebugBreakCallHelper(masm, edi.bit(), eax.bit(), false);
 }
 
 
@@ -213,7 +237,7 @@ void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- eax: return value
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, eax.bit(), true);
+  Generate_DebugBreakCallHelper(masm, eax.bit(), 0, true);
 }
 
 
@@ -222,7 +246,7 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  No registers used on entry.
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, 0, false);
+  Generate_DebugBreakCallHelper(masm, 0, 0, false);
 }
 
 
@@ -242,7 +266,7 @@ void Debug::GenerateSlot(MacroAssembler* masm) {
 void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
   // In the places where a debug break slot is inserted no registers can contain
   // object pointers.
-  Generate_DebugBreakCallHelper(masm, 0, true);
+  Generate_DebugBreakCallHelper(masm, 0, 0, true);
 }
 
 
index 212cfde..c3ff913 100644 (file)
@@ -58,6 +58,7 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
   state->fp = fp;
   state->sp = sp;
   state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
+  ASSERT(*state->pc_address != NULL);
   return EXIT;
 }
 
index ff48d54..82ea841 100644 (file)
@@ -191,81 +191,6 @@ void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
 
 
 #ifdef ENABLE_DEBUGGER_SUPPORT
-void MacroAssembler::SaveRegistersToMemory(RegList regs) {
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Copy the content of registers to memory location.
-  for (int i = 0; i < kNumJSCallerSaved; i++) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      Register reg = { r };
-      ExternalReference reg_addr =
-          ExternalReference(Debug_Address::Register(i));
-      mov(Operand::StaticVariable(reg_addr), reg);
-    }
-  }
-}
-
-
-void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Copy the content of memory location to registers.
-  for (int i = kNumJSCallerSaved; --i >= 0;) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      Register reg = { r };
-      ExternalReference reg_addr =
-          ExternalReference(Debug_Address::Register(i));
-      mov(reg, Operand::StaticVariable(reg_addr));
-    }
-  }
-}
-
-
-void MacroAssembler::PushRegistersFromMemory(RegList regs) {
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Push the content of the memory location to the stack.
-  for (int i = 0; i < kNumJSCallerSaved; i++) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      ExternalReference reg_addr =
-          ExternalReference(Debug_Address::Register(i));
-      push(Operand::StaticVariable(reg_addr));
-    }
-  }
-}
-
-
-void MacroAssembler::PopRegistersToMemory(RegList regs) {
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Pop the content from the stack to the memory location.
-  for (int i = kNumJSCallerSaved; --i >= 0;) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      ExternalReference reg_addr =
-          ExternalReference(Debug_Address::Register(i));
-      pop(Operand::StaticVariable(reg_addr));
-    }
-  }
-}
-
-
-void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
-                                                    Register scratch,
-                                                    RegList regs) {
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Copy the content of the stack to the memory location and adjust base.
-  for (int i = kNumJSCallerSaved; --i >= 0;) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      mov(scratch, Operand(base, 0));
-      ExternalReference reg_addr =
-          ExternalReference(Debug_Address::Register(i));
-      mov(Operand::StaticVariable(reg_addr), scratch);
-      lea(base, Operand(base, kPointerSize));
-    }
-  }
-}
-
 void MacroAssembler::DebugBreak() {
   Set(eax, Immediate(0));
   mov(ebx, Immediate(ExternalReference(Runtime::kDebugBreak)));
@@ -274,6 +199,7 @@ void MacroAssembler::DebugBreak() {
 }
 #endif
 
+
 void MacroAssembler::Set(Register dst, const Immediate& x) {
   if (x.is_zero()) {
     xor_(dst, Operand(dst));  // shorter than mov
@@ -405,7 +331,8 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
   leave();
 }
 
-void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode) {
+
+void MacroAssembler::EnterExitFramePrologue() {
   // Setup the frame structure on the stack.
   ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
   ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
@@ -413,7 +340,7 @@ void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode) {
   push(ebp);
   mov(ebp, Operand(esp));
 
-  // Reserve room for entry stack pointer and push the debug marker.
+  // Reserve room for entry stack pointer and push the code object.
   ASSERT(ExitFrameConstants::kSPOffset  == -1 * kPointerSize);
   push(Immediate(0));  // Saved entry sp, patched before call.
   push(Immediate(CodeObject()));  // Accessed from ExitFrame::code_slot.
@@ -425,21 +352,8 @@ void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode) {
   mov(Operand::StaticVariable(context_address), esi);
 }
 
-void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc) {
-#ifdef ENABLE_DEBUGGER_SUPPORT
-  // Save the state of all registers to the stack from the memory
-  // location. This is needed to allow nested break points.
-  if (mode == ExitFrame::MODE_DEBUG) {
-    // TODO(1243899): This should be symmetric to
-    // CopyRegistersFromStackToMemory() but it isn't! esp is assumed
-    // correct here, but computed for the other call. Very error
-    // prone! FIX THIS.  Actually there are deeper problems with
-    // register saving than this asymmetry (see the bug report
-    // associated with this issue).
-    PushRegistersFromMemory(kJSCallerSaved);
-  }
-#endif
 
+void MacroAssembler::EnterExitFrameEpilogue(int argc) {
   // Reserve space for arguments.
   sub(Operand(esp), Immediate(argc * kPointerSize));
 
@@ -455,44 +369,30 @@ void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc) {
 }
 
 
-void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) {
-  EnterExitFramePrologue(mode);
+void MacroAssembler::EnterExitFrame() {
+  EnterExitFramePrologue();
 
   // Setup argc and argv in callee-saved registers.
   int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
   mov(edi, Operand(eax));
   lea(esi, Operand(ebp, eax, times_4, offset));
 
-  EnterExitFrameEpilogue(mode, 2);
+  EnterExitFrameEpilogue(2);
 }
 
 
-void MacroAssembler::EnterApiExitFrame(ExitFrame::Mode mode,
-                                       int stack_space,
+void MacroAssembler::EnterApiExitFrame(int stack_space,
                                        int argc) {
-  EnterExitFramePrologue(mode);
+  EnterExitFramePrologue();
 
   int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
   lea(esi, Operand(ebp, (stack_space * kPointerSize) + offset));
 
-  EnterExitFrameEpilogue(mode, argc);
+  EnterExitFrameEpilogue(argc);
 }
 
 
-void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode) {
-#ifdef ENABLE_DEBUGGER_SUPPORT
-  // Restore the memory copy of the registers by digging them out from
-  // the stack. This is needed to allow nested break points.
-  if (mode == ExitFrame::MODE_DEBUG) {
-    // It's okay to clobber register ebx below because we don't need
-    // the function pointer after this.
-    const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
-    int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize;
-    lea(ebx, Operand(ebp, kOffset));
-    CopyRegistersFromStackToMemory(ebx, ecx, kJSCallerSaved);
-  }
-#endif
-
+void MacroAssembler::LeaveExitFrame() {
   // Get the return address from the stack and restore the frame pointer.
   mov(ecx, Operand(ebp, 1 * kPointerSize));
   mov(ebp, Operand(ebp, 0 * kPointerSize));
index cd2f0f5..f626e3e 100644 (file)
@@ -99,13 +99,6 @@ class MacroAssembler: public Assembler {
   // ---------------------------------------------------------------------------
   // Debugger Support
 
-  void SaveRegistersToMemory(RegList regs);
-  void RestoreRegistersFromMemory(RegList regs);
-  void PushRegistersFromMemory(RegList regs);
-  void PopRegistersToMemory(RegList regs);
-  void CopyRegistersFromStackToMemory(Register base,
-                                      Register scratch,
-                                      RegList regs);
   void DebugBreak();
 #endif
 
@@ -128,14 +121,14 @@ class MacroAssembler: public Assembler {
   // Expects the number of arguments in register eax and
   // sets up the number of arguments in register edi and the pointer
   // to the first argument in register esi.
-  void EnterExitFrame(ExitFrame::Mode mode);
+  void EnterExitFrame();
 
-  void EnterApiExitFrame(ExitFrame::Mode mode, int stack_space, int argc);
+  void EnterApiExitFrame(int stack_space, int argc);
 
   // Leave the current exit frame. Expects the return value in
   // register eax:edx (untouched) and the pointer to the first
   // argument in register esi.
-  void LeaveExitFrame(ExitFrame::Mode mode);
+  void LeaveExitFrame();
 
   // Find the function context up the context chain.
   void LoadContext(Register dst, int context_chain_length);
@@ -571,8 +564,8 @@ class MacroAssembler: public Assembler {
   void EnterFrame(StackFrame::Type type);
   void LeaveFrame(StackFrame::Type type);
 
-  void EnterExitFramePrologue(ExitFrame::Mode mode);
-  void EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc);
+  void EnterExitFramePrologue();
+  void EnterExitFrameEpilogue(int argc);
 
   // Allocation support helpers.
   void LoadAllocationTopHelper(Register result,
index cdde07e..cde7577 100644 (file)
@@ -241,16 +241,6 @@ void ExternalReferenceTable::PopulateTable() {
       DEBUG_ADDRESS,
       Debug::k_restarter_frame_function_pointer << kDebugIdShift,
       "Debug::restarter_frame_function_pointer_address()");
-  const char* debug_register_format = "Debug::register_address(%i)";
-  int dr_format_length = StrLength(debug_register_format);
-  for (int i = 0; i < kNumJSCallerSaved; ++i) {
-    Vector<char> name = Vector<char>::New(dr_format_length + 1);
-    OS::SNPrintF(name, debug_register_format, i);
-    Add(Debug_Address(Debug::k_register_address, i).address(),
-        DEBUG_ADDRESS,
-        Debug::k_register_address << kDebugIdShift | i,
-        name.start());
-  }
 #endif
 
   // Stat counters
index 304e65c..028de50 100644 (file)
@@ -2476,7 +2476,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
   Label empty_result;
   Label prologue;
   Label promote_scheduled_exception;
-  __ EnterApiExitFrame(ExitFrame::MODE_NORMAL, kStackSpace, 0);
+  __ EnterApiExitFrame(kStackSpace, 0);
   ASSERT_EQ(kArgc, 4);
 #ifdef _WIN64
   // All the parameters should be set up by a caller.
@@ -2507,7 +2507,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
   // It was non-zero.  Dereference to get the result value.
   __ movq(rax, Operand(rax, 0));
   __ bind(&prologue);
-  __ LeaveExitFrame(ExitFrame::MODE_NORMAL);
+  __ LeaveExitFrame();
   __ ret(0);
   __ bind(&promote_scheduled_exception);
   __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
@@ -2617,7 +2617,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   __ j(zero, &failure_returned);
 
   // Exit the JavaScript to C++ exit frame.
-  __ LeaveExitFrame(mode_, result_size_);
+  __ LeaveExitFrame(result_size_);
   __ ret(0);
 
   // Handling of failure.
@@ -2721,7 +2721,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // builtin once.
 
   // Enter the exit frame that transitions from JavaScript to C++.
-  __ EnterExitFrame(mode_, result_size_);
+  __ EnterExitFrame(result_size_);
 
   // rax: Holds the context at this point, but should not be used.
   //      On entry to code generated by GenerateCore, it must hold
index fb4429d..cb5b8ab 100644 (file)
@@ -47,22 +47,35 @@ bool Debug::IsDebugBreakAtReturn(v8::internal::RelocInfo* rinfo) {
 #define __ ACCESS_MASM(masm)
 
 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
-                                          RegList pointer_regs,
+                                          RegList object_regs,
+                                          RegList non_object_regs,
                                           bool convert_call_to_jmp) {
-  // Save the content of all general purpose registers in memory. This copy in
-  // memory is later pushed onto the JS expression stack for the fake JS frame
-  // generated and also to the C frame generated on top of that. In the JS
-  // frame ONLY the registers containing pointers will be pushed on the
-  // expression stack. This causes the GC to update these pointers so that
-  // they will have the correct value when returning from the debugger.
-  __ SaveRegistersToMemory(kJSCallerSaved);
-
   // Enter an internal frame.
   __ EnterInternalFrame();
 
-  // Store the registers containing object pointers on the expression stack to
-  // make sure that these are correctly updated during GC.
-  __ PushRegistersFromMemory(pointer_regs);
+  // 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 as two smi causing it to be untouched by GC.
+  ASSERT((object_regs & ~kJSCallerSaved) == 0);
+  ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
+  ASSERT((object_regs & non_object_regs) == 0);
+  for (int i = 0; i < kNumJSCallerSaved; i++) {
+    int r = JSCallerSavedCode(i);
+    Register reg = { r };
+    ASSERT(!reg.is(kScratchRegister));
+    if ((object_regs & (1 << r)) != 0) {
+      __ push(reg);
+    }
+    // Store the 64-bit value as two smis.
+    if ((non_object_regs & (1 << r)) != 0) {
+      __ movq(kScratchRegister, reg);
+      __ Integer32ToSmi(reg, reg);
+      __ push(reg);
+      __ sar(kScratchRegister, Immediate(32));
+      __ Integer32ToSmi(kScratchRegister, kScratchRegister);
+      __ push(kScratchRegister);
+    }
+  }
 
 #ifdef DEBUG
   __ RecordComment("// Calling from debug break to runtime - come in - over");
@@ -70,12 +83,29 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
   __ xor_(rax, rax);  // No arguments (argc == 0).
   __ movq(rbx, ExternalReference::debug_break());
 
-  CEntryStub ceb(1, ExitFrame::MODE_DEBUG);
+  CEntryStub ceb(1);
   __ CallStub(&ceb);
 
-  // Restore the register values containing object pointers from the expression
-  // stack in the reverse order as they where pushed.
-  __ PopRegistersToMemory(pointer_regs);
+  // Restore the register values from the expression stack.
+  for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
+    int r = JSCallerSavedCode(i);
+    Register reg = { r };
+    if (FLAG_debug_code) {
+      __ Set(reg, kDebugZapValue);
+    }
+    if ((object_regs & (1 << r)) != 0) {
+      __ pop(reg);
+    }
+    // Reconstruct the 64-bit value from two smis.
+    if ((non_object_regs & (1 << r)) != 0) {
+      __ pop(kScratchRegister);
+      __ SmiToInteger32(kScratchRegister, kScratchRegister);
+      __ shl(kScratchRegister, Immediate(32));
+      __ pop(reg);
+      __ SmiToInteger32(reg, reg);
+      __ or_(reg, kScratchRegister);
+    }
+ }
 
   // Get rid of the internal frame.
   __ LeaveInternalFrame();
@@ -83,12 +113,9 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
   // If this call did not replace a call but patched other code then there will
   // be an unwanted return address left on the stack. Here we get rid of that.
   if (convert_call_to_jmp) {
-    __ pop(rax);
+    __ addq(rsp, Immediate(kPointerSize));
   }
 
-  // Finally restore all registers.
-  __ RestoreRegistersFromMemory(kJSCallerSaved);
-
   // Now that the break point has been handled, resume normal execution by
   // jumping to the target address intended by the caller and that was
   // overwritten by the address of DebugBreakXXX.
@@ -104,7 +131,7 @@ void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- rcx: function name
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, rcx.bit(), false);
+  Generate_DebugBreakCallHelper(masm, rcx.bit(), 0, false);
 }
 
 
@@ -116,7 +143,7 @@ void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) {
   //  -- rax: number of arguments
   // -----------------------------------
   // The number of arguments in rax is not smi encoded.
-  Generate_DebugBreakCallHelper(masm, 0, false);
+  Generate_DebugBreakCallHelper(masm, rdi.bit(), rax.bit(), false);
 }
 
 
@@ -126,7 +153,7 @@ void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
   //  -- rax     : key
   //  -- rdx     : receiver
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, rax.bit() | rdx.bit(), false);
+  Generate_DebugBreakCallHelper(masm, rax.bit() | rdx.bit(), 0, false);
 }
 
 
@@ -137,7 +164,8 @@ void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
   //  -- rcx    : key
   //  -- rdx    : receiver
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, rax.bit() | rcx.bit() | rdx.bit(), false);
+  Generate_DebugBreakCallHelper(
+      masm, rax.bit() | rcx.bit() | rdx.bit(), 0, false);
 }
 
 
@@ -147,7 +175,7 @@ void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
   //  -- rax    : receiver
   //  -- rcx    : name
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, rax.bit() | rcx.bit(), false);
+  Generate_DebugBreakCallHelper(masm, rax.bit() | rcx.bit(), 0, false);
 }
 
 
@@ -156,7 +184,7 @@ void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- rax: return value
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, rax.bit(), true);
+  Generate_DebugBreakCallHelper(masm, rax.bit(), 0, true);
 }
 
 
@@ -167,7 +195,8 @@ void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
   //  -- rcx    : name
   //  -- rdx    : receiver
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, rax.bit() | rcx.bit() | rdx.bit(), false);
+  Generate_DebugBreakCallHelper(
+      masm, rax.bit() | rcx.bit() | rdx.bit(), 0, false);
 }
 
 
@@ -176,7 +205,7 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  No registers used on entry.
   // -----------------------------------
-  Generate_DebugBreakCallHelper(masm, 0, false);
+  Generate_DebugBreakCallHelper(masm, 0, 0, false);
 }
 
 
@@ -196,7 +225,7 @@ void Debug::GenerateSlot(MacroAssembler* masm) {
 void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
   // In the places where a debug break slot is inserted no registers can contain
   // object pointers.
-  Generate_DebugBreakCallHelper(masm, 0, true);
+  Generate_DebugBreakCallHelper(masm, 0, 0, true);
 }
 
 
index 85ebc95..770a974 100644 (file)
@@ -58,7 +58,7 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
   state->fp = fp;
   state->sp = sp;
   state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
-  // Determine frame type.
+  ASSERT(*state->pc_address != NULL);
   return EXIT;
 }
 
index a6837bb..b8f6c37 100644 (file)
@@ -2102,91 +2102,8 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
   }
 }
 
-#ifdef ENABLE_DEBUGGER_SUPPORT
-
-void MacroAssembler::PushRegistersFromMemory(RegList regs) {
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Push the content of the memory location to the stack.
-  for (int i = 0; i < kNumJSCallerSaved; i++) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      ExternalReference reg_addr =
-          ExternalReference(Debug_Address::Register(i));
-      movq(kScratchRegister, reg_addr);
-      push(Operand(kScratchRegister, 0));
-    }
-  }
-}
-
-
-void MacroAssembler::SaveRegistersToMemory(RegList regs) {
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Copy the content of registers to memory location.
-  for (int i = 0; i < kNumJSCallerSaved; i++) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      Register reg = { r };
-      ExternalReference reg_addr =
-          ExternalReference(Debug_Address::Register(i));
-      movq(kScratchRegister, reg_addr);
-      movq(Operand(kScratchRegister, 0), reg);
-    }
-  }
-}
-
-
-void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Copy the content of memory location to registers.
-  for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      Register reg = { r };
-      ExternalReference reg_addr =
-          ExternalReference(Debug_Address::Register(i));
-      movq(kScratchRegister, reg_addr);
-      movq(reg, Operand(kScratchRegister, 0));
-    }
-  }
-}
-
-
-void MacroAssembler::PopRegistersToMemory(RegList regs) {
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Pop the content from the stack to the memory location.
-  for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      ExternalReference reg_addr =
-          ExternalReference(Debug_Address::Register(i));
-      movq(kScratchRegister, reg_addr);
-      pop(Operand(kScratchRegister, 0));
-    }
-  }
-}
-
-
-void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
-                                                    Register scratch,
-                                                    RegList regs) {
-  ASSERT(!scratch.is(kScratchRegister));
-  ASSERT(!base.is(kScratchRegister));
-  ASSERT(!base.is(scratch));
-  ASSERT((regs & ~kJSCallerSaved) == 0);
-  // Copy the content of the stack to the memory location and adjust base.
-  for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
-    int r = JSCallerSavedCode(i);
-    if ((regs & (1 << r)) != 0) {
-      movq(scratch, Operand(base, 0));
-      ExternalReference reg_addr =
-          ExternalReference(Debug_Address::Register(i));
-      movq(kScratchRegister, reg_addr);
-      movq(Operand(kScratchRegister, 0), scratch);
-      lea(base, Operand(base, kPointerSize));
-    }
-  }
-}
 
+#ifdef ENABLE_DEBUGGER_SUPPORT
 void MacroAssembler::DebugBreak() {
   ASSERT(allow_stub_calls());
   xor_(rax, rax);  // no arguments
@@ -2356,8 +2273,7 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
 }
 
 
-void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode,
-                                            bool save_rax) {
+void MacroAssembler::EnterExitFramePrologue(bool save_rax) {
   // Setup the frame structure on the stack.
   // All constants are relative to the frame pointer of the exit frame.
   ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
@@ -2366,7 +2282,7 @@ void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode,
   push(rbp);
   movq(rbp, rsp);
 
-  // Reserve room for entry stack pointer and push the debug marker.
+  // Reserve room for entry stack pointer and push the code object.
   ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize);
   push(Immediate(0));  // Saved entry sp, patched before call.
   movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT);
@@ -2385,23 +2301,8 @@ void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode,
   store_rax(context_address);
 }
 
-void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode,
-                                            int result_size,
+void MacroAssembler::EnterExitFrameEpilogue(int result_size,
                                             int argc) {
-#ifdef ENABLE_DEBUGGER_SUPPORT
-  // Save the state of all registers to the stack from the memory
-  // location. This is needed to allow nested break points.
-  if (mode == ExitFrame::MODE_DEBUG) {
-    // TODO(1243899): This should be symmetric to
-    // CopyRegistersFromStackToMemory() but it isn't! esp is assumed
-    // correct here, but computed for the other call. Very error
-    // prone! FIX THIS.  Actually there are deeper problems with
-    // register saving than this asymmetry (see the bug report
-    // associated with this issue).
-    PushRegistersFromMemory(kJSCallerSaved);
-  }
-#endif
-
 #ifdef _WIN64
   // Reserve space on stack for result and argument structures, if necessary.
   int result_stack_space = (result_size < 2) ? 0 : result_size * kPointerSize;
@@ -2430,48 +2331,35 @@ void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode,
 }
 
 
-void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) {
-  EnterExitFramePrologue(mode, true);
+void MacroAssembler::EnterExitFrame(int result_size) {
+  EnterExitFramePrologue(true);
 
   // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
   // so it must be retained across the C-call.
   int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
   lea(r12, Operand(rbp, r14, times_pointer_size, offset));
 
-  EnterExitFrameEpilogue(mode, result_size, 2);
+  EnterExitFrameEpilogue(result_size, 2);
 }
 
 
-void MacroAssembler::EnterApiExitFrame(ExitFrame::Mode mode,
-                                       int stack_space,
+void MacroAssembler::EnterApiExitFrame(int stack_space,
                                        int argc,
                                        int result_size) {
-  EnterExitFramePrologue(mode, false);
+  EnterExitFramePrologue(false);
 
   // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
   // so it must be retained across the C-call.
   int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
   lea(r12, Operand(rbp, (stack_space * kPointerSize) + offset));
 
-  EnterExitFrameEpilogue(mode, result_size, argc);
+  EnterExitFrameEpilogue(result_size, argc);
 }
 
 
-void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode, int result_size) {
+void MacroAssembler::LeaveExitFrame(int result_size) {
   // Registers:
   // r12 : argv
-#ifdef ENABLE_DEBUGGER_SUPPORT
-  // Restore the memory copy of the registers by digging them out from
-  // the stack. This is needed to allow nested break points.
-  if (mode == ExitFrame::MODE_DEBUG) {
-    // It's okay to clobber register rbx below because we don't need
-    // the function pointer after this.
-    const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
-    int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize;
-    lea(rbx, Operand(rbp, kOffset));
-    CopyRegistersFromStackToMemory(rbx, rcx, kJSCallerSaved);
-  }
-#endif
 
   // Get the return address from the stack and restore the frame pointer.
   movq(rcx, Operand(rbp, 1 * kPointerSize));
index 08cb377..681f38d 100644 (file)
@@ -132,13 +132,6 @@ class MacroAssembler: public Assembler {
   // ---------------------------------------------------------------------------
   // Debugger Support
 
-  void SaveRegistersToMemory(RegList regs);
-  void RestoreRegistersFromMemory(RegList regs);
-  void PushRegistersFromMemory(RegList regs);
-  void PopRegistersToMemory(RegList regs);
-  void CopyRegistersFromStackToMemory(Register base,
-                                      Register scratch,
-                                      RegList regs);
   void DebugBreak();
 #endif
 
@@ -161,17 +154,16 @@ class MacroAssembler: public Assembler {
   // debug mode. Expects the number of arguments in register rax and
   // sets up the number of arguments in register rdi and the pointer
   // to the first argument in register rsi.
-  void EnterExitFrame(ExitFrame::Mode mode, int result_size = 1);
+  void EnterExitFrame(int result_size = 1);
 
-  void EnterApiExitFrame(ExitFrame::Mode mode,
-                         int stack_space,
+  void EnterApiExitFrame(int stack_space,
                          int argc,
                          int result_size = 1);
 
   // Leave the current exit frame. Expects/provides the return value in
   // register rax:rdx (untouched) and the pointer to the first
   // argument in register rsi.
-  void LeaveExitFrame(ExitFrame::Mode mode, int result_size = 1);
+  void LeaveExitFrame(int result_size = 1);
 
 
   // ---------------------------------------------------------------------------
@@ -878,8 +870,8 @@ class MacroAssembler: public Assembler {
   void EnterFrame(StackFrame::Type type);
   void LeaveFrame(StackFrame::Type type);
 
-  void EnterExitFramePrologue(ExitFrame::Mode mode, bool save_rax);
-  void EnterExitFrameEpilogue(ExitFrame::Mode mode, int result_size, int argc);
+  void EnterExitFramePrologue(bool save_rax);
+  void EnterExitFrameEpilogue(int result_size, int argc);
 
   // Allocation support helpers.
   // Loads the top of new-space into the result register.
index 5141531..d03f5f7 100644 (file)
@@ -56,10 +56,6 @@ test-api/OutOfMemoryNested: SKIP
 # BUG(355): Test crashes on ARM.
 test-log/ProfLazyMode: SKIP
 
-# BUG(845)
-test-debug/GCDuringBreakPointProcessing: SKIP
-test-debug/BreakPointICCallWithGC: SKIP
-
 [ $arch == mips ]
 test-accessors: SKIP
 test-alloc: SKIP
index 3a1390c..9531b57 100644 (file)
@@ -869,7 +869,7 @@ static void DebugEventBreakPointCollectGarbage(
       // Scavenge.
       Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
     } else {
-      // Mark sweep (and perhaps compact).
+      // Mark sweep compact.
       Heap::CollectAllGarbage(true);
     }
   }
@@ -1177,6 +1177,40 @@ TEST(BreakPointICCallWithGC) {
 }
 
 
+// Test that a break point can be set at an IC call location and survive a GC.
+TEST(BreakPointConstructCallWithGC) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
+                                   v8::Undefined());
+  v8::Script::Compile(v8::String::New("function bar(){ this.x = 1;}"))->Run();
+  v8::Script::Compile(v8::String::New(
+      "function foo(){return new bar(1).x;}"))->Run();
+  v8::Local<v8::Function> foo =
+      v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
+
+  // Run without breakpoints.
+  CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
+  CHECK_EQ(0, break_point_hit_count);
+
+  // Run with breakpoint.
+  int bp = SetBreakPoint(foo, 0);
+  CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
+  CHECK_EQ(1, break_point_hit_count);
+  CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
+  CHECK_EQ(2, break_point_hit_count);
+
+  // Run without breakpoints.
+  ClearBreakPoint(bp);
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  v8::Debug::SetDebugEventListener(NULL);
+  CheckDebuggerUnloaded();
+}
+
+
 // Test that a break point can be set at a return store location.
 TEST(BreakPointReturn) {
   break_point_hit_count = 0;
index 3ec25c9..20fb2fe 100644 (file)
@@ -98,13 +98,6 @@ static int make_code(TypeCode type, int id) {
 }
 
 
-#ifdef ENABLE_DEBUGGER_SUPPORT
-static int register_code(int reg) {
-  return Debug::k_register_address << kDebugIdShift | reg;
-}
-#endif  // ENABLE_DEBUGGER_SUPPORT
-
-
 TEST(ExternalReferenceEncoder) {
   StatsTable::SetCounterFunction(counter_function);
   Heap::Setup(false);
@@ -115,10 +108,6 @@ TEST(ExternalReferenceEncoder) {
            Encode(encoder, Runtime::kAbort));
   CHECK_EQ(make_code(IC_UTILITY, IC::kLoadCallbackProperty),
            Encode(encoder, IC_Utility(IC::kLoadCallbackProperty)));
-#ifdef ENABLE_DEBUGGER_SUPPORT
-  CHECK_EQ(make_code(DEBUG_ADDRESS, register_code(3)),
-           Encode(encoder, Debug_Address(Debug::k_register_address, 3)));
-#endif  // ENABLE_DEBUGGER_SUPPORT
   ExternalReference keyed_load_function_prototype =
       ExternalReference(&Counters::keyed_load_function_prototype);
   CHECK_EQ(make_code(STATS_COUNTER, Counters::k_keyed_load_function_prototype),
@@ -156,10 +145,6 @@ TEST(ExternalReferenceDecoder) {
            decoder.Decode(make_code(RUNTIME_FUNCTION, Runtime::kAbort)));
   CHECK_EQ(AddressOf(IC_Utility(IC::kLoadCallbackProperty)),
            decoder.Decode(make_code(IC_UTILITY, IC::kLoadCallbackProperty)));
-#ifdef ENABLE_DEBUGGER_SUPPORT
-  CHECK_EQ(AddressOf(Debug_Address(Debug::k_register_address, 3)),
-           decoder.Decode(make_code(DEBUG_ADDRESS, register_code(3))));
-#endif  // ENABLE_DEBUGGER_SUPPORT
   ExternalReference keyed_load_function =
       ExternalReference(&Counters::keyed_load_function_prototype);
   CHECK_EQ(keyed_load_function.address(),