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 |