Commit fdf31f7f authored by lrn@chromium.org's avatar lrn@chromium.org

X64: Implement debugger hooks.

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
parent f68b81b0
...@@ -430,7 +430,10 @@ class Assembler : public Malloced { ...@@ -430,7 +430,10 @@ class Assembler : public Malloced {
// Distance between the instruction referring to the address of the call // Distance between the instruction referring to the address of the call
// target (ldr pc, [target addr in const pool]) and the return address // 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;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
......
...@@ -132,7 +132,7 @@ void MacroAssembler::Call(intptr_t target, RelocInfo::Mode rmode, ...@@ -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 // 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 // instruction rather than the second one, which would make it harder to patch
// (two instructions before the return address, instead of one). // (two instructions before the return address, instead of one).
ASSERT(kTargetAddrToReturnAddrDist == sizeof(Instr)); ASSERT(kPatchReturnSequenceLength == sizeof(Instr));
} }
......
...@@ -216,6 +216,9 @@ class RelocInfo BASE_EMBEDDED { ...@@ -216,6 +216,9 @@ class RelocInfo BASE_EMBEDDED {
// Patch the code with a call. // Patch the code with a call.
void PatchCodeWithCall(Address target, int guard_bytes); 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()); INLINE(bool IsCallInstruction());
#ifdef ENABLE_DISASSEMBLER #ifdef ENABLE_DISASSEMBLER
......
...@@ -1452,14 +1452,15 @@ void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { ...@@ -1452,14 +1452,15 @@ void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
// Find the call address in the running code. This address holds the call to // 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 // either a DebugBreakXXX or to the debug break return entry code if the
// break point is still active after processing the break point. // 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. // Check if the location is at JS exit.
bool at_js_exit = false; bool at_js_exit = false;
RelocIterator it(debug_info->code()); RelocIterator it(debug_info->code());
while (!it.done()) { while (!it.done()) {
if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) { 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(); it.next();
} }
...@@ -1477,8 +1478,9 @@ void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { ...@@ -1477,8 +1478,9 @@ void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
addr += original_code->instruction_start() - code->instruction_start(); addr += original_code->instruction_start() - code->instruction_start();
} }
// Move one byte back to where the call instruction was placed. // Move back to where the call instruction sequence started.
thread_local_.after_break_target_ = addr - 1; thread_local_.after_break_target_ =
addr - Assembler::kPatchReturnSequenceAddressOffset;
} else { } else {
// Check if there still is a debug break call at the target address. If the // 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 // break point has been removed it will have disappeared. If it have
......
...@@ -238,7 +238,10 @@ class Debug { ...@@ -238,7 +238,10 @@ class Debug {
// Returns whether the operation succeeded. // Returns whether the operation succeeded.
static bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared); static bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared);
// Returns true if the current stub call is patched to call the debugger.
static bool IsDebugBreak(Address addr); 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); static bool IsDebugBreakAtReturn(RelocInfo* rinfo);
// Check whether a code stub with the specified major key is a possible break // Check whether a code stub with the specified major key is a possible break
...@@ -366,6 +369,7 @@ class Debug { ...@@ -366,6 +369,7 @@ class Debug {
// The x64 JS return sequence is padded with int3 to make it large // The x64 JS return sequence is padded with int3 to make it large
// enough to hold a call instruction when the debugger patches it. // enough to hold a call instruction when the debugger patches it.
static const int kX64CallInstructionLength = 13;
static const int kX64JSReturnSequenceLength = 13; static const int kX64JSReturnSequenceLength = 13;
// Code generator routines. // Code generator routines.
......
...@@ -206,8 +206,13 @@ class StackGuard BASE_EMBEDDED { ...@@ -206,8 +206,13 @@ class StackGuard BASE_EMBEDDED {
static void DisableInterrupts(); static void DisableInterrupts();
static const uintptr_t kLimitSize = kPointerSize * 128 * KB; 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 kInterruptLimit = 0xfffffffe;
static const uintptr_t kIllegalLimit = 0xffffffff; static const uintptr_t kIllegalLimit = 0xffffffff;
#endif
class ThreadLocal { class ThreadLocal {
public: public:
......
...@@ -437,7 +437,10 @@ class Assembler : public Malloced { ...@@ -437,7 +437,10 @@ class Assembler : public Malloced {
// Distance between the address of the code target in the call instruction // Distance between the address of the code target in the call instruction
// and the return address // 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.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
......
...@@ -195,8 +195,8 @@ void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) { ...@@ -195,8 +195,8 @@ void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
void Debug::GenerateReturnDebugBreakEntry(MacroAssembler* masm) { void Debug::GenerateReturnDebugBreakEntry(MacroAssembler* masm) {
// OK to clobber ebx as we are returning from a JS function in the code // OK to clobber ebx as we are returning from a JS function through the code
// generated by Ia32CodeGenerator::ExitJSFrame. // generated by CodeGenerator::GenerateReturnSequence()
ExternalReference debug_break_return = ExternalReference debug_break_return =
ExternalReference(Debug_Address::DebugBreakReturn()); ExternalReference(Debug_Address::DebugBreakReturn());
__ mov(ebx, Operand::StaticVariable(debug_break_return)); __ mov(ebx, Operand::StaticVariable(debug_break_return));
......
...@@ -840,7 +840,7 @@ void KeyedStoreIC::RestoreInlinedVersion(Address address) { ...@@ -840,7 +840,7 @@ void KeyedStoreIC::RestoreInlinedVersion(Address address) {
bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
// The address of the instruction following the call. // The address of the instruction following the call.
Address test_instruction_address = Address test_instruction_address =
address + Assembler::kTargetAddrToReturnAddrDist; address + Assembler::kPatchReturnSequenceLength;
// If the instruction following the call is not a test eax, nothing // If the instruction following the call is not a test eax, nothing
// was inlined. // was inlined.
if (*test_instruction_address != kTestEaxByte) return false; if (*test_instruction_address != kTestEaxByte) return false;
...@@ -867,7 +867,7 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { ...@@ -867,7 +867,7 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
static bool PatchInlinedMapCheck(Address address, Object* map) { static bool PatchInlinedMapCheck(Address address, Object* map) {
Address test_instruction_address = Address test_instruction_address =
address + Assembler::kTargetAddrToReturnAddrDist; address + Assembler::kPatchReturnSequenceLength;
// The keyed load has a fast inlined case if the IC call instruction // The keyed load has a fast inlined case if the IC call instruction
// is immediately followed by a test instruction. // is immediately followed by a test instruction.
if (*test_instruction_address != kTestEaxByte) return false; if (*test_instruction_address != kTestEaxByte) return false;
......
...@@ -38,7 +38,7 @@ namespace internal { ...@@ -38,7 +38,7 @@ namespace internal {
Address IC::address() { Address IC::address() {
// Get the address of the call. // Get the address of the call.
Address result = pc() - Assembler::kTargetAddrToReturnAddrDist; Address result = pc() - Assembler::kPatchReturnSequenceLength;
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
// First check if any break points are active if not just return the address // First check if any break points are active if not just return the address
......
...@@ -122,7 +122,7 @@ Address IC::OriginalCodeAddress() { ...@@ -122,7 +122,7 @@ Address IC::OriginalCodeAddress() {
// Get the address of the call site in the active code. This is the // 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 // place where the call to DebugBreakXXX is and where the IC
// normally would be. // 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 // Return the address in the original code. This is the place where
// the call which has been overwritten by the DebugBreakXXX resides // the call which has been overwritten by the DebugBreakXXX resides
// and the place where the inline cache system should look. // and the place where the inline cache system should look.
......
...@@ -390,7 +390,7 @@ class KeyedStoreIC: public IC { ...@@ -390,7 +390,7 @@ class KeyedStoreIC: public IC {
// Support for patching the map that is checked in an inlined // Support for patching the map that is checked in an inlined
// version of keyed store. // version of keyed store.
// The address is the patch point for the IC call // 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 call/return address).
// The map is the new map that the inlined code should check against. // The map is the new map that the inlined code should check against.
static bool PatchInlinedStore(Address address, Object* map); static bool PatchInlinedStore(Address address, Object* map);
......
...@@ -228,43 +228,47 @@ void RelocInfo::set_target_object(Object* target) { ...@@ -228,43 +228,47 @@ void RelocInfo::set_target_object(Object* target) {
bool RelocInfo::IsCallInstruction() { bool RelocInfo::IsCallInstruction() {
UNIMPLEMENTED(); // IA32 code below. // The recognized call sequence is:
return *pc_ == 0xE8; // 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() { Address RelocInfo::call_address() {
UNIMPLEMENTED(); // IA32 code below.
ASSERT(IsCallInstruction()); ASSERT(IsCallInstruction());
return Assembler::target_address_at(pc_ + 1); return Assembler::target_address_at(
pc_ + Assembler::kPatchReturnSequenceAddressOffset);
} }
void RelocInfo::set_call_address(Address target) { void RelocInfo::set_call_address(Address target) {
UNIMPLEMENTED(); // IA32 code below.
ASSERT(IsCallInstruction()); ASSERT(IsCallInstruction());
Assembler::set_target_address_at(pc_ + 1, target); Assembler::set_target_address_at(
pc_ + Assembler::kPatchReturnSequenceAddressOffset,
target);
} }
Object* RelocInfo::call_object() { Object* RelocInfo::call_object() {
UNIMPLEMENTED(); // IA32 code below.
ASSERT(IsCallInstruction()); ASSERT(IsCallInstruction());
return *call_object_address(); return *call_object_address();
} }
void RelocInfo::set_call_object(Object* target) { void RelocInfo::set_call_object(Object* target) {
UNIMPLEMENTED(); // IA32 code below.
ASSERT(IsCallInstruction()); ASSERT(IsCallInstruction());
*call_object_address() = target; *call_object_address() = target;
} }
Object** RelocInfo::call_object_address() { Object** RelocInfo::call_object_address() {
UNIMPLEMENTED(); // IA32 code below.
ASSERT(IsCallInstruction()); ASSERT(IsCallInstruction());
return reinterpret_cast<Object**>(pc_ + 1); return reinterpret_cast<Object**>(
pc_ + Assembler::kPatchReturnSequenceAddressOffset);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
......
...@@ -178,6 +178,13 @@ void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) { ...@@ -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 // Implementation of Operand
...@@ -1071,6 +1078,16 @@ void Assembler::jmp(Register target) { ...@@ -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) { void Assembler::lea(Register dst, const Operand& src) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
last_pc_ = pc_; last_pc_ = pc_;
......
...@@ -442,8 +442,10 @@ class Assembler : public Malloced { ...@@ -442,8 +442,10 @@ class Assembler : public Malloced {
// Distance between the address of the code target in the call instruction // Distance between the address of the code target in the call instruction
// and the return address. Checked in the debug build. // 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 // Code generation
...@@ -917,6 +919,9 @@ class Assembler : public Malloced { ...@@ -917,6 +919,9 @@ class Assembler : public Malloced {
// Jump near absolute indirect (r64) // Jump near absolute indirect (r64)
void jmp(Register adr); void jmp(Register adr);
// Jump near absolute indirect (m64)
void jmp(const Operand& src);
// Conditional jumps // Conditional jumps
void j(Condition cc, Label* L); void j(Condition cc, Label* L);
......
...@@ -505,7 +505,14 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { ...@@ -505,7 +505,14 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Label rt_call, allocated; Label rt_call, allocated;
if (FLAG_inline_new) { if (FLAG_inline_new) {
Label undo_allocation; 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. // Verified that the constructor is a JSFunction.
// Load the initial map and verify that it is in fact a map. // Load the initial map and verify that it is in fact a map.
...@@ -828,10 +835,8 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, ...@@ -828,10 +835,8 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
// Invoke the code. // Invoke the code.
if (is_construct) { if (is_construct) {
// Expects rdi to hold function pointer. // Expects rdi to hold function pointer.
__ movq(kScratchRegister, __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
__ call(kScratchRegister);
} else { } else {
ParameterCount actual(rax); ParameterCount actual(rax);
// Function must be in rdi. // Function must be in rdi.
......
...@@ -114,8 +114,8 @@ void ExitNode::Compile(MacroAssembler* masm) { ...@@ -114,8 +114,8 @@ void ExitNode::Compile(MacroAssembler* masm) {
int count = CfgGlobals::current()->fun()->scope()->num_parameters(); int count = CfgGlobals::current()->fun()->scope()->num_parameters();
__ ret((count + 1) * kPointerSize); __ ret((count + 1) * kPointerSize);
// Add padding that will be overwritten by a debugger breakpoint. // Add padding that will be overwritten by a debugger breakpoint.
// "movq rsp, rbp; pop rbp" has length 5. "ret k" has length 2. // "movq rsp, rbp; pop rbp" has length 4. "ret k" has length 3.
const int kPadding = Debug::kX64JSReturnSequenceLength - 5 - 2; const int kPadding = Debug::kX64JSReturnSequenceLength - 4 - 3;
for (int i = 0; i < kPadding; ++i) { for (int i = 0; i < kPadding; ++i) {
__ int3(); __ int3();
} }
......
...@@ -500,17 +500,19 @@ void CodeGenerator::GenerateReturnSequence(Result* return_value) { ...@@ -500,17 +500,19 @@ void CodeGenerator::GenerateReturnSequence(Result* return_value) {
return_value->ToRegister(rax); return_value->ToRegister(rax);
// Add a label for checking the size of the code used for returning. // Add a label for checking the size of the code used for returning.
#ifdef DEBUG
Label check_exit_codesize; Label check_exit_codesize;
masm_->bind(&check_exit_codesize); masm_->bind(&check_exit_codesize);
#endif
// Leave the frame and return popping the arguments and the // Leave the frame and return popping the arguments and the
// receiver. // receiver.
frame_->Exit(); frame_->Exit();
masm_->ret((scope_->num_parameters() + 1) * kPointerSize); masm_->ret((scope_->num_parameters() + 1) * kPointerSize);
// Add padding that will be overwritten by a debugger breakpoint. // Add padding that will be overwritten by a debugger breakpoint.
// frame_->Exit() generates "movq rsp, rbp; pop rbp" length 5. // frame_->Exit() generates "movq rsp, rbp; pop rbp; ret k"
// "ret k" has length 2. // with length 7 (3 + 1 + 3).
const int kPadding = Debug::kX64JSReturnSequenceLength - 5 - 2; const int kPadding = Debug::kX64JSReturnSequenceLength - 7;
for (int i = 0; i < kPadding; ++i) { for (int i = 0; i < kPadding; ++i) {
masm_->int3(); masm_->int3();
} }
...@@ -5731,6 +5733,13 @@ void Reference::GetValue(TypeofState typeof_state) { ...@@ -5731,6 +5733,13 @@ void Reference::GetValue(TypeofState typeof_state) {
ASSERT(cgen_->HasValidEntryRegisters()); ASSERT(cgen_->HasValidEntryRegisters());
ASSERT(!is_illegal()); ASSERT(!is_illegal());
MacroAssembler* masm = cgen_->masm(); 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_) { switch (type_) {
case SLOT: { case SLOT: {
Comment cmnt(masm, "[ Load from Slot"); Comment cmnt(masm, "[ Load from Slot");
......
...@@ -39,60 +39,176 @@ namespace internal { ...@@ -39,60 +39,176 @@ namespace internal {
bool Debug::IsDebugBreakAtReturn(v8::internal::RelocInfo* rinfo) { bool Debug::IsDebugBreakAtReturn(v8::internal::RelocInfo* rinfo) {
ASSERT(RelocInfo::IsJSReturn(rinfo->rmode())); 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); 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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() { void BreakLocationIterator::ClearDebugBreakAtReturn() {
// TODO(X64): Implement this when we start setting Debug breaks. rinfo()->PatchCode(original_rinfo()->pc(),
UNIMPLEMENTED(); Debug::kX64JSReturnSequenceLength);
} }
bool BreakLocationIterator::IsDebugBreakAtReturn() { bool BreakLocationIterator::IsDebugBreakAtReturn() {
// TODO(X64): Implement this when we start setting Debug breaks. return Debug::IsDebugBreakAtReturn(rinfo());
UNIMPLEMENTED();
return false;
} }
void BreakLocationIterator::SetDebugBreakAtReturn() { 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 #endif // ENABLE_DEBUGGER_SUPPORT
......
...@@ -167,7 +167,7 @@ static bool PatchInlinedMapCheck(Address address, Object* map) { ...@@ -167,7 +167,7 @@ static bool PatchInlinedMapCheck(Address address, Object* map) {
// Arguments are address of start of call sequence that called // Arguments are address of start of call sequence that called
// the IC, // the IC,
Address test_instruction_address = Address test_instruction_address =
address + Assembler::kTargetAddrToReturnAddrDist; address + Assembler::kPatchReturnSequenceLength;
// The keyed load has a fast inlined case if the IC call instruction // The keyed load has a fast inlined case if the IC call instruction
// is immediately followed by a test instruction. // is immediately followed by a test instruction.
if (*test_instruction_address != kTestEaxByte) return false; if (*test_instruction_address != kTestEaxByte) return false;
...@@ -845,7 +845,7 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm) { ...@@ -845,7 +845,7 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm) {
bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
// The address of the instruction following the call. // The address of the instruction following the call.
Address test_instruction_address = Address test_instruction_address =
address + Assembler::kTargetAddrToReturnAddrDist; address + Assembler::kPatchReturnSequenceLength;
// If the instruction following the call is not a test eax, nothing // If the instruction following the call is not a test eax, nothing
// was inlined. // was inlined.
if (*test_instruction_address != kTestEaxByte) return false; if (*test_instruction_address != kTestEaxByte) return false;
......
...@@ -262,8 +262,7 @@ void MacroAssembler::Abort(const char* msg) { ...@@ -262,8 +262,7 @@ void MacroAssembler::Abort(const char* msg) {
void MacroAssembler::CallStub(CodeStub* stub) { void MacroAssembler::CallStub(CodeStub* stub) {
ASSERT(allow_stub_calls()); // calls are not allowed in some stubs ASSERT(allow_stub_calls()); // calls are not allowed in some stubs
movq(kScratchRegister, stub->GetCode(), RelocInfo::CODE_TARGET); Call(stub->GetCode(), RelocInfo::CODE_TARGET);
call(kScratchRegister);
} }
...@@ -495,7 +494,6 @@ void MacroAssembler::Jump(Address destination, RelocInfo::Mode rmode) { ...@@ -495,7 +494,6 @@ void MacroAssembler::Jump(Address destination, RelocInfo::Mode rmode) {
void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) { void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
WriteRecordedPositions();
ASSERT(RelocInfo::IsCodeTarget(rmode)); ASSERT(RelocInfo::IsCodeTarget(rmode));
movq(kScratchRegister, code_object, rmode); movq(kScratchRegister, code_object, rmode);
#ifdef DEBUG #ifdef DEBUG
...@@ -504,7 +502,7 @@ void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) { ...@@ -504,7 +502,7 @@ void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
#endif #endif
jmp(kScratchRegister); jmp(kScratchRegister);
#ifdef DEBUG #ifdef DEBUG
ASSERT_EQ(kTargetAddrToReturnAddrDist, ASSERT_EQ(kPatchReturnSequenceLength,
SizeOfCodeGeneratedSince(&target) + kPointerSize); SizeOfCodeGeneratedSince(&target) + kPointerSize);
#endif #endif
} }
...@@ -523,8 +521,8 @@ void MacroAssembler::Call(Address destination, RelocInfo::Mode rmode) { ...@@ -523,8 +521,8 @@ void MacroAssembler::Call(Address destination, RelocInfo::Mode rmode) {
void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) { void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
WriteRecordedPositions();
ASSERT(RelocInfo::IsCodeTarget(rmode)); ASSERT(RelocInfo::IsCodeTarget(rmode));
WriteRecordedPositions();
movq(kScratchRegister, code_object, rmode); movq(kScratchRegister, code_object, rmode);
#ifdef DEBUG #ifdef DEBUG
// Patch target is kPointer size bytes *before* target label. // Patch target is kPointer size bytes *before* target label.
...@@ -533,7 +531,7 @@ void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) { ...@@ -533,7 +531,7 @@ void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
#endif #endif
call(kScratchRegister); call(kScratchRegister);
#ifdef DEBUG #ifdef DEBUG
ASSERT_EQ(kTargetAddrToReturnAddrDist, ASSERT_EQ(kPatchReturnSequenceLength,
SizeOfCodeGeneratedSince(&target) + kPointerSize); SizeOfCodeGeneratedSince(&target) + kPointerSize);
#endif #endif
} }
...@@ -799,7 +797,7 @@ void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) { ...@@ -799,7 +797,7 @@ void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
Bootstrapper::FixupFlagsIsPCRelative::encode(false) | Bootstrapper::FixupFlagsIsPCRelative::encode(false) |
Bootstrapper::FixupFlagsUseCodeObject::encode(false); Bootstrapper::FixupFlagsUseCodeObject::encode(false);
Unresolved entry = Unresolved entry =
{ pc_offset() - kTargetAddrToReturnAddrDist, flags, name }; { pc_offset() - kPatchReturnSequenceLength, flags, name };
unresolved_.Add(entry); unresolved_.Add(entry);
} }
} }
...@@ -859,12 +857,11 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, ...@@ -859,12 +857,11 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
movq(rdx, code_register); movq(rdx, code_register);
} }
movq(kScratchRegister, adaptor, RelocInfo::CODE_TARGET);
if (flag == CALL_FUNCTION) { if (flag == CALL_FUNCTION) {
call(kScratchRegister); Call(adaptor, RelocInfo::CODE_TARGET);
jmp(done); jmp(done);
} else { } else {
jmp(kScratchRegister); Jump(adaptor, RelocInfo::CODE_TARGET);
} }
bind(&invoke); bind(&invoke);
} }
......
...@@ -60,55 +60,3 @@ test-log/ProfLazyMode: SKIP ...@@ -60,55 +60,3 @@ test-log/ProfLazyMode: SKIP
# the JavaScript stacks are separate. # the JavaScript stacks are separate.
test-api/ExceptionOrder: FAIL test-api/ExceptionOrder: FAIL
test-api/TryCatchInTryFinally: 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
...@@ -487,9 +487,7 @@ void CheckDebugBreakFunction(DebugLocalContext* env, ...@@ -487,9 +487,7 @@ void CheckDebugBreakFunction(DebugLocalContext* env,
CHECK_EQ(debug_break, CHECK_EQ(debug_break,
Code::GetCodeFromTargetAddress(it1.it()->rinfo()->target_address())); Code::GetCodeFromTargetAddress(it1.it()->rinfo()->target_address()));
} else { } else {
// TODO(1240753): Make the test architecture independent or split CHECK(Debug::IsDebugBreakAtReturn(it1.it()->rinfo()));
// parts of the debugger into architecture dependent files.
CHECK_EQ(0xE8, *(it1.rinfo()->pc()));
} }
// Clear the break point and check that the debug break function is no longer // Clear the break point and check that the debug break function is no longer
...@@ -501,9 +499,7 @@ void CheckDebugBreakFunction(DebugLocalContext* env, ...@@ -501,9 +499,7 @@ void CheckDebugBreakFunction(DebugLocalContext* env,
it2.FindBreakLocationFromPosition(position); it2.FindBreakLocationFromPosition(position);
CHECK_EQ(mode, it2.it()->rinfo()->rmode()); CHECK_EQ(mode, it2.it()->rinfo()->rmode());
if (mode == v8::internal::RelocInfo::JS_RETURN) { if (mode == v8::internal::RelocInfo::JS_RETURN) {
// TODO(1240753): Make the test architecture independent or split CHECK(!Debug::IsDebugBreakAtReturn(it2.it()->rinfo()));
// parts of the debugger into architecture dependent files.
CHECK_NE(0xE8, *(it2.rinfo()->pc()));
} }
} }
......
...@@ -29,16 +29,3 @@ prefix message ...@@ -29,16 +29,3 @@ prefix message
# All tests in the bug directory are expected to fail. # All tests in the bug directory are expected to fail.
bugs: 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
...@@ -73,33 +73,3 @@ string-compare-alignment: PASS || FAIL ...@@ -73,33 +73,3 @@ string-compare-alignment: PASS || FAIL
# Times out often in release mode on ARM. # Times out often in release mode on ARM.
array-splice: PASS || TIMEOUT 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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment