Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "bootstrapper.h" | 30 #include "bootstrapper.h" |
| 31 #include "codegen-inl.h" | 31 #include "codegen-inl.h" |
| 32 #include "assembler-x64.h" | |
| 32 #include "macro-assembler-x64.h" | 33 #include "macro-assembler-x64.h" |
| 34 #include "debug.h" | |
| 33 | 35 |
| 34 namespace v8 { | 36 namespace v8 { |
| 35 namespace internal { | 37 namespace internal { |
| 36 | 38 |
| 37 MacroAssembler::MacroAssembler(void* buffer, int size) | 39 MacroAssembler::MacroAssembler(void* buffer, int size) |
| 38 : Assembler(buffer, size), | 40 : Assembler(buffer, size), |
| 39 unresolved_(0), | 41 unresolved_(0), |
| 40 generating_stub_(false), | 42 generating_stub_(false), |
| 41 allow_stub_calls_(true), | 43 allow_stub_calls_(true), |
| 42 code_object_(Heap::undefined_value()) { | 44 code_object_(Heap::undefined_value()) { |
| 43 } | 45 } |
| 44 | 46 |
| 45 | 47 |
| 48 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
| |
| 49 #ifdef DEBUG | |
| 50 // Not implemented yet. | |
| 51 #endif | |
| 52 } | |
| 53 | |
| 54 | |
| 46 void MacroAssembler::TailCallRuntime(ExternalReference const& a, int b) { | 55 void MacroAssembler::TailCallRuntime(ExternalReference const& a, int b) { |
| 47 UNIMPLEMENTED(); | 56 UNIMPLEMENTED(); |
| 48 } | 57 } |
| 49 | 58 |
| 50 | 59 |
| 51 void MacroAssembler::Set(Register dst, int64_t x) { | 60 void MacroAssembler::Set(Register dst, int64_t x) { |
| 52 if (is_int32(x)) { | 61 if (is_int32(x)) { |
| 53 movq(dst, Immediate(x)); | 62 movq(dst, Immediate(x)); |
| 54 } else if (is_uint32(x)) { | 63 } else if (is_uint32(x)) { |
| 55 movl(dst, Immediate(x)); | 64 movl(dst, Immediate(x)); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 68 movq(kScratchRegister, x, RelocInfo::NONE); | 77 movq(kScratchRegister, x, RelocInfo::NONE); |
| 69 } | 78 } |
| 70 movq(dst, kScratchRegister); | 79 movq(dst, kScratchRegister); |
| 71 } | 80 } |
| 72 | 81 |
| 73 | 82 |
| 74 void MacroAssembler::PushTryHandler(CodeLocation try_location, | 83 void MacroAssembler::PushTryHandler(CodeLocation try_location, |
| 75 HandlerType type) { | 84 HandlerType type) { |
| 76 // The pc (return address) is already on TOS. | 85 // The pc (return address) is already on TOS. |
| 77 // This code pushes state, code, frame pointer and parameter pointer. | 86 // This code pushes state, code, frame pointer and parameter pointer. |
| 78 // Check that they are expected next on the stack, int that order. | 87 // Check that they are expected next on the stack, in that order. |
| 79 ASSERT_EQ(StackHandlerConstants::kStateOffset, | 88 ASSERT_EQ(StackHandlerConstants::kStateOffset, |
| 80 StackHandlerConstants::kPCOffset - kPointerSize); | 89 StackHandlerConstants::kPCOffset - kPointerSize); |
| 81 ASSERT_EQ(StackHandlerConstants::kCodeOffset, | 90 ASSERT_EQ(StackHandlerConstants::kCodeOffset, |
| 82 StackHandlerConstants::kStateOffset - kPointerSize); | 91 StackHandlerConstants::kStateOffset - kPointerSize); |
| 83 ASSERT_EQ(StackHandlerConstants::kFPOffset, | 92 ASSERT_EQ(StackHandlerConstants::kFPOffset, |
| 84 StackHandlerConstants::kCodeOffset - kPointerSize); | 93 StackHandlerConstants::kCodeOffset - kPointerSize); |
| 85 ASSERT_EQ(StackHandlerConstants::kPPOffset, | |
| 86 StackHandlerConstants::kFPOffset - kPointerSize); | |
| 87 | 94 |
| 88 if (try_location == IN_JAVASCRIPT) { | 95 if (try_location == IN_JAVASCRIPT) { |
| 89 if (type == TRY_CATCH_HANDLER) { | 96 if (type == TRY_CATCH_HANDLER) { |
| 90 push(Immediate(StackHandler::TRY_CATCH)); | 97 push(Immediate(StackHandler::TRY_CATCH)); |
| 91 } else { | 98 } else { |
| 92 push(Immediate(StackHandler::TRY_FINALLY)); | 99 push(Immediate(StackHandler::TRY_FINALLY)); |
| 93 } | 100 } |
| 94 push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent))); | 101 push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent))); |
| 95 push(rbp); | 102 push(rbp); |
| 96 push(rdi); | |
| 97 } else { | 103 } else { |
| 98 ASSERT(try_location == IN_JS_ENTRY); | 104 ASSERT(try_location == IN_JS_ENTRY); |
| 99 // The parameter pointer is meaningless here and ebp does not | 105 // The parameter pointer is meaningless here and ebp does not |
| 100 // point to a JS frame. So we save NULL for both pp and ebp. We | 106 // point to a JS frame. So we save NULL for both pp and ebp. We |
| 101 // expect the code throwing an exception to check ebp before | 107 // expect the code throwing an exception to check ebp before |
| 102 // dereferencing it to restore the context. | 108 // dereferencing it to restore the context. |
| 103 push(Immediate(StackHandler::ENTRY)); | 109 push(Immediate(StackHandler::ENTRY)); |
| 104 push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent))); | 110 push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent))); |
| 105 push(Immediate(0)); // NULL frame pointer | 111 push(Immediate(0)); // NULL frame pointer |
| 106 push(Immediate(0)); // NULL parameter pointer | |
| 107 } | 112 } |
| 108 movq(kScratchRegister, ExternalReference(Top::k_handler_address)); | 113 movq(kScratchRegister, ExternalReference(Top::k_handler_address)); |
| 109 // Cached TOS. | 114 // Cached TOS. |
| 110 movq(rax, Operand(kScratchRegister, 0)); | 115 movq(rax, Operand(kScratchRegister, 0)); |
| 111 // Link this handler. | 116 // Link this handler. |
| 112 movq(Operand(kScratchRegister, 0), rsp); | 117 movq(Operand(kScratchRegister, 0), rsp); |
| 113 } | 118 } |
| 114 | 119 |
| 115 | 120 |
| 121 #ifdef ENABLE_DEBUGGER_SUPPORT | |
| 122 | |
| 123 void MacroAssembler::PushRegistersFromMemory(RegList regs) { | |
| 124 ASSERT((regs & ~kJSCallerSaved) == 0); | |
| 125 // Push the content of the memory location to the stack. | |
| 126 for (int i = 0; i < kNumJSCallerSaved; i++) { | |
| 127 int r = JSCallerSavedCode(i); | |
| 128 if ((regs & (1 << r)) != 0) { | |
| 129 ExternalReference reg_addr = | |
| 130 ExternalReference(Debug_Address::Register(i)); | |
| 131 movq(kScratchRegister, reg_addr); | |
| 132 push(Operand(kScratchRegister, 0)); | |
| 133 } | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 void MacroAssembler::SaveRegistersToMemory(RegList regs) { | |
| 138 ASSERT((regs & ~kJSCallerSaved) == 0); | |
| 139 // Copy the content of registers to memory location. | |
| 140 for (int i = 0; i < kNumJSCallerSaved; i++) { | |
| 141 int r = JSCallerSavedCode(i); | |
| 142 if ((regs & (1 << r)) != 0) { | |
| 143 Register reg = { r }; | |
| 144 ExternalReference reg_addr = | |
| 145 ExternalReference(Debug_Address::Register(i)); | |
| 146 movq(kScratchRegister, reg_addr); | |
| 147 movq(Operand(kScratchRegister, 0), reg); | |
| 148 } | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 | |
| 153 void MacroAssembler::RestoreRegistersFromMemory(RegList regs) { | |
| 154 ASSERT((regs & ~kJSCallerSaved) == 0); | |
| 155 // Copy the content of memory location to registers. | |
| 156 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) { | |
| 157 int r = JSCallerSavedCode(i); | |
| 158 if ((regs & (1 << r)) != 0) { | |
| 159 Register reg = { r }; | |
| 160 ExternalReference reg_addr = | |
| 161 ExternalReference(Debug_Address::Register(i)); | |
| 162 movq(kScratchRegister, reg_addr); | |
| 163 movq(reg, Operand(kScratchRegister, 0)); | |
| 164 } | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 | |
| 169 void MacroAssembler::PopRegistersToMemory(RegList regs) { | |
| 170 ASSERT((regs & ~kJSCallerSaved) == 0); | |
| 171 // Pop the content from the stack to the memory location. | |
| 172 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) { | |
| 173 int r = JSCallerSavedCode(i); | |
| 174 if ((regs & (1 << r)) != 0) { | |
| 175 ExternalReference reg_addr = | |
| 176 ExternalReference(Debug_Address::Register(i)); | |
| 177 movq(kScratchRegister, reg_addr); | |
| 178 pop(Operand(kScratchRegister, 0)); | |
| 179 } | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 | |
| 184 void MacroAssembler::CopyRegistersFromStackToMemory(Register base, | |
| 185 Register scratch, | |
| 186 RegList regs) { | |
| 187 ASSERT(!scratch.is(kScratchRegister)); | |
| 188 ASSERT(!base.is(kScratchRegister)); | |
| 189 ASSERT(!base.is(scratch)); | |
| 190 ASSERT((regs & ~kJSCallerSaved) == 0); | |
| 191 // Copy the content of the stack to the memory location and adjust base. | |
| 192 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) { | |
| 193 int r = JSCallerSavedCode(i); | |
| 194 if ((regs & (1 << r)) != 0) { | |
| 195 movq(scratch, Operand(base, 0)); | |
| 196 ExternalReference reg_addr = | |
| 197 ExternalReference(Debug_Address::Register(i)); | |
| 198 movq(kScratchRegister, reg_addr); | |
| 199 movq(Operand(kScratchRegister, 0), scratch); | |
| 200 lea(base, Operand(base, kPointerSize)); | |
| 201 } | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 #endif // ENABLE_DEBUGGER_SUPPORT | |
| 206 | |
| 207 | |
| 208 | |
| 209 | |
| 210 void MacroAssembler::InvokeFunction(Register fun, | |
| 211 const ParameterCount& actual, | |
| 212 InvokeFlag flag) { | |
| 213 UNIMPLEMENTED(); | |
| 214 } | |
| 215 | |
| 216 | |
| 217 void MacroAssembler::EnterFrame(StackFrame::Type type) { | |
| 218 push(rbp); | |
| 219 movq(rbp, rsp); | |
| 220 push(rsi); // Context. | |
| 221 push(Immediate(Smi::FromInt(type))); | |
| 222 movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT); | |
| 223 push(kScratchRegister); | |
| 224 if (FLAG_debug_code) { | |
| 225 movq(kScratchRegister, | |
| 226 Factory::undefined_value(), | |
| 227 RelocInfo::EMBEDDED_OBJECT); | |
| 228 cmp(Operand(rsp, 0), kScratchRegister); | |
| 229 Check(not_equal, "code object not properly patched"); | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 | |
| 234 void MacroAssembler::LeaveFrame(StackFrame::Type type) { | |
| 235 if (FLAG_debug_code) { | |
| 236 movq(kScratchRegister, Immediate(Smi::FromInt(type))); | |
| 237 cmp(Operand(rbp, StandardFrameConstants::kMarkerOffset), kScratchRegister); | |
| 238 Check(equal, "stack frame types must match"); | |
| 239 } | |
| 240 movq(rsp, rbp); | |
| 241 pop(rbp); | |
| 242 } | |
| 243 | |
| 244 | |
| 245 | |
| 246 void MacroAssembler::EnterExitFrame(StackFrame::Type type) { | |
| 247 ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG); | |
| 248 | |
| 249 // Setup the frame structure on the stack. | |
| 250 ASSERT(ExitFrameConstants::kPPDisplacement == +2 * kPointerSize); | |
| 251 ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize); | |
| 252 ASSERT(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize); | |
| 253 push(rbp); | |
| 254 movq(rbp, rsp); | |
| 255 | |
| 256 // Reserve room for entry stack pointer and push the debug marker. | |
| 257 ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize); | |
| 258 push(Immediate(0)); // saved entry sp, patched before call | |
| 259 push(Immediate(type == StackFrame::EXIT_DEBUG ? 1 : 0)); | |
| 260 | |
| 261 // Save the frame pointer and the context in top. | |
| 262 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address); | |
| 263 ExternalReference context_address(Top::k_context_address); | |
| 264 movq(kScratchRegister, rax); | |
| 265 movq(rax, rbp); | |
| 266 store_rax(c_entry_fp_address); | |
| 267 movq(rax, rsi); | |
| 268 store_rax(context_address); | |
| 269 movq(rax, kScratchRegister); | |
| 270 | |
| 271 // Setup argc and argv in callee-saved registers. | |
| 272 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; | |
| 273 movq(rdi, rax); | |
| 274 lea(rsi, Operand(rbp, rax, kTimesPointerSize, offset)); | |
| 275 | |
| 276 #ifdef ENABLE_DEBUGGER_SUPPORT | |
| 277 // Save the state of all registers to the stack from the memory | |
| 278 // location. This is needed to allow nested break points. | |
| 279 if (type == StackFrame::EXIT_DEBUG) { | |
| 280 // TODO(1243899): This should be symmetric to | |
| 281 // CopyRegistersFromStackToMemory() but it isn't! esp is assumed | |
| 282 // correct here, but computed for the other call. Very error | |
| 283 // prone! FIX THIS. Actually there are deeper problems with | |
| 284 // register saving than this asymmetry (see the bug report | |
| 285 // associated with this issue). | |
| 286 PushRegistersFromMemory(kJSCallerSaved); | |
| 287 } | |
| 288 #endif | |
| 289 | |
| 290 // Reserve space for two arguments: argc and argv. | |
| 291 sub(rsp, Immediate(2 * kPointerSize)); | |
| 292 | |
| 293 // Get the required frame alignment for the OS. | |
| 294 static const int kFrameAlignment = OS::ActivationFrameAlignment(); | |
| 295 if (kFrameAlignment > 0) { | |
| 296 ASSERT(IsPowerOf2(kFrameAlignment)); | |
| 297 movq(r10, Immediate(-kFrameAlignment)); | |
| 298 and_(rsp, r10); | |
| 299 } | |
| 300 | |
| 301 // Patch the saved entry sp. | |
| 302 movq(Operand(rbp, ExitFrameConstants::kSPOffset), rsp); | |
| 303 } | |
| 304 | |
| 305 | |
| 306 void MacroAssembler::LeaveExitFrame(StackFrame::Type type) { | |
| 307 #ifdef ENABLE_DEBUGGER_SUPPORT | |
| 308 // Restore the memory copy of the registers by digging them out from | |
| 309 // the stack. This is needed to allow nested break points. | |
| 310 if (type == StackFrame::EXIT_DEBUG) { | |
| 311 // It's okay to clobber register ebx below because we don't need | |
| 312 // the function pointer after this. | |
| 313 const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize; | |
| 314 int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize; | |
| 315 lea(rbx, Operand(rbp, kOffset)); | |
| 316 CopyRegistersFromStackToMemory(rbx, rcx, kJSCallerSaved); | |
| 317 } | |
| 318 #endif | |
| 319 | |
| 320 // Get the return address from the stack and restore the frame pointer. | |
| 321 movq(rcx, Operand(rbp, 1 * kPointerSize)); | |
| 322 movq(rbp, Operand(rbp, 0 * kPointerSize)); | |
| 323 | |
| 324 // Pop the arguments and the receiver from the caller stack. | |
| 325 lea(rsp, Operand(rsi, 1 * kPointerSize)); | |
| 326 | |
| 327 // Restore current context from top and clear it in debug mode. | |
| 328 ExternalReference context_address(Top::k_context_address); | |
| 329 movq(kScratchRegister, context_address); | |
| 330 movq(rsi, Operand(kScratchRegister, 0)); | |
| 331 #ifdef DEBUG | |
| 332 movq(Operand(kScratchRegister, 0), Immediate(0)); | |
| 333 #endif | |
| 334 | |
| 335 // Push the return address to get ready to return. | |
| 336 push(rcx); | |
| 337 | |
| 338 // Clear the top frame. | |
| 339 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address); | |
| 340 movq(kScratchRegister, c_entry_fp_address); | |
| 341 movq(Operand(kScratchRegister, 0), Immediate(0)); | |
| 342 } | |
| 343 | |
| 344 | |
| 116 } } // namespace v8::internal | 345 } } // namespace v8::internal |
| OLD | NEW |