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 |