Chromium Code Reviews| Index: src/x64/macro-assembler-x64.cc | 
| diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc | 
| index 54c299dbfae9894ff96cec5b59fbf835d3a99c57..cf9d8a02025255790061743468a1fce933ace207 100644 | 
| --- a/src/x64/macro-assembler-x64.cc | 
| +++ b/src/x64/macro-assembler-x64.cc | 
| @@ -29,7 +29,9 @@ | 
| #include "bootstrapper.h" | 
| #include "codegen-inl.h" | 
| +#include "assembler-x64.h" | 
| #include "macro-assembler-x64.h" | 
| +#include "debug.h" | 
| namespace v8 { | 
| namespace internal { | 
| @@ -43,6 +45,13 @@ MacroAssembler::MacroAssembler(void* buffer, int size) | 
| } | 
| +void MacroAssembler::Check(Condition cc, const char* message) { | 
| 
 
William Hesse
2009/06/10 08:09:09
We want this to be inline if the debug check is in
 
 | 
| +#ifdef DEBUG | 
| + // Not implemented yet. | 
| +#endif | 
| +} | 
| + | 
| + | 
| void MacroAssembler::TailCallRuntime(ExternalReference const& a, int b) { | 
| UNIMPLEMENTED(); | 
| } | 
| @@ -75,15 +84,13 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, | 
| HandlerType type) { | 
| // The pc (return address) is already on TOS. | 
| // This code pushes state, code, frame pointer and parameter pointer. | 
| - // Check that they are expected next on the stack, int that order. | 
| + // Check that they are expected next on the stack, in that order. | 
| ASSERT_EQ(StackHandlerConstants::kStateOffset, | 
| StackHandlerConstants::kPCOffset - kPointerSize); | 
| ASSERT_EQ(StackHandlerConstants::kCodeOffset, | 
| StackHandlerConstants::kStateOffset - kPointerSize); | 
| ASSERT_EQ(StackHandlerConstants::kFPOffset, | 
| StackHandlerConstants::kCodeOffset - kPointerSize); | 
| - ASSERT_EQ(StackHandlerConstants::kPPOffset, | 
| - StackHandlerConstants::kFPOffset - kPointerSize); | 
| if (try_location == IN_JAVASCRIPT) { | 
| if (type == TRY_CATCH_HANDLER) { | 
| @@ -93,7 +100,6 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, | 
| } | 
| push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent))); | 
| push(rbp); | 
| - push(rdi); | 
| } else { | 
| ASSERT(try_location == IN_JS_ENTRY); | 
| // The parameter pointer is meaningless here and ebp does not | 
| @@ -103,7 +109,6 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, | 
| push(Immediate(StackHandler::ENTRY)); | 
| push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent))); | 
| push(Immediate(0)); // NULL frame pointer | 
| - push(Immediate(0)); // NULL parameter pointer | 
| } | 
| movq(kScratchRegister, ExternalReference(Top::k_handler_address)); | 
| // Cached TOS. | 
| @@ -113,4 +118,228 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, | 
| } | 
| +#ifdef ENABLE_DEBUGGER_SUPPORT | 
| + | 
| +void MacroAssembler::PushRegistersFromMemory(RegList regs) { | 
| + ASSERT((regs & ~kJSCallerSaved) == 0); | 
| + // Push the content of the memory location to the stack. | 
| + for (int i = 0; i < kNumJSCallerSaved; i++) { | 
| + int r = JSCallerSavedCode(i); | 
| + if ((regs & (1 << r)) != 0) { | 
| + ExternalReference reg_addr = | 
| + ExternalReference(Debug_Address::Register(i)); | 
| + movq(kScratchRegister, reg_addr); | 
| + push(Operand(kScratchRegister, 0)); | 
| + } | 
| + } | 
| +} | 
| + | 
| +void MacroAssembler::SaveRegistersToMemory(RegList regs) { | 
| + ASSERT((regs & ~kJSCallerSaved) == 0); | 
| + // Copy the content of registers to memory location. | 
| + for (int i = 0; i < kNumJSCallerSaved; i++) { | 
| + int r = JSCallerSavedCode(i); | 
| + if ((regs & (1 << r)) != 0) { | 
| + Register reg = { r }; | 
| + ExternalReference reg_addr = | 
| + ExternalReference(Debug_Address::Register(i)); | 
| + movq(kScratchRegister, reg_addr); | 
| + movq(Operand(kScratchRegister, 0), reg); | 
| + } | 
| + } | 
| +} | 
| + | 
| + | 
| +void MacroAssembler::RestoreRegistersFromMemory(RegList regs) { | 
| + ASSERT((regs & ~kJSCallerSaved) == 0); | 
| + // Copy the content of memory location to registers. | 
| + for (int i = kNumJSCallerSaved - 1; i >= 0; i--) { | 
| + int r = JSCallerSavedCode(i); | 
| + if ((regs & (1 << r)) != 0) { | 
| + Register reg = { r }; | 
| + ExternalReference reg_addr = | 
| + ExternalReference(Debug_Address::Register(i)); | 
| + movq(kScratchRegister, reg_addr); | 
| + movq(reg, Operand(kScratchRegister, 0)); | 
| + } | 
| + } | 
| +} | 
| + | 
| + | 
| +void MacroAssembler::PopRegistersToMemory(RegList regs) { | 
| + ASSERT((regs & ~kJSCallerSaved) == 0); | 
| + // Pop the content from the stack to the memory location. | 
| + for (int i = kNumJSCallerSaved - 1; i >= 0; i--) { | 
| + int r = JSCallerSavedCode(i); | 
| + if ((regs & (1 << r)) != 0) { | 
| + ExternalReference reg_addr = | 
| + ExternalReference(Debug_Address::Register(i)); | 
| + movq(kScratchRegister, reg_addr); | 
| + pop(Operand(kScratchRegister, 0)); | 
| + } | 
| + } | 
| +} | 
| + | 
| + | 
| +void MacroAssembler::CopyRegistersFromStackToMemory(Register base, | 
| + Register scratch, | 
| + RegList regs) { | 
| + ASSERT(!scratch.is(kScratchRegister)); | 
| + ASSERT(!base.is(kScratchRegister)); | 
| + ASSERT(!base.is(scratch)); | 
| + ASSERT((regs & ~kJSCallerSaved) == 0); | 
| + // Copy the content of the stack to the memory location and adjust base. | 
| + for (int i = kNumJSCallerSaved - 1; i >= 0; i--) { | 
| + int r = JSCallerSavedCode(i); | 
| + if ((regs & (1 << r)) != 0) { | 
| + movq(scratch, Operand(base, 0)); | 
| + ExternalReference reg_addr = | 
| + ExternalReference(Debug_Address::Register(i)); | 
| + movq(kScratchRegister, reg_addr); | 
| + movq(Operand(kScratchRegister, 0), scratch); | 
| + lea(base, Operand(base, kPointerSize)); | 
| + } | 
| + } | 
| +} | 
| + | 
| +#endif // ENABLE_DEBUGGER_SUPPORT | 
| + | 
| + | 
| + | 
| + | 
| +void MacroAssembler::InvokeFunction(Register fun, | 
| + const ParameterCount& actual, | 
| + InvokeFlag flag) { | 
| + UNIMPLEMENTED(); | 
| +} | 
| + | 
| + | 
| +void MacroAssembler::EnterFrame(StackFrame::Type type) { | 
| + push(rbp); | 
| + movq(rbp, rsp); | 
| + push(rsi); // Context. | 
| + push(Immediate(Smi::FromInt(type))); | 
| + movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT); | 
| + push(kScratchRegister); | 
| + if (FLAG_debug_code) { | 
| + movq(kScratchRegister, | 
| + Factory::undefined_value(), | 
| + RelocInfo::EMBEDDED_OBJECT); | 
| + cmp(Operand(rsp, 0), kScratchRegister); | 
| + Check(not_equal, "code object not properly patched"); | 
| + } | 
| +} | 
| + | 
| + | 
| +void MacroAssembler::LeaveFrame(StackFrame::Type type) { | 
| + if (FLAG_debug_code) { | 
| + movq(kScratchRegister, Immediate(Smi::FromInt(type))); | 
| + cmp(Operand(rbp, StandardFrameConstants::kMarkerOffset), kScratchRegister); | 
| + Check(equal, "stack frame types must match"); | 
| + } | 
| + movq(rsp, rbp); | 
| + pop(rbp); | 
| +} | 
| + | 
| + | 
| + | 
| +void MacroAssembler::EnterExitFrame(StackFrame::Type type) { | 
| + ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG); | 
| + | 
| + // Setup the frame structure on the stack. | 
| + ASSERT(ExitFrameConstants::kPPDisplacement == +2 * kPointerSize); | 
| + ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize); | 
| + ASSERT(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize); | 
| + push(rbp); | 
| + movq(rbp, rsp); | 
| + | 
| + // Reserve room for entry stack pointer and push the debug marker. | 
| + ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize); | 
| + push(Immediate(0)); // saved entry sp, patched before call | 
| + push(Immediate(type == StackFrame::EXIT_DEBUG ? 1 : 0)); | 
| + | 
| + // Save the frame pointer and the context in top. | 
| + ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address); | 
| + ExternalReference context_address(Top::k_context_address); | 
| + movq(kScratchRegister, rax); | 
| + movq(rax, rbp); | 
| + store_rax(c_entry_fp_address); | 
| + movq(rax, rsi); | 
| + store_rax(context_address); | 
| + movq(rax, kScratchRegister); | 
| + | 
| + // Setup argc and argv in callee-saved registers. | 
| + int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; | 
| + movq(rdi, rax); | 
| + lea(rsi, Operand(rbp, rax, kTimesPointerSize, offset)); | 
| + | 
| +#ifdef ENABLE_DEBUGGER_SUPPORT | 
| + // Save the state of all registers to the stack from the memory | 
| + // location. This is needed to allow nested break points. | 
| + if (type == StackFrame::EXIT_DEBUG) { | 
| + // TODO(1243899): This should be symmetric to | 
| + // CopyRegistersFromStackToMemory() but it isn't! esp is assumed | 
| + // correct here, but computed for the other call. Very error | 
| + // prone! FIX THIS. Actually there are deeper problems with | 
| + // register saving than this asymmetry (see the bug report | 
| + // associated with this issue). | 
| + PushRegistersFromMemory(kJSCallerSaved); | 
| + } | 
| +#endif | 
| + | 
| + // Reserve space for two arguments: argc and argv. | 
| + sub(rsp, Immediate(2 * kPointerSize)); | 
| + | 
| + // Get the required frame alignment for the OS. | 
| + static const int kFrameAlignment = OS::ActivationFrameAlignment(); | 
| + if (kFrameAlignment > 0) { | 
| + ASSERT(IsPowerOf2(kFrameAlignment)); | 
| + movq(r10, Immediate(-kFrameAlignment)); | 
| + and_(rsp, r10); | 
| + } | 
| + | 
| + // Patch the saved entry sp. | 
| + movq(Operand(rbp, ExitFrameConstants::kSPOffset), rsp); | 
| +} | 
| + | 
| + | 
| +void MacroAssembler::LeaveExitFrame(StackFrame::Type type) { | 
| +#ifdef ENABLE_DEBUGGER_SUPPORT | 
| + // Restore the memory copy of the registers by digging them out from | 
| + // the stack. This is needed to allow nested break points. | 
| + if (type == StackFrame::EXIT_DEBUG) { | 
| + // It's okay to clobber register ebx below because we don't need | 
| + // the function pointer after this. | 
| + const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize; | 
| + int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize; | 
| + lea(rbx, Operand(rbp, kOffset)); | 
| + CopyRegistersFromStackToMemory(rbx, rcx, kJSCallerSaved); | 
| + } | 
| +#endif | 
| + | 
| + // Get the return address from the stack and restore the frame pointer. | 
| + movq(rcx, Operand(rbp, 1 * kPointerSize)); | 
| + movq(rbp, Operand(rbp, 0 * kPointerSize)); | 
| + | 
| + // Pop the arguments and the receiver from the caller stack. | 
| + lea(rsp, Operand(rsi, 1 * kPointerSize)); | 
| + | 
| + // Restore current context from top and clear it in debug mode. | 
| + ExternalReference context_address(Top::k_context_address); | 
| + movq(kScratchRegister, context_address); | 
| + movq(rsi, Operand(kScratchRegister, 0)); | 
| +#ifdef DEBUG | 
| + movq(Operand(kScratchRegister, 0), Immediate(0)); | 
| +#endif | 
| + | 
| + // Push the return address to get ready to return. | 
| + push(rcx); | 
| + | 
| + // Clear the top frame. | 
| + ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address); | 
| + movq(kScratchRegister, c_entry_fp_address); | 
| + movq(Operand(kScratchRegister, 0), Immediate(0)); | 
| +} | 
| + | 
| + | 
| } } // namespace v8::internal |