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::load32;
54     using MacroAssemblerX86Shared::store32;
55     using MacroAssemblerX86Shared::store16;
56     using MacroAssemblerX86Shared::call;
57 
MacroAssemblerX86()58     MacroAssemblerX86()
59     {
60     }
61 
62     // The buffer is about to be linked, make sure any constant pools or excess
63     // bookkeeping has been flushed to the instruction stream.
64     void finish();
65 
66     /////////////////////////////////////////////////////////////////
67     // X86-specific interface.
68     /////////////////////////////////////////////////////////////////
69 
ToPayload(Operand base)70     Operand ToPayload(Operand base) {
71         return base;
72     }
ToPayload(Address base)73     Address ToPayload(Address base) {
74         return base;
75     }
ToPayload(BaseIndex base)76     BaseIndex ToPayload(BaseIndex base) {
77         return base;
78     }
ToType(Operand base)79     Operand ToType(Operand base) {
80         switch (base.kind()) {
81           case Operand::MEM_REG_DISP:
82             return Operand(Register::FromCode(base.base()), base.disp() + sizeof(void*));
83 
84           case Operand::MEM_SCALE:
85             return Operand(Register::FromCode(base.base()), Register::FromCode(base.index()),
86                            base.scale(), base.disp() + sizeof(void*));
87 
88           default:
89             MOZ_CRASH("unexpected operand kind");
90         }
91     }
ToType(Address base)92     Address ToType(Address base) {
93         return ToType(Operand(base)).toAddress();
94     }
moveValue(const Value & val,Register type,Register data)95     void moveValue(const Value& val, Register type, Register data) {
96         movl(Imm32(val.toNunboxTag()), type);
97         if (val.isMarkable())
98             movl(ImmGCPtr(val.toMarkablePointer()), data);
99         else
100             movl(Imm32(val.toNunboxPayload()), data);
101     }
moveValue(const Value & val,const ValueOperand & dest)102     void moveValue(const Value& val, const ValueOperand& dest) {
103         moveValue(val, dest.typeReg(), dest.payloadReg());
104     }
moveValue(const ValueOperand & src,const ValueOperand & dest)105     void moveValue(const ValueOperand& src, const ValueOperand& dest) {
106         Register s0 = src.typeReg(), d0 = dest.typeReg(),
107                  s1 = src.payloadReg(), d1 = dest.payloadReg();
108 
109         // Either one or both of the source registers could be the same as a
110         // destination register.
111         if (s1 == d0) {
112             if (s0 == d1) {
113                 // If both are, this is just a swap of two registers.
114                 xchgl(d0, d1);
115                 return;
116             }
117             // If only one is, copy that source first.
118             mozilla::Swap(s0, s1);
119             mozilla::Swap(d0, d1);
120         }
121 
122         if (s0 != d0)
123             movl(s0, d0);
124         if (s1 != d1)
125             movl(s1, d1);
126     }
127 
128     /////////////////////////////////////////////////////////////////
129     // X86/X64-common interface.
130     /////////////////////////////////////////////////////////////////
storeValue(ValueOperand val,Operand dest)131     void storeValue(ValueOperand val, Operand dest) {
132         movl(val.payloadReg(), ToPayload(dest));
133         movl(val.typeReg(), ToType(dest));
134     }
storeValue(ValueOperand val,const Address & dest)135     void storeValue(ValueOperand val, const Address& dest) {
136         storeValue(val, Operand(dest));
137     }
138     template <typename T>
storeValue(JSValueType type,Register reg,const T & dest)139     void storeValue(JSValueType type, Register reg, const T& dest) {
140         storeTypeTag(ImmTag(JSVAL_TYPE_TO_TAG(type)), Operand(dest));
141         storePayload(reg, Operand(dest));
142     }
143     template <typename T>
storeValue(const Value & val,const T & dest)144     void storeValue(const Value& val, const T& dest) {
145         storeTypeTag(ImmTag(val.toNunboxTag()), 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     }
storeValue(const Address & src,const Address & dest,Register temp)151     void storeValue(const Address& src, const Address& dest, Register temp) {
152         MOZ_ASSERT(src.base != temp);
153         MOZ_ASSERT(dest.base != temp);
154 
155         load32(ToType(src), temp);
156         store32(temp, ToType(dest));
157 
158         load32(ToPayload(src), temp);
159         store32(temp, ToPayload(dest));
160     }
loadValue(Operand src,ValueOperand val)161     void loadValue(Operand src, ValueOperand val) {
162         Operand payload = ToPayload(src);
163         Operand type = ToType(src);
164 
165         // Ensure that loading the payload does not erase the pointer to the
166         // Value in memory or the index.
167         Register baseReg = Register::FromCode(src.base());
168         Register indexReg = (src.kind() == Operand::MEM_SCALE) ? Register::FromCode(src.index()) : InvalidReg;
169 
170         // If we have a BaseIndex that uses both result registers, first compute
171         // the address and then load the Value from there.
172         if ((baseReg == val.payloadReg() && indexReg == val.typeReg()) ||
173             (baseReg == val.typeReg() && indexReg == val.payloadReg()))
174         {
175             computeEffectiveAddress(src, val.scratchReg());
176             loadValue(Address(val.scratchReg(), 0), val);
177             return;
178         }
179 
180         if (baseReg == val.payloadReg() || indexReg == val.payloadReg()) {
181             MOZ_ASSERT(baseReg != val.typeReg());
182             MOZ_ASSERT(indexReg != val.typeReg());
183 
184             movl(type, val.typeReg());
185             movl(payload, val.payloadReg());
186         } else {
187             MOZ_ASSERT(baseReg != val.payloadReg());
188             MOZ_ASSERT(indexReg != val.payloadReg());
189 
190             movl(payload, val.payloadReg());
191             movl(type, val.typeReg());
192         }
193     }
loadValue(Address src,ValueOperand val)194     void loadValue(Address src, ValueOperand val) {
195         loadValue(Operand(src), val);
196     }
loadValue(const BaseIndex & src,ValueOperand val)197     void loadValue(const BaseIndex& src, ValueOperand val) {
198         loadValue(Operand(src), val);
199     }
tagValue(JSValueType type,Register payload,ValueOperand dest)200     void tagValue(JSValueType type, Register payload, ValueOperand dest) {
201         MOZ_ASSERT(dest.typeReg() != dest.payloadReg());
202         if (payload != dest.payloadReg())
203             movl(payload, dest.payloadReg());
204         movl(ImmType(type), dest.typeReg());
205     }
pushValue(ValueOperand val)206     void pushValue(ValueOperand val) {
207         push(val.typeReg());
208         push(val.payloadReg());
209     }
popValue(ValueOperand val)210     void popValue(ValueOperand val) {
211         pop(val.payloadReg());
212         pop(val.typeReg());
213     }
pushValue(const Value & val)214     void pushValue(const Value& val) {
215         push(Imm32(val.toNunboxTag()));
216         if (val.isMarkable())
217             push(ImmGCPtr(val.toMarkablePointer()));
218         else
219             push(Imm32(val.toNunboxPayload()));
220     }
pushValue(JSValueType type,Register reg)221     void pushValue(JSValueType type, Register reg) {
222         push(ImmTag(JSVAL_TYPE_TO_TAG(type)));
223         push(reg);
224     }
pushValue(const Address & addr)225     void pushValue(const Address& addr) {
226         push(tagOf(addr));
227         push(payloadOfAfterStackPush(addr));
228     }
push64(Register64 src)229     void push64(Register64 src) {
230         push(src.high);
231         push(src.low);
232     }
pop64(Register64 dest)233     void pop64(Register64 dest) {
234         pop(dest.low);
235         pop(dest.high);
236     }
storePayload(const Value & val,Operand dest)237     void storePayload(const Value& val, Operand dest) {
238         if (val.isMarkable())
239             movl(ImmGCPtr(val.toMarkablePointer()), ToPayload(dest));
240         else
241             movl(Imm32(val.toNunboxPayload()), ToPayload(dest));
242     }
storePayload(Register src,Operand dest)243     void storePayload(Register src, Operand dest) {
244         movl(src, ToPayload(dest));
245     }
storeTypeTag(ImmTag tag,Operand dest)246     void storeTypeTag(ImmTag tag, Operand dest) {
247         movl(tag, ToType(dest));
248     }
249 
movePtr(Register src,Register dest)250     void movePtr(Register src, Register dest) {
251         movl(src, dest);
252     }
movePtr(Register src,const Operand & dest)253     void movePtr(Register src, const Operand& dest) {
254         movl(src, dest);
255     }
256 
257     // Returns the register containing the type tag.
splitTagForTest(const ValueOperand & value)258     Register splitTagForTest(const ValueOperand& value) {
259         return value.typeReg();
260     }
261 
testUndefined(Condition cond,Register tag)262     Condition testUndefined(Condition cond, Register tag) {
263         MOZ_ASSERT(cond == Equal || cond == NotEqual);
264         cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED));
265         return cond;
266     }
testBoolean(Condition cond,Register tag)267     Condition testBoolean(Condition cond, Register tag) {
268         MOZ_ASSERT(cond == Equal || cond == NotEqual);
269         cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN));
270         return cond;
271     }
testInt32(Condition cond,Register tag)272     Condition testInt32(Condition cond, Register tag) {
273         MOZ_ASSERT(cond == Equal || cond == NotEqual);
274         cmp32(tag, ImmTag(JSVAL_TAG_INT32));
275         return cond;
276     }
testDouble(Condition cond,Register tag)277     Condition testDouble(Condition cond, Register tag) {
278         MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
279         Condition actual = (cond == Equal) ? Below : AboveOrEqual;
280         cmp32(tag, ImmTag(JSVAL_TAG_CLEAR));
281         return actual;
282     }
testNull(Condition cond,Register tag)283     Condition testNull(Condition cond, Register tag) {
284         MOZ_ASSERT(cond == Equal || cond == NotEqual);
285         cmp32(tag, ImmTag(JSVAL_TAG_NULL));
286         return cond;
287     }
testString(Condition cond,Register tag)288     Condition testString(Condition cond, Register tag) {
289         MOZ_ASSERT(cond == Equal || cond == NotEqual);
290         cmp32(tag, ImmTag(JSVAL_TAG_STRING));
291         return cond;
292     }
testSymbol(Condition cond,Register tag)293     Condition testSymbol(Condition cond, Register tag) {
294         MOZ_ASSERT(cond == Equal || cond == NotEqual);
295         cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL));
296         return cond;
297     }
testObject(Condition cond,Register tag)298     Condition testObject(Condition cond, Register tag) {
299         MOZ_ASSERT(cond == Equal || cond == NotEqual);
300         cmp32(tag, ImmTag(JSVAL_TAG_OBJECT));
301         return cond;
302     }
testNumber(Condition cond,Register tag)303     Condition testNumber(Condition cond, Register tag) {
304         MOZ_ASSERT(cond == Equal || cond == NotEqual);
305         cmp32(tag, ImmTag(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET));
306         return cond == Equal ? BelowOrEqual : Above;
307     }
testGCThing(Condition cond,Register tag)308     Condition testGCThing(Condition cond, Register tag) {
309         MOZ_ASSERT(cond == Equal || cond == NotEqual);
310         cmp32(tag, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
311         return cond == Equal ? AboveOrEqual : Below;
312     }
testGCThing(Condition cond,const Address & address)313     Condition testGCThing(Condition cond, const Address& address) {
314         MOZ_ASSERT(cond == Equal || cond == NotEqual);
315         cmp32(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
316         return cond == Equal ? AboveOrEqual : Below;
317     }
testMagic(Condition cond,const Address & address)318     Condition testMagic(Condition cond, const Address& address) {
319         MOZ_ASSERT(cond == Equal || cond == NotEqual);
320         cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC));
321         return cond;
322     }
testMagic(Condition cond,Register tag)323     Condition testMagic(Condition cond, Register tag) {
324         MOZ_ASSERT(cond == Equal || cond == NotEqual);
325         cmp32(tag, ImmTag(JSVAL_TAG_MAGIC));
326         return cond;
327     }
testMagic(Condition cond,const Operand & operand)328     Condition testMagic(Condition cond, const Operand& operand) {
329         MOZ_ASSERT(cond == Equal || cond == NotEqual);
330         cmp32(ToType(operand), ImmTag(JSVAL_TAG_MAGIC));
331         return cond;
332     }
testPrimitive(Condition cond,Register tag)333     Condition testPrimitive(Condition cond, Register tag) {
334         MOZ_ASSERT(cond == Equal || cond == NotEqual);
335         cmp32(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET));
336         return cond == Equal ? Below : AboveOrEqual;
337     }
testError(Condition cond,Register tag)338     Condition testError(Condition cond, Register tag) {
339         return testMagic(cond, tag);
340     }
testBoolean(Condition cond,const Address & address)341     Condition testBoolean(Condition cond, const Address& address) {
342         MOZ_ASSERT(cond == Equal || cond == NotEqual);
343         cmp32(Operand(ToType(address)), ImmTag(JSVAL_TAG_BOOLEAN));
344         return cond;
345     }
testInt32(Condition cond,const Operand & operand)346     Condition testInt32(Condition cond, const Operand& operand) {
347         MOZ_ASSERT(cond == Equal || cond == NotEqual);
348         cmp32(ToType(operand), ImmTag(JSVAL_TAG_INT32));
349         return cond;
350     }
testInt32(Condition cond,const Address & address)351     Condition testInt32(Condition cond, const Address& address) {
352         MOZ_ASSERT(cond == Equal || cond == NotEqual);
353         return testInt32(cond, Operand(address));
354     }
testObject(Condition cond,const Operand & operand)355     Condition testObject(Condition cond, const Operand& operand) {
356         MOZ_ASSERT(cond == Equal || cond == NotEqual);
357         cmp32(ToType(operand), ImmTag(JSVAL_TAG_OBJECT));
358         return cond;
359     }
testObject(Condition cond,const Address & address)360     Condition testObject(Condition cond, const Address& address) {
361         MOZ_ASSERT(cond == Equal || cond == NotEqual);
362         return testObject(cond, Operand(address));
363     }
testDouble(Condition cond,const Operand & operand)364     Condition testDouble(Condition cond, const Operand& operand) {
365         MOZ_ASSERT(cond == Equal || cond == NotEqual);
366         Condition actual = (cond == Equal) ? Below : AboveOrEqual;
367         cmp32(ToType(operand), ImmTag(JSVAL_TAG_CLEAR));
368         return actual;
369     }
testDouble(Condition cond,const Address & address)370     Condition testDouble(Condition cond, const Address& address) {
371         MOZ_ASSERT(cond == Equal || cond == NotEqual);
372         return testDouble(cond, Operand(address));
373     }
374 
375 
testUndefined(Condition cond,const Operand & operand)376     Condition testUndefined(Condition cond, const Operand& operand) {
377         MOZ_ASSERT(cond == Equal || cond == NotEqual);
378         cmp32(ToType(operand), ImmTag(JSVAL_TAG_UNDEFINED));
379         return cond;
380     }
testUndefined(Condition cond,const Address & addr)381     Condition testUndefined(Condition cond, const Address& addr) {
382         return testUndefined(cond, Operand(addr));
383     }
testNull(Condition cond,const Operand & operand)384     Condition testNull(Condition cond, const Operand& operand) {
385         MOZ_ASSERT(cond == Equal || cond == NotEqual);
386         cmp32(ToType(operand), ImmTag(JSVAL_TAG_NULL));
387         return cond;
388     }
testNull(Condition cond,const Address & addr)389     Condition testNull(Condition cond, const Address& addr) {
390         return testNull(cond, Operand(addr));
391     }
392 
testUndefined(Condition cond,const ValueOperand & value)393     Condition testUndefined(Condition cond, const ValueOperand& value) {
394         return testUndefined(cond, value.typeReg());
395     }
testBoolean(Condition cond,const ValueOperand & value)396     Condition testBoolean(Condition cond, const ValueOperand& value) {
397         return testBoolean(cond, value.typeReg());
398     }
testInt32(Condition cond,const ValueOperand & value)399     Condition testInt32(Condition cond, const ValueOperand& value) {
400         return testInt32(cond, value.typeReg());
401     }
testDouble(Condition cond,const ValueOperand & value)402     Condition testDouble(Condition cond, const ValueOperand& value) {
403         return testDouble(cond, value.typeReg());
404     }
testNull(Condition cond,const ValueOperand & value)405     Condition testNull(Condition cond, const ValueOperand& value) {
406         return testNull(cond, value.typeReg());
407     }
testString(Condition cond,const ValueOperand & value)408     Condition testString(Condition cond, const ValueOperand& value) {
409         return testString(cond, value.typeReg());
410     }
testSymbol(Condition cond,const ValueOperand & value)411     Condition testSymbol(Condition cond, const ValueOperand& value) {
412         return testSymbol(cond, value.typeReg());
413     }
testObject(Condition cond,const ValueOperand & value)414     Condition testObject(Condition cond, const ValueOperand& value) {
415         return testObject(cond, value.typeReg());
416     }
testMagic(Condition cond,const ValueOperand & value)417     Condition testMagic(Condition cond, const ValueOperand& value) {
418         return testMagic(cond, value.typeReg());
419     }
testError(Condition cond,const ValueOperand & value)420     Condition testError(Condition cond, const ValueOperand& value) {
421         return testMagic(cond, value);
422     }
testNumber(Condition cond,const ValueOperand & value)423     Condition testNumber(Condition cond, const ValueOperand& value) {
424         return testNumber(cond, value.typeReg());
425     }
testGCThing(Condition cond,const ValueOperand & value)426     Condition testGCThing(Condition cond, const ValueOperand& value) {
427         return testGCThing(cond, value.typeReg());
428     }
testPrimitive(Condition cond,const ValueOperand & value)429     Condition testPrimitive(Condition cond, const ValueOperand& value) {
430         return testPrimitive(cond, value.typeReg());
431     }
432 
433 
testUndefined(Condition cond,const BaseIndex & address)434     Condition testUndefined(Condition cond, const BaseIndex& address) {
435         MOZ_ASSERT(cond == Equal || cond == NotEqual);
436         cmp32(tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED));
437         return cond;
438     }
testNull(Condition cond,const BaseIndex & address)439     Condition testNull(Condition cond, const BaseIndex& address) {
440         MOZ_ASSERT(cond == Equal || cond == NotEqual);
441         cmp32(tagOf(address), ImmTag(JSVAL_TAG_NULL));
442         return cond;
443     }
testBoolean(Condition cond,const BaseIndex & address)444     Condition testBoolean(Condition cond, const BaseIndex& address) {
445         MOZ_ASSERT(cond == Equal || cond == NotEqual);
446         cmp32(tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN));
447         return cond;
448     }
testString(Condition cond,const BaseIndex & address)449     Condition testString(Condition cond, const BaseIndex& address) {
450         MOZ_ASSERT(cond == Equal || cond == NotEqual);
451         cmp32(tagOf(address), ImmTag(JSVAL_TAG_STRING));
452         return cond;
453     }
testSymbol(Condition cond,const BaseIndex & address)454     Condition testSymbol(Condition cond, const BaseIndex& address) {
455         MOZ_ASSERT(cond == Equal || cond == NotEqual);
456         cmp32(tagOf(address), ImmTag(JSVAL_TAG_SYMBOL));
457         return cond;
458     }
testInt32(Condition cond,const BaseIndex & address)459     Condition testInt32(Condition cond, const BaseIndex& address) {
460         MOZ_ASSERT(cond == Equal || cond == NotEqual);
461         cmp32(tagOf(address), ImmTag(JSVAL_TAG_INT32));
462         return cond;
463     }
testObject(Condition cond,const BaseIndex & address)464     Condition testObject(Condition cond, const BaseIndex& address) {
465         MOZ_ASSERT(cond == Equal || cond == NotEqual);
466         cmp32(tagOf(address), ImmTag(JSVAL_TAG_OBJECT));
467         return cond;
468     }
testDouble(Condition cond,const BaseIndex & address)469     Condition testDouble(Condition cond, const BaseIndex& address) {
470         MOZ_ASSERT(cond == Equal || cond == NotEqual);
471         Condition actual = (cond == Equal) ? Below : AboveOrEqual;
472         cmp32(tagOf(address), ImmTag(JSVAL_TAG_CLEAR));
473         return actual;
474     }
testMagic(Condition cond,const BaseIndex & address)475     Condition testMagic(Condition cond, const BaseIndex& address) {
476         MOZ_ASSERT(cond == Equal || cond == NotEqual);
477         cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC));
478         return cond;
479     }
testGCThing(Condition cond,const BaseIndex & address)480     Condition testGCThing(Condition cond, const BaseIndex& address) {
481         MOZ_ASSERT(cond == Equal || cond == NotEqual);
482         cmp32(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
483         return cond == Equal ? AboveOrEqual : Below;
484     }
485 
testNullSet(Condition cond,const ValueOperand & value,Register dest)486     void testNullSet(Condition cond, const ValueOperand& value, Register dest) {
487         cond = testNull(cond, value);
488         emitSet(cond, dest);
489     }
490 
testObjectSet(Condition cond,const ValueOperand & value,Register dest)491     void testObjectSet(Condition cond, const ValueOperand& value, Register dest) {
492         cond = testObject(cond, value);
493         emitSet(cond, dest);
494     }
495 
testUndefinedSet(Condition cond,const ValueOperand & value,Register dest)496     void testUndefinedSet(Condition cond, const ValueOperand& value, Register dest) {
497         cond = testUndefined(cond, value);
498         emitSet(cond, dest);
499     }
500 
cmpPtr(Register lhs,const ImmWord rhs)501     void cmpPtr(Register lhs, const ImmWord rhs) {
502         cmpl(Imm32(rhs.value), lhs);
503     }
cmpPtr(Register lhs,const ImmPtr imm)504     void cmpPtr(Register lhs, const ImmPtr imm) {
505         cmpPtr(lhs, ImmWord(uintptr_t(imm.value)));
506     }
cmpPtr(Register lhs,const ImmGCPtr rhs)507     void cmpPtr(Register lhs, const ImmGCPtr rhs) {
508         cmpl(rhs, lhs);
509     }
cmpPtr(const Operand & lhs,Imm32 rhs)510     void cmpPtr(const Operand& lhs, Imm32 rhs) {
511         cmp32(lhs, rhs);
512     }
cmpPtr(const Operand & lhs,const ImmWord rhs)513     void cmpPtr(const Operand& lhs, const ImmWord rhs) {
514         cmp32(lhs, Imm32(rhs.value));
515     }
cmpPtr(const Operand & lhs,const ImmPtr imm)516     void cmpPtr(const Operand& lhs, const ImmPtr imm) {
517         cmpPtr(lhs, ImmWord(uintptr_t(imm.value)));
518     }
cmpPtr(const Operand & lhs,const ImmGCPtr rhs)519     void cmpPtr(const Operand& lhs, const ImmGCPtr rhs) {
520         cmpl(rhs, lhs);
521     }
cmpPtr(const Address & lhs,Register rhs)522     void cmpPtr(const Address& lhs, Register rhs) {
523         cmpPtr(Operand(lhs), rhs);
524     }
cmpPtr(const Operand & lhs,Register rhs)525     void cmpPtr(const Operand& lhs, Register rhs) {
526         cmp32(lhs, rhs);
527     }
cmpPtr(const Address & lhs,const ImmWord rhs)528     void cmpPtr(const Address& lhs, const ImmWord rhs) {
529         cmpPtr(Operand(lhs), rhs);
530     }
cmpPtr(const Address & lhs,const ImmPtr rhs)531     void cmpPtr(const Address& lhs, const ImmPtr rhs) {
532         cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
533     }
cmpPtr(const Address & lhs,const ImmGCPtr rhs)534     void cmpPtr(const Address& lhs, const ImmGCPtr rhs) {
535         cmpPtr(Operand(lhs), rhs);
536     }
cmpPtr(Register lhs,Register rhs)537     void cmpPtr(Register lhs, Register rhs) {
538         cmp32(lhs, rhs);
539     }
testPtr(Register lhs,Register rhs)540     void testPtr(Register lhs, Register rhs) {
541         test32(lhs, rhs);
542     }
testPtr(Register lhs,Imm32 rhs)543     void testPtr(Register lhs, Imm32 rhs) {
544         test32(lhs, rhs);
545     }
testPtr(Register lhs,ImmWord rhs)546     void testPtr(Register lhs, ImmWord rhs) {
547         test32(lhs, Imm32(rhs.value));
548     }
testPtr(const Operand & lhs,Imm32 rhs)549     void testPtr(const Operand& lhs, Imm32 rhs) {
550         test32(lhs, rhs);
551     }
testPtr(const Operand & lhs,ImmWord rhs)552     void testPtr(const Operand& lhs, ImmWord rhs) {
553         test32(lhs, Imm32(rhs.value));
554     }
555 
556     /////////////////////////////////////////////////////////////////
557     // Common interface.
558     /////////////////////////////////////////////////////////////////
559 
560     template <typename T, typename S>
branchPtr(Condition cond,T lhs,S ptr,RepatchLabel * label)561     void branchPtr(Condition cond, T lhs, S ptr, RepatchLabel* label) {
562         cmpPtr(Operand(lhs), ptr);
563         j(cond, label);
564     }
565 
566     CodeOffsetJump jumpWithPatch(RepatchLabel* label, Label* documentation = nullptr) {
567         jump(label);
568         return CodeOffsetJump(size());
569     }
570 
571     CodeOffsetJump jumpWithPatch(RepatchLabel* label, Assembler::Condition cond,
572                                  Label* documentation = nullptr)
573     {
574         j(cond, label);
575         return CodeOffsetJump(size());
576     }
577 
578     CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation = nullptr) {
579         return jumpWithPatch(label);
580     }
581 
branchPtr(Condition cond,Register lhs,Register rhs,RepatchLabel * label)582     void branchPtr(Condition cond, Register lhs, Register rhs, RepatchLabel* label) {
583         cmpPtr(lhs, rhs);
584         j(cond, label);
585     }
586 
movePtr(ImmWord imm,Register dest)587     void movePtr(ImmWord imm, Register dest) {
588         movl(Imm32(imm.value), dest);
589     }
movePtr(ImmPtr imm,Register dest)590     void movePtr(ImmPtr imm, Register dest) {
591         movl(imm, dest);
592     }
movePtr(wasm::SymbolicAddress imm,Register dest)593     void movePtr(wasm::SymbolicAddress imm, Register dest) {
594         mov(imm, dest);
595     }
movePtr(ImmGCPtr imm,Register dest)596     void movePtr(ImmGCPtr imm, Register dest) {
597         movl(imm, dest);
598     }
loadPtr(const Address & address,Register dest)599     void loadPtr(const Address& address, Register dest) {
600         movl(Operand(address), dest);
601     }
loadPtr(const Operand & src,Register dest)602     void loadPtr(const Operand& src, Register dest) {
603         movl(src, dest);
604     }
loadPtr(const BaseIndex & src,Register dest)605     void loadPtr(const BaseIndex& src, Register dest) {
606         movl(Operand(src), dest);
607     }
loadPtr(AbsoluteAddress address,Register dest)608     void loadPtr(AbsoluteAddress address, Register dest) {
609         movl(Operand(address), dest);
610     }
loadPrivate(const Address & src,Register dest)611     void loadPrivate(const Address& src, Register dest) {
612         movl(payloadOf(src), dest);
613     }
load32(AbsoluteAddress address,Register dest)614     void load32(AbsoluteAddress address, Register dest) {
615         movl(Operand(address), dest);
616     }
load64(const Address & address,Register64 dest)617     void load64(const Address& address, Register64 dest) {
618         movl(Operand(Address(address.base, address.offset + INT64LOW_OFFSET)), dest.low);
619         int32_t highOffset = (address.offset < 0) ? -int32_t(INT64HIGH_OFFSET) : INT64HIGH_OFFSET;
620         movl(Operand(Address(address.base, address.offset + highOffset)), dest.high);
621     }
622     template <typename T>
storePtr(ImmWord imm,T address)623     void storePtr(ImmWord imm, T address) {
624         movl(Imm32(imm.value), Operand(address));
625     }
626     template <typename T>
storePtr(ImmPtr imm,T address)627     void storePtr(ImmPtr imm, T address) {
628         storePtr(ImmWord(uintptr_t(imm.value)), address);
629     }
630     template <typename T>
storePtr(ImmGCPtr imm,T address)631     void storePtr(ImmGCPtr imm, T address) {
632         movl(imm, Operand(address));
633     }
storePtr(Register src,const Address & address)634     void storePtr(Register src, const Address& address) {
635         movl(src, Operand(address));
636     }
storePtr(Register src,const BaseIndex & address)637     void storePtr(Register src, const BaseIndex& address) {
638         movl(src, Operand(address));
639     }
storePtr(Register src,const Operand & dest)640     void storePtr(Register src, const Operand& dest) {
641         movl(src, dest);
642     }
storePtr(Register src,AbsoluteAddress address)643     void storePtr(Register src, AbsoluteAddress address) {
644         movl(src, Operand(address));
645     }
store32(Register src,AbsoluteAddress address)646     void store32(Register src, AbsoluteAddress address) {
647         movl(src, Operand(address));
648     }
store16(Register src,AbsoluteAddress address)649     void store16(Register src, AbsoluteAddress address) {
650         movw(src, Operand(address));
651     }
store64(Register64 src,Address address)652     void store64(Register64 src, Address address) {
653         movl(src.low, Operand(Address(address.base, address.offset + INT64LOW_OFFSET)));
654         movl(src.high, Operand(Address(address.base, address.offset + INT64HIGH_OFFSET)));
655     }
store64(Imm64 imm,Address address)656     void store64(Imm64 imm, Address address) {
657         movl(imm.low(), Operand(Address(address.base, address.offset + INT64LOW_OFFSET)));
658         movl(imm.hi(), Operand(Address(address.base, address.offset + INT64HIGH_OFFSET)));
659     }
660 
setStackArg(Register reg,uint32_t arg)661     void setStackArg(Register reg, uint32_t arg) {
662         movl(reg, Operand(esp, arg * sizeof(intptr_t)));
663     }
664 
665     // Note: this function clobbers the source register.
boxDouble(FloatRegister src,const ValueOperand & dest)666     void boxDouble(FloatRegister src, const ValueOperand& dest) {
667         if (Assembler::HasSSE41()) {
668             vmovd(src, dest.payloadReg());
669             vpextrd(1, src, dest.typeReg());
670         } else {
671             vmovd(src, dest.payloadReg());
672             vpsrldq(Imm32(4), src, src);
673             vmovd(src, dest.typeReg());
674         }
675     }
boxNonDouble(JSValueType type,Register src,const ValueOperand & dest)676     void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) {
677         if (src != dest.payloadReg())
678             movl(src, dest.payloadReg());
679         movl(ImmType(type), dest.typeReg());
680     }
681 
unboxNonDouble(const ValueOperand & src,Register dest)682     void unboxNonDouble(const ValueOperand& src, Register dest) {
683         if (src.payloadReg() != dest)
684             movl(src.payloadReg(), dest);
685     }
unboxNonDouble(const Address & src,Register dest)686     void unboxNonDouble(const Address& src, Register dest) {
687         movl(payloadOf(src), dest);
688     }
unboxNonDouble(const BaseIndex & src,Register dest)689     void unboxNonDouble(const BaseIndex& src, Register dest) {
690         movl(payloadOf(src), dest);
691     }
unboxInt32(const ValueOperand & src,Register dest)692     void unboxInt32(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
unboxInt32(const Address & src,Register dest)693     void unboxInt32(const Address& src, Register dest) { unboxNonDouble(src, dest); }
unboxBoolean(const ValueOperand & src,Register dest)694     void unboxBoolean(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
unboxBoolean(const Address & src,Register dest)695     void unboxBoolean(const Address& src, Register dest) { unboxNonDouble(src, dest); }
unboxString(const ValueOperand & src,Register dest)696     void unboxString(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
unboxString(const Address & src,Register dest)697     void unboxString(const Address& src, Register dest) { unboxNonDouble(src, dest); }
unboxSymbol(const ValueOperand & src,Register dest)698     void unboxSymbol(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
unboxSymbol(const Address & src,Register dest)699     void unboxSymbol(const Address& src, Register dest) { unboxNonDouble(src, dest); }
unboxObject(const ValueOperand & src,Register dest)700     void unboxObject(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
unboxObject(const Address & src,Register dest)701     void unboxObject(const Address& src, Register dest) { unboxNonDouble(src, dest); }
unboxObject(const BaseIndex & src,Register dest)702     void unboxObject(const BaseIndex& src, Register dest) { unboxNonDouble(src, dest); }
unboxDouble(const Address & src,FloatRegister dest)703     void unboxDouble(const Address& src, FloatRegister dest) {
704         loadDouble(Operand(src), dest);
705     }
unboxDouble(const ValueOperand & src,FloatRegister dest)706     void unboxDouble(const ValueOperand& src, FloatRegister dest) {
707         MOZ_ASSERT(dest != ScratchDoubleReg);
708         if (Assembler::HasSSE41()) {
709             vmovd(src.payloadReg(), dest);
710             vpinsrd(1, src.typeReg(), dest, dest);
711         } else {
712             vmovd(src.payloadReg(), dest);
713             vmovd(src.typeReg(), ScratchDoubleReg);
714             vunpcklps(ScratchDoubleReg, dest, dest);
715         }
716     }
unboxDouble(const Operand & payload,const Operand & type,Register scratch,FloatRegister dest)717     void unboxDouble(const Operand& payload, const Operand& type,
718                      Register scratch, FloatRegister dest) {
719         MOZ_ASSERT(dest != ScratchDoubleReg);
720         if (Assembler::HasSSE41()) {
721             movl(payload, scratch);
722             vmovd(scratch, dest);
723             movl(type, scratch);
724             vpinsrd(1, scratch, dest, dest);
725         } else {
726             movl(payload, scratch);
727             vmovd(scratch, dest);
728             movl(type, scratch);
729             vmovd(scratch, ScratchDoubleReg);
730             vunpcklps(ScratchDoubleReg, dest, dest);
731         }
732     }
733     inline void unboxValue(const ValueOperand& src, AnyRegister dest);
unboxPrivate(const ValueOperand & src,Register dest)734     void unboxPrivate(const ValueOperand& src, Register dest) {
735         if (src.payloadReg() != dest)
736             movl(src.payloadReg(), dest);
737     }
738 
notBoolean(const ValueOperand & val)739     void notBoolean(const ValueOperand& val) {
740         xorl(Imm32(1), val.payloadReg());
741     }
742 
743     // Extended unboxing API. If the payload is already in a register, returns
744     // that register. Otherwise, provides a move to the given scratch register,
745     // and returns that.
extractObject(const Address & address,Register scratch)746     Register extractObject(const Address& address, Register scratch) {
747         movl(payloadOf(address), scratch);
748         return scratch;
749     }
extractObject(const ValueOperand & value,Register scratch)750     Register extractObject(const ValueOperand& value, Register scratch) {
751         return value.payloadReg();
752     }
extractInt32(const ValueOperand & value,Register scratch)753     Register extractInt32(const ValueOperand& value, Register scratch) {
754         return value.payloadReg();
755     }
extractBoolean(const ValueOperand & value,Register scratch)756     Register extractBoolean(const ValueOperand& value, Register scratch) {
757         return value.payloadReg();
758     }
extractTag(const Address & address,Register scratch)759     Register extractTag(const Address& address, Register scratch) {
760         movl(tagOf(address), scratch);
761         return scratch;
762     }
extractTag(const ValueOperand & value,Register scratch)763     Register extractTag(const ValueOperand& value, Register scratch) {
764         return value.typeReg();
765     }
766 
boolValueToDouble(const ValueOperand & operand,FloatRegister dest)767     void boolValueToDouble(const ValueOperand& operand, FloatRegister dest) {
768         convertInt32ToDouble(operand.payloadReg(), dest);
769     }
boolValueToFloat32(const ValueOperand & operand,FloatRegister dest)770     void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
771         convertInt32ToFloat32(operand.payloadReg(), dest);
772     }
int32ValueToDouble(const ValueOperand & operand,FloatRegister dest)773     void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest) {
774         convertInt32ToDouble(operand.payloadReg(), dest);
775     }
int32ValueToFloat32(const ValueOperand & operand,FloatRegister dest)776     void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
777         convertInt32ToFloat32(operand.payloadReg(), dest);
778     }
779 
780     void loadConstantDouble(double d, FloatRegister dest);
781     void loadConstantFloat32(float f, FloatRegister dest);
782     void loadConstantDouble(wasm::RawF64 d, FloatRegister dest);
783     void loadConstantFloat32(wasm::RawF32 f, FloatRegister dest);
784 
785     void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest);
786     void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest);
787 
testInt32Truthy(bool truthy,const ValueOperand & operand)788     Condition testInt32Truthy(bool truthy, const ValueOperand& operand) {
789         test32(operand.payloadReg(), operand.payloadReg());
790         return truthy ? NonZero : Zero;
791     }
testStringTruthy(bool truthy,const ValueOperand & value)792     Condition testStringTruthy(bool truthy, const ValueOperand& value) {
793         Register string = value.payloadReg();
794         cmp32(Operand(string, JSString::offsetOfLength()), Imm32(0));
795         return truthy ? Assembler::NotEqual : Assembler::Equal;
796     }
797 
798     template <typename T>
799     inline void loadInt32OrDouble(const T& src, FloatRegister dest);
800 
801     template <typename T>
802     inline void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest);
803 
804     template <typename T>
storeUnboxedPayload(ValueOperand value,T address,size_t nbytes)805     void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
806         switch (nbytes) {
807           case 4:
808             storePtr(value.payloadReg(), address);
809             return;
810           case 1:
811             store8(value.payloadReg(), address);
812             return;
813           default: MOZ_CRASH("Bad payload width");
814         }
815     }
816 
loadInstructionPointerAfterCall(Register dest)817     void loadInstructionPointerAfterCall(Register dest) {
818         movl(Operand(StackPointer, 0x0), dest);
819     }
820 
821     // Note: this function clobbers the source register.
822     inline void convertUInt32ToDouble(Register src, FloatRegister dest);
823 
824     // Note: this function clobbers the source register.
825     inline void convertUInt32ToFloat32(Register src, FloatRegister dest);
826 
827     void convertUInt64ToFloat32(Register64 src, FloatRegister dest, Register temp);
828     void convertInt64ToFloat32(Register64 src, FloatRegister dest);
829     static bool convertUInt64ToDoubleNeedsTemp();
830     void convertUInt64ToDouble(Register64 src, FloatRegister dest, Register temp);
831     void convertInt64ToDouble(Register64 src, FloatRegister dest);
832 
833     void wasmTruncateDoubleToInt64(FloatRegister input, Register64 output, Label* oolEntry,
834                                    Label* oolRejoin, FloatRegister tempDouble);
835     void wasmTruncateDoubleToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
836                                     Label* oolRejoin, FloatRegister tempDouble);
837     void wasmTruncateFloat32ToInt64(FloatRegister input, Register64 output, Label* oolEntry,
838                                     Label* oolRejoin, FloatRegister tempDouble);
839     void wasmTruncateFloat32ToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
840                                      Label* oolRejoin, FloatRegister tempDouble);
841 
incrementInt32Value(const Address & addr)842     void incrementInt32Value(const Address& addr) {
843         addl(Imm32(1), payloadOf(addr));
844     }
845 
846     inline void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure);
847 
loadWasmGlobalPtr(uint32_t globalDataOffset,Register dest)848     void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) {
849         CodeOffset label = movlWithPatch(PatchedAbsoluteAddress(), dest);
850         append(wasm::GlobalAccess(label, globalDataOffset));
851     }
loadWasmPinnedRegsFromTls()852     void loadWasmPinnedRegsFromTls() {
853         // x86 doesn't have any pinned registers.
854     }
855 
856   public:
857     // Used from within an Exit frame to handle a pending exception.
858     void handleFailureWithHandlerTail(void* handler);
859 
860     // Instrumentation for entering and leaving the profiler.
861     void profilerEnterFrame(Register framePtr, Register scratch);
862     void profilerExitFrame();
863 };
864 
865 typedef MacroAssemblerX86 MacroAssemblerSpecific;
866 
867 } // namespace jit
868 } // namespace js
869 
870 #endif /* jit_x86_MacroAssembler_x86_h */
871