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/JitFrames.h"
13 #include "jit/MoveResolver.h"
14 #include "jit/x86-shared/MacroAssembler-x86-shared.h"
15 
16 namespace js {
17 namespace jit {
18 
19 class MacroAssemblerX86 : public MacroAssemblerX86Shared
20 {
21   private:
22     // Perform a downcast. Should be removed by Bug 996602.
23     MacroAssembler& asMasm();
24     const MacroAssembler& asMasm() const;
25 
26   protected:
27     MoveResolver moveResolver_;
28 
29   private:
payloadOfAfterStackPush(const Address & address)30     Operand payloadOfAfterStackPush(const Address& address) {
31         // If we are basing off %esp, the address will be invalid after the
32         // first push.
33         if (address.base == StackPointer)
34             return Operand(address.base, address.offset + 4);
35         return payloadOf(address);
36     }
payloadOf(const Address & address)37     Operand payloadOf(const Address& address) {
38         return Operand(address.base, address.offset);
39     }
payloadOf(const BaseIndex & address)40     Operand payloadOf(const BaseIndex& address) {
41         return Operand(address.base, address.index, address.scale, address.offset);
42     }
tagOf(const Address & address)43     Operand tagOf(const Address& address) {
44         return Operand(address.base, address.offset + 4);
45     }
tagOf(const BaseIndex & address)46     Operand tagOf(const BaseIndex& address) {
47         return Operand(address.base, address.index, address.scale, address.offset + 4);
48     }
49 
50     void setupABICall(uint32_t args);
51 
52   public:
53     using MacroAssemblerX86Shared::branch32;
54     using MacroAssemblerX86Shared::branchTest32;
55     using MacroAssemblerX86Shared::load32;
56     using MacroAssemblerX86Shared::store32;
57     using MacroAssemblerX86Shared::call;
58 
MacroAssemblerX86()59     MacroAssemblerX86()
60     {
61     }
62 
63     // The buffer is about to be linked, make sure any constant pools or excess
64     // bookkeeping has been flushed to the instruction stream.
65     void finish();
66 
67     /////////////////////////////////////////////////////////////////
68     // X86-specific interface.
69     /////////////////////////////////////////////////////////////////
70 
ToPayload(Operand base)71     Operand ToPayload(Operand base) {
72         return base;
73     }
ToPayload(Address base)74     Address ToPayload(Address base) {
75         return base;
76     }
ToType(Operand base)77     Operand ToType(Operand base) {
78         switch (base.kind()) {
79           case Operand::MEM_REG_DISP:
80             return Operand(Register::FromCode(base.base()), base.disp() + sizeof(void*));
81 
82           case Operand::MEM_SCALE:
83             return Operand(Register::FromCode(base.base()), Register::FromCode(base.index()),
84                            base.scale(), base.disp() + sizeof(void*));
85 
86           default:
87             MOZ_CRASH("unexpected operand kind");
88         }
89     }
ToType(Address base)90     Address ToType(Address base) {
91         return ToType(Operand(base)).toAddress();
92     }
moveValue(const Value & val,Register type,Register data)93     void moveValue(const Value& val, Register type, Register data) {
94         jsval_layout jv = JSVAL_TO_IMPL(val);
95         movl(Imm32(jv.s.tag), type);
96         if (val.isMarkable())
97             movl(ImmGCPtr(reinterpret_cast<gc::Cell*>(val.toGCThing())), data);
98         else
99             movl(Imm32(jv.s.payload.i32), data);
100     }
moveValue(const Value & val,const ValueOperand & dest)101     void moveValue(const Value& val, const ValueOperand& dest) {
102         moveValue(val, dest.typeReg(), dest.payloadReg());
103     }
moveValue(const ValueOperand & src,const ValueOperand & dest)104     void moveValue(const ValueOperand& src, const ValueOperand& dest) {
105         Register s0 = src.typeReg(), d0 = dest.typeReg(),
106                  s1 = src.payloadReg(), d1 = dest.payloadReg();
107 
108         // Either one or both of the source registers could be the same as a
109         // destination register.
110         if (s1 == d0) {
111             if (s0 == d1) {
112                 // If both are, this is just a swap of two registers.
113                 xchgl(d0, d1);
114                 return;
115             }
116             // If only one is, copy that source first.
117             mozilla::Swap(s0, s1);
118             mozilla::Swap(d0, d1);
119         }
120 
121         if (s0 != d0)
122             movl(s0, d0);
123         if (s1 != d1)
124             movl(s1, d1);
125     }
126 
127     /////////////////////////////////////////////////////////////////
128     // X86/X64-common interface.
129     /////////////////////////////////////////////////////////////////
storeValue(ValueOperand val,Operand dest)130     void storeValue(ValueOperand val, Operand dest) {
131         movl(val.payloadReg(), ToPayload(dest));
132         movl(val.typeReg(), ToType(dest));
133     }
storeValue(ValueOperand val,const Address & dest)134     void storeValue(ValueOperand val, const Address& dest) {
135         storeValue(val, Operand(dest));
136     }
137     template <typename T>
storeValue(JSValueType type,Register reg,const T & dest)138     void storeValue(JSValueType type, Register reg, const T& dest) {
139         storeTypeTag(ImmTag(JSVAL_TYPE_TO_TAG(type)), Operand(dest));
140         storePayload(reg, Operand(dest));
141     }
142     template <typename T>
storeValue(const Value & val,const T & dest)143     void storeValue(const Value& val, const T& dest) {
144         jsval_layout jv = JSVAL_TO_IMPL(val);
145         storeTypeTag(ImmTag(jv.s.tag), Operand(dest));
146         storePayload(val, Operand(dest));
147     }
storeValue(ValueOperand val,BaseIndex dest)148     void storeValue(ValueOperand val, BaseIndex dest) {
149         storeValue(val, Operand(dest));
150     }
loadValue(Operand src,ValueOperand val)151     void loadValue(Operand src, ValueOperand val) {
152         Operand payload = ToPayload(src);
153         Operand type = ToType(src);
154 
155         // Ensure that loading the payload does not erase the pointer to the
156         // Value in memory or the index.
157         Register baseReg = Register::FromCode(src.base());
158         Register indexReg = (src.kind() == Operand::MEM_SCALE) ? Register::FromCode(src.index()) : InvalidReg;
159 
160         if (baseReg == val.payloadReg() || indexReg == val.payloadReg()) {
161             MOZ_ASSERT(baseReg != val.typeReg());
162             MOZ_ASSERT(indexReg != val.typeReg());
163 
164             movl(type, val.typeReg());
165             movl(payload, val.payloadReg());
166         } else {
167             MOZ_ASSERT(baseReg != val.payloadReg());
168             MOZ_ASSERT(indexReg != val.payloadReg());
169 
170             movl(payload, val.payloadReg());
171             movl(type, val.typeReg());
172         }
173     }
loadValue(Address src,ValueOperand val)174     void loadValue(Address src, ValueOperand val) {
175         loadValue(Operand(src), val);
176     }
loadValue(const BaseIndex & src,ValueOperand val)177     void loadValue(const BaseIndex& src, ValueOperand val) {
178         loadValue(Operand(src), val);
179     }
tagValue(JSValueType type,Register payload,ValueOperand dest)180     void tagValue(JSValueType type, Register payload, ValueOperand dest) {
181         MOZ_ASSERT(dest.typeReg() != dest.payloadReg());
182         if (payload != dest.payloadReg())
183             movl(payload, dest.payloadReg());
184         movl(ImmType(type), dest.typeReg());
185     }
pushValue(ValueOperand val)186     void pushValue(ValueOperand val) {
187         push(val.typeReg());
188         push(val.payloadReg());
189     }
popValue(ValueOperand val)190     void popValue(ValueOperand val) {
191         pop(val.payloadReg());
192         pop(val.typeReg());
193     }
pushValue(const Value & val)194     void pushValue(const Value& val) {
195         jsval_layout jv = JSVAL_TO_IMPL(val);
196         push(Imm32(jv.s.tag));
197         if (val.isMarkable())
198             push(ImmGCPtr(reinterpret_cast<gc::Cell*>(val.toGCThing())));
199         else
200             push(Imm32(jv.s.payload.i32));
201     }
pushValue(JSValueType type,Register reg)202     void pushValue(JSValueType type, Register reg) {
203         push(ImmTag(JSVAL_TYPE_TO_TAG(type)));
204         push(reg);
205     }
pushValue(const Address & addr)206     void pushValue(const Address& addr) {
207         push(tagOf(addr));
208         push(payloadOfAfterStackPush(addr));
209     }
push64(Register64 src)210     void push64(Register64 src) {
211         push(src.high);
212         push(src.low);
213     }
pop64(Register64 dest)214     void pop64(Register64 dest) {
215         pop(dest.low);
216         pop(dest.high);
217     }
storePayload(const Value & val,Operand dest)218     void storePayload(const Value& val, Operand dest) {
219         jsval_layout jv = JSVAL_TO_IMPL(val);
220         if (val.isMarkable())
221             movl(ImmGCPtr((gc::Cell*)jv.s.payload.ptr), ToPayload(dest));
222         else
223             movl(Imm32(jv.s.payload.i32), ToPayload(dest));
224     }
storePayload(Register src,Operand dest)225     void storePayload(Register src, Operand dest) {
226         movl(src, ToPayload(dest));
227     }
storeTypeTag(ImmTag tag,Operand dest)228     void storeTypeTag(ImmTag tag, Operand dest) {
229         movl(tag, ToType(dest));
230     }
231 
movePtr(Register src,Register dest)232     void movePtr(Register src, Register dest) {
233         movl(src, dest);
234     }
movePtr(Register src,const Operand & dest)235     void movePtr(Register src, const Operand& dest) {
236         movl(src, dest);
237     }
238 
239     // Returns the register containing the type tag.
splitTagForTest(const ValueOperand & value)240     Register splitTagForTest(const ValueOperand& value) {
241         return value.typeReg();
242     }
243 
testUndefined(Condition cond,Register tag)244     Condition testUndefined(Condition cond, Register tag) {
245         MOZ_ASSERT(cond == Equal || cond == NotEqual);
246         cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED));
247         return cond;
248     }
testBoolean(Condition cond,Register tag)249     Condition testBoolean(Condition cond, Register tag) {
250         MOZ_ASSERT(cond == Equal || cond == NotEqual);
251         cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN));
252         return cond;
253     }
testInt32(Condition cond,Register tag)254     Condition testInt32(Condition cond, Register tag) {
255         MOZ_ASSERT(cond == Equal || cond == NotEqual);
256         cmp32(tag, ImmTag(JSVAL_TAG_INT32));
257         return cond;
258     }
testDouble(Condition cond,Register tag)259     Condition testDouble(Condition cond, Register tag) {
260         MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
261         Condition actual = (cond == Equal) ? Below : AboveOrEqual;
262         cmp32(tag, ImmTag(JSVAL_TAG_CLEAR));
263         return actual;
264     }
testNull(Condition cond,Register tag)265     Condition testNull(Condition cond, Register tag) {
266         MOZ_ASSERT(cond == Equal || cond == NotEqual);
267         cmp32(tag, ImmTag(JSVAL_TAG_NULL));
268         return cond;
269     }
testString(Condition cond,Register tag)270     Condition testString(Condition cond, Register tag) {
271         MOZ_ASSERT(cond == Equal || cond == NotEqual);
272         cmp32(tag, ImmTag(JSVAL_TAG_STRING));
273         return cond;
274     }
testSymbol(Condition cond,Register tag)275     Condition testSymbol(Condition cond, Register tag) {
276         MOZ_ASSERT(cond == Equal || cond == NotEqual);
277         cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL));
278         return cond;
279     }
testObject(Condition cond,Register tag)280     Condition testObject(Condition cond, Register tag) {
281         MOZ_ASSERT(cond == Equal || cond == NotEqual);
282         cmp32(tag, ImmTag(JSVAL_TAG_OBJECT));
283         return cond;
284     }
testNumber(Condition cond,Register tag)285     Condition testNumber(Condition cond, Register tag) {
286         MOZ_ASSERT(cond == Equal || cond == NotEqual);
287         cmp32(tag, ImmTag(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET));
288         return cond == Equal ? BelowOrEqual : Above;
289     }
testGCThing(Condition cond,Register tag)290     Condition testGCThing(Condition cond, Register tag) {
291         MOZ_ASSERT(cond == Equal || cond == NotEqual);
292         cmp32(tag, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
293         return cond == Equal ? AboveOrEqual : Below;
294     }
testGCThing(Condition cond,const Address & address)295     Condition testGCThing(Condition cond, const Address& address) {
296         MOZ_ASSERT(cond == Equal || cond == NotEqual);
297         cmp32(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
298         return cond == Equal ? AboveOrEqual : Below;
299     }
testMagic(Condition cond,const Address & address)300     Condition testMagic(Condition cond, const Address& address) {
301         MOZ_ASSERT(cond == Equal || cond == NotEqual);
302         cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC));
303         return cond;
304     }
testMagic(Condition cond,Register tag)305     Condition testMagic(Condition cond, Register tag) {
306         MOZ_ASSERT(cond == Equal || cond == NotEqual);
307         cmp32(tag, ImmTag(JSVAL_TAG_MAGIC));
308         return cond;
309     }
testMagic(Condition cond,const Operand & operand)310     Condition testMagic(Condition cond, const Operand& operand) {
311         MOZ_ASSERT(cond == Equal || cond == NotEqual);
312         cmp32(ToType(operand), ImmTag(JSVAL_TAG_MAGIC));
313         return cond;
314     }
testPrimitive(Condition cond,Register tag)315     Condition testPrimitive(Condition cond, Register tag) {
316         MOZ_ASSERT(cond == Equal || cond == NotEqual);
317         cmp32(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET));
318         return cond == Equal ? Below : AboveOrEqual;
319     }
testError(Condition cond,Register tag)320     Condition testError(Condition cond, Register tag) {
321         return testMagic(cond, tag);
322     }
testBoolean(Condition cond,const Address & address)323     Condition testBoolean(Condition cond, const Address& address) {
324         MOZ_ASSERT(cond == Equal || cond == NotEqual);
325         cmp32(Operand(ToType(address)), ImmTag(JSVAL_TAG_BOOLEAN));
326         return cond;
327     }
testInt32(Condition cond,const Operand & operand)328     Condition testInt32(Condition cond, const Operand& operand) {
329         MOZ_ASSERT(cond == Equal || cond == NotEqual);
330         cmp32(ToType(operand), ImmTag(JSVAL_TAG_INT32));
331         return cond;
332     }
testInt32(Condition cond,const Address & address)333     Condition testInt32(Condition cond, const Address& address) {
334         MOZ_ASSERT(cond == Equal || cond == NotEqual);
335         return testInt32(cond, Operand(address));
336     }
testObject(Condition cond,const Operand & operand)337     Condition testObject(Condition cond, const Operand& operand) {
338         MOZ_ASSERT(cond == Equal || cond == NotEqual);
339         cmp32(ToType(operand), ImmTag(JSVAL_TAG_OBJECT));
340         return cond;
341     }
testObject(Condition cond,const Address & address)342     Condition testObject(Condition cond, const Address& address) {
343         MOZ_ASSERT(cond == Equal || cond == NotEqual);
344         return testObject(cond, Operand(address));
345     }
testDouble(Condition cond,const Operand & operand)346     Condition testDouble(Condition cond, const Operand& operand) {
347         MOZ_ASSERT(cond == Equal || cond == NotEqual);
348         Condition actual = (cond == Equal) ? Below : AboveOrEqual;
349         cmp32(ToType(operand), ImmTag(JSVAL_TAG_CLEAR));
350         return actual;
351     }
testDouble(Condition cond,const Address & address)352     Condition testDouble(Condition cond, const Address& address) {
353         MOZ_ASSERT(cond == Equal || cond == NotEqual);
354         return testDouble(cond, Operand(address));
355     }
356 
357 
testUndefined(Condition cond,const Operand & operand)358     Condition testUndefined(Condition cond, const Operand& operand) {
359         MOZ_ASSERT(cond == Equal || cond == NotEqual);
360         cmp32(ToType(operand), ImmTag(JSVAL_TAG_UNDEFINED));
361         return cond;
362     }
testUndefined(Condition cond,const Address & addr)363     Condition testUndefined(Condition cond, const Address& addr) {
364         return testUndefined(cond, Operand(addr));
365     }
testNull(Condition cond,const Operand & operand)366     Condition testNull(Condition cond, const Operand& operand) {
367         MOZ_ASSERT(cond == Equal || cond == NotEqual);
368         cmp32(ToType(operand), ImmTag(JSVAL_TAG_NULL));
369         return cond;
370     }
testNull(Condition cond,const Address & addr)371     Condition testNull(Condition cond, const Address& addr) {
372         return testNull(cond, Operand(addr));
373     }
374 
testUndefined(Condition cond,const ValueOperand & value)375     Condition testUndefined(Condition cond, const ValueOperand& value) {
376         return testUndefined(cond, value.typeReg());
377     }
testBoolean(Condition cond,const ValueOperand & value)378     Condition testBoolean(Condition cond, const ValueOperand& value) {
379         return testBoolean(cond, value.typeReg());
380     }
testInt32(Condition cond,const ValueOperand & value)381     Condition testInt32(Condition cond, const ValueOperand& value) {
382         return testInt32(cond, value.typeReg());
383     }
testDouble(Condition cond,const ValueOperand & value)384     Condition testDouble(Condition cond, const ValueOperand& value) {
385         return testDouble(cond, value.typeReg());
386     }
testNull(Condition cond,const ValueOperand & value)387     Condition testNull(Condition cond, const ValueOperand& value) {
388         return testNull(cond, value.typeReg());
389     }
testString(Condition cond,const ValueOperand & value)390     Condition testString(Condition cond, const ValueOperand& value) {
391         return testString(cond, value.typeReg());
392     }
testSymbol(Condition cond,const ValueOperand & value)393     Condition testSymbol(Condition cond, const ValueOperand& value) {
394         return testSymbol(cond, value.typeReg());
395     }
testObject(Condition cond,const ValueOperand & value)396     Condition testObject(Condition cond, const ValueOperand& value) {
397         return testObject(cond, value.typeReg());
398     }
testMagic(Condition cond,const ValueOperand & value)399     Condition testMagic(Condition cond, const ValueOperand& value) {
400         return testMagic(cond, value.typeReg());
401     }
testError(Condition cond,const ValueOperand & value)402     Condition testError(Condition cond, const ValueOperand& value) {
403         return testMagic(cond, value);
404     }
testNumber(Condition cond,const ValueOperand & value)405     Condition testNumber(Condition cond, const ValueOperand& value) {
406         return testNumber(cond, value.typeReg());
407     }
testGCThing(Condition cond,const ValueOperand & value)408     Condition testGCThing(Condition cond, const ValueOperand& value) {
409         return testGCThing(cond, value.typeReg());
410     }
testPrimitive(Condition cond,const ValueOperand & value)411     Condition testPrimitive(Condition cond, const ValueOperand& value) {
412         return testPrimitive(cond, value.typeReg());
413     }
414 
415 
testUndefined(Condition cond,const BaseIndex & address)416     Condition testUndefined(Condition cond, const BaseIndex& address) {
417         MOZ_ASSERT(cond == Equal || cond == NotEqual);
418         cmp32(tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED));
419         return cond;
420     }
testNull(Condition cond,const BaseIndex & address)421     Condition testNull(Condition cond, const BaseIndex& address) {
422         MOZ_ASSERT(cond == Equal || cond == NotEqual);
423         cmp32(tagOf(address), ImmTag(JSVAL_TAG_NULL));
424         return cond;
425     }
testBoolean(Condition cond,const BaseIndex & address)426     Condition testBoolean(Condition cond, const BaseIndex& address) {
427         MOZ_ASSERT(cond == Equal || cond == NotEqual);
428         cmp32(tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN));
429         return cond;
430     }
testString(Condition cond,const BaseIndex & address)431     Condition testString(Condition cond, const BaseIndex& address) {
432         MOZ_ASSERT(cond == Equal || cond == NotEqual);
433         cmp32(tagOf(address), ImmTag(JSVAL_TAG_STRING));
434         return cond;
435     }
testSymbol(Condition cond,const BaseIndex & address)436     Condition testSymbol(Condition cond, const BaseIndex& address) {
437         MOZ_ASSERT(cond == Equal || cond == NotEqual);
438         cmp32(tagOf(address), ImmTag(JSVAL_TAG_SYMBOL));
439         return cond;
440     }
testInt32(Condition cond,const BaseIndex & address)441     Condition testInt32(Condition cond, const BaseIndex& address) {
442         MOZ_ASSERT(cond == Equal || cond == NotEqual);
443         cmp32(tagOf(address), ImmTag(JSVAL_TAG_INT32));
444         return cond;
445     }
testObject(Condition cond,const BaseIndex & address)446     Condition testObject(Condition cond, const BaseIndex& address) {
447         MOZ_ASSERT(cond == Equal || cond == NotEqual);
448         cmp32(tagOf(address), ImmTag(JSVAL_TAG_OBJECT));
449         return cond;
450     }
testDouble(Condition cond,const BaseIndex & address)451     Condition testDouble(Condition cond, const BaseIndex& address) {
452         MOZ_ASSERT(cond == Equal || cond == NotEqual);
453         Condition actual = (cond == Equal) ? Below : AboveOrEqual;
454         cmp32(tagOf(address), ImmTag(JSVAL_TAG_CLEAR));
455         return actual;
456     }
testMagic(Condition cond,const BaseIndex & address)457     Condition testMagic(Condition cond, const BaseIndex& address) {
458         MOZ_ASSERT(cond == Equal || cond == NotEqual);
459         cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC));
460         return cond;
461     }
testGCThing(Condition cond,const BaseIndex & address)462     Condition testGCThing(Condition cond, const BaseIndex& address) {
463         MOZ_ASSERT(cond == Equal || cond == NotEqual);
464         cmp32(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
465         return cond == Equal ? AboveOrEqual : Below;
466     }
467 
468 
469 
470     void branchTestValue(Condition cond, const ValueOperand& value, const Value& v, Label* label);
branchTestValue(Condition cond,const Address & valaddr,const ValueOperand & value,Label * label)471     void branchTestValue(Condition cond, const Address& valaddr, const ValueOperand& value,
472                          Label* label)
473     {
474         MOZ_ASSERT(cond == Equal || cond == NotEqual);
475         // Check payload before tag, since payload is more likely to differ.
476         if (cond == NotEqual) {
477             branchPtr(NotEqual, payloadOf(valaddr), value.payloadReg(), label);
478             branchPtr(NotEqual, tagOf(valaddr), value.typeReg(), label);
479 
480         } else {
481             Label fallthrough;
482             branchPtr(NotEqual, payloadOf(valaddr), value.payloadReg(), &fallthrough);
483             branchPtr(Equal, tagOf(valaddr), value.typeReg(), label);
484             bind(&fallthrough);
485         }
486     }
487 
testNullSet(Condition cond,const ValueOperand & value,Register dest)488     void testNullSet(Condition cond, const ValueOperand& value, Register dest) {
489         cond = testNull(cond, value);
490         emitSet(cond, dest);
491     }
492 
testObjectSet(Condition cond,const ValueOperand & value,Register dest)493     void testObjectSet(Condition cond, const ValueOperand& value, Register dest) {
494         cond = testObject(cond, value);
495         emitSet(cond, dest);
496     }
497 
testUndefinedSet(Condition cond,const ValueOperand & value,Register dest)498     void testUndefinedSet(Condition cond, const ValueOperand& value, Register dest) {
499         cond = testUndefined(cond, value);
500         emitSet(cond, dest);
501     }
502 
cmpPtr(Register lhs,const ImmWord rhs)503     void cmpPtr(Register lhs, const ImmWord rhs) {
504         cmpl(Imm32(rhs.value), lhs);
505     }
cmpPtr(Register lhs,const ImmPtr imm)506     void cmpPtr(Register lhs, const ImmPtr imm) {
507         cmpPtr(lhs, ImmWord(uintptr_t(imm.value)));
508     }
cmpPtr(Register lhs,const ImmGCPtr rhs)509     void cmpPtr(Register lhs, const ImmGCPtr rhs) {
510         cmpl(rhs, lhs);
511     }
cmpPtr(const Operand & lhs,Imm32 rhs)512     void cmpPtr(const Operand& lhs, Imm32 rhs) {
513         cmp32(lhs, rhs);
514     }
cmpPtr(const Operand & lhs,const ImmWord rhs)515     void cmpPtr(const Operand& lhs, const ImmWord rhs) {
516         cmp32(lhs, Imm32(rhs.value));
517     }
cmpPtr(const Operand & lhs,const ImmPtr imm)518     void cmpPtr(const Operand& lhs, const ImmPtr imm) {
519         cmpPtr(lhs, ImmWord(uintptr_t(imm.value)));
520     }
cmpPtr(const Operand & lhs,const ImmGCPtr rhs)521     void cmpPtr(const Operand& lhs, const ImmGCPtr rhs) {
522         cmpl(rhs, lhs);
523     }
cmpPtr(const Address & lhs,Register rhs)524     void cmpPtr(const Address& lhs, Register rhs) {
525         cmpPtr(Operand(lhs), rhs);
526     }
cmpPtr(const Operand & lhs,Register rhs)527     void cmpPtr(const Operand& lhs, Register rhs) {
528         cmp32(lhs, rhs);
529     }
cmpPtr(const Address & lhs,const ImmWord rhs)530     void cmpPtr(const Address& lhs, const ImmWord rhs) {
531         cmpPtr(Operand(lhs), rhs);
532     }
cmpPtr(const Address & lhs,const ImmPtr rhs)533     void cmpPtr(const Address& lhs, const ImmPtr rhs) {
534         cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
535     }
cmpPtr(const Address & lhs,const ImmGCPtr rhs)536     void cmpPtr(const Address& lhs, const ImmGCPtr rhs) {
537         cmpPtr(Operand(lhs), rhs);
538     }
cmpPtr(Register lhs,Register rhs)539     void cmpPtr(Register lhs, Register rhs) {
540         cmp32(lhs, rhs);
541     }
testPtr(Register lhs,Register rhs)542     void testPtr(Register lhs, Register rhs) {
543         test32(lhs, rhs);
544     }
testPtr(Register lhs,Imm32 rhs)545     void testPtr(Register lhs, Imm32 rhs) {
546         test32(lhs, rhs);
547     }
testPtr(Register lhs,ImmWord rhs)548     void testPtr(Register lhs, ImmWord rhs) {
549         test32(lhs, Imm32(rhs.value));
550     }
testPtr(const Operand & lhs,Imm32 rhs)551     void testPtr(const Operand& lhs, Imm32 rhs) {
552         test32(lhs, rhs);
553     }
testPtr(const Operand & lhs,ImmWord rhs)554     void testPtr(const Operand& lhs, ImmWord rhs) {
555         test32(lhs, Imm32(rhs.value));
556     }
557 
558     template <typename T1, typename T2>
cmpPtrSet(Assembler::Condition cond,T1 lhs,T2 rhs,Register dest)559     void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest)
560     {
561         cmpPtr(lhs, rhs);
562         emitSet(cond, dest);
563     }
564 
565     /////////////////////////////////////////////////////////////////
566     // Common interface.
567     /////////////////////////////////////////////////////////////////
568 
addPtr(Register src,Register dest)569     void addPtr(Register src, Register dest) {
570         add32(src, dest);
571     }
addPtr(Imm32 imm,Register dest)572     void addPtr(Imm32 imm, Register dest) {
573         add32(imm, dest);
574     }
addPtr(ImmWord imm,Register dest)575     void addPtr(ImmWord imm, Register dest) {
576         add32(Imm32(imm.value), dest);
577     }
addPtr(ImmPtr imm,Register dest)578     void addPtr(ImmPtr imm, Register dest) {
579         addPtr(ImmWord(uintptr_t(imm.value)), dest);
580     }
addPtr(Imm32 imm,const Address & dest)581     void addPtr(Imm32 imm, const Address& dest) {
582         add32(imm, Operand(dest));
583     }
addPtr(Imm32 imm,const Operand & dest)584     void addPtr(Imm32 imm, const Operand& dest) {
585         add32(imm, dest);
586     }
addPtr(const Address & src,Register dest)587     void addPtr(const Address& src, Register dest) {
588         addl(Operand(src), dest);
589     }
add64(Imm32 imm,Register64 dest)590     void add64(Imm32 imm, Register64 dest) {
591         addl(imm, dest.low);
592         adcl(Imm32(0), dest.high);
593     }
subPtr(Imm32 imm,Register dest)594     void subPtr(Imm32 imm, Register dest) {
595         subl(imm, dest);
596     }
subPtr(Register src,Register dest)597     void subPtr(Register src, Register dest) {
598         subl(src, dest);
599     }
subPtr(const Address & addr,Register dest)600     void subPtr(const Address& addr, Register dest) {
601         subl(Operand(addr), dest);
602     }
subPtr(Register src,const Address & dest)603     void subPtr(Register src, const Address& dest) {
604         subl(src, Operand(dest));
605     }
mulBy3(const Register & src,const Register & dest)606     void mulBy3(const Register& src, const Register& dest) {
607         lea(Operand(src, src, TimesTwo), dest);
608     }
609     // Note: this function clobbers eax and edx.
mul64(Imm64 imm,const Register64 & dest)610     void mul64(Imm64 imm, const Register64& dest) {
611         // LOW32  = LOW(LOW(dest) * LOW(imm));
612         // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits]
613         //        + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits]
614         //        + HIGH(LOW(dest) * LOW(imm)) [carry]
615 
616         MOZ_ASSERT(dest.low != eax && dest.low != edx);
617         MOZ_ASSERT(dest.high != eax && dest.high != edx);
618 
619         // HIGH(dest) = LOW(HIGH(dest) * LOW(imm));
620         movl(Imm32(imm.value & 0xFFFFFFFFL), edx);
621         imull(edx, dest.high);
622 
623         // edx:eax = LOW(dest) * LOW(imm);
624         movl(Imm32(imm.value & 0xFFFFFFFFL), edx);
625         movl(dest.low, eax);
626         mull(edx);
627 
628         // HIGH(dest) += edx;
629         addl(edx, dest.high);
630 
631         // HIGH(dest) += LOW(LOW(dest) * HIGH(imm));
632         if (((imm.value >> 32) & 0xFFFFFFFFL) == 5)
633             leal(Operand(dest.low, dest.low, TimesFour), edx);
634         else
635             MOZ_CRASH("Unsupported imm");
636         addl(edx, dest.high);
637 
638         // LOW(dest) = eax;
639         movl(eax, dest.low);
640     }
641 
branch32(Condition cond,AbsoluteAddress lhs,Imm32 rhs,Label * label)642     void branch32(Condition cond, AbsoluteAddress lhs, Imm32 rhs, Label* label) {
643         cmp32(Operand(lhs), rhs);
644         j(cond, label);
645     }
branch32(Condition cond,wasm::SymbolicAddress lhs,Imm32 rhs,Label * label)646     void branch32(Condition cond, wasm::SymbolicAddress lhs, Imm32 rhs, Label* label) {
647         cmpl(rhs, lhs);
648         j(cond, label);
649     }
branch32(Condition cond,AbsoluteAddress lhs,Register rhs,Label * label)650     void branch32(Condition cond, AbsoluteAddress lhs, Register rhs, Label* label) {
651         cmp32(Operand(lhs), rhs);
652         j(cond, label);
653     }
branchTest32(Condition cond,AbsoluteAddress address,Imm32 imm,Label * label)654     void branchTest32(Condition cond, AbsoluteAddress address, Imm32 imm, Label* label) {
655         test32(Operand(address), imm);
656         j(cond, label);
657     }
658 
branchPtr(Condition cond,wasm::SymbolicAddress lhs,Register ptr,Label * label)659     void branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register ptr, Label* label) {
660         cmpl(ptr, lhs);
661         j(cond, label);
662     }
663 
664     template <typename T, typename S>
branchPtr(Condition cond,T lhs,S ptr,Label * label)665     void branchPtr(Condition cond, T lhs, S ptr, Label* label) {
666         cmpPtr(Operand(lhs), ptr);
667         j(cond, label);
668     }
669 
branchPrivatePtr(Condition cond,const Address & lhs,ImmPtr ptr,Label * label)670     void branchPrivatePtr(Condition cond, const Address& lhs, ImmPtr ptr, Label* label) {
671         branchPtr(cond, lhs, ptr, label);
672     }
673 
branchPrivatePtr(Condition cond,const Address & lhs,Register ptr,Label * label)674     void branchPrivatePtr(Condition cond, const Address& lhs, Register ptr, Label* label) {
675         branchPtr(cond, lhs, ptr, label);
676     }
677 
678     template <typename T, typename S>
branchPtr(Condition cond,T lhs,S ptr,RepatchLabel * label)679     void branchPtr(Condition cond, T lhs, S ptr, RepatchLabel* label) {
680         cmpPtr(Operand(lhs), ptr);
681         j(cond, label);
682     }
683 
684     CodeOffsetJump jumpWithPatch(RepatchLabel* label, Label* documentation = nullptr) {
685         jump(label);
686         return CodeOffsetJump(size());
687     }
688 
689     CodeOffsetJump jumpWithPatch(RepatchLabel* label, Assembler::Condition cond,
690                                  Label* documentation = nullptr)
691     {
692         j(cond, label);
693         return CodeOffsetJump(size());
694     }
695 
696     CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation = nullptr) {
697         return jumpWithPatch(label);
698     }
699 
700     template <typename S, typename T>
branchPtrWithPatch(Condition cond,S lhs,T ptr,RepatchLabel * label)701     CodeOffsetJump branchPtrWithPatch(Condition cond, S lhs, T ptr, RepatchLabel* label) {
702         branchPtr(cond, lhs, ptr, label);
703         return CodeOffsetJump(size());
704     }
branchPtr(Condition cond,Register lhs,Register rhs,RepatchLabel * label)705     void branchPtr(Condition cond, Register lhs, Register rhs, RepatchLabel* label) {
706         cmpPtr(lhs, rhs);
707         j(cond, label);
708     }
branchPtr(Condition cond,Register lhs,Register rhs,Label * label)709     void branchPtr(Condition cond, Register lhs, Register rhs, Label* label) {
710         cmpPtr(lhs, rhs);
711         j(cond, label);
712     }
branchTestPtr(Condition cond,Register lhs,Register rhs,Label * label)713     void branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label) {
714         testPtr(lhs, rhs);
715         j(cond, label);
716     }
branchTestPtr(Condition cond,Register lhs,Imm32 imm,Label * label)717     void branchTestPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
718         testPtr(lhs, imm);
719         j(cond, label);
720     }
branchTestPtr(Condition cond,const Address & lhs,Imm32 imm,Label * label)721     void branchTestPtr(Condition cond, const Address& lhs, Imm32 imm, Label* label) {
722         testPtr(Operand(lhs), imm);
723         j(cond, label);
724     }
decBranchPtr(Condition cond,Register lhs,Imm32 imm,Label * label)725     void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
726         subPtr(imm, lhs);
727         j(cond, label);
728     }
729 
branchTest64(Condition cond,Register64 lhs,Register64 rhs,Register temp,Label * label)730     void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, Label* label) {
731         if (cond == Assembler::Zero) {
732             MOZ_ASSERT(lhs.low == rhs.low);
733             MOZ_ASSERT(lhs.high == rhs.high);
734             movl(lhs.low, temp);
735             orl(lhs.high, temp);
736             branchTestPtr(cond, temp, temp, label);
737         } else {
738             MOZ_CRASH("Unsupported condition");
739         }
740     }
741 
movePtr(ImmWord imm,Register dest)742     void movePtr(ImmWord imm, Register dest) {
743         movl(Imm32(imm.value), dest);
744     }
movePtr(ImmPtr imm,Register dest)745     void movePtr(ImmPtr imm, Register dest) {
746         movl(imm, dest);
747     }
movePtr(wasm::SymbolicAddress imm,Register dest)748     void movePtr(wasm::SymbolicAddress imm, Register dest) {
749         mov(imm, dest);
750     }
movePtr(ImmGCPtr imm,Register dest)751     void movePtr(ImmGCPtr imm, Register dest) {
752         movl(imm, dest);
753     }
move64(Register64 src,Register64 dest)754     void move64(Register64 src, Register64 dest) {
755         movl(src.low, dest.low);
756         movl(src.high, dest.high);
757     }
loadPtr(const Address & address,Register dest)758     void loadPtr(const Address& address, Register dest) {
759         movl(Operand(address), dest);
760     }
loadPtr(const Operand & src,Register dest)761     void loadPtr(const Operand& src, Register dest) {
762         movl(src, dest);
763     }
loadPtr(const BaseIndex & src,Register dest)764     void loadPtr(const BaseIndex& src, Register dest) {
765         movl(Operand(src), dest);
766     }
loadPtr(AbsoluteAddress address,Register dest)767     void loadPtr(AbsoluteAddress address, Register dest) {
768         movl(Operand(address), dest);
769     }
loadPrivate(const Address & src,Register dest)770     void loadPrivate(const Address& src, Register dest) {
771         movl(payloadOf(src), dest);
772     }
load32(AbsoluteAddress address,Register dest)773     void load32(AbsoluteAddress address, Register dest) {
774         movl(Operand(address), dest);
775     }
load64(const Address & address,Register64 dest)776     void load64(const Address& address, Register64 dest) {
777         movl(Operand(address), dest.low);
778         movl(Operand(Address(address.base, address.offset + 4)), dest.high);
779     }
780 
branch64(Condition cond,const Address & lhs,Imm64 val,Label * label)781     void branch64(Condition cond, const Address& lhs, Imm64 val, Label* label) {
782         MOZ_ASSERT(cond == Assembler::NotEqual,
783                    "other condition codes not supported");
784 
785         branch32(cond, lhs, val.firstHalf(), label);
786         branch32(cond, Address(lhs.base, lhs.offset + sizeof(uint32_t)), val.secondHalf(), label);
787     }
788 
branch64(Condition cond,const Address & lhs,const Address & rhs,Register scratch,Label * label)789     void branch64(Condition cond, const Address& lhs, const Address& rhs, Register scratch,
790                   Label* label)
791     {
792         MOZ_ASSERT(cond == Assembler::NotEqual,
793                    "other condition codes not supported");
794         MOZ_ASSERT(lhs.base != scratch);
795         MOZ_ASSERT(rhs.base != scratch);
796 
797         load32(rhs, scratch);
798         branch32(cond, lhs, scratch, label);
799 
800         load32(Address(rhs.base, rhs.offset + sizeof(uint32_t)), scratch);
801         branch32(cond, Address(lhs.base, lhs.offset + sizeof(uint32_t)), scratch, label);
802     }
803 
804     template <typename T>
storePtr(ImmWord imm,T address)805     void storePtr(ImmWord imm, T address) {
806         movl(Imm32(imm.value), Operand(address));
807     }
808     template <typename T>
storePtr(ImmPtr imm,T address)809     void storePtr(ImmPtr imm, T address) {
810         storePtr(ImmWord(uintptr_t(imm.value)), address);
811     }
812     template <typename T>
storePtr(ImmGCPtr imm,T address)813     void storePtr(ImmGCPtr imm, T address) {
814         movl(imm, Operand(address));
815     }
storePtr(Register src,const Address & address)816     void storePtr(Register src, const Address& address) {
817         movl(src, Operand(address));
818     }
storePtr(Register src,const BaseIndex & address)819     void storePtr(Register src, const BaseIndex& address) {
820         movl(src, Operand(address));
821     }
storePtr(Register src,const Operand & dest)822     void storePtr(Register src, const Operand& dest) {
823         movl(src, dest);
824     }
storePtr(Register src,AbsoluteAddress address)825     void storePtr(Register src, AbsoluteAddress address) {
826         movl(src, Operand(address));
827     }
store32(Register src,AbsoluteAddress address)828     void store32(Register src, AbsoluteAddress address) {
829         movl(src, Operand(address));
830     }
store64(Register64 src,Address address)831     void store64(Register64 src, Address address) {
832         movl(src.low, Operand(address));
833         movl(src.high, Operand(Address(address.base, address.offset + 4)));
834     }
835 
setStackArg(Register reg,uint32_t arg)836     void setStackArg(Register reg, uint32_t arg) {
837         movl(reg, Operand(esp, arg * sizeof(intptr_t)));
838     }
839 
840     // Type testing instructions can take a tag in a register or a
841     // ValueOperand.
842     template <typename T>
branchTestUndefined(Condition cond,const T & t,Label * label)843     void branchTestUndefined(Condition cond, const T& t, Label* label) {
844         cond = testUndefined(cond, t);
845         j(cond, label);
846     }
847     template <typename T>
branchTestInt32(Condition cond,const T & t,Label * label)848     void branchTestInt32(Condition cond, const T& t, Label* label) {
849         cond = testInt32(cond, t);
850         j(cond, label);
851     }
852     template <typename T>
branchTestBoolean(Condition cond,const T & t,Label * label)853     void branchTestBoolean(Condition cond, const T& t, Label* label) {
854         cond = testBoolean(cond, t);
855         j(cond, label);
856     }
857     template <typename T>
branchTestDouble(Condition cond,const T & t,Label * label)858     void branchTestDouble(Condition cond, const T& t, Label* label) {
859         cond = testDouble(cond, t);
860         j(cond, label);
861     }
862     template <typename T>
branchTestNull(Condition cond,const T & t,Label * label)863     void branchTestNull(Condition cond, const T& t, Label* label) {
864         cond = testNull(cond, t);
865         j(cond, label);
866     }
867     template <typename T>
branchTestString(Condition cond,const T & t,Label * label)868     void branchTestString(Condition cond, const T& t, Label* label) {
869         cond = testString(cond, t);
870         j(cond, label);
871     }
872     template <typename T>
branchTestSymbol(Condition cond,const T & t,Label * label)873     void branchTestSymbol(Condition cond, const T& t, Label* label) {
874         cond = testSymbol(cond, t);
875         j(cond, label);
876     }
877     template <typename T>
branchTestObject(Condition cond,const T & t,Label * label)878     void branchTestObject(Condition cond, const T& t, Label* label) {
879         cond = testObject(cond, t);
880         j(cond, label);
881     }
882     template <typename T>
branchTestNumber(Condition cond,const T & t,Label * label)883     void branchTestNumber(Condition cond, const T& t, Label* label) {
884         cond = testNumber(cond, t);
885         j(cond, label);
886     }
887     template <typename T>
branchTestGCThing(Condition cond,const T & t,Label * label)888     void branchTestGCThing(Condition cond, const T& t, Label* label) {
889         cond = testGCThing(cond, t);
890         j(cond, label);
891     }
892     template <typename T>
branchTestPrimitive(Condition cond,const T & t,Label * label)893     void branchTestPrimitive(Condition cond, const T& t, Label* label) {
894         cond = testPrimitive(cond, t);
895         j(cond, label);
896     }
897     template <typename T>
branchTestMagic(Condition cond,const T & t,Label * label)898     void branchTestMagic(Condition cond, const T& t, Label* label) {
899         cond = testMagic(cond, t);
900         j(cond, label);
901     }
branchTestMagicValue(Condition cond,const ValueOperand & val,JSWhyMagic why,Label * label)902     void branchTestMagicValue(Condition cond, const ValueOperand& val, JSWhyMagic why,
903                               Label* label)
904     {
905         MOZ_ASSERT(cond == Equal || cond == NotEqual);
906         branchTestValue(cond, val, MagicValue(why), label);
907     }
908 
909     // Note: this function clobbers the source register.
boxDouble(FloatRegister src,const ValueOperand & dest)910     void boxDouble(FloatRegister src, const ValueOperand& dest) {
911         if (Assembler::HasSSE41()) {
912             vmovd(src, dest.payloadReg());
913             vpextrd(1, src, dest.typeReg());
914         } else {
915             vmovd(src, dest.payloadReg());
916             vpsrldq(Imm32(4), src, src);
917             vmovd(src, dest.typeReg());
918         }
919     }
boxNonDouble(JSValueType type,Register src,const ValueOperand & dest)920     void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) {
921         if (src != dest.payloadReg())
922             movl(src, dest.payloadReg());
923         movl(ImmType(type), dest.typeReg());
924     }
925 
unboxNonDouble(const ValueOperand & src,Register dest)926     void unboxNonDouble(const ValueOperand& src, Register dest) {
927         if (src.payloadReg() != dest)
928             movl(src.payloadReg(), dest);
929     }
unboxNonDouble(const Address & src,Register dest)930     void unboxNonDouble(const Address& src, Register dest) {
931         movl(payloadOf(src), dest);
932     }
unboxNonDouble(const BaseIndex & src,Register dest)933     void unboxNonDouble(const BaseIndex& src, Register dest) {
934         movl(payloadOf(src), dest);
935     }
unboxInt32(const ValueOperand & src,Register dest)936     void unboxInt32(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
unboxInt32(const Address & src,Register dest)937     void unboxInt32(const Address& src, Register dest) { unboxNonDouble(src, dest); }
unboxBoolean(const ValueOperand & src,Register dest)938     void unboxBoolean(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
unboxBoolean(const Address & src,Register dest)939     void unboxBoolean(const Address& src, Register dest) { unboxNonDouble(src, dest); }
unboxString(const ValueOperand & src,Register dest)940     void unboxString(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
unboxString(const Address & src,Register dest)941     void unboxString(const Address& src, Register dest) { unboxNonDouble(src, dest); }
unboxSymbol(const ValueOperand & src,Register dest)942     void unboxSymbol(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
unboxSymbol(const Address & src,Register dest)943     void unboxSymbol(const Address& src, Register dest) { unboxNonDouble(src, dest); }
unboxObject(const ValueOperand & src,Register dest)944     void unboxObject(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
unboxObject(const Address & src,Register dest)945     void unboxObject(const Address& src, Register dest) { unboxNonDouble(src, dest); }
unboxObject(const BaseIndex & src,Register dest)946     void unboxObject(const BaseIndex& src, Register dest) { unboxNonDouble(src, dest); }
unboxDouble(const Address & src,FloatRegister dest)947     void unboxDouble(const Address& src, FloatRegister dest) {
948         loadDouble(Operand(src), dest);
949     }
unboxDouble(const ValueOperand & src,FloatRegister dest)950     void unboxDouble(const ValueOperand& src, FloatRegister dest) {
951         MOZ_ASSERT(dest != ScratchDoubleReg);
952         if (Assembler::HasSSE41()) {
953             vmovd(src.payloadReg(), dest);
954             vpinsrd(1, src.typeReg(), dest, dest);
955         } else {
956             vmovd(src.payloadReg(), dest);
957             vmovd(src.typeReg(), ScratchDoubleReg);
958             vunpcklps(ScratchDoubleReg, dest, dest);
959         }
960     }
unboxDouble(const Operand & payload,const Operand & type,Register scratch,FloatRegister dest)961     void unboxDouble(const Operand& payload, const Operand& type,
962                      Register scratch, FloatRegister dest) {
963         MOZ_ASSERT(dest != ScratchDoubleReg);
964         if (Assembler::HasSSE41()) {
965             movl(payload, scratch);
966             vmovd(scratch, dest);
967             movl(type, scratch);
968             vpinsrd(1, scratch, dest, dest);
969         } else {
970             movl(payload, scratch);
971             vmovd(scratch, dest);
972             movl(type, scratch);
973             vmovd(scratch, ScratchDoubleReg);
974             vunpcklps(ScratchDoubleReg, dest, dest);
975         }
976     }
unboxValue(const ValueOperand & src,AnyRegister dest)977     void unboxValue(const ValueOperand& src, AnyRegister dest) {
978         if (dest.isFloat()) {
979             Label notInt32, end;
980             branchTestInt32(Assembler::NotEqual, src, &notInt32);
981             convertInt32ToDouble(src.payloadReg(), dest.fpu());
982             jump(&end);
983             bind(&notInt32);
984             unboxDouble(src, dest.fpu());
985             bind(&end);
986         } else {
987             if (src.payloadReg() != dest.gpr())
988                 movl(src.payloadReg(), dest.gpr());
989         }
990     }
unboxPrivate(const ValueOperand & src,Register dest)991     void unboxPrivate(const ValueOperand& src, Register dest) {
992         if (src.payloadReg() != dest)
993             movl(src.payloadReg(), dest);
994     }
995 
notBoolean(const ValueOperand & val)996     void notBoolean(const ValueOperand& val) {
997         xorl(Imm32(1), val.payloadReg());
998     }
999 
1000     // Extended unboxing API. If the payload is already in a register, returns
1001     // that register. Otherwise, provides a move to the given scratch register,
1002     // and returns that.
extractObject(const Address & address,Register scratch)1003     Register extractObject(const Address& address, Register scratch) {
1004         movl(payloadOf(address), scratch);
1005         return scratch;
1006     }
extractObject(const ValueOperand & value,Register scratch)1007     Register extractObject(const ValueOperand& value, Register scratch) {
1008         return value.payloadReg();
1009     }
extractInt32(const ValueOperand & value,Register scratch)1010     Register extractInt32(const ValueOperand& value, Register scratch) {
1011         return value.payloadReg();
1012     }
extractBoolean(const ValueOperand & value,Register scratch)1013     Register extractBoolean(const ValueOperand& value, Register scratch) {
1014         return value.payloadReg();
1015     }
extractTag(const Address & address,Register scratch)1016     Register extractTag(const Address& address, Register scratch) {
1017         movl(tagOf(address), scratch);
1018         return scratch;
1019     }
extractTag(const ValueOperand & value,Register scratch)1020     Register extractTag(const ValueOperand& value, Register scratch) {
1021         return value.typeReg();
1022     }
1023 
boolValueToDouble(const ValueOperand & operand,FloatRegister dest)1024     void boolValueToDouble(const ValueOperand& operand, FloatRegister dest) {
1025         convertInt32ToDouble(operand.payloadReg(), dest);
1026     }
boolValueToFloat32(const ValueOperand & operand,FloatRegister dest)1027     void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
1028         convertInt32ToFloat32(operand.payloadReg(), dest);
1029     }
int32ValueToDouble(const ValueOperand & operand,FloatRegister dest)1030     void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest) {
1031         convertInt32ToDouble(operand.payloadReg(), dest);
1032     }
int32ValueToFloat32(const ValueOperand & operand,FloatRegister dest)1033     void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
1034         convertInt32ToFloat32(operand.payloadReg(), dest);
1035     }
1036 
1037     void loadConstantDouble(double d, FloatRegister dest);
1038     void addConstantDouble(double d, FloatRegister dest);
1039     void loadConstantFloat32(float f, FloatRegister dest);
1040     void addConstantFloat32(float f, FloatRegister dest);
1041     void loadConstantInt32x4(const SimdConstant& v, FloatRegister dest);
1042     void loadConstantFloat32x4(const SimdConstant& v, FloatRegister dest);
1043 
branchTruncateDouble(FloatRegister src,Register dest,Label * fail)1044     void branchTruncateDouble(FloatRegister src, Register dest, Label* fail) {
1045         vcvttsd2si(src, dest);
1046 
1047         // vcvttsd2si returns 0x80000000 on failure. Test for it by
1048         // subtracting 1 and testing overflow (this permits the use of a
1049         // smaller immediate field).
1050         cmp32(dest, Imm32(1));
1051         j(Assembler::Overflow, fail);
1052     }
branchTruncateFloat32(FloatRegister src,Register dest,Label * fail)1053     void branchTruncateFloat32(FloatRegister src, Register dest, Label* fail) {
1054         vcvttss2si(src, dest);
1055 
1056         // vcvttss2si returns 0x80000000 on failure. Test for it by
1057         // subtracting 1 and testing overflow (this permits the use of a
1058         // smaller immediate field).
1059         cmp32(dest, Imm32(1));
1060         j(Assembler::Overflow, fail);
1061     }
1062 
testInt32Truthy(bool truthy,const ValueOperand & operand)1063     Condition testInt32Truthy(bool truthy, const ValueOperand& operand) {
1064         test32(operand.payloadReg(), operand.payloadReg());
1065         return truthy ? NonZero : Zero;
1066     }
branchTestInt32Truthy(bool truthy,const ValueOperand & operand,Label * label)1067     void branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label) {
1068         Condition cond = testInt32Truthy(truthy, operand);
1069         j(cond, label);
1070     }
branchTestBooleanTruthy(bool truthy,const ValueOperand & operand,Label * label)1071     void branchTestBooleanTruthy(bool truthy, const ValueOperand& operand, Label* label) {
1072         test32(operand.payloadReg(), operand.payloadReg());
1073         j(truthy ? NonZero : Zero, label);
1074     }
testStringTruthy(bool truthy,const ValueOperand & value)1075     Condition testStringTruthy(bool truthy, const ValueOperand& value) {
1076         Register string = value.payloadReg();
1077         cmp32(Operand(string, JSString::offsetOfLength()), Imm32(0));
1078         return truthy ? Assembler::NotEqual : Assembler::Equal;
1079     }
branchTestStringTruthy(bool truthy,const ValueOperand & value,Label * label)1080     void branchTestStringTruthy(bool truthy, const ValueOperand& value, Label* label) {
1081         Condition cond = testStringTruthy(truthy, value);
1082         j(cond, label);
1083     }
1084 
loadInt32OrDouble(const Operand & operand,FloatRegister dest)1085     void loadInt32OrDouble(const Operand& operand, FloatRegister dest) {
1086         Label notInt32, end;
1087         branchTestInt32(Assembler::NotEqual, operand, &notInt32);
1088         convertInt32ToDouble(ToPayload(operand), dest);
1089         jump(&end);
1090         bind(&notInt32);
1091         loadDouble(operand, dest);
1092         bind(&end);
1093     }
1094 
1095     template <typename T>
loadUnboxedValue(const T & src,MIRType type,AnyRegister dest)1096     void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) {
1097         if (dest.isFloat())
1098             loadInt32OrDouble(Operand(src), dest.fpu());
1099         else
1100             movl(Operand(src), dest.gpr());
1101     }
1102 
1103     template <typename T>
1104     void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
1105                            MIRType slotType);
1106 
1107     template <typename T>
storeUnboxedPayload(ValueOperand value,T address,size_t nbytes)1108     void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
1109         switch (nbytes) {
1110           case 4:
1111             storePtr(value.payloadReg(), address);
1112             return;
1113           case 1:
1114             store8(value.payloadReg(), address);
1115             return;
1116           default: MOZ_CRASH("Bad payload width");
1117         }
1118     }
1119 
loadInstructionPointerAfterCall(Register dest)1120     void loadInstructionPointerAfterCall(Register dest) {
1121         movl(Operand(StackPointer, 0x0), dest);
1122     }
1123 
1124     // Note: this function clobbers the source register.
convertUInt32ToDouble(Register src,FloatRegister dest)1125     void convertUInt32ToDouble(Register src, FloatRegister dest) {
1126         // src is [0, 2^32-1]
1127         subl(Imm32(0x80000000), src);
1128 
1129         // Now src is [-2^31, 2^31-1] - int range, but not the same value.
1130         convertInt32ToDouble(src, dest);
1131 
1132         // dest is now a double with the int range.
1133         // correct the double value by adding 0x80000000.
1134         addConstantDouble(2147483648.0, dest);
1135     }
1136 
1137     // Note: this function clobbers the source register.
convertUInt32ToFloat32(Register src,FloatRegister dest)1138     void convertUInt32ToFloat32(Register src, FloatRegister dest) {
1139         convertUInt32ToDouble(src, dest);
1140         convertDoubleToFloat32(dest, dest);
1141     }
1142 
1143     void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest);
1144 
mulDoublePtr(ImmPtr imm,Register temp,FloatRegister dest)1145     void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) {
1146         movl(imm, temp);
1147         vmulsd(Operand(temp, 0), dest, dest);
1148     }
1149 
inc64(AbsoluteAddress dest)1150     void inc64(AbsoluteAddress dest) {
1151         addl(Imm32(1), Operand(dest));
1152         Label noOverflow;
1153         j(NonZero, &noOverflow);
1154         addl(Imm32(1), Operand(dest.offset(4)));
1155         bind(&noOverflow);
1156     }
1157 
incrementInt32Value(const Address & addr)1158     void incrementInt32Value(const Address& addr) {
1159         addl(Imm32(1), payloadOf(addr));
1160     }
1161 
1162     // If source is a double, load it into dest. If source is int32,
1163     // convert it to double. Else, branch to failure.
ensureDouble(const ValueOperand & source,FloatRegister dest,Label * failure)1164     void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure) {
1165         Label isDouble, done;
1166         branchTestDouble(Assembler::Equal, source.typeReg(), &isDouble);
1167         branchTestInt32(Assembler::NotEqual, source.typeReg(), failure);
1168 
1169         convertInt32ToDouble(source.payloadReg(), dest);
1170         jump(&done);
1171 
1172         bind(&isDouble);
1173         unboxDouble(source, dest);
1174 
1175         bind(&done);
1176     }
1177 
1178   public:
1179     // Used from within an Exit frame to handle a pending exception.
1180     void handleFailureWithHandlerTail(void* handler);
1181 
1182     void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label);
1183     void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label);
1184 
1185     // Instrumentation for entering and leaving the profiler.
1186     void profilerEnterFrame(Register framePtr, Register scratch);
1187     void profilerExitFrame();
1188 };
1189 
1190 typedef MacroAssemblerX86 MacroAssemblerSpecific;
1191 
1192 } // namespace jit
1193 } // namespace js
1194 
1195 #endif /* jit_x86_MacroAssembler_x86_h */
1196