X64: Implement debugger hooks.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 19 Aug 2009 10:18:30 +0000 (10:18 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 19 Aug 2009 10:18:30 +0000 (10:18 +0000)
Debugger is now fully functional.
Fix difference in emitting statement positions to match ia32.

Review URL: http://codereview.chromium.org/171107

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

25 files changed:
src/arm/assembler-arm.h
src/arm/macro-assembler-arm.cc
src/assembler.h
src/debug.cc
src/debug.h
src/execution.h
src/ia32/assembler-ia32.h
src/ia32/debug-ia32.cc
src/ia32/ic-ia32.cc
src/ic-inl.h
src/ic.cc
src/ic.h
src/x64/assembler-x64-inl.h
src/x64/assembler-x64.cc
src/x64/assembler-x64.h
src/x64/builtins-x64.cc
src/x64/cfg-x64.cc
src/x64/codegen-x64.cc
src/x64/debug-x64.cc
src/x64/ic-x64.cc
src/x64/macro-assembler-x64.cc
test/cctest/cctest.status
test/cctest/test-debug.cc
test/message/message.status
test/mjsunit/mjsunit.status

index eeab4a72cc9e5e139b27177a98fb3de23b660fdf..b3ebb8be8b8369c3b387acbe6f28ef5b87d22cff 100644 (file)
@@ -430,7 +430,10 @@ class Assembler : public Malloced {
 
   // Distance between the instruction referring to the address of the call
   // target (ldr pc, [target addr in const pool]) and the return address
-  static const int kTargetAddrToReturnAddrDist = sizeof(Instr);
+  static const int kPatchReturnSequenceLength = sizeof(Instr);
+  // Distance between start of patched return sequence and the emitted address
+  // to jump to.
+  static const int kPatchReturnSequenceAddressOffset = 1;
 
 
   // ---------------------------------------------------------------------------
index 875c91e96437f4a96384012aedc2cba239512b5d..4b02e2d688f6a5d49bc6021c7f1626b7eee87da9 100644 (file)
@@ -132,7 +132,7 @@ void MacroAssembler::Call(intptr_t target, RelocInfo::Mode rmode,
   // and the target address of the call would be referenced by the first
   // instruction rather than the second one, which would make it harder to patch
   // (two instructions before the return address, instead of one).
-  ASSERT(kTargetAddrToReturnAddrDist == sizeof(Instr));
+  ASSERT(kPatchReturnSequenceLength == sizeof(Instr));
 }
 
 
index 879ee5410a9e66519a7b336705f86663055e3767..1ddc8a31e892a34eb78cb23a6a2105d5e5261cfa 100644 (file)
@@ -216,6 +216,9 @@ class RelocInfo BASE_EMBEDDED {
 
   // Patch the code with a call.
   void PatchCodeWithCall(Address target, int guard_bytes);
+  // Check whether the current instruction is currently a call
+  // sequence (whether naturally or a return sequence overwritten
+  // to enter the debugger).
   INLINE(bool IsCallInstruction());
 
 #ifdef ENABLE_DISASSEMBLER
index 18536f5c7a9fe6cba3403d4cf98546db41c4143e..f2a28148b16acebe5c2d063584fa5a05925abd48 100644 (file)
@@ -1452,14 +1452,15 @@ void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
   // Find the call address in the running code. This address holds the call to
   // either a DebugBreakXXX or to the debug break return entry code if the
   // break point is still active after processing the break point.
-  Address addr = frame->pc() - Assembler::kTargetAddrToReturnAddrDist;
+  Address addr = frame->pc() - Assembler::kPatchReturnSequenceLength;
 
   // Check if the location is at JS exit.
   bool at_js_exit = false;
   RelocIterator it(debug_info->code());
   while (!it.done()) {
     if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
-      at_js_exit = it.rinfo()->pc() == addr - 1;
+      at_js_exit = (it.rinfo()->pc() ==
+                        addr - Assembler::kPatchReturnSequenceAddressOffset);
     }
     it.next();
   }
@@ -1477,8 +1478,9 @@ void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
       addr +=  original_code->instruction_start() - code->instruction_start();
     }
 
-    // Move one byte back to where the call instruction was placed.
-    thread_local_.after_break_target_ = addr - 1;
+    // Move back to where the call instruction sequence started.
+    thread_local_.after_break_target_ =
+        addr - Assembler::kPatchReturnSequenceAddressOffset;
   } else {
     // Check if there still is a debug break call at the target address. If the
     // break point has been removed it will have disappeared. If it have
index 970dbbe5ce2a07636218fbfb261b54e87e3f8fbf..5b0273aa2244a883457683de8318c43c6676486c 100644 (file)
@@ -238,7 +238,10 @@ class Debug {
   // Returns whether the operation succeeded.
   static bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared);
 
+  // Returns true if the current stub call is patched to call the debugger.
   static bool IsDebugBreak(Address addr);
+  // Returns true if the current return statement has been patched to be
+  // a debugger breakpoint.
   static bool IsDebugBreakAtReturn(RelocInfo* rinfo);
 
   // Check whether a code stub with the specified major key is a possible break
@@ -366,6 +369,7 @@ class Debug {
 
   // The x64 JS return sequence is padded with int3 to make it large
   // enough to hold a call instruction when the debugger patches it.
+  static const int kX64CallInstructionLength = 13;
   static const int kX64JSReturnSequenceLength = 13;
 
   // Code generator routines.
index 126b172d21e327cfc841922fc09160659c4a7061..fba696e72cc5cb1d32dcaedcddbae692a286fa85 100644 (file)
@@ -206,8 +206,13 @@ class StackGuard BASE_EMBEDDED {
   static void DisableInterrupts();
 
   static const uintptr_t kLimitSize = kPointerSize * 128 * KB;
+#ifdef V8_TARGET_ARCH_X64
+  static const uintptr_t kInterruptLimit = V8_UINT64_C(0xfffffffffffffffe);
+  static const uintptr_t kIllegalLimit = V8_UINT64_C(0xffffffffffffffff);
+#else
   static const uintptr_t kInterruptLimit = 0xfffffffe;
   static const uintptr_t kIllegalLimit = 0xffffffff;
+#endif
 
   class ThreadLocal {
    public:
index b648055f1b9addecf6c7f3c2fe234d9b726682ac..6a90e070d8ee1aaa6522826f79a5c0104da1cced 100644 (file)
@@ -437,7 +437,10 @@ class Assembler : public Malloced {
 
   // Distance between the address of the code target in the call instruction
   // and the return address
-  static const int kTargetAddrToReturnAddrDist = kPointerSize;
+  static const int kPatchReturnSequenceLength = kPointerSize;
+  // Distance between start of patched return sequence and the emitted address
+  // to jump to.
+  static const int kPatchReturnSequenceAddressOffset = 1;  // JMP imm32.
 
 
   // ---------------------------------------------------------------------------
index 9913a39ba97decf8b872e40ec52ce55b761d7945..4ef0862af19bc368d8f87782b7e17bd20e4d78be 100644 (file)
@@ -195,8 +195,8 @@ void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
 
 
 void Debug::GenerateReturnDebugBreakEntry(MacroAssembler* masm) {
-  // OK to clobber ebx as we are returning from a JS function in the code
-  // generated by Ia32CodeGenerator::ExitJSFrame.
+  // OK to clobber ebx as we are returning from a JS function through the code
+  // generated by CodeGenerator::GenerateReturnSequence()
   ExternalReference debug_break_return =
       ExternalReference(Debug_Address::DebugBreakReturn());
   __ mov(ebx, Operand::StaticVariable(debug_break_return));
index 08ffe2f14172b58cceeb72f76ad213e2ae245ebb..fa9b8a20f64b8596d0c11a6911e9ef2a0e65bec5 100644 (file)
@@ -840,7 +840,7 @@ void KeyedStoreIC::RestoreInlinedVersion(Address address) {
 bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
   // The address of the instruction following the call.
   Address test_instruction_address =
-      address + Assembler::kTargetAddrToReturnAddrDist;
+      address + Assembler::kPatchReturnSequenceLength;
   // If the instruction following the call is not a test eax, nothing
   // was inlined.
   if (*test_instruction_address != kTestEaxByte) return false;
@@ -867,7 +867,7 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
 
 static bool PatchInlinedMapCheck(Address address, Object* map) {
   Address test_instruction_address =
-      address + Assembler::kTargetAddrToReturnAddrDist;
+      address + Assembler::kPatchReturnSequenceLength;
   // The keyed load has a fast inlined case if the IC call instruction
   // is immediately followed by a test instruction.
   if (*test_instruction_address != kTestEaxByte) return false;
index 08304d83e7b79244fbf8d570a5e0e46491753cba..38d61dcbb46039e922d78330c630b2e3a4e5f018 100644 (file)
@@ -38,7 +38,7 @@ namespace internal {
 
 Address IC::address() {
   // Get the address of the call.
-  Address result = pc() - Assembler::kTargetAddrToReturnAddrDist;
+  Address result = pc() - Assembler::kPatchReturnSequenceLength;
 
 #ifdef ENABLE_DEBUGGER_SUPPORT
   // First check if any break points are active if not just return the address
index f4d74c93541fe47907ad2fb7400642269df288e2..393ccbf6a752a32fd6b7385ab8f7fbc44f96a65c 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -122,7 +122,7 @@ Address IC::OriginalCodeAddress() {
   // Get the address of the call site in the active code. This is the
   // place where the call to DebugBreakXXX is and where the IC
   // normally would be.
-  Address addr = pc() - Assembler::kTargetAddrToReturnAddrDist;
+  Address addr = pc() - Assembler::kPatchReturnSequenceLength;
   // Return the address in the original code. This is the place where
   // the call which has been overwritten by the DebugBreakXXX resides
   // and the place where the inline cache system should look.
index 860b7e60d61a52e86f1ece8fa15fd5cec5b3d7f6..007b0352e994e989e8088d383b06f617d80727ff 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -390,7 +390,7 @@ class KeyedStoreIC: public IC {
   // Support for patching the map that is checked in an inlined
   // version of keyed store.
   // The address is the patch point for the IC call
-  // (Assembler::kTargetAddrToReturnAddrDist before the end of
+  // (Assembler::kPatchReturnSequenceLength before the end of
   // the call/return address).
   // The map is the new map that the inlined code should check against.
   static bool PatchInlinedStore(Address address, Object* map);
index 196f2eedbd474cf855b7a1ecef304e5b6f9c0ff6..f51a3ea8871712bd6b04d42f1ab14ed01e682523 100644 (file)
@@ -228,43 +228,47 @@ void RelocInfo::set_target_object(Object* target) {
 
 
 bool RelocInfo::IsCallInstruction() {
-  UNIMPLEMENTED();  // IA32 code below.
-  return *pc_ == 0xE8;
+  // The recognized call sequence is:
+  //  movq(kScratchRegister, immediate64); call(kScratchRegister);
+  // It only needs to be distinguished from a return sequence
+  //  movq(rsp, rbp); pop(rbp); ret(n); int3 *6
+  // The 11th byte is int3 (0xCC) in the return sequence and
+  // REX.WB (0x48+register bit) for the call sequence.
+  return pc_[10] != 0xCC;
 }
 
 
 Address RelocInfo::call_address() {
-  UNIMPLEMENTED();  // IA32 code below.
   ASSERT(IsCallInstruction());
-  return Assembler::target_address_at(pc_ + 1);
+  return Assembler::target_address_at(
+      pc_ + Assembler::kPatchReturnSequenceAddressOffset);
 }
 
 
 void RelocInfo::set_call_address(Address target) {
-  UNIMPLEMENTED();  // IA32 code below.
   ASSERT(IsCallInstruction());
-  Assembler::set_target_address_at(pc_ + 1, target);
+  Assembler::set_target_address_at(
+      pc_ + Assembler::kPatchReturnSequenceAddressOffset,
+      target);
 }
 
 
 Object* RelocInfo::call_object() {
-  UNIMPLEMENTED();  // IA32 code below.
   ASSERT(IsCallInstruction());
   return *call_object_address();
 }
 
 
 void RelocInfo::set_call_object(Object* target) {
-  UNIMPLEMENTED();  // IA32 code below.
   ASSERT(IsCallInstruction());
   *call_object_address() = target;
 }
 
 
 Object** RelocInfo::call_object_address() {
-  UNIMPLEMENTED();  // IA32 code below.
   ASSERT(IsCallInstruction());
-  return reinterpret_cast<Object**>(pc_ + 1);
+  return reinterpret_cast<Object**>(
+      pc_ + Assembler::kPatchReturnSequenceAddressOffset);
 }
 
 // -----------------------------------------------------------------------------
index 2607ecc99e014bd06c3498307acf146b56d9b498..a02557e96a0501a7d551c037c55d275396ef3a1f 100644 (file)
@@ -178,6 +178,13 @@ void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
 }
 
 
+void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
+  // Patch the code at the current address with the supplied instructions.
+  for (int i = 0; i < instruction_count; i++) {
+    *(pc_ + i) = *(instructions + i);
+  }
+}
+
 // -----------------------------------------------------------------------------
 // Implementation of Operand
 
@@ -1071,6 +1078,16 @@ void Assembler::jmp(Register target) {
 }
 
 
+void Assembler::jmp(const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  // Opcode FF/4 m64
+  emit_optional_rex_32(src);
+  emit(0xFF);
+  emit_operand(0x4, src);
+}
+
+
 void Assembler::lea(Register dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
index 2130fb0379c245e2c78185ae4999648d67bf4472..9d602b9ef1ddb493b0fd819e6a0e238055865afa 100644 (file)
@@ -442,8 +442,10 @@ class Assembler : public Malloced {
 
   // Distance between the address of the code target in the call instruction
   // and the return address.  Checked in the debug build.
-  static const int kTargetAddrToReturnAddrDist = 3 + kPointerSize;
-
+  static const int kPatchReturnSequenceLength = 3 + kPointerSize;
+  // Distance between start of patched return sequence and the emitted address
+  // to jump to (movq = REX.W 0xB8+r.).
+  static const int kPatchReturnSequenceAddressOffset = 2;
 
   // ---------------------------------------------------------------------------
   // Code generation
@@ -917,6 +919,9 @@ class Assembler : public Malloced {
   // Jump near absolute indirect (r64)
   void jmp(Register adr);
 
+  // Jump near absolute indirect (m64)
+  void jmp(const Operand& src);
+
   // Conditional jumps
   void j(Condition cc, Label* L);
 
index 98b456df22ff3e8317663f2f39cfac156a64c7cf..6988d720822f6f505e937b4a9502cdd985012062 100644 (file)
@@ -505,7 +505,14 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
   Label rt_call, allocated;
   if (FLAG_inline_new) {
     Label undo_allocation;
-    // TODO(X64): Enable debugger support, using debug_step_in_fp.
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+    ExternalReference debug_step_in_fp =
+        ExternalReference::debug_step_in_fp_address();
+    __ movq(kScratchRegister, debug_step_in_fp);
+    __ cmpq(Operand(kScratchRegister, 0), Immediate(0));
+    __ j(not_equal, &rt_call);
+#endif
 
     // Verified that the constructor is a JSFunction.
     // Load the initial map and verify that it is in fact a map.
@@ -828,10 +835,8 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
   // Invoke the code.
   if (is_construct) {
     // Expects rdi to hold function pointer.
-    __ movq(kScratchRegister,
-            Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
+    __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
             RelocInfo::CODE_TARGET);
-    __ call(kScratchRegister);
   } else {
     ParameterCount actual(rax);
     // Function must be in rdi.
index 8d01ed28e13dcf9d7e435abe2789e3942d901576..34ddbbf0258c3c814e1f74d62852887fdae9fc68 100644 (file)
@@ -114,8 +114,8 @@ void ExitNode::Compile(MacroAssembler* masm) {
   int count = CfgGlobals::current()->fun()->scope()->num_parameters();
   __ ret((count + 1) * kPointerSize);
   // Add padding that will be overwritten by a debugger breakpoint.
-  // "movq rsp, rbp; pop rbp" has length 5.  "ret k" has length 2.
-  const int kPadding = Debug::kX64JSReturnSequenceLength - 5 - 2;
+  // "movq rsp, rbp; pop rbp" has length 4.  "ret k" has length 3.
+  const int kPadding = Debug::kX64JSReturnSequenceLength - 4 - 3;
   for (int i = 0; i < kPadding; ++i) {
     __ int3();
   }
index fe644ee90a90718307dd7056615bd151b38e32b8..7fe6ebdb8b10f86129e4574506077d7048a9adad 100644 (file)
@@ -500,17 +500,19 @@ void CodeGenerator::GenerateReturnSequence(Result* return_value) {
   return_value->ToRegister(rax);
 
   // Add a label for checking the size of the code used for returning.
+#ifdef DEBUG
   Label check_exit_codesize;
   masm_->bind(&check_exit_codesize);
+#endif
 
   // Leave the frame and return popping the arguments and the
   // receiver.
   frame_->Exit();
   masm_->ret((scope_->num_parameters() + 1) * kPointerSize);
   // Add padding that will be overwritten by a debugger breakpoint.
-  // frame_->Exit() generates "movq rsp, rbp; pop rbp" length 5.
-  // "ret k" has length 2.
-  const int kPadding = Debug::kX64JSReturnSequenceLength - 5 - 2;
+  // frame_->Exit() generates "movq rsp, rbp; pop rbp; ret k"
+  // with length 7 (3 + 1 + 3).
+  const int kPadding = Debug::kX64JSReturnSequenceLength - 7;
   for (int i = 0; i < kPadding; ++i) {
     masm_->int3();
   }
@@ -5731,6 +5733,13 @@ void Reference::GetValue(TypeofState typeof_state) {
   ASSERT(cgen_->HasValidEntryRegisters());
   ASSERT(!is_illegal());
   MacroAssembler* masm = cgen_->masm();
+
+  // Record the source position for the property load.
+  Property* property = expression_->AsProperty();
+  if (property != NULL) {
+    cgen_->CodeForSourcePosition(property->position());
+  }
+
   switch (type_) {
     case SLOT: {
       Comment cmnt(masm, "[ Load from Slot");
index 177eb90a490a39fb4cceb0bc283a6d296339f123..f2bb62bc696e8ff7b4171d2172ad75d553f93577 100644 (file)
@@ -39,60 +39,176 @@ namespace internal {
 
 bool Debug::IsDebugBreakAtReturn(v8::internal::RelocInfo* rinfo) {
   ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
-  // 11th byte of patch is 0x49, 11th byte of JS return is 0xCC (int3).
+  // 11th byte of patch is 0x49 (REX.WB byte of computed jump/call to r10),
+  // 11th byte of JS return is 0xCC (int3).
   ASSERT(*(rinfo->pc() + 10) == 0x49 || *(rinfo->pc() + 10) == 0xCC);
-  return (*(rinfo->pc() + 10) == 0x49);
+  return (*(rinfo->pc() + 10) != 0xCC);
 }
 
+#define __ ACCESS_MASM(masm)
+
+static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
+                                          RegList pointer_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);
+
+#ifdef DEBUG
+  __ RecordComment("// Calling from debug break to runtime - come in - over");
+#endif
+  __ xor_(rax, rax);  // No arguments (argc == 0).
+  __ movq(rbx, ExternalReference::debug_break());
+
+  CEntryDebugBreakStub ceb;
+  __ CallStub(&ceb);
+
+  // Restore the register values containing object pointers from the expression
+  // stack in the reverse order as they where pushed.
+  __ PopRegistersToMemory(pointer_regs);
+
+  // Get rid of the internal frame.
+  __ LeaveInternalFrame();
+
+  // 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);
+  }
+
+  // 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.
+  ExternalReference after_break_target =
+      ExternalReference(Debug_Address::AfterBreakTarget());
+  __ movq(kScratchRegister, after_break_target);
+  __ jmp(Operand(kScratchRegister, 0));
+}
+
+
 void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED
+  // Register state for keyed IC call call (from ic-x64.cc)
+  // ----------- S t a t e -------------
+  //  -- rax: number of arguments
+  // -----------------------------------
+  // The number of arguments in rax is not smi encoded.
+  Generate_DebugBreakCallHelper(masm, 0, false);
 }
 
+
 void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED
+  // Register state just before return from JS function (from codegen-x64.cc).
+  // rax is the actual number of arguments not encoded as a smi, see comment
+  // above IC call.
+  // ----------- S t a t e -------------
+  //  -- rax: number of arguments
+  // -----------------------------------
+  // The number of arguments in rax is not smi encoded.
+  Generate_DebugBreakCallHelper(masm, 0, false);
 }
 
+
 void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED
+  // Register state for keyed IC load call (from ic-x64.cc).
+  // ----------- S t a t e -------------
+  //  No registers used on entry.
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, 0, false);
 }
 
+
 void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED
+  // Register state for keyed IC load call (from ic-x64.cc).
+  // ----------- S t a t e -------------
+  //  -- rax    : value
+  // -----------------------------------
+  // Register rax contains an object that needs to be pushed on the
+  // expression stack of the fake JS frame.
+  Generate_DebugBreakCallHelper(masm, rax.bit(), false);
 }
 
+
 void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED
+  // Register state for IC load call (from ic-x64.cc).
+  // ----------- S t a t e -------------
+  //  -- rcx    : name
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, rcx.bit(), false);
 }
 
+
 void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED
+  // Register state just before return from JS function (from codegen-x64.cc).
+  // ----------- S t a t e -------------
+  //  -- rax: return value
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, rax.bit(), true);
 }
 
+
 void Debug::GenerateReturnDebugBreakEntry(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED
+  // OK to clobber rbx as we are returning from a JS function through the code
+  // generated by CodeGenerator::GenerateReturnSequence()
+  ExternalReference debug_break_return =
+      ExternalReference(Debug_Address::DebugBreakReturn());
+  __ movq(rbx, debug_break_return);
+  __ movq(rbx, Operand(rbx, 0));
+  __ addq(rbx, Immediate(Code::kHeaderSize - kHeapObjectTag));
+  __ jmp(rbx);
 }
 
+
 void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED
+  // REgister state for IC store call (from ic-x64.cc).
+  // ----------- S t a t e -------------
+  //  -- rax    : value
+  //  -- rcx    : name
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, rax.bit() | rcx.bit(), false);
 }
 
+
 void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED
+  // Register state for stub CallFunction (from CallFunctionStub in ic-x64.cc).
+  // ----------- S t a t e -------------
+  //  No registers used on entry.
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, 0, false);
 }
 
+
+#undef __
+
+
 void BreakLocationIterator::ClearDebugBreakAtReturn() {
-  // TODO(X64): Implement this when we start setting Debug breaks.
-  UNIMPLEMENTED();
+  rinfo()->PatchCode(original_rinfo()->pc(),
+                     Debug::kX64JSReturnSequenceLength);
 }
 
+
 bool BreakLocationIterator::IsDebugBreakAtReturn()  {
-  // TODO(X64): Implement this when we start setting Debug breaks.
-  UNIMPLEMENTED();
-  return false;
+  return Debug::IsDebugBreakAtReturn(rinfo());
 }
 
+
 void BreakLocationIterator::SetDebugBreakAtReturn()  {
-  UNIMPLEMENTED();
+  ASSERT(Debug::kX64JSReturnSequenceLength >= Debug::kX64CallInstructionLength);
+  rinfo()->PatchCodeWithCall(Debug::debug_break_return_entry()->entry(),
+      Debug::kX64JSReturnSequenceLength - Debug::kX64CallInstructionLength);
 }
 
 #endif  // ENABLE_DEBUGGER_SUPPORT
index 86008eb325039c3022c43a457ef6ff1084d79eb0..1c74a44d0226764de48f77d03c8d492e166e6c9d 100644 (file)
@@ -167,7 +167,7 @@ static bool PatchInlinedMapCheck(Address address, Object* map) {
   // Arguments are address of start of call sequence that called
   // the IC,
   Address test_instruction_address =
-      address + Assembler::kTargetAddrToReturnAddrDist;
+      address + Assembler::kPatchReturnSequenceLength;
   // The keyed load has a fast inlined case if the IC call instruction
   // is immediately followed by a test instruction.
   if (*test_instruction_address != kTestEaxByte) return false;
@@ -845,7 +845,7 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm) {
 bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
   // The address of the instruction following the call.
   Address test_instruction_address =
-      address + Assembler::kTargetAddrToReturnAddrDist;
+      address + Assembler::kPatchReturnSequenceLength;
   // If the instruction following the call is not a test eax, nothing
   // was inlined.
   if (*test_instruction_address != kTestEaxByte) return false;
index 2219a5a0ee81821c9431103f7d67b4e6b6ffb62d..8f8398dc9d63f821c356df8656fed0a901482333 100644 (file)
@@ -262,8 +262,7 @@ void MacroAssembler::Abort(const char* msg) {
 
 void MacroAssembler::CallStub(CodeStub* stub) {
   ASSERT(allow_stub_calls());  // calls are not allowed in some stubs
-  movq(kScratchRegister, stub->GetCode(), RelocInfo::CODE_TARGET);
-  call(kScratchRegister);
+  Call(stub->GetCode(), RelocInfo::CODE_TARGET);
 }
 
 
@@ -495,7 +494,6 @@ void MacroAssembler::Jump(Address destination, RelocInfo::Mode rmode) {
 
 
 void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
-  WriteRecordedPositions();
   ASSERT(RelocInfo::IsCodeTarget(rmode));
   movq(kScratchRegister, code_object, rmode);
 #ifdef DEBUG
@@ -504,7 +502,7 @@ void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
 #endif
   jmp(kScratchRegister);
 #ifdef DEBUG
-  ASSERT_EQ(kTargetAddrToReturnAddrDist,
+  ASSERT_EQ(kPatchReturnSequenceLength,
             SizeOfCodeGeneratedSince(&target) + kPointerSize);
 #endif
 }
@@ -523,8 +521,8 @@ void MacroAssembler::Call(Address destination, RelocInfo::Mode rmode) {
 
 
 void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
-  WriteRecordedPositions();
   ASSERT(RelocInfo::IsCodeTarget(rmode));
+  WriteRecordedPositions();
   movq(kScratchRegister, code_object, rmode);
 #ifdef DEBUG
   // Patch target is kPointer size bytes *before* target label.
@@ -533,7 +531,7 @@ void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
 #endif
   call(kScratchRegister);
 #ifdef DEBUG
-  ASSERT_EQ(kTargetAddrToReturnAddrDist,
+  ASSERT_EQ(kPatchReturnSequenceLength,
             SizeOfCodeGeneratedSince(&target) + kPointerSize);
 #endif
 }
@@ -799,7 +797,7 @@ void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
         Bootstrapper::FixupFlagsIsPCRelative::encode(false) |
         Bootstrapper::FixupFlagsUseCodeObject::encode(false);
     Unresolved entry =
-        { pc_offset() - kTargetAddrToReturnAddrDist, flags, name };
+        { pc_offset() - kPatchReturnSequenceLength, flags, name };
     unresolved_.Add(entry);
   }
 }
@@ -859,12 +857,11 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
       movq(rdx, code_register);
     }
 
-    movq(kScratchRegister, adaptor, RelocInfo::CODE_TARGET);
     if (flag == CALL_FUNCTION) {
-      call(kScratchRegister);
+      Call(adaptor, RelocInfo::CODE_TARGET);
       jmp(done);
     } else {
-      jmp(kScratchRegister);
+      Jump(adaptor, RelocInfo::CODE_TARGET);
     }
     bind(&invoke);
   }
index ead0d92d42aa2ecff2626e7d48e03d107bfc0304..68aabb5165b756443780344dde203525e1519c9c 100644 (file)
@@ -60,55 +60,3 @@ test-log/ProfLazyMode: SKIP
 # the JavaScript stacks are separate.
 test-api/ExceptionOrder: FAIL
 test-api/TryCatchInTryFinally: FAIL
-
-
-[ $arch == x64 ]
-test-debug/DebugStub: CRASH || FAIL
-test-debug/DebugInfo: CRASH || FAIL
-test-debug/BreakPointICStore: CRASH || FAIL
-test-debug/BreakPointICLoad: CRASH || FAIL
-test-debug/BreakPointICCall: CRASH || FAIL
-test-debug/BreakPointReturn: CRASH || FAIL
-test-debug/GCDuringBreakPointProcessing: CRASH || FAIL
-test-debug/BreakPointSurviveGC: CRASH || FAIL
-test-debug/BreakPointThroughJavaScript: CRASH || FAIL
-test-debug/ScriptBreakPointByNameThroughJavaScript: CRASH || FAIL
-test-debug/ScriptBreakPointByIdThroughJavaScript: CRASH || FAIL
-test-debug/EnableDisableScriptBreakPoint: CRASH || FAIL
-test-debug/ConditionalScriptBreakPoint: CRASH || FAIL
-test-debug/ScriptBreakPointIgnoreCount: CRASH || FAIL
-test-debug/ScriptBreakPointReload: CRASH || FAIL
-test-debug/ScriptBreakPointMultiple: CRASH || FAIL
-test-debug/RemoveBreakPointInBreak: CRASH || FAIL
-test-debug/DebugEvaluate: CRASH || FAIL
-test-debug/ScriptBreakPointLine: CRASH || FAIL
-test-debug/ScriptBreakPointLineOffset: CRASH || FAIL
-test-debug/DebugStepLinear: CRASH || FAIL
-test-debug/DebugStepKeyedLoadLoop: CRASH || FAIL
-test-debug/DebugStepKeyedStoreLoop: CRASH || FAIL
-test-debug/DebugStepLinearMixedICs: CRASH || FAIL
-test-debug/DebugStepFor: CRASH || FAIL
-test-debug/DebugStepIf: CRASH || FAIL
-test-debug/DebugStepSwitch: CRASH || FAIL
-test-debug/StepInOutSimple: CRASH || FAIL
-test-debug/StepInOutBranch: CRASH || FAIL
-test-debug/StepInOutTree: CRASH || FAIL
-test-debug/DebugStepNatives: CRASH || FAIL
-test-debug/DebugStepFunctionApply: CRASH || FAIL
-test-debug/DebugStepFunctionCall: CRASH || FAIL
-test-debug/StepWithException: CRASH || FAIL
-test-debug/DebugBreak: CRASH || FAIL
-test-debug/DisableBreak: CRASH || FAIL
-test-debug/MessageQueues: CRASH || FAIL
-test-debug/CallFunctionInDebugger: SKIP
-test-debug/RecursiveBreakpoints: CRASH || FAIL
-test-debug/DebuggerUnload: CRASH || FAIL
-test-debug/DebuggerHostDispatch: CRASH || FAIL
-test-debug/DebugBreakInMessageHandler: CRASH || FAIL
-test-debug/NoDebugBreakInAfterCompileMessageHandler: CRASH || FAIL
-test-debug/RegExpDebugBreak: FAIL
-test-api/Threading: CRASH || FAIL
-test-api/Threading2: PASS || TIMEOUT
-test-api/TryCatchSourceInfo: CRASH || FAIL
-test-api/RegExpInterruption: PASS || TIMEOUT
-test-api/RegExpStringModification: PASS || TIMEOUT
index a86317ad3861582b9a0e62fc4fe41018f8dd7d9c..f5e4f3a4fcd50dc23512c969d3a1f932a7334d0d 100644 (file)
@@ -487,9 +487,7 @@ void CheckDebugBreakFunction(DebugLocalContext* env,
     CHECK_EQ(debug_break,
         Code::GetCodeFromTargetAddress(it1.it()->rinfo()->target_address()));
   } else {
-    // TODO(1240753): Make the test architecture independent or split
-    // parts of the debugger into architecture dependent files.
-    CHECK_EQ(0xE8, *(it1.rinfo()->pc()));
+    CHECK(Debug::IsDebugBreakAtReturn(it1.it()->rinfo()));
   }
 
   // Clear the break point and check that the debug break function is no longer
@@ -501,9 +499,7 @@ void CheckDebugBreakFunction(DebugLocalContext* env,
   it2.FindBreakLocationFromPosition(position);
   CHECK_EQ(mode, it2.it()->rinfo()->rmode());
   if (mode == v8::internal::RelocInfo::JS_RETURN) {
-    // TODO(1240753): Make the test architecture independent or split
-    // parts of the debugger into architecture dependent files.
-    CHECK_NE(0xE8, *(it2.rinfo()->pc()));
+    CHECK(!Debug::IsDebugBreakAtReturn(it2.it()->rinfo()));
   }
 }
 
index 9afaa0f1480e889b9d25ab899ef9ecb8d3979d42..fc2896b1c98585cf8107194233e3c52058b2ab6a 100644 (file)
@@ -29,16 +29,3 @@ prefix message
 
 # All tests in the bug directory are expected to fail.
 bugs: FAIL
-
-[ $arch == x64 ]
-
-simple-throw: FAIL
-try-catch-finally-throw-in-catch-and-finally: FAIL
-try-catch-finally-throw-in-catch: FAIL
-try-catch-finally-throw-in-finally: FAIL
-try-finally-throw-in-finally: FAIL
-try-finally-throw-in-try-and-finally: FAIL
-try-finally-throw-in-try: FAIL
-overwritten-builtins: FAIL
-regress/regress-73: FAIL
-regress/regress-75: FAIL
index 6853cdc65a4cd95f3b4c0ba48099adfd8a6e2a32..4bf67e80d68a13b8425f9eece6b540e89a15b4a1 100644 (file)
@@ -73,33 +73,3 @@ string-compare-alignment: PASS || FAIL
 
 # Times out often in release mode on ARM.
 array-splice: PASS || TIMEOUT
-
-[ $arch == x64 ]
-
-debug-backtrace: CRASH || FAIL
-debug-backtrace-text: CRASH || FAIL
-debug-multiple-breakpoints: CRASH || FAIL
-debug-breakpoints: CRASH || FAIL
-debug-changebreakpoint: CRASH || FAIL
-debug-clearbreakpoint: CRASH || FAIL
-debug-conditional-breakpoints: CRASH || FAIL
-debug-constructor: CRASH || FAIL
-debug-continue: CRASH || FAIL
-debug-enable-disable-breakpoints: CRASH || FAIL
-debug-evaluate-recursive: CRASH || FAIL
-debug-event-listener: CRASH || FAIL
-debug-evaluate: CRASH || FAIL
-debug-ignore-breakpoints: CRASH || FAIL
-debug-setbreakpoint: CRASH || FAIL
-debug-step-stub-callfunction: CRASH || FAIL
-debug-step: CRASH || FAIL
-debug-stepin-builtin: CRASH || FAIL
-debug-stepin-constructor: CRASH || FAIL
-debug-stepin-function-call: CRASH || FAIL
-debug-stepin-accessor: CRASH || FAIL
-fuzz-natives: PASS || TIMEOUT
-debug-handle: CRASH || FAIL
-debug-clearbreakpointgroup: CRASH || FAIL
-regress/regress-269: CRASH || FAIL
-regress/regress-998565: CRASH || FAIL
-tools/tickprocessor: PASS || CRASH || FAIL