|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifndef jit_x86_MacroAssembler_x86_h |
|
8 #define jit_x86_MacroAssembler_x86_h |
|
9 |
|
10 #include "jscompartment.h" |
|
11 |
|
12 #include "jit/IonFrames.h" |
|
13 #include "jit/MoveResolver.h" |
|
14 #include "jit/shared/MacroAssembler-x86-shared.h" |
|
15 |
|
16 namespace js { |
|
17 namespace jit { |
|
18 |
|
19 class MacroAssemblerX86 : public MacroAssemblerX86Shared |
|
20 { |
|
21 // Number of bytes the stack is adjusted inside a call to C. Calls to C may |
|
22 // not be nested. |
|
23 bool inCall_; |
|
24 uint32_t args_; |
|
25 uint32_t passedArgs_; |
|
26 uint32_t stackForCall_; |
|
27 bool dynamicAlignment_; |
|
28 bool enoughMemory_; |
|
29 |
|
30 struct Double { |
|
31 double value; |
|
32 AbsoluteLabel uses; |
|
33 Double(double value) : value(value) {} |
|
34 }; |
|
35 Vector<Double, 0, SystemAllocPolicy> doubles_; |
|
36 struct Float { |
|
37 float value; |
|
38 AbsoluteLabel uses; |
|
39 Float(float value) : value(value) {} |
|
40 }; |
|
41 Vector<Float, 0, SystemAllocPolicy> floats_; |
|
42 |
|
43 typedef HashMap<double, size_t, DefaultHasher<double>, SystemAllocPolicy> DoubleMap; |
|
44 DoubleMap doubleMap_; |
|
45 typedef HashMap<float, size_t, DefaultHasher<float>, SystemAllocPolicy> FloatMap; |
|
46 FloatMap floatMap_; |
|
47 |
|
48 Double *getDouble(double d); |
|
49 Float *getFloat(float f); |
|
50 |
|
51 protected: |
|
52 MoveResolver moveResolver_; |
|
53 |
|
54 private: |
|
55 Operand payloadOf(const Address &address) { |
|
56 return Operand(address.base, address.offset); |
|
57 } |
|
58 Operand tagOf(const Address &address) { |
|
59 return Operand(address.base, address.offset + 4); |
|
60 } |
|
61 Operand tagOf(const BaseIndex &address) { |
|
62 return Operand(address.base, address.index, address.scale, address.offset + 4); |
|
63 } |
|
64 |
|
65 void setupABICall(uint32_t args); |
|
66 |
|
67 public: |
|
68 using MacroAssemblerX86Shared::Push; |
|
69 using MacroAssemblerX86Shared::Pop; |
|
70 using MacroAssemblerX86Shared::callWithExitFrame; |
|
71 using MacroAssemblerX86Shared::branch32; |
|
72 using MacroAssemblerX86Shared::load32; |
|
73 using MacroAssemblerX86Shared::store32; |
|
74 using MacroAssemblerX86Shared::call; |
|
75 |
|
76 MacroAssemblerX86() |
|
77 : inCall_(false), |
|
78 enoughMemory_(true) |
|
79 { |
|
80 } |
|
81 |
|
82 // The buffer is about to be linked, make sure any constant pools or excess |
|
83 // bookkeeping has been flushed to the instruction stream. |
|
84 void finish(); |
|
85 |
|
86 bool oom() const { |
|
87 return MacroAssemblerX86Shared::oom() || !enoughMemory_; |
|
88 } |
|
89 |
|
90 ///////////////////////////////////////////////////////////////// |
|
91 // X86-specific interface. |
|
92 ///////////////////////////////////////////////////////////////// |
|
93 |
|
94 Operand ToPayload(Operand base) { |
|
95 return base; |
|
96 } |
|
97 Address ToPayload(Address base) { |
|
98 return base; |
|
99 } |
|
100 Operand ToType(Operand base) { |
|
101 switch (base.kind()) { |
|
102 case Operand::MEM_REG_DISP: |
|
103 return Operand(Register::FromCode(base.base()), base.disp() + sizeof(void *)); |
|
104 |
|
105 case Operand::MEM_SCALE: |
|
106 return Operand(Register::FromCode(base.base()), Register::FromCode(base.index()), |
|
107 base.scale(), base.disp() + sizeof(void *)); |
|
108 |
|
109 default: |
|
110 MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); |
|
111 } |
|
112 } |
|
113 Address ToType(Address base) { |
|
114 return ToType(Operand(base)).toAddress(); |
|
115 } |
|
116 void moveValue(const Value &val, Register type, Register data) { |
|
117 jsval_layout jv = JSVAL_TO_IMPL(val); |
|
118 movl(Imm32(jv.s.tag), type); |
|
119 if (val.isMarkable()) |
|
120 movl(ImmGCPtr(reinterpret_cast<gc::Cell *>(val.toGCThing())), data); |
|
121 else |
|
122 movl(Imm32(jv.s.payload.i32), data); |
|
123 } |
|
124 void moveValue(const Value &val, const ValueOperand &dest) { |
|
125 moveValue(val, dest.typeReg(), dest.payloadReg()); |
|
126 } |
|
127 void moveValue(const ValueOperand &src, const ValueOperand &dest) { |
|
128 Register s0 = src.typeReg(), d0 = dest.typeReg(), |
|
129 s1 = src.payloadReg(), d1 = dest.payloadReg(); |
|
130 |
|
131 // Either one or both of the source registers could be the same as a |
|
132 // destination register. |
|
133 if (s1 == d0) { |
|
134 if (s0 == d1) { |
|
135 // If both are, this is just a swap of two registers. |
|
136 xchgl(d0, d1); |
|
137 return; |
|
138 } |
|
139 // If only one is, copy that source first. |
|
140 mozilla::Swap(s0, s1); |
|
141 mozilla::Swap(d0, d1); |
|
142 } |
|
143 |
|
144 if (s0 != d0) |
|
145 movl(s0, d0); |
|
146 if (s1 != d1) |
|
147 movl(s1, d1); |
|
148 } |
|
149 |
|
150 ///////////////////////////////////////////////////////////////// |
|
151 // X86/X64-common interface. |
|
152 ///////////////////////////////////////////////////////////////// |
|
153 void storeValue(ValueOperand val, Operand dest) { |
|
154 movl(val.payloadReg(), ToPayload(dest)); |
|
155 movl(val.typeReg(), ToType(dest)); |
|
156 } |
|
157 void storeValue(ValueOperand val, const Address &dest) { |
|
158 storeValue(val, Operand(dest)); |
|
159 } |
|
160 template <typename T> |
|
161 void storeValue(JSValueType type, Register reg, const T &dest) { |
|
162 storeTypeTag(ImmTag(JSVAL_TYPE_TO_TAG(type)), Operand(dest)); |
|
163 storePayload(reg, Operand(dest)); |
|
164 } |
|
165 template <typename T> |
|
166 void storeValue(const Value &val, const T &dest) { |
|
167 jsval_layout jv = JSVAL_TO_IMPL(val); |
|
168 storeTypeTag(ImmTag(jv.s.tag), Operand(dest)); |
|
169 storePayload(val, Operand(dest)); |
|
170 } |
|
171 void storeValue(ValueOperand val, BaseIndex dest) { |
|
172 storeValue(val, Operand(dest)); |
|
173 } |
|
174 void loadValue(Operand src, ValueOperand val) { |
|
175 Operand payload = ToPayload(src); |
|
176 Operand type = ToType(src); |
|
177 |
|
178 // Ensure that loading the payload does not erase the pointer to the |
|
179 // Value in memory or the index. |
|
180 Register baseReg = Register::FromCode(src.base()); |
|
181 Register indexReg = (src.kind() == Operand::MEM_SCALE) ? Register::FromCode(src.index()) : InvalidReg; |
|
182 |
|
183 if (baseReg == val.payloadReg() || indexReg == val.payloadReg()) { |
|
184 JS_ASSERT(baseReg != val.typeReg()); |
|
185 JS_ASSERT(indexReg != val.typeReg()); |
|
186 |
|
187 movl(type, val.typeReg()); |
|
188 movl(payload, val.payloadReg()); |
|
189 } else { |
|
190 JS_ASSERT(baseReg != val.payloadReg()); |
|
191 JS_ASSERT(indexReg != val.payloadReg()); |
|
192 |
|
193 movl(payload, val.payloadReg()); |
|
194 movl(type, val.typeReg()); |
|
195 } |
|
196 } |
|
197 void loadValue(Address src, ValueOperand val) { |
|
198 loadValue(Operand(src), val); |
|
199 } |
|
200 void loadValue(const BaseIndex &src, ValueOperand val) { |
|
201 loadValue(Operand(src), val); |
|
202 } |
|
203 void tagValue(JSValueType type, Register payload, ValueOperand dest) { |
|
204 JS_ASSERT(dest.typeReg() != dest.payloadReg()); |
|
205 if (payload != dest.payloadReg()) |
|
206 movl(payload, dest.payloadReg()); |
|
207 movl(ImmType(type), dest.typeReg()); |
|
208 } |
|
209 void pushValue(ValueOperand val) { |
|
210 push(val.typeReg()); |
|
211 push(val.payloadReg()); |
|
212 } |
|
213 void popValue(ValueOperand val) { |
|
214 pop(val.payloadReg()); |
|
215 pop(val.typeReg()); |
|
216 } |
|
217 void pushValue(const Value &val) { |
|
218 jsval_layout jv = JSVAL_TO_IMPL(val); |
|
219 push(Imm32(jv.s.tag)); |
|
220 if (val.isMarkable()) |
|
221 push(ImmGCPtr(reinterpret_cast<gc::Cell *>(val.toGCThing()))); |
|
222 else |
|
223 push(Imm32(jv.s.payload.i32)); |
|
224 } |
|
225 void pushValue(JSValueType type, Register reg) { |
|
226 push(ImmTag(JSVAL_TYPE_TO_TAG(type))); |
|
227 push(reg); |
|
228 } |
|
229 void pushValue(const Address &addr) { |
|
230 push(tagOf(addr)); |
|
231 push(payloadOf(addr)); |
|
232 } |
|
233 void Push(const ValueOperand &val) { |
|
234 pushValue(val); |
|
235 framePushed_ += sizeof(Value); |
|
236 } |
|
237 void Pop(const ValueOperand &val) { |
|
238 popValue(val); |
|
239 framePushed_ -= sizeof(Value); |
|
240 } |
|
241 void storePayload(const Value &val, Operand dest) { |
|
242 jsval_layout jv = JSVAL_TO_IMPL(val); |
|
243 if (val.isMarkable()) |
|
244 movl(ImmGCPtr((gc::Cell *)jv.s.payload.ptr), ToPayload(dest)); |
|
245 else |
|
246 movl(Imm32(jv.s.payload.i32), ToPayload(dest)); |
|
247 } |
|
248 void storePayload(Register src, Operand dest) { |
|
249 movl(src, ToPayload(dest)); |
|
250 } |
|
251 void storeTypeTag(ImmTag tag, Operand dest) { |
|
252 movl(tag, ToType(dest)); |
|
253 } |
|
254 |
|
255 void movePtr(const Register &src, const Register &dest) { |
|
256 movl(src, dest); |
|
257 } |
|
258 void movePtr(const Register &src, const Operand &dest) { |
|
259 movl(src, dest); |
|
260 } |
|
261 |
|
262 // Returns the register containing the type tag. |
|
263 Register splitTagForTest(const ValueOperand &value) { |
|
264 return value.typeReg(); |
|
265 } |
|
266 |
|
267 Condition testUndefined(Condition cond, const Register &tag) { |
|
268 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
269 cmpl(tag, ImmTag(JSVAL_TAG_UNDEFINED)); |
|
270 return cond; |
|
271 } |
|
272 Condition testBoolean(Condition cond, const Register &tag) { |
|
273 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
274 cmpl(tag, ImmTag(JSVAL_TAG_BOOLEAN)); |
|
275 return cond; |
|
276 } |
|
277 Condition testInt32(Condition cond, const Register &tag) { |
|
278 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
279 cmpl(tag, ImmTag(JSVAL_TAG_INT32)); |
|
280 return cond; |
|
281 } |
|
282 Condition testDouble(Condition cond, const Register &tag) { |
|
283 JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); |
|
284 Condition actual = (cond == Equal) ? Below : AboveOrEqual; |
|
285 cmpl(tag, ImmTag(JSVAL_TAG_CLEAR)); |
|
286 return actual; |
|
287 } |
|
288 Condition testNull(Condition cond, const Register &tag) { |
|
289 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
290 cmpl(tag, ImmTag(JSVAL_TAG_NULL)); |
|
291 return cond; |
|
292 } |
|
293 Condition testString(Condition cond, const Register &tag) { |
|
294 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
295 cmpl(tag, ImmTag(JSVAL_TAG_STRING)); |
|
296 return cond; |
|
297 } |
|
298 Condition testObject(Condition cond, const Register &tag) { |
|
299 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
300 cmpl(tag, ImmTag(JSVAL_TAG_OBJECT)); |
|
301 return cond; |
|
302 } |
|
303 Condition testNumber(Condition cond, const Register &tag) { |
|
304 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
305 cmpl(tag, ImmTag(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET)); |
|
306 return cond == Equal ? BelowOrEqual : Above; |
|
307 } |
|
308 Condition testGCThing(Condition cond, const Register &tag) { |
|
309 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
310 cmpl(tag, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); |
|
311 return cond == Equal ? AboveOrEqual : Below; |
|
312 } |
|
313 Condition testGCThing(Condition cond, const Address &address) { |
|
314 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
315 cmpl(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); |
|
316 return cond == Equal ? AboveOrEqual : Below; |
|
317 } |
|
318 Condition testMagic(Condition cond, const Address &address) { |
|
319 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
320 cmpl(tagOf(address), ImmTag(JSVAL_TAG_MAGIC)); |
|
321 return cond; |
|
322 } |
|
323 Condition testMagic(Condition cond, const Register &tag) { |
|
324 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
325 cmpl(tag, ImmTag(JSVAL_TAG_MAGIC)); |
|
326 return cond; |
|
327 } |
|
328 Condition testMagic(Condition cond, const Operand &operand) { |
|
329 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
330 cmpl(ToType(operand), ImmTag(JSVAL_TAG_MAGIC)); |
|
331 return cond; |
|
332 } |
|
333 Condition testPrimitive(Condition cond, const Register &tag) { |
|
334 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
335 cmpl(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET)); |
|
336 return cond == Equal ? Below : AboveOrEqual; |
|
337 } |
|
338 Condition testError(Condition cond, const Register &tag) { |
|
339 return testMagic(cond, tag); |
|
340 } |
|
341 Condition testInt32(Condition cond, const Operand &operand) { |
|
342 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
343 cmpl(ToType(operand), ImmTag(JSVAL_TAG_INT32)); |
|
344 return cond; |
|
345 } |
|
346 Condition testInt32(Condition cond, const Address &address) { |
|
347 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
348 return testInt32(cond, Operand(address)); |
|
349 } |
|
350 Condition testDouble(Condition cond, const Operand &operand) { |
|
351 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
352 Condition actual = (cond == Equal) ? Below : AboveOrEqual; |
|
353 cmpl(ToType(operand), ImmTag(JSVAL_TAG_CLEAR)); |
|
354 return actual; |
|
355 } |
|
356 Condition testDouble(Condition cond, const Address &address) { |
|
357 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
358 return testDouble(cond, Operand(address)); |
|
359 } |
|
360 |
|
361 |
|
362 Condition testUndefined(Condition cond, const Operand &operand) { |
|
363 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
364 cmpl(ToType(operand), ImmTag(JSVAL_TAG_UNDEFINED)); |
|
365 return cond; |
|
366 } |
|
367 Condition testUndefined(Condition cond, const Address &addr) { |
|
368 return testUndefined(cond, Operand(addr)); |
|
369 } |
|
370 |
|
371 |
|
372 Condition testUndefined(Condition cond, const ValueOperand &value) { |
|
373 return testUndefined(cond, value.typeReg()); |
|
374 } |
|
375 Condition testBoolean(Condition cond, const ValueOperand &value) { |
|
376 return testBoolean(cond, value.typeReg()); |
|
377 } |
|
378 Condition testInt32(Condition cond, const ValueOperand &value) { |
|
379 return testInt32(cond, value.typeReg()); |
|
380 } |
|
381 Condition testDouble(Condition cond, const ValueOperand &value) { |
|
382 return testDouble(cond, value.typeReg()); |
|
383 } |
|
384 Condition testNull(Condition cond, const ValueOperand &value) { |
|
385 return testNull(cond, value.typeReg()); |
|
386 } |
|
387 Condition testString(Condition cond, const ValueOperand &value) { |
|
388 return testString(cond, value.typeReg()); |
|
389 } |
|
390 Condition testObject(Condition cond, const ValueOperand &value) { |
|
391 return testObject(cond, value.typeReg()); |
|
392 } |
|
393 Condition testMagic(Condition cond, const ValueOperand &value) { |
|
394 return testMagic(cond, value.typeReg()); |
|
395 } |
|
396 Condition testError(Condition cond, const ValueOperand &value) { |
|
397 return testMagic(cond, value); |
|
398 } |
|
399 Condition testNumber(Condition cond, const ValueOperand &value) { |
|
400 return testNumber(cond, value.typeReg()); |
|
401 } |
|
402 Condition testGCThing(Condition cond, const ValueOperand &value) { |
|
403 return testGCThing(cond, value.typeReg()); |
|
404 } |
|
405 Condition testPrimitive(Condition cond, const ValueOperand &value) { |
|
406 return testPrimitive(cond, value.typeReg()); |
|
407 } |
|
408 |
|
409 |
|
410 Condition testUndefined(Condition cond, const BaseIndex &address) { |
|
411 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
412 cmpl(tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED)); |
|
413 return cond; |
|
414 } |
|
415 Condition testNull(Condition cond, const BaseIndex &address) { |
|
416 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
417 cmpl(tagOf(address), ImmTag(JSVAL_TAG_NULL)); |
|
418 return cond; |
|
419 } |
|
420 Condition testBoolean(Condition cond, const BaseIndex &address) { |
|
421 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
422 cmpl(tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN)); |
|
423 return cond; |
|
424 } |
|
425 Condition testString(Condition cond, const BaseIndex &address) { |
|
426 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
427 cmpl(tagOf(address), ImmTag(JSVAL_TAG_STRING)); |
|
428 return cond; |
|
429 } |
|
430 Condition testInt32(Condition cond, const BaseIndex &address) { |
|
431 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
432 cmpl(tagOf(address), ImmTag(JSVAL_TAG_INT32)); |
|
433 return cond; |
|
434 } |
|
435 Condition testObject(Condition cond, const BaseIndex &address) { |
|
436 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
437 cmpl(tagOf(address), ImmTag(JSVAL_TAG_OBJECT)); |
|
438 return cond; |
|
439 } |
|
440 Condition testDouble(Condition cond, const BaseIndex &address) { |
|
441 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
442 Condition actual = (cond == Equal) ? Below : AboveOrEqual; |
|
443 cmpl(tagOf(address), ImmTag(JSVAL_TAG_CLEAR)); |
|
444 return actual; |
|
445 } |
|
446 Condition testMagic(Condition cond, const BaseIndex &address) { |
|
447 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
448 cmpl(tagOf(address), ImmTag(JSVAL_TAG_MAGIC)); |
|
449 return cond; |
|
450 } |
|
451 Condition testGCThing(Condition cond, const BaseIndex &address) { |
|
452 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
453 cmpl(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); |
|
454 return cond == Equal ? AboveOrEqual : Below; |
|
455 } |
|
456 |
|
457 |
|
458 |
|
459 void branchTestValue(Condition cond, const ValueOperand &value, const Value &v, Label *label); |
|
460 void branchTestValue(Condition cond, const Address &valaddr, const ValueOperand &value, |
|
461 Label *label) |
|
462 { |
|
463 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
464 // Check payload before tag, since payload is more likely to differ. |
|
465 if (cond == NotEqual) { |
|
466 branchPtr(NotEqual, payloadOf(valaddr), value.payloadReg(), label); |
|
467 branchPtr(NotEqual, tagOf(valaddr), value.typeReg(), label); |
|
468 |
|
469 } else { |
|
470 Label fallthrough; |
|
471 branchPtr(NotEqual, payloadOf(valaddr), value.payloadReg(), &fallthrough); |
|
472 branchPtr(Equal, tagOf(valaddr), value.typeReg(), label); |
|
473 bind(&fallthrough); |
|
474 } |
|
475 } |
|
476 |
|
477 void testNullSet(Condition cond, const ValueOperand &value, Register dest) { |
|
478 cond = testNull(cond, value); |
|
479 emitSet(cond, dest); |
|
480 } |
|
481 void testUndefinedSet(Condition cond, const ValueOperand &value, Register dest) { |
|
482 cond = testUndefined(cond, value); |
|
483 emitSet(cond, dest); |
|
484 } |
|
485 |
|
486 void cmpPtr(Register lhs, const ImmWord rhs) { |
|
487 cmpl(lhs, Imm32(rhs.value)); |
|
488 } |
|
489 void cmpPtr(Register lhs, const ImmPtr imm) { |
|
490 cmpPtr(lhs, ImmWord(uintptr_t(imm.value))); |
|
491 } |
|
492 void cmpPtr(Register lhs, const ImmGCPtr rhs) { |
|
493 cmpl(lhs, rhs); |
|
494 } |
|
495 void cmpPtr(Register lhs, const Imm32 rhs) { |
|
496 cmpl(lhs, rhs); |
|
497 } |
|
498 void cmpPtr(const Operand &lhs, const ImmWord rhs) { |
|
499 cmpl(lhs, rhs); |
|
500 } |
|
501 void cmpPtr(const Operand &lhs, const ImmPtr imm) { |
|
502 cmpPtr(lhs, ImmWord(uintptr_t(imm.value))); |
|
503 } |
|
504 void cmpPtr(const Operand &lhs, const ImmGCPtr rhs) { |
|
505 cmpl(lhs, rhs); |
|
506 } |
|
507 void cmpPtr(const Operand &lhs, const Imm32 rhs) { |
|
508 cmpl(lhs, rhs); |
|
509 } |
|
510 void cmpPtr(const Address &lhs, Register rhs) { |
|
511 cmpl(Operand(lhs), rhs); |
|
512 } |
|
513 void cmpPtr(const Address &lhs, const ImmWord rhs) { |
|
514 cmpl(Operand(lhs), rhs); |
|
515 } |
|
516 void cmpPtr(const Address &lhs, const ImmPtr rhs) { |
|
517 cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); |
|
518 } |
|
519 void cmpPtr(Register lhs, Register rhs) { |
|
520 cmpl(lhs, rhs); |
|
521 } |
|
522 void testPtr(Register lhs, Register rhs) { |
|
523 testl(lhs, rhs); |
|
524 } |
|
525 |
|
526 template <typename T1, typename T2> |
|
527 void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, const Register &dest) |
|
528 { |
|
529 cmpPtr(lhs, rhs); |
|
530 emitSet(cond, dest); |
|
531 } |
|
532 |
|
533 ///////////////////////////////////////////////////////////////// |
|
534 // Common interface. |
|
535 ///////////////////////////////////////////////////////////////// |
|
536 void reserveStack(uint32_t amount) { |
|
537 if (amount) |
|
538 subl(Imm32(amount), StackPointer); |
|
539 framePushed_ += amount; |
|
540 } |
|
541 void freeStack(uint32_t amount) { |
|
542 JS_ASSERT(amount <= framePushed_); |
|
543 if (amount) |
|
544 addl(Imm32(amount), StackPointer); |
|
545 framePushed_ -= amount; |
|
546 } |
|
547 void freeStack(Register amount) { |
|
548 addl(amount, StackPointer); |
|
549 } |
|
550 |
|
551 void addPtr(const Register &src, const Register &dest) { |
|
552 addl(src, dest); |
|
553 } |
|
554 void addPtr(Imm32 imm, const Register &dest) { |
|
555 addl(imm, dest); |
|
556 } |
|
557 void addPtr(ImmWord imm, const Register &dest) { |
|
558 addl(Imm32(imm.value), dest); |
|
559 } |
|
560 void addPtr(ImmPtr imm, const Register &dest) { |
|
561 addPtr(ImmWord(uintptr_t(imm.value)), dest); |
|
562 } |
|
563 void addPtr(Imm32 imm, const Address &dest) { |
|
564 addl(imm, Operand(dest)); |
|
565 } |
|
566 void addPtr(Imm32 imm, const Operand &dest) { |
|
567 addl(imm, dest); |
|
568 } |
|
569 void addPtr(const Address &src, const Register &dest) { |
|
570 addl(Operand(src), dest); |
|
571 } |
|
572 void subPtr(Imm32 imm, const Register &dest) { |
|
573 subl(imm, dest); |
|
574 } |
|
575 void subPtr(const Register &src, const Register &dest) { |
|
576 subl(src, dest); |
|
577 } |
|
578 void subPtr(const Address &addr, const Register &dest) { |
|
579 subl(Operand(addr), dest); |
|
580 } |
|
581 void subPtr(const Register &src, const Address &dest) { |
|
582 subl(src, Operand(dest)); |
|
583 } |
|
584 |
|
585 void branch32(Condition cond, const AbsoluteAddress &lhs, Imm32 rhs, Label *label) { |
|
586 cmpl(Operand(lhs), rhs); |
|
587 j(cond, label); |
|
588 } |
|
589 void branch32(Condition cond, const AbsoluteAddress &lhs, Register rhs, Label *label) { |
|
590 cmpl(Operand(lhs), rhs); |
|
591 j(cond, label); |
|
592 } |
|
593 |
|
594 // Specialization for AsmJSAbsoluteAddress. |
|
595 void branchPtr(Condition cond, AsmJSAbsoluteAddress lhs, Register ptr, Label *label) { |
|
596 cmpl(lhs, ptr); |
|
597 j(cond, label); |
|
598 } |
|
599 |
|
600 template <typename T, typename S> |
|
601 void branchPtr(Condition cond, T lhs, S ptr, Label *label) { |
|
602 cmpl(Operand(lhs), ptr); |
|
603 j(cond, label); |
|
604 } |
|
605 |
|
606 void branchPrivatePtr(Condition cond, const Address &lhs, ImmPtr ptr, Label *label) { |
|
607 branchPtr(cond, lhs, ptr, label); |
|
608 } |
|
609 |
|
610 void branchPrivatePtr(Condition cond, const Address &lhs, Register ptr, Label *label) { |
|
611 branchPtr(cond, lhs, ptr, label); |
|
612 } |
|
613 |
|
614 template <typename T, typename S> |
|
615 void branchPtr(Condition cond, T lhs, S ptr, RepatchLabel *label) { |
|
616 cmpl(Operand(lhs), ptr); |
|
617 j(cond, label); |
|
618 } |
|
619 |
|
620 CodeOffsetJump jumpWithPatch(RepatchLabel *label) { |
|
621 jump(label); |
|
622 return CodeOffsetJump(size()); |
|
623 } |
|
624 |
|
625 CodeOffsetJump jumpWithPatch(RepatchLabel *label, Assembler::Condition cond) { |
|
626 j(cond, label); |
|
627 return CodeOffsetJump(size()); |
|
628 } |
|
629 |
|
630 template <typename S, typename T> |
|
631 CodeOffsetJump branchPtrWithPatch(Condition cond, S lhs, T ptr, RepatchLabel *label) { |
|
632 branchPtr(cond, lhs, ptr, label); |
|
633 return CodeOffsetJump(size()); |
|
634 } |
|
635 void branchPtr(Condition cond, Register lhs, Register rhs, RepatchLabel *label) { |
|
636 cmpl(lhs, rhs); |
|
637 j(cond, label); |
|
638 } |
|
639 void branchPtr(Condition cond, Register lhs, Register rhs, Label *label) { |
|
640 cmpl(lhs, rhs); |
|
641 j(cond, label); |
|
642 } |
|
643 void branchTestPtr(Condition cond, Register lhs, Register rhs, Label *label) { |
|
644 testl(lhs, rhs); |
|
645 j(cond, label); |
|
646 } |
|
647 void branchTestPtr(Condition cond, Register lhs, Imm32 imm, Label *label) { |
|
648 testl(lhs, imm); |
|
649 j(cond, label); |
|
650 } |
|
651 void branchTestPtr(Condition cond, const Address &lhs, Imm32 imm, Label *label) { |
|
652 testl(Operand(lhs), imm); |
|
653 j(cond, label); |
|
654 } |
|
655 void decBranchPtr(Condition cond, const Register &lhs, Imm32 imm, Label *label) { |
|
656 subPtr(imm, lhs); |
|
657 j(cond, label); |
|
658 } |
|
659 |
|
660 void movePtr(ImmWord imm, Register dest) { |
|
661 movl(Imm32(imm.value), dest); |
|
662 } |
|
663 void movePtr(ImmPtr imm, Register dest) { |
|
664 movl(imm, dest); |
|
665 } |
|
666 void movePtr(AsmJSImmPtr imm, Register dest) { |
|
667 mov(imm, dest); |
|
668 } |
|
669 void movePtr(ImmGCPtr imm, Register dest) { |
|
670 movl(imm, dest); |
|
671 } |
|
672 void loadPtr(const Address &address, Register dest) { |
|
673 movl(Operand(address), dest); |
|
674 } |
|
675 void loadPtr(const Operand &src, Register dest) { |
|
676 movl(src, dest); |
|
677 } |
|
678 void loadPtr(const BaseIndex &src, Register dest) { |
|
679 movl(Operand(src), dest); |
|
680 } |
|
681 void loadPtr(const AbsoluteAddress &address, Register dest) { |
|
682 movl(Operand(address), dest); |
|
683 } |
|
684 void loadPrivate(const Address &src, Register dest) { |
|
685 movl(payloadOf(src), dest); |
|
686 } |
|
687 void load32(const AbsoluteAddress &address, Register dest) { |
|
688 movl(Operand(address), dest); |
|
689 } |
|
690 void storePtr(ImmWord imm, const Address &address) { |
|
691 movl(Imm32(imm.value), Operand(address)); |
|
692 } |
|
693 void storePtr(ImmPtr imm, const Address &address) { |
|
694 storePtr(ImmWord(uintptr_t(imm.value)), address); |
|
695 } |
|
696 void storePtr(ImmGCPtr imm, const Address &address) { |
|
697 movl(imm, Operand(address)); |
|
698 } |
|
699 void storePtr(Register src, const Address &address) { |
|
700 movl(src, Operand(address)); |
|
701 } |
|
702 void storePtr(Register src, const Operand &dest) { |
|
703 movl(src, dest); |
|
704 } |
|
705 void storePtr(Register src, const AbsoluteAddress &address) { |
|
706 movl(src, Operand(address)); |
|
707 } |
|
708 void store32(Register src, const AbsoluteAddress &address) { |
|
709 movl(src, Operand(address)); |
|
710 } |
|
711 |
|
712 void setStackArg(const Register ®, uint32_t arg) { |
|
713 movl(reg, Operand(esp, arg * sizeof(intptr_t))); |
|
714 } |
|
715 |
|
716 // Type testing instructions can take a tag in a register or a |
|
717 // ValueOperand. |
|
718 template <typename T> |
|
719 void branchTestUndefined(Condition cond, const T &t, Label *label) { |
|
720 cond = testUndefined(cond, t); |
|
721 j(cond, label); |
|
722 } |
|
723 template <typename T> |
|
724 void branchTestInt32(Condition cond, const T &t, Label *label) { |
|
725 cond = testInt32(cond, t); |
|
726 j(cond, label); |
|
727 } |
|
728 template <typename T> |
|
729 void branchTestBoolean(Condition cond, const T &t, Label *label) { |
|
730 cond = testBoolean(cond, t); |
|
731 j(cond, label); |
|
732 } |
|
733 template <typename T> |
|
734 void branchTestDouble(Condition cond, const T &t, Label *label) { |
|
735 cond = testDouble(cond, t); |
|
736 j(cond, label); |
|
737 } |
|
738 template <typename T> |
|
739 void branchTestNull(Condition cond, const T &t, Label *label) { |
|
740 cond = testNull(cond, t); |
|
741 j(cond, label); |
|
742 } |
|
743 template <typename T> |
|
744 void branchTestString(Condition cond, const T &t, Label *label) { |
|
745 cond = testString(cond, t); |
|
746 j(cond, label); |
|
747 } |
|
748 template <typename T> |
|
749 void branchTestObject(Condition cond, const T &t, Label *label) { |
|
750 cond = testObject(cond, t); |
|
751 j(cond, label); |
|
752 } |
|
753 template <typename T> |
|
754 void branchTestNumber(Condition cond, const T &t, Label *label) { |
|
755 cond = testNumber(cond, t); |
|
756 j(cond, label); |
|
757 } |
|
758 template <typename T> |
|
759 void branchTestGCThing(Condition cond, const T &t, Label *label) { |
|
760 cond = testGCThing(cond, t); |
|
761 j(cond, label); |
|
762 } |
|
763 template <typename T> |
|
764 void branchTestPrimitive(Condition cond, const T &t, Label *label) { |
|
765 cond = testPrimitive(cond, t); |
|
766 j(cond, label); |
|
767 } |
|
768 template <typename T> |
|
769 void branchTestMagic(Condition cond, const T &t, Label *label) { |
|
770 cond = testMagic(cond, t); |
|
771 j(cond, label); |
|
772 } |
|
773 void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why, |
|
774 Label *label) |
|
775 { |
|
776 JS_ASSERT(cond == Equal || cond == NotEqual); |
|
777 if (cond == Equal) { |
|
778 // Test for magic |
|
779 Label notmagic; |
|
780 Condition testCond = testMagic(Equal, val); |
|
781 j(InvertCondition(testCond), ¬magic); |
|
782 // Test magic value |
|
783 branch32(Equal, val.payloadReg(), Imm32(static_cast<int32_t>(why)), label); |
|
784 bind(¬magic); |
|
785 } else { |
|
786 Condition testCond = testMagic(NotEqual, val); |
|
787 j(testCond, label); |
|
788 branch32(NotEqual, val.payloadReg(), Imm32(static_cast<int32_t>(why)), label); |
|
789 } |
|
790 } |
|
791 |
|
792 // Note: this function clobbers the source register. |
|
793 void boxDouble(const FloatRegister &src, const ValueOperand &dest) { |
|
794 movd(src, dest.payloadReg()); |
|
795 psrldq(Imm32(4), src); |
|
796 movd(src, dest.typeReg()); |
|
797 } |
|
798 void boxNonDouble(JSValueType type, const Register &src, const ValueOperand &dest) { |
|
799 if (src != dest.payloadReg()) |
|
800 movl(src, dest.payloadReg()); |
|
801 movl(ImmType(type), dest.typeReg()); |
|
802 } |
|
803 void unboxInt32(const ValueOperand &src, const Register &dest) { |
|
804 movl(src.payloadReg(), dest); |
|
805 } |
|
806 void unboxInt32(const Address &src, const Register &dest) { |
|
807 movl(payloadOf(src), dest); |
|
808 } |
|
809 void unboxDouble(const Address &src, const FloatRegister &dest) { |
|
810 loadDouble(Operand(src), dest); |
|
811 } |
|
812 void unboxBoolean(const ValueOperand &src, const Register &dest) { |
|
813 movl(src.payloadReg(), dest); |
|
814 } |
|
815 void unboxBoolean(const Address &src, const Register &dest) { |
|
816 movl(payloadOf(src), dest); |
|
817 } |
|
818 void unboxObject(const ValueOperand &src, const Register &dest) { |
|
819 if (src.payloadReg() != dest) |
|
820 movl(src.payloadReg(), dest); |
|
821 } |
|
822 void unboxDouble(const ValueOperand &src, const FloatRegister &dest) { |
|
823 JS_ASSERT(dest != ScratchFloatReg); |
|
824 if (Assembler::HasSSE41()) { |
|
825 movd(src.payloadReg(), dest); |
|
826 pinsrd(src.typeReg(), dest); |
|
827 } else { |
|
828 movd(src.payloadReg(), dest); |
|
829 movd(src.typeReg(), ScratchFloatReg); |
|
830 unpcklps(ScratchFloatReg, dest); |
|
831 } |
|
832 } |
|
833 void unboxDouble(const Operand &payload, const Operand &type, |
|
834 const Register &scratch, const FloatRegister &dest) { |
|
835 JS_ASSERT(dest != ScratchFloatReg); |
|
836 if (Assembler::HasSSE41()) { |
|
837 movl(payload, scratch); |
|
838 movd(scratch, dest); |
|
839 movl(type, scratch); |
|
840 pinsrd(scratch, dest); |
|
841 } else { |
|
842 movl(payload, scratch); |
|
843 movd(scratch, dest); |
|
844 movl(type, scratch); |
|
845 movd(scratch, ScratchFloatReg); |
|
846 unpcklps(ScratchFloatReg, dest); |
|
847 } |
|
848 } |
|
849 void unboxString(const ValueOperand &src, const Register &dest) { |
|
850 movl(src.payloadReg(), dest); |
|
851 } |
|
852 void unboxString(const Address &src, const Register &dest) { |
|
853 movl(payloadOf(src), dest); |
|
854 } |
|
855 void unboxValue(const ValueOperand &src, AnyRegister dest) { |
|
856 if (dest.isFloat()) { |
|
857 Label notInt32, end; |
|
858 branchTestInt32(Assembler::NotEqual, src, ¬Int32); |
|
859 convertInt32ToDouble(src.payloadReg(), dest.fpu()); |
|
860 jump(&end); |
|
861 bind(¬Int32); |
|
862 unboxDouble(src, dest.fpu()); |
|
863 bind(&end); |
|
864 } else { |
|
865 if (src.payloadReg() != dest.gpr()) |
|
866 movl(src.payloadReg(), dest.gpr()); |
|
867 } |
|
868 } |
|
869 void unboxPrivate(const ValueOperand &src, Register dest) { |
|
870 if (src.payloadReg() != dest) |
|
871 movl(src.payloadReg(), dest); |
|
872 } |
|
873 |
|
874 void notBoolean(const ValueOperand &val) { |
|
875 xorl(Imm32(1), val.payloadReg()); |
|
876 } |
|
877 |
|
878 // Extended unboxing API. If the payload is already in a register, returns |
|
879 // that register. Otherwise, provides a move to the given scratch register, |
|
880 // and returns that. |
|
881 Register extractObject(const Address &address, Register scratch) { |
|
882 movl(payloadOf(address), scratch); |
|
883 return scratch; |
|
884 } |
|
885 Register extractObject(const ValueOperand &value, Register scratch) { |
|
886 return value.payloadReg(); |
|
887 } |
|
888 Register extractInt32(const ValueOperand &value, Register scratch) { |
|
889 return value.payloadReg(); |
|
890 } |
|
891 Register extractBoolean(const ValueOperand &value, Register scratch) { |
|
892 return value.payloadReg(); |
|
893 } |
|
894 Register extractTag(const Address &address, Register scratch) { |
|
895 movl(tagOf(address), scratch); |
|
896 return scratch; |
|
897 } |
|
898 Register extractTag(const ValueOperand &value, Register scratch) { |
|
899 return value.typeReg(); |
|
900 } |
|
901 |
|
902 void boolValueToDouble(const ValueOperand &operand, const FloatRegister &dest) { |
|
903 convertInt32ToDouble(operand.payloadReg(), dest); |
|
904 } |
|
905 void boolValueToFloat32(const ValueOperand &operand, const FloatRegister &dest) { |
|
906 convertInt32ToFloat32(operand.payloadReg(), dest); |
|
907 } |
|
908 void int32ValueToDouble(const ValueOperand &operand, const FloatRegister &dest) { |
|
909 convertInt32ToDouble(operand.payloadReg(), dest); |
|
910 } |
|
911 void int32ValueToFloat32(const ValueOperand &operand, const FloatRegister &dest) { |
|
912 convertInt32ToFloat32(operand.payloadReg(), dest); |
|
913 } |
|
914 |
|
915 void loadConstantDouble(double d, const FloatRegister &dest); |
|
916 void addConstantDouble(double d, const FloatRegister &dest); |
|
917 void loadConstantFloat32(float f, const FloatRegister &dest); |
|
918 void addConstantFloat32(float f, const FloatRegister &dest); |
|
919 |
|
920 void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail) { |
|
921 cvttsd2si(src, dest); |
|
922 |
|
923 // cvttsd2si returns 0x80000000 on failure. Test for it by |
|
924 // subtracting 1 and testing overflow (this permits the use of a |
|
925 // smaller immediate field). |
|
926 cmpl(dest, Imm32(1)); |
|
927 j(Assembler::Overflow, fail); |
|
928 } |
|
929 void branchTruncateFloat32(const FloatRegister &src, const Register &dest, Label *fail) { |
|
930 cvttss2si(src, dest); |
|
931 |
|
932 // cvttss2si returns 0x80000000 on failure. Test for it by |
|
933 // subtracting 1 and testing overflow (this permits the use of a |
|
934 // smaller immediate field). |
|
935 cmpl(dest, Imm32(1)); |
|
936 j(Assembler::Overflow, fail); |
|
937 } |
|
938 |
|
939 Condition testInt32Truthy(bool truthy, const ValueOperand &operand) { |
|
940 testl(operand.payloadReg(), operand.payloadReg()); |
|
941 return truthy ? NonZero : Zero; |
|
942 } |
|
943 void branchTestInt32Truthy(bool truthy, const ValueOperand &operand, Label *label) { |
|
944 Condition cond = testInt32Truthy(truthy, operand); |
|
945 j(cond, label); |
|
946 } |
|
947 void branchTestBooleanTruthy(bool truthy, const ValueOperand &operand, Label *label) { |
|
948 testl(operand.payloadReg(), operand.payloadReg()); |
|
949 j(truthy ? NonZero : Zero, label); |
|
950 } |
|
951 Condition testStringTruthy(bool truthy, const ValueOperand &value) { |
|
952 Register string = value.payloadReg(); |
|
953 Operand lengthAndFlags(string, JSString::offsetOfLengthAndFlags()); |
|
954 |
|
955 size_t mask = (0xFFFFFFFF << JSString::LENGTH_SHIFT); |
|
956 testl(lengthAndFlags, Imm32(mask)); |
|
957 return truthy ? Assembler::NonZero : Assembler::Zero; |
|
958 } |
|
959 void branchTestStringTruthy(bool truthy, const ValueOperand &value, Label *label) { |
|
960 Condition cond = testStringTruthy(truthy, value); |
|
961 j(cond, label); |
|
962 } |
|
963 |
|
964 void loadInt32OrDouble(const Operand &operand, const FloatRegister &dest) { |
|
965 Label notInt32, end; |
|
966 branchTestInt32(Assembler::NotEqual, operand, ¬Int32); |
|
967 convertInt32ToDouble(ToPayload(operand), dest); |
|
968 jump(&end); |
|
969 bind(¬Int32); |
|
970 loadDouble(operand, dest); |
|
971 bind(&end); |
|
972 } |
|
973 |
|
974 template <typename T> |
|
975 void loadUnboxedValue(const T &src, MIRType type, AnyRegister dest) { |
|
976 if (dest.isFloat()) |
|
977 loadInt32OrDouble(Operand(src), dest.fpu()); |
|
978 else |
|
979 movl(Operand(src), dest.gpr()); |
|
980 } |
|
981 |
|
982 void rshiftPtr(Imm32 imm, Register dest) { |
|
983 shrl(imm, dest); |
|
984 } |
|
985 void lshiftPtr(Imm32 imm, Register dest) { |
|
986 shll(imm, dest); |
|
987 } |
|
988 void xorPtr(Imm32 imm, Register dest) { |
|
989 xorl(imm, dest); |
|
990 } |
|
991 void xorPtr(Register src, Register dest) { |
|
992 xorl(src, dest); |
|
993 } |
|
994 void orPtr(Imm32 imm, Register dest) { |
|
995 orl(imm, dest); |
|
996 } |
|
997 void orPtr(Register src, Register dest) { |
|
998 orl(src, dest); |
|
999 } |
|
1000 void andPtr(Imm32 imm, Register dest) { |
|
1001 andl(imm, dest); |
|
1002 } |
|
1003 void andPtr(Register src, Register dest) { |
|
1004 andl(src, dest); |
|
1005 } |
|
1006 |
|
1007 void loadInstructionPointerAfterCall(const Register &dest) { |
|
1008 movl(Operand(StackPointer, 0x0), dest); |
|
1009 } |
|
1010 |
|
1011 // Note: this function clobbers the source register. |
|
1012 void convertUInt32ToDouble(const Register &src, const FloatRegister &dest) { |
|
1013 // src is [0, 2^32-1] |
|
1014 subl(Imm32(0x80000000), src); |
|
1015 |
|
1016 // Now src is [-2^31, 2^31-1] - int range, but not the same value. |
|
1017 convertInt32ToDouble(src, dest); |
|
1018 |
|
1019 // dest is now a double with the int range. |
|
1020 // correct the double value by adding 0x80000000. |
|
1021 addConstantDouble(2147483648.0, dest); |
|
1022 } |
|
1023 |
|
1024 // Note: this function clobbers the source register. |
|
1025 void convertUInt32ToFloat32(const Register &src, const FloatRegister &dest) { |
|
1026 convertUInt32ToDouble(src, dest); |
|
1027 convertDoubleToFloat32(dest, dest); |
|
1028 } |
|
1029 |
|
1030 void inc64(AbsoluteAddress dest) { |
|
1031 addl(Imm32(1), Operand(dest)); |
|
1032 Label noOverflow; |
|
1033 j(NonZero, &noOverflow); |
|
1034 addl(Imm32(1), Operand(dest.offset(4))); |
|
1035 bind(&noOverflow); |
|
1036 } |
|
1037 |
|
1038 |
|
1039 // If source is a double, load it into dest. If source is int32, |
|
1040 // convert it to double. Else, branch to failure. |
|
1041 void ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure) { |
|
1042 Label isDouble, done; |
|
1043 branchTestDouble(Assembler::Equal, source.typeReg(), &isDouble); |
|
1044 branchTestInt32(Assembler::NotEqual, source.typeReg(), failure); |
|
1045 |
|
1046 convertInt32ToDouble(source.payloadReg(), dest); |
|
1047 jump(&done); |
|
1048 |
|
1049 bind(&isDouble); |
|
1050 unboxDouble(source, dest); |
|
1051 |
|
1052 bind(&done); |
|
1053 } |
|
1054 |
|
1055 // Setup a call to C/C++ code, given the number of general arguments it |
|
1056 // takes. Note that this only supports cdecl. |
|
1057 // |
|
1058 // In order for alignment to work correctly, the MacroAssembler must have a |
|
1059 // consistent view of the stack displacement. It is okay to call "push" |
|
1060 // manually, however, if the stack alignment were to change, the macro |
|
1061 // assembler should be notified before starting a call. |
|
1062 void setupAlignedABICall(uint32_t args); |
|
1063 |
|
1064 // Sets up an ABI call for when the alignment is not known. This may need a |
|
1065 // scratch register. |
|
1066 void setupUnalignedABICall(uint32_t args, const Register &scratch); |
|
1067 |
|
1068 // Arguments must be assigned to a C/C++ call in order. They are moved |
|
1069 // in parallel immediately before performing the call. This process may |
|
1070 // temporarily use more stack, in which case esp-relative addresses will be |
|
1071 // automatically adjusted. It is extremely important that esp-relative |
|
1072 // addresses are computed *after* setupABICall(). Furthermore, no |
|
1073 // operations should be emitted while setting arguments. |
|
1074 void passABIArg(const MoveOperand &from, MoveOp::Type type); |
|
1075 void passABIArg(const Register ®); |
|
1076 void passABIArg(const FloatRegister ®, MoveOp::Type type); |
|
1077 |
|
1078 private: |
|
1079 void callWithABIPre(uint32_t *stackAdjust); |
|
1080 void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result); |
|
1081 |
|
1082 public: |
|
1083 // Emits a call to a C/C++ function, resolving all argument moves. |
|
1084 void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL); |
|
1085 void callWithABI(AsmJSImmPtr fun, MoveOp::Type result = MoveOp::GENERAL); |
|
1086 void callWithABI(const Address &fun, MoveOp::Type result = MoveOp::GENERAL); |
|
1087 |
|
1088 // Used from within an Exit frame to handle a pending exception. |
|
1089 void handleFailureWithHandler(void *handler); |
|
1090 void handleFailureWithHandlerTail(); |
|
1091 |
|
1092 void makeFrameDescriptor(Register frameSizeReg, FrameType type) { |
|
1093 shll(Imm32(FRAMESIZE_SHIFT), frameSizeReg); |
|
1094 orl(Imm32(type), frameSizeReg); |
|
1095 } |
|
1096 |
|
1097 // Save an exit frame (which must be aligned to the stack pointer) to |
|
1098 // ThreadData::ionTop of the main thread. |
|
1099 void linkExitFrame() { |
|
1100 movl(StackPointer, Operand(AbsoluteAddress(GetIonContext()->runtime->addressOfIonTop()))); |
|
1101 } |
|
1102 |
|
1103 void callWithExitFrame(JitCode *target, Register dynStack) { |
|
1104 addPtr(Imm32(framePushed()), dynStack); |
|
1105 makeFrameDescriptor(dynStack, JitFrame_IonJS); |
|
1106 Push(dynStack); |
|
1107 call(target); |
|
1108 } |
|
1109 void call(const CallSiteDesc &desc, AsmJSImmPtr target) { |
|
1110 call(target); |
|
1111 appendCallSite(desc); |
|
1112 } |
|
1113 void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) { |
|
1114 call(CallSiteDesc::Exit(), target); |
|
1115 } |
|
1116 |
|
1117 // Save an exit frame to the thread data of the current thread, given a |
|
1118 // register that holds a PerThreadData *. |
|
1119 void linkParallelExitFrame(const Register &pt) { |
|
1120 movl(StackPointer, Operand(pt, offsetof(PerThreadData, ionTop))); |
|
1121 } |
|
1122 |
|
1123 #ifdef JSGC_GENERATIONAL |
|
1124 void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); |
|
1125 void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label); |
|
1126 #endif |
|
1127 }; |
|
1128 |
|
1129 typedef MacroAssemblerX86 MacroAssemblerSpecific; |
|
1130 |
|
1131 } // namespace jit |
|
1132 } // namespace js |
|
1133 |
|
1134 #endif /* jit_x86_MacroAssembler_x86_h */ |