Revision: 2716 Author: [email protected] Date: Wed Aug 19 03:18:30 2009 Log: 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 http://code.google.com/p/v8/source/detail?r=2716 Modified: /branches/bleeding_edge/src/arm/assembler-arm.h /branches/bleeding_edge/src/arm/macro-assembler-arm.cc /branches/bleeding_edge/src/assembler.h /branches/bleeding_edge/src/debug.cc /branches/bleeding_edge/src/debug.h /branches/bleeding_edge/src/execution.h /branches/bleeding_edge/src/ia32/assembler-ia32.h /branches/bleeding_edge/src/ia32/debug-ia32.cc /branches/bleeding_edge/src/ia32/ic-ia32.cc /branches/bleeding_edge/src/ic-inl.h /branches/bleeding_edge/src/ic.cc /branches/bleeding_edge/src/ic.h /branches/bleeding_edge/src/x64/assembler-x64-inl.h /branches/bleeding_edge/src/x64/assembler-x64.cc /branches/bleeding_edge/src/x64/assembler-x64.h /branches/bleeding_edge/src/x64/builtins-x64.cc /branches/bleeding_edge/src/x64/cfg-x64.cc /branches/bleeding_edge/src/x64/codegen-x64.cc /branches/bleeding_edge/src/x64/debug-x64.cc /branches/bleeding_edge/src/x64/ic-x64.cc /branches/bleeding_edge/src/x64/macro-assembler-x64.cc /branches/bleeding_edge/test/cctest/cctest.status /branches/bleeding_edge/test/cctest/test-debug.cc /branches/bleeding_edge/test/message/message.status /branches/bleeding_edge/test/mjsunit/mjsunit.status ======================================= --- /branches/bleeding_edge/src/arm/assembler-arm.h Wed May 27 00:53:47 2009 +++ /branches/bleeding_edge/src/arm/assembler-arm.h Wed Aug 19 03:18:30 2009 @@ -430,7 +430,10 @@ // 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; // --------------------------------------------------------------------------- ======================================= --- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Aug 17 17:12:26 2009 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Wed Aug 19 03:18:30 2009 @@ -132,7 +132,7 @@ // 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)); } ======================================= --- /branches/bleeding_edge/src/assembler.h Mon Aug 17 17:12:26 2009 +++ /branches/bleeding_edge/src/assembler.h Wed Aug 19 03:18:30 2009 @@ -216,6 +216,9 @@ // 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 ======================================= --- /branches/bleeding_edge/src/debug.cc Wed Jul 29 02:51:41 2009 +++ /branches/bleeding_edge/src/debug.cc Wed Aug 19 03:18:30 2009 @@ -1452,14 +1452,15 @@ // 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 @@ 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 ======================================= --- /branches/bleeding_edge/src/debug.h Fri Jul 10 02:57:53 2009 +++ /branches/bleeding_edge/src/debug.h Wed Aug 19 03:18:30 2009 @@ -238,7 +238,10 @@ // 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 @@ // 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. ======================================= --- /branches/bleeding_edge/src/execution.h Tue Aug 4 05:30:21 2009 +++ /branches/bleeding_edge/src/execution.h Wed Aug 19 03:18:30 2009 @@ -206,8 +206,13 @@ 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: ======================================= --- /branches/bleeding_edge/src/ia32/assembler-ia32.h Mon Aug 3 06:17:34 2009 +++ /branches/bleeding_edge/src/ia32/assembler-ia32.h Wed Aug 19 03:18:30 2009 @@ -437,7 +437,10 @@ // 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. // --------------------------------------------------------------------------- ======================================= --- /branches/bleeding_edge/src/ia32/debug-ia32.cc Mon May 25 03:05:56 2009 +++ /branches/bleeding_edge/src/ia32/debug-ia32.cc Wed Aug 19 03:18:30 2009 @@ -195,8 +195,8 @@ 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)); ======================================= --- /branches/bleeding_edge/src/ia32/ic-ia32.cc Thu Jul 30 02:18:14 2009 +++ /branches/bleeding_edge/src/ia32/ic-ia32.cc Wed Aug 19 03:18:30 2009 @@ -840,7 +840,7 @@ 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 @@ 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; ======================================= --- /branches/bleeding_edge/src/ic-inl.h Mon May 25 03:05:56 2009 +++ /branches/bleeding_edge/src/ic-inl.h Wed Aug 19 03:18:30 2009 @@ -38,7 +38,7 @@ 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 ======================================= --- /branches/bleeding_edge/src/ic.cc Thu Jul 30 05:09:51 2009 +++ /branches/bleeding_edge/src/ic.cc Wed Aug 19 03:18:30 2009 @@ -122,7 +122,7 @@ // 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. ======================================= --- /branches/bleeding_edge/src/ic.h Thu Jul 30 02:18:14 2009 +++ /branches/bleeding_edge/src/ic.h Wed Aug 19 03:18:30 2009 @@ -390,7 +390,7 @@ // 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); ======================================= --- /branches/bleeding_edge/src/x64/assembler-x64-inl.h Tue Jun 23 04:26:05 2009 +++ /branches/bleeding_edge/src/x64/assembler-x64-inl.h Wed Aug 19 03:18:30 2009 @@ -228,43 +228,47 @@ 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); } // ----------------------------------------------------------------------------- ======================================= --- /branches/bleeding_edge/src/x64/assembler-x64.cc Fri Aug 14 04:24:32 2009 +++ /branches/bleeding_edge/src/x64/assembler-x64.cc Wed Aug 19 03:18:30 2009 @@ -178,6 +178,13 @@ } +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 @@ -1069,6 +1076,16 @@ emit(0xFF); emit_modrm(0x4, 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) { ======================================= --- /branches/bleeding_edge/src/x64/assembler-x64.h Fri Aug 14 04:24:32 2009 +++ /branches/bleeding_edge/src/x64/assembler-x64.h Wed Aug 19 03:18:30 2009 @@ -442,8 +442,10 @@ // 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 @@ // 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); ======================================= --- /branches/bleeding_edge/src/x64/builtins-x64.cc Wed Aug 19 00:30:20 2009 +++ /branches/bleeding_edge/src/x64/builtins-x64.cc Wed Aug 19 03:18:30 2009 @@ -505,7 +505,14 @@ 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 @@ // 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. ======================================= --- /branches/bleeding_edge/src/x64/cfg-x64.cc Fri Aug 7 06:32:39 2009 +++ /branches/bleeding_edge/src/x64/cfg-x64.cc Wed Aug 19 03:18:30 2009 @@ -114,8 +114,8 @@ 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(); } ======================================= --- /branches/bleeding_edge/src/x64/codegen-x64.cc Tue Aug 18 03:52:14 2009 +++ /branches/bleeding_edge/src/x64/codegen-x64.cc Wed Aug 19 03:18:30 2009 @@ -500,17 +500,19 @@ 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 @@ 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"); ======================================= --- /branches/bleeding_edge/src/x64/debug-x64.cc Wed Jul 15 05:30:28 2009 +++ /branches/bleeding_edge/src/x64/debug-x64.cc Wed Aug 19 03:18:30 2009 @@ -39,60 +39,176 @@ 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 ======================================= --- /branches/bleeding_edge/src/x64/ic-x64.cc Thu Aug 6 00:42:04 2009 +++ /branches/bleeding_edge/src/x64/ic-x64.cc Wed Aug 19 03:18:30 2009 @@ -167,7 +167,7 @@ // 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 @@ 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; ======================================= --- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Wed Aug 5 04:08:24 2009 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Wed Aug 19 03:18:30 2009 @@ -262,8 +262,7 @@ 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(Handle<Code> code_object, RelocInfo::Mode rmode) { - WriteRecordedPositions(); ASSERT(RelocInfo::IsCodeTarget(rmode)); movq(kScratchRegister, code_object, rmode); #ifdef DEBUG @@ -504,7 +502,7 @@ #endif jmp(kScratchRegister); #ifdef DEBUG - ASSERT_EQ(kTargetAddrToReturnAddrDist, + ASSERT_EQ(kPatchReturnSequenceLength, SizeOfCodeGeneratedSince(&target) + kPointerSize); #endif } @@ -523,8 +521,8 @@ 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 @@ #endif call(kScratchRegister); #ifdef DEBUG - ASSERT_EQ(kTargetAddrToReturnAddrDist, + ASSERT_EQ(kPatchReturnSequenceLength, SizeOfCodeGeneratedSince(&target) + kPointerSize); #endif } @@ -799,7 +797,7 @@ 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 @@ 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); } ======================================= --- /branches/bleeding_edge/test/cctest/cctest.status Tue Aug 18 05:43:36 2009 +++ /branches/bleeding_edge/test/cctest/cctest.status Wed Aug 19 03:18:30 2009 @@ -60,55 +60,3 @@ # 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 ======================================= --- /branches/bleeding_edge/test/cctest/test-debug.cc Mon Aug 17 07:26:48 2009 +++ /branches/bleeding_edge/test/cctest/test-debug.cc Wed Aug 19 03:18:30 2009 @@ -487,9 +487,7 @@ 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 @@ 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())); } } ======================================= --- /branches/bleeding_edge/test/message/message.status Tue Jul 14 04:39:45 2009 +++ /branches/bleeding_edge/test/message/message.status Wed Aug 19 03:18:30 2009 @@ -29,16 +29,3 @@ # 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 ======================================= --- /branches/bleeding_edge/test/mjsunit/mjsunit.status Fri Jul 31 06:17:59 2009 +++ /branches/bleeding_edge/test/mjsunit/mjsunit.status Wed Aug 19 03:18:30 2009 @@ -73,33 +73,3 @@ # 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 --~--~---------~--~----~------------~-------~--~----~ v8-dev mailing list [email protected] http://groups.google.com/group/v8-dev -~----------~----~----~----~------~----~------~--~---
