Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
7 #ifndef jit_x86_MacroAssembler_x86_h
8 #define jit_x86_MacroAssembler_x86_h
10 #include "jscompartment.h"
12 #include "jit/IonFrames.h"
13 #include "jit/MoveResolver.h"
14 #include "jit/shared/MacroAssembler-x86-shared.h"
16 namespace js {
17 namespace jit {
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_;
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_;
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_;
48 Double *getDouble(double d);
49 Float *getFloat(float f);
51 protected:
52 MoveResolver moveResolver_;
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 }
65 void setupABICall(uint32_t args);
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;
76 MacroAssemblerX86()
77 : inCall_(false),
78 enoughMemory_(true)
79 {
80 }
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();
86 bool oom() const {
87 return MacroAssemblerX86Shared::oom() || !enoughMemory_;
88 }
90 /////////////////////////////////////////////////////////////////
91 // X86-specific interface.
92 /////////////////////////////////////////////////////////////////
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 *));
105 case Operand::MEM_SCALE:
106 return Operand(Register::FromCode(base.base()), Register::FromCode(base.index()),
107 base.scale(), base.disp() + sizeof(void *));
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();
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 }
144 if (s0 != d0)
145 movl(s0, d0);
146 if (s1 != d1)
147 movl(s1, d1);
148 }
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);
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;
183 if (baseReg == val.payloadReg() || indexReg == val.payloadReg()) {
184 JS_ASSERT(baseReg != val.typeReg());
185 JS_ASSERT(indexReg != val.typeReg());
187 movl(type, val.typeReg());
188 movl(payload, val.payloadReg());
189 } else {
190 JS_ASSERT(baseReg != val.payloadReg());
191 JS_ASSERT(indexReg != val.payloadReg());
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 }
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 }
262 // Returns the register containing the type tag.
263 Register splitTagForTest(const ValueOperand &value) {
264 return value.typeReg();
265 }
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 }
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 }
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 }
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 }
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);
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 }
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 }
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 }
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 }
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 }
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 }
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 }
594 // Specialization for AsmJSAbsoluteAddress.
595 void branchPtr(Condition cond, AsmJSAbsoluteAddress lhs, Register ptr, Label *label) {
596 cmpl(lhs, ptr);
597 j(cond, label);
598 }
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 }
606 void branchPrivatePtr(Condition cond, const Address &lhs, ImmPtr ptr, Label *label) {
607 branchPtr(cond, lhs, ptr, label);
608 }
610 void branchPrivatePtr(Condition cond, const Address &lhs, Register ptr, Label *label) {
611 branchPtr(cond, lhs, ptr, label);
612 }
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 }
620 CodeOffsetJump jumpWithPatch(RepatchLabel *label) {
621 jump(label);
622 return CodeOffsetJump(size());
623 }
625 CodeOffsetJump jumpWithPatch(RepatchLabel *label, Assembler::Condition cond) {
626 j(cond, label);
627 return CodeOffsetJump(size());
628 }
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 }
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 }
712 void setStackArg(const Register ®, uint32_t arg) {
713 movl(reg, Operand(esp, arg * sizeof(intptr_t)));
714 }
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 }
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 }
874 void notBoolean(const ValueOperand &val) {
875 xorl(Imm32(1), val.payloadReg());
876 }
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 }
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 }
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);
920 void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail) {
921 cvttsd2si(src, dest);
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);
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 }
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());
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 }
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 }
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 }
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 }
1007 void loadInstructionPointerAfterCall(const Register &dest) {
1008 movl(Operand(StackPointer, 0x0), dest);
1009 }
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);
1016 // Now src is [-2^31, 2^31-1] - int range, but not the same value.
1017 convertInt32ToDouble(src, dest);
1019 // dest is now a double with the int range.
1020 // correct the double value by adding 0x80000000.
1021 addConstantDouble(2147483648.0, dest);
1022 }
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 }
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 }
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);
1046 convertInt32ToDouble(source.payloadReg(), dest);
1047 jump(&done);
1049 bind(&isDouble);
1050 unboxDouble(source, dest);
1052 bind(&done);
1053 }
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);
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);
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);
1078 private:
1079 void callWithABIPre(uint32_t *stackAdjust);
1080 void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result);
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);
1088 // Used from within an Exit frame to handle a pending exception.
1089 void handleFailureWithHandler(void *handler);
1090 void handleFailureWithHandlerTail();
1092 void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
1093 shll(Imm32(FRAMESIZE_SHIFT), frameSizeReg);
1094 orl(Imm32(type), frameSizeReg);
1095 }
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 }
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 }
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 }
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 };
1129 typedef MacroAssemblerX86 MacroAssemblerSpecific;
1131 } // namespace jit
1132 } // namespace js
1134 #endif /* jit_x86_MacroAssembler_x86_h */