1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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 "jit/MoveResolver.h"
11 #include "jit/x86-shared/MacroAssembler-x86-shared.h"
12 #include "js/HeapAPI.h"
13 #include "vm/BigIntType.h"  // JS::BigInt
14 #include "vm/Realm.h"
15 #include "wasm/WasmTypes.h"
16 
17 namespace js {
18 namespace jit {
19 
20 // See documentation for ScratchTagScope and ScratchTagScopeRelease in
21 // MacroAssembler-x64.h.
22 
23 class ScratchTagScope {
24   const ValueOperand& v_;
25 
26  public:
ScratchTagScope(MacroAssembler &,const ValueOperand & v)27   ScratchTagScope(MacroAssembler&, const ValueOperand& v) : v_(v) {}
Register()28   operator Register() { return v_.typeReg(); }
release()29   void release() {}
reacquire()30   void reacquire() {}
31 };
32 
33 class ScratchTagScopeRelease {
34  public:
ScratchTagScopeRelease(ScratchTagScope *)35   explicit ScratchTagScopeRelease(ScratchTagScope*) {}
36 };
37 
38 class MacroAssemblerX86 : public MacroAssemblerX86Shared {
39  private:
40   // Perform a downcast. Should be removed by Bug 996602.
41   MacroAssembler& asMasm();
42   const MacroAssembler& asMasm() const;
43 
44  protected:
45   MoveResolver moveResolver_;
46 
47  private:
payloadOfAfterStackPush(const Address & address)48   Operand payloadOfAfterStackPush(const Address& address) {
49     // If we are basing off %esp, the address will be invalid after the
50     // first push.
51     if (address.base == StackPointer) {
52       return Operand(address.base, address.offset + 4);
53     }
54     return payloadOf(address);
55   }
payloadOf(const Address & address)56   Operand payloadOf(const Address& address) {
57     return Operand(address.base, address.offset);
58   }
payloadOf(const BaseIndex & address)59   Operand payloadOf(const BaseIndex& address) {
60     return Operand(address.base, address.index, address.scale, address.offset);
61   }
tagOf(const Address & address)62   Operand tagOf(const Address& address) {
63     return Operand(address.base, address.offset + 4);
64   }
tagOf(const BaseIndex & address)65   Operand tagOf(const BaseIndex& address) {
66     return Operand(address.base, address.index, address.scale,
67                    address.offset + 4);
68   }
69 
70   void setupABICall(uint32_t args);
71 
72   void vpPatchOpSimd128(const SimdConstant& v, FloatRegister reg,
73                         void (X86Encoding::BaseAssemblerX86::*op)(
74                             const void* address,
75                             X86Encoding::XMMRegisterID srcId,
76                             X86Encoding::XMMRegisterID destId));
77 
78   void vpPatchOpSimd128(const SimdConstant& v, FloatRegister reg,
79                         size_t (X86Encoding::BaseAssemblerX86::*op)(
80                             const void* address,
81                             X86Encoding::XMMRegisterID srcId,
82                             X86Encoding::XMMRegisterID destId));
83 
84  public:
85   using MacroAssemblerX86Shared::call;
86   using MacroAssemblerX86Shared::load32;
87   using MacroAssemblerX86Shared::store16;
88   using MacroAssemblerX86Shared::store32;
89 
MacroAssemblerX86()90   MacroAssemblerX86() {}
91 
92   // The buffer is about to be linked, make sure any constant pools or excess
93   // bookkeeping has been flushed to the instruction stream.
94   void finish();
95 
96   /////////////////////////////////////////////////////////////////
97   // X86-specific interface.
98   /////////////////////////////////////////////////////////////////
99 
ToPayload(Operand base)100   Operand ToPayload(Operand base) { return base; }
ToPayload(Address base)101   Address ToPayload(Address base) { return base; }
ToPayload(BaseIndex base)102   BaseIndex ToPayload(BaseIndex base) { return base; }
ToType(Operand base)103   Operand ToType(Operand base) {
104     switch (base.kind()) {
105       case Operand::MEM_REG_DISP:
106         return Operand(Register::FromCode(base.base()),
107                        base.disp() + sizeof(void*));
108 
109       case Operand::MEM_SCALE:
110         return Operand(Register::FromCode(base.base()),
111                        Register::FromCode(base.index()), base.scale(),
112                        base.disp() + sizeof(void*));
113 
114       default:
115         MOZ_CRASH("unexpected operand kind");
116     }
117   }
ToType(Address base)118   Address ToType(Address base) { return ToType(Operand(base)).toAddress(); }
ToType(BaseIndex base)119   BaseIndex ToType(BaseIndex base) {
120     return ToType(Operand(base)).toBaseIndex();
121   }
122 
123   template <typename T>
add64FromMemory(const T & address,Register64 dest)124   void add64FromMemory(const T& address, Register64 dest) {
125     addl(Operand(LowWord(address)), dest.low);
126     adcl(Operand(HighWord(address)), dest.high);
127   }
128   template <typename T>
sub64FromMemory(const T & address,Register64 dest)129   void sub64FromMemory(const T& address, Register64 dest) {
130     subl(Operand(LowWord(address)), dest.low);
131     sbbl(Operand(HighWord(address)), dest.high);
132   }
133   template <typename T>
and64FromMemory(const T & address,Register64 dest)134   void and64FromMemory(const T& address, Register64 dest) {
135     andl(Operand(LowWord(address)), dest.low);
136     andl(Operand(HighWord(address)), dest.high);
137   }
138   template <typename T>
or64FromMemory(const T & address,Register64 dest)139   void or64FromMemory(const T& address, Register64 dest) {
140     orl(Operand(LowWord(address)), dest.low);
141     orl(Operand(HighWord(address)), dest.high);
142   }
143   template <typename T>
xor64FromMemory(const T & address,Register64 dest)144   void xor64FromMemory(const T& address, Register64 dest) {
145     xorl(Operand(LowWord(address)), dest.low);
146     xorl(Operand(HighWord(address)), dest.high);
147   }
148 
149   /////////////////////////////////////////////////////////////////
150   // X86/X64-common interface.
151   /////////////////////////////////////////////////////////////////
storeValue(ValueOperand val,Operand dest)152   void storeValue(ValueOperand val, Operand dest) {
153     movl(val.payloadReg(), ToPayload(dest));
154     movl(val.typeReg(), ToType(dest));
155   }
storeValue(ValueOperand val,const Address & dest)156   void storeValue(ValueOperand val, const Address& dest) {
157     storeValue(val, Operand(dest));
158   }
159   template <typename T>
storeValue(JSValueType type,Register reg,const T & dest)160   void storeValue(JSValueType type, Register reg, const T& dest) {
161     storeTypeTag(ImmTag(JSVAL_TYPE_TO_TAG(type)), Operand(dest));
162     storePayload(reg, Operand(dest));
163   }
164   template <typename T>
storeValue(const Value & val,const T & dest)165   void storeValue(const Value& val, const T& dest) {
166     storeTypeTag(ImmTag(val.toNunboxTag()), Operand(dest));
167     storePayload(val, Operand(dest));
168   }
storeValue(ValueOperand val,BaseIndex dest)169   void storeValue(ValueOperand val, BaseIndex dest) {
170     storeValue(val, Operand(dest));
171   }
storeValue(const Address & src,const Address & dest,Register temp)172   void storeValue(const Address& src, const Address& dest, Register temp) {
173     MOZ_ASSERT(src.base != temp);
174     MOZ_ASSERT(dest.base != temp);
175 
176     load32(ToType(src), temp);
177     store32(temp, ToType(dest));
178 
179     load32(ToPayload(src), temp);
180     store32(temp, ToPayload(dest));
181   }
loadValue(Operand src,ValueOperand val)182   void loadValue(Operand src, ValueOperand val) {
183     Operand payload = ToPayload(src);
184     Operand type = ToType(src);
185 
186     // Ensure that loading the payload does not erase the pointer to the
187     // Value in memory or the index.
188     Register baseReg = Register::FromCode(src.base());
189     Register indexReg = (src.kind() == Operand::MEM_SCALE)
190                             ? Register::FromCode(src.index())
191                             : InvalidReg;
192 
193     // If we have a BaseIndex that uses both result registers, first compute
194     // the address and then load the Value from there.
195     if ((baseReg == val.payloadReg() && indexReg == val.typeReg()) ||
196         (baseReg == val.typeReg() && indexReg == val.payloadReg())) {
197       computeEffectiveAddress(src, val.scratchReg());
198       loadValue(Address(val.scratchReg(), 0), val);
199       return;
200     }
201 
202     if (baseReg == val.payloadReg() || indexReg == val.payloadReg()) {
203       MOZ_ASSERT(baseReg != val.typeReg());
204       MOZ_ASSERT(indexReg != val.typeReg());
205 
206       movl(type, val.typeReg());
207       movl(payload, val.payloadReg());
208     } else {
209       MOZ_ASSERT(baseReg != val.payloadReg());
210       MOZ_ASSERT(indexReg != val.payloadReg());
211 
212       movl(payload, val.payloadReg());
213       movl(type, val.typeReg());
214     }
215   }
loadValue(Address src,ValueOperand val)216   void loadValue(Address src, ValueOperand val) {
217     loadValue(Operand(src), val);
218   }
loadValue(const BaseIndex & src,ValueOperand val)219   void loadValue(const BaseIndex& src, ValueOperand val) {
220     loadValue(Operand(src), val);
221   }
loadUnalignedValue(const Address & src,ValueOperand dest)222   void loadUnalignedValue(const Address& src, ValueOperand dest) {
223     loadValue(src, dest);
224   }
tagValue(JSValueType type,Register payload,ValueOperand dest)225   void tagValue(JSValueType type, Register payload, ValueOperand dest) {
226     MOZ_ASSERT(dest.typeReg() != dest.payloadReg());
227     if (payload != dest.payloadReg()) {
228       movl(payload, dest.payloadReg());
229     }
230     movl(ImmType(type), dest.typeReg());
231   }
pushValue(ValueOperand val)232   void pushValue(ValueOperand val) {
233     push(val.typeReg());
234     push(val.payloadReg());
235   }
popValue(ValueOperand val)236   void popValue(ValueOperand val) {
237     pop(val.payloadReg());
238     pop(val.typeReg());
239   }
pushValue(const Value & val)240   void pushValue(const Value& val) {
241     push(Imm32(val.toNunboxTag()));
242     if (val.isGCThing()) {
243       push(ImmGCPtr(val.toGCThing()));
244     } else {
245       push(Imm32(val.toNunboxPayload()));
246     }
247   }
pushValue(JSValueType type,Register reg)248   void pushValue(JSValueType type, Register reg) {
249     push(ImmTag(JSVAL_TYPE_TO_TAG(type)));
250     push(reg);
251   }
pushValue(const Address & addr)252   void pushValue(const Address& addr) {
253     push(tagOf(addr));
254     push(payloadOfAfterStackPush(addr));
255   }
push64(Register64 src)256   void push64(Register64 src) {
257     push(src.high);
258     push(src.low);
259   }
pop64(Register64 dest)260   void pop64(Register64 dest) {
261     pop(dest.low);
262     pop(dest.high);
263   }
storePayload(const Value & val,Operand dest)264   void storePayload(const Value& val, Operand dest) {
265     if (val.isGCThing()) {
266       movl(ImmGCPtr(val.toGCThing()), ToPayload(dest));
267     } else {
268       movl(Imm32(val.toNunboxPayload()), ToPayload(dest));
269     }
270   }
storePayload(Register src,Operand dest)271   void storePayload(Register src, Operand dest) { movl(src, ToPayload(dest)); }
storeTypeTag(ImmTag tag,Operand dest)272   void storeTypeTag(ImmTag tag, Operand dest) { movl(tag, ToType(dest)); }
273 
movePtr(Register src,Register dest)274   void movePtr(Register src, Register dest) { movl(src, dest); }
movePtr(Register src,const Operand & dest)275   void movePtr(Register src, const Operand& dest) { movl(src, dest); }
276 
splitTagForTest(const ValueOperand & value,ScratchTagScope & tag)277   void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag) {
278     MOZ_ASSERT(value.typeReg() == tag);
279   }
280 
testUndefined(Condition cond,Register tag)281   Condition testUndefined(Condition cond, Register tag) {
282     MOZ_ASSERT(cond == Equal || cond == NotEqual);
283     cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED));
284     return cond;
285   }
testBoolean(Condition cond,Register tag)286   Condition testBoolean(Condition cond, Register tag) {
287     MOZ_ASSERT(cond == Equal || cond == NotEqual);
288     cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN));
289     return cond;
290   }
testInt32(Condition cond,Register tag)291   Condition testInt32(Condition cond, Register tag) {
292     MOZ_ASSERT(cond == Equal || cond == NotEqual);
293     cmp32(tag, ImmTag(JSVAL_TAG_INT32));
294     return cond;
295   }
testDouble(Condition cond,Register tag)296   Condition testDouble(Condition cond, Register tag) {
297     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
298     Condition actual = (cond == Equal) ? Below : AboveOrEqual;
299     cmp32(tag, ImmTag(JSVAL_TAG_CLEAR));
300     return actual;
301   }
testNull(Condition cond,Register tag)302   Condition testNull(Condition cond, Register tag) {
303     MOZ_ASSERT(cond == Equal || cond == NotEqual);
304     cmp32(tag, ImmTag(JSVAL_TAG_NULL));
305     return cond;
306   }
testString(Condition cond,Register tag)307   Condition testString(Condition cond, Register tag) {
308     MOZ_ASSERT(cond == Equal || cond == NotEqual);
309     cmp32(tag, ImmTag(JSVAL_TAG_STRING));
310     return cond;
311   }
testSymbol(Condition cond,Register tag)312   Condition testSymbol(Condition cond, Register tag) {
313     MOZ_ASSERT(cond == Equal || cond == NotEqual);
314     cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL));
315     return cond;
316   }
testBigInt(Condition cond,Register tag)317   Condition testBigInt(Condition cond, Register tag) {
318     MOZ_ASSERT(cond == Equal || cond == NotEqual);
319     cmp32(tag, ImmTag(JSVAL_TAG_BIGINT));
320     return cond;
321   }
testObject(Condition cond,Register tag)322   Condition testObject(Condition cond, Register tag) {
323     MOZ_ASSERT(cond == Equal || cond == NotEqual);
324     cmp32(tag, ImmTag(JSVAL_TAG_OBJECT));
325     return cond;
326   }
testNumber(Condition cond,Register tag)327   Condition testNumber(Condition cond, Register tag) {
328     MOZ_ASSERT(cond == Equal || cond == NotEqual);
329     cmp32(tag, ImmTag(JS::detail::ValueUpperInclNumberTag));
330     return cond == Equal ? BelowOrEqual : Above;
331   }
testGCThing(Condition cond,Register tag)332   Condition testGCThing(Condition cond, Register tag) {
333     MOZ_ASSERT(cond == Equal || cond == NotEqual);
334     cmp32(tag, ImmTag(JS::detail::ValueLowerInclGCThingTag));
335     return cond == Equal ? AboveOrEqual : Below;
336   }
testGCThing(Condition cond,const Address & address)337   Condition testGCThing(Condition cond, const Address& address) {
338     MOZ_ASSERT(cond == Equal || cond == NotEqual);
339     cmp32(tagOf(address), ImmTag(JS::detail::ValueLowerInclGCThingTag));
340     return cond == Equal ? AboveOrEqual : Below;
341   }
testMagic(Condition cond,const Address & address)342   Condition testMagic(Condition cond, const Address& address) {
343     MOZ_ASSERT(cond == Equal || cond == NotEqual);
344     cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC));
345     return cond;
346   }
testMagic(Condition cond,Register tag)347   Condition testMagic(Condition cond, Register tag) {
348     MOZ_ASSERT(cond == Equal || cond == NotEqual);
349     cmp32(tag, ImmTag(JSVAL_TAG_MAGIC));
350     return cond;
351   }
testMagic(Condition cond,const Operand & operand)352   Condition testMagic(Condition cond, const Operand& operand) {
353     MOZ_ASSERT(cond == Equal || cond == NotEqual);
354     cmp32(ToType(operand), ImmTag(JSVAL_TAG_MAGIC));
355     return cond;
356   }
testPrimitive(Condition cond,Register tag)357   Condition testPrimitive(Condition cond, Register tag) {
358     MOZ_ASSERT(cond == Equal || cond == NotEqual);
359     cmp32(tag, ImmTag(JS::detail::ValueUpperExclPrimitiveTag));
360     return cond == Equal ? Below : AboveOrEqual;
361   }
testError(Condition cond,Register tag)362   Condition testError(Condition cond, Register tag) {
363     return testMagic(cond, tag);
364   }
testBoolean(Condition cond,const Address & address)365   Condition testBoolean(Condition cond, const Address& address) {
366     MOZ_ASSERT(cond == Equal || cond == NotEqual);
367     cmp32(Operand(ToType(address)), ImmTag(JSVAL_TAG_BOOLEAN));
368     return cond;
369   }
testInt32(Condition cond,const Operand & operand)370   Condition testInt32(Condition cond, const Operand& operand) {
371     MOZ_ASSERT(cond == Equal || cond == NotEqual);
372     cmp32(ToType(operand), ImmTag(JSVAL_TAG_INT32));
373     return cond;
374   }
testInt32(Condition cond,const Address & address)375   Condition testInt32(Condition cond, const Address& address) {
376     MOZ_ASSERT(cond == Equal || cond == NotEqual);
377     return testInt32(cond, Operand(address));
378   }
testObject(Condition cond,const Operand & operand)379   Condition testObject(Condition cond, const Operand& operand) {
380     MOZ_ASSERT(cond == Equal || cond == NotEqual);
381     cmp32(ToType(operand), ImmTag(JSVAL_TAG_OBJECT));
382     return cond;
383   }
testObject(Condition cond,const Address & address)384   Condition testObject(Condition cond, const Address& address) {
385     MOZ_ASSERT(cond == Equal || cond == NotEqual);
386     return testObject(cond, Operand(address));
387   }
testDouble(Condition cond,const Operand & operand)388   Condition testDouble(Condition cond, const Operand& operand) {
389     MOZ_ASSERT(cond == Equal || cond == NotEqual);
390     Condition actual = (cond == Equal) ? Below : AboveOrEqual;
391     cmp32(ToType(operand), ImmTag(JSVAL_TAG_CLEAR));
392     return actual;
393   }
testDouble(Condition cond,const Address & address)394   Condition testDouble(Condition cond, const Address& address) {
395     MOZ_ASSERT(cond == Equal || cond == NotEqual);
396     return testDouble(cond, Operand(address));
397   }
398 
testUndefined(Condition cond,const Operand & operand)399   Condition testUndefined(Condition cond, const Operand& operand) {
400     MOZ_ASSERT(cond == Equal || cond == NotEqual);
401     cmp32(ToType(operand), ImmTag(JSVAL_TAG_UNDEFINED));
402     return cond;
403   }
testUndefined(Condition cond,const Address & addr)404   Condition testUndefined(Condition cond, const Address& addr) {
405     return testUndefined(cond, Operand(addr));
406   }
testNull(Condition cond,const Operand & operand)407   Condition testNull(Condition cond, const Operand& operand) {
408     MOZ_ASSERT(cond == Equal || cond == NotEqual);
409     cmp32(ToType(operand), ImmTag(JSVAL_TAG_NULL));
410     return cond;
411   }
testNull(Condition cond,const Address & addr)412   Condition testNull(Condition cond, const Address& addr) {
413     return testNull(cond, Operand(addr));
414   }
415 
testUndefined(Condition cond,const ValueOperand & value)416   Condition testUndefined(Condition cond, const ValueOperand& value) {
417     return testUndefined(cond, value.typeReg());
418   }
testBoolean(Condition cond,const ValueOperand & value)419   Condition testBoolean(Condition cond, const ValueOperand& value) {
420     return testBoolean(cond, value.typeReg());
421   }
testInt32(Condition cond,const ValueOperand & value)422   Condition testInt32(Condition cond, const ValueOperand& value) {
423     return testInt32(cond, value.typeReg());
424   }
testDouble(Condition cond,const ValueOperand & value)425   Condition testDouble(Condition cond, const ValueOperand& value) {
426     return testDouble(cond, value.typeReg());
427   }
testNull(Condition cond,const ValueOperand & value)428   Condition testNull(Condition cond, const ValueOperand& value) {
429     return testNull(cond, value.typeReg());
430   }
testString(Condition cond,const ValueOperand & value)431   Condition testString(Condition cond, const ValueOperand& value) {
432     return testString(cond, value.typeReg());
433   }
testSymbol(Condition cond,const ValueOperand & value)434   Condition testSymbol(Condition cond, const ValueOperand& value) {
435     return testSymbol(cond, value.typeReg());
436   }
testBigInt(Condition cond,const ValueOperand & value)437   Condition testBigInt(Condition cond, const ValueOperand& value) {
438     return testBigInt(cond, value.typeReg());
439   }
testObject(Condition cond,const ValueOperand & value)440   Condition testObject(Condition cond, const ValueOperand& value) {
441     return testObject(cond, value.typeReg());
442   }
testMagic(Condition cond,const ValueOperand & value)443   Condition testMagic(Condition cond, const ValueOperand& value) {
444     return testMagic(cond, value.typeReg());
445   }
testError(Condition cond,const ValueOperand & value)446   Condition testError(Condition cond, const ValueOperand& value) {
447     return testMagic(cond, value);
448   }
testNumber(Condition cond,const ValueOperand & value)449   Condition testNumber(Condition cond, const ValueOperand& value) {
450     return testNumber(cond, value.typeReg());
451   }
testGCThing(Condition cond,const ValueOperand & value)452   Condition testGCThing(Condition cond, const ValueOperand& value) {
453     return testGCThing(cond, value.typeReg());
454   }
testPrimitive(Condition cond,const ValueOperand & value)455   Condition testPrimitive(Condition cond, const ValueOperand& value) {
456     return testPrimitive(cond, value.typeReg());
457   }
458 
testUndefined(Condition cond,const BaseIndex & address)459   Condition testUndefined(Condition cond, const BaseIndex& address) {
460     MOZ_ASSERT(cond == Equal || cond == NotEqual);
461     cmp32(tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED));
462     return cond;
463   }
testNull(Condition cond,const BaseIndex & address)464   Condition testNull(Condition cond, const BaseIndex& address) {
465     MOZ_ASSERT(cond == Equal || cond == NotEqual);
466     cmp32(tagOf(address), ImmTag(JSVAL_TAG_NULL));
467     return cond;
468   }
testBoolean(Condition cond,const BaseIndex & address)469   Condition testBoolean(Condition cond, const BaseIndex& address) {
470     MOZ_ASSERT(cond == Equal || cond == NotEqual);
471     cmp32(tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN));
472     return cond;
473   }
testString(Condition cond,const Address & address)474   Condition testString(Condition cond, const Address& address) {
475     MOZ_ASSERT(cond == Equal || cond == NotEqual);
476     cmp32(tagOf(address), ImmTag(JSVAL_TAG_STRING));
477     return cond;
478   }
testString(Condition cond,const BaseIndex & address)479   Condition testString(Condition cond, const BaseIndex& address) {
480     MOZ_ASSERT(cond == Equal || cond == NotEqual);
481     cmp32(tagOf(address), ImmTag(JSVAL_TAG_STRING));
482     return cond;
483   }
testSymbol(Condition cond,const Address & address)484   Condition testSymbol(Condition cond, const Address& address) {
485     MOZ_ASSERT(cond == Equal || cond == NotEqual);
486     cmp32(tagOf(address), ImmTag(JSVAL_TAG_SYMBOL));
487     return cond;
488   }
testSymbol(Condition cond,const BaseIndex & address)489   Condition testSymbol(Condition cond, const BaseIndex& address) {
490     MOZ_ASSERT(cond == Equal || cond == NotEqual);
491     cmp32(tagOf(address), ImmTag(JSVAL_TAG_SYMBOL));
492     return cond;
493   }
testBigInt(Condition cond,const Address & address)494   Condition testBigInt(Condition cond, const Address& address) {
495     MOZ_ASSERT(cond == Equal || cond == NotEqual);
496     cmp32(tagOf(address), ImmTag(JSVAL_TAG_BIGINT));
497     return cond;
498   }
testBigInt(Condition cond,const BaseIndex & address)499   Condition testBigInt(Condition cond, const BaseIndex& address) {
500     MOZ_ASSERT(cond == Equal || cond == NotEqual);
501     cmp32(tagOf(address), ImmTag(JSVAL_TAG_BIGINT));
502     return cond;
503   }
testInt32(Condition cond,const BaseIndex & address)504   Condition testInt32(Condition cond, const BaseIndex& address) {
505     MOZ_ASSERT(cond == Equal || cond == NotEqual);
506     cmp32(tagOf(address), ImmTag(JSVAL_TAG_INT32));
507     return cond;
508   }
testObject(Condition cond,const BaseIndex & address)509   Condition testObject(Condition cond, const BaseIndex& address) {
510     MOZ_ASSERT(cond == Equal || cond == NotEqual);
511     cmp32(tagOf(address), ImmTag(JSVAL_TAG_OBJECT));
512     return cond;
513   }
testDouble(Condition cond,const BaseIndex & address)514   Condition testDouble(Condition cond, const BaseIndex& address) {
515     MOZ_ASSERT(cond == Equal || cond == NotEqual);
516     Condition actual = (cond == Equal) ? Below : AboveOrEqual;
517     cmp32(tagOf(address), ImmTag(JSVAL_TAG_CLEAR));
518     return actual;
519   }
testMagic(Condition cond,const BaseIndex & address)520   Condition testMagic(Condition cond, const BaseIndex& address) {
521     MOZ_ASSERT(cond == Equal || cond == NotEqual);
522     cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC));
523     return cond;
524   }
testGCThing(Condition cond,const BaseIndex & address)525   Condition testGCThing(Condition cond, const BaseIndex& address) {
526     MOZ_ASSERT(cond == Equal || cond == NotEqual);
527     cmp32(tagOf(address), ImmTag(JS::detail::ValueLowerInclGCThingTag));
528     return cond == Equal ? AboveOrEqual : Below;
529   }
530 
testNullSet(Condition cond,const ValueOperand & value,Register dest)531   void testNullSet(Condition cond, const ValueOperand& value, Register dest) {
532     cond = testNull(cond, value);
533     emitSet(cond, dest);
534   }
535 
testObjectSet(Condition cond,const ValueOperand & value,Register dest)536   void testObjectSet(Condition cond, const ValueOperand& value, Register dest) {
537     cond = testObject(cond, value);
538     emitSet(cond, dest);
539   }
540 
testUndefinedSet(Condition cond,const ValueOperand & value,Register dest)541   void testUndefinedSet(Condition cond, const ValueOperand& value,
542                         Register dest) {
543     cond = testUndefined(cond, value);
544     emitSet(cond, dest);
545   }
546 
cmpPtr(Register lhs,const ImmWord rhs)547   void cmpPtr(Register lhs, const ImmWord rhs) { cmpl(Imm32(rhs.value), lhs); }
cmpPtr(Register lhs,const ImmPtr imm)548   void cmpPtr(Register lhs, const ImmPtr imm) {
549     cmpPtr(lhs, ImmWord(uintptr_t(imm.value)));
550   }
cmpPtr(Register lhs,const ImmGCPtr rhs)551   void cmpPtr(Register lhs, const ImmGCPtr rhs) { cmpl(rhs, lhs); }
cmpPtr(const Operand & lhs,Imm32 rhs)552   void cmpPtr(const Operand& lhs, Imm32 rhs) { cmp32(lhs, rhs); }
cmpPtr(const Operand & lhs,const ImmWord rhs)553   void cmpPtr(const Operand& lhs, const ImmWord rhs) {
554     cmp32(lhs, Imm32(rhs.value));
555   }
cmpPtr(const Operand & lhs,const ImmPtr imm)556   void cmpPtr(const Operand& lhs, const ImmPtr imm) {
557     cmpPtr(lhs, ImmWord(uintptr_t(imm.value)));
558   }
cmpPtr(const Operand & lhs,const ImmGCPtr rhs)559   void cmpPtr(const Operand& lhs, const ImmGCPtr rhs) { cmpl(rhs, lhs); }
cmpPtr(const Address & lhs,Register rhs)560   void cmpPtr(const Address& lhs, Register rhs) { cmpPtr(Operand(lhs), rhs); }
cmpPtr(const Operand & lhs,Register rhs)561   void cmpPtr(const Operand& lhs, Register rhs) { cmp32(lhs, rhs); }
cmpPtr(const Address & lhs,const ImmWord rhs)562   void cmpPtr(const Address& lhs, const ImmWord rhs) {
563     cmpPtr(Operand(lhs), rhs);
564   }
cmpPtr(const Address & lhs,const ImmPtr rhs)565   void cmpPtr(const Address& lhs, const ImmPtr rhs) {
566     cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
567   }
cmpPtr(const Address & lhs,const ImmGCPtr rhs)568   void cmpPtr(const Address& lhs, const ImmGCPtr rhs) {
569     cmpPtr(Operand(lhs), rhs);
570   }
cmpPtr(Register lhs,Register rhs)571   void cmpPtr(Register lhs, Register rhs) { cmp32(lhs, rhs); }
testPtr(Register lhs,Register rhs)572   void testPtr(Register lhs, Register rhs) { test32(lhs, rhs); }
testPtr(Register lhs,Imm32 rhs)573   void testPtr(Register lhs, Imm32 rhs) { test32(lhs, rhs); }
testPtr(Register lhs,ImmWord rhs)574   void testPtr(Register lhs, ImmWord rhs) { test32(lhs, Imm32(rhs.value)); }
testPtr(const Operand & lhs,Imm32 rhs)575   void testPtr(const Operand& lhs, Imm32 rhs) { test32(lhs, rhs); }
testPtr(const Operand & lhs,ImmWord rhs)576   void testPtr(const Operand& lhs, ImmWord rhs) {
577     test32(lhs, Imm32(rhs.value));
578   }
579 
580   /////////////////////////////////////////////////////////////////
581   // Common interface.
582   /////////////////////////////////////////////////////////////////
583 
movePtr(ImmWord imm,Register dest)584   void movePtr(ImmWord imm, Register dest) { movl(Imm32(imm.value), dest); }
movePtr(ImmPtr imm,Register dest)585   void movePtr(ImmPtr imm, Register dest) { movl(imm, dest); }
movePtr(wasm::SymbolicAddress imm,Register dest)586   void movePtr(wasm::SymbolicAddress imm, Register dest) { mov(imm, dest); }
movePtr(ImmGCPtr imm,Register dest)587   void movePtr(ImmGCPtr imm, Register dest) { movl(imm, dest); }
loadPtr(const Address & address,Register dest)588   void loadPtr(const Address& address, Register dest) {
589     movl(Operand(address), dest);
590   }
loadPtr(const Operand & src,Register dest)591   void loadPtr(const Operand& src, Register dest) { movl(src, dest); }
loadPtr(const BaseIndex & src,Register dest)592   void loadPtr(const BaseIndex& src, Register dest) {
593     movl(Operand(src), dest);
594   }
loadPtr(AbsoluteAddress address,Register dest)595   void loadPtr(AbsoluteAddress address, Register dest) {
596     movl(Operand(address), dest);
597   }
loadPrivate(const Address & src,Register dest)598   void loadPrivate(const Address& src, Register dest) {
599     movl(payloadOf(src), dest);
600   }
load32(AbsoluteAddress address,Register dest)601   void load32(AbsoluteAddress address, Register dest) {
602     movl(Operand(address), dest);
603   }
604   template <typename T>
load64(const T & address,Register64 dest)605   void load64(const T& address, Register64 dest) {
606     movl(Operand(LowWord(address)), dest.low);
607     movl(Operand(HighWord(address)), dest.high);
608   }
609   template <typename T>
load64Unaligned(const T & address,Register64 dest)610   void load64Unaligned(const T& address, Register64 dest) {
611     load64(address, dest);
612   }
613   template <typename T>
storePtr(ImmWord imm,T address)614   void storePtr(ImmWord imm, T address) {
615     movl(Imm32(imm.value), Operand(address));
616   }
617   template <typename T>
storePtr(ImmPtr imm,T address)618   void storePtr(ImmPtr imm, T address) {
619     storePtr(ImmWord(uintptr_t(imm.value)), address);
620   }
621   template <typename T>
storePtr(ImmGCPtr imm,T address)622   void storePtr(ImmGCPtr imm, T address) {
623     movl(imm, Operand(address));
624   }
storePtr(Register src,const Address & address)625   void storePtr(Register src, const Address& address) {
626     movl(src, Operand(address));
627   }
storePtr(Register src,const BaseIndex & address)628   void storePtr(Register src, const BaseIndex& address) {
629     movl(src, Operand(address));
630   }
storePtr(Register src,const Operand & dest)631   void storePtr(Register src, const Operand& dest) { movl(src, dest); }
storePtr(Register src,AbsoluteAddress address)632   void storePtr(Register src, AbsoluteAddress address) {
633     movl(src, Operand(address));
634   }
store32(Register src,AbsoluteAddress address)635   void store32(Register src, AbsoluteAddress address) {
636     movl(src, Operand(address));
637   }
store16(Register src,AbsoluteAddress address)638   void store16(Register src, AbsoluteAddress address) {
639     movw(src, Operand(address));
640   }
641   template <typename T>
store64(Register64 src,const T & address)642   void store64(Register64 src, const T& address) {
643     movl(src.low, Operand(LowWord(address)));
644     movl(src.high, Operand(HighWord(address)));
645   }
store64(Imm64 imm,Address address)646   void store64(Imm64 imm, Address address) {
647     movl(imm.low(), Operand(LowWord(address)));
648     movl(imm.hi(), Operand(HighWord(address)));
649   }
650   template <typename S, typename T>
store64Unaligned(const S & src,const T & dest)651   void store64Unaligned(const S& src, const T& dest) {
652     store64(src, dest);
653   }
654 
setStackArg(Register reg,uint32_t arg)655   void setStackArg(Register reg, uint32_t arg) {
656     movl(reg, Operand(esp, arg * sizeof(intptr_t)));
657   }
658 
boxDouble(FloatRegister src,const ValueOperand & dest,FloatRegister temp)659   void boxDouble(FloatRegister src, const ValueOperand& dest,
660                  FloatRegister temp) {
661     if (Assembler::HasSSE41()) {
662       vmovd(src, dest.payloadReg());
663       vpextrd(1, src, dest.typeReg());
664     } else {
665       vmovd(src, dest.payloadReg());
666       if (src != temp) {
667         moveDouble(src, temp);
668       }
669       vpsrldq(Imm32(4), temp, temp);
670       vmovd(temp, dest.typeReg());
671     }
672   }
boxNonDouble(JSValueType type,Register src,const ValueOperand & dest)673   void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) {
674     if (src != dest.payloadReg()) {
675       movl(src, dest.payloadReg());
676     }
677     movl(ImmType(type), dest.typeReg());
678   }
679 
680   void unboxNonDouble(const ValueOperand& src, Register dest, JSValueType type,
681                       Register scratch = InvalidReg) {
682     unboxNonDouble(Operand(src.typeReg()), Operand(src.payloadReg()), dest,
683                    type, scratch);
684   }
685   void unboxNonDouble(const Operand& tag, const Operand& payload, Register dest,
686                       JSValueType type, Register scratch = InvalidReg) {
687     auto movPayloadToDest = [&]() {
688       if (payload.kind() != Operand::REG || !payload.containsReg(dest)) {
689         movl(payload, dest);
690       }
691     };
692     if (!JitOptions.spectreValueMasking) {
693       movPayloadToDest();
694       return;
695     }
696 
697     // Spectre mitigation: We zero the payload if the tag does not match the
698     // expected type and if this is a pointer type.
699     if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
700       movPayloadToDest();
701       return;
702     }
703 
704     if (!tag.containsReg(dest) && !payload.containsReg(dest)) {
705       // We zero the destination register and move the payload into it if
706       // the tag corresponds to the given type.
707       xorl(dest, dest);
708       cmpl(Imm32(JSVAL_TYPE_TO_TAG(type)), tag);
709       cmovCCl(Condition::Equal, payload, dest);
710       return;
711     }
712 
713     if (scratch == InvalidReg || scratch == dest || tag.containsReg(scratch) ||
714         payload.containsReg(scratch)) {
715       // UnboxedLayout::makeConstructorCode calls extractObject with a
716       // scratch register which aliases the tag register, thus we cannot
717       // assert the above condition.
718       scratch = InvalidReg;
719     }
720 
721     // The destination register aliases one of the operands. We create a
722     // zero value either in a scratch register or on the stack and use it
723     // to reset the destination register after reading both the tag and the
724     // payload.
725     Operand zero(Address(esp, 0));
726     if (scratch == InvalidReg) {
727       push(Imm32(0));
728     } else {
729       xorl(scratch, scratch);
730       zero = Operand(scratch);
731     }
732     cmpl(Imm32(JSVAL_TYPE_TO_TAG(type)), tag);
733     movPayloadToDest();
734     cmovCCl(Condition::NotEqual, zero, dest);
735     if (scratch == InvalidReg) {
736       addl(Imm32(sizeof(void*)), esp);
737     }
738   }
unboxNonDouble(const Address & src,Register dest,JSValueType type)739   void unboxNonDouble(const Address& src, Register dest, JSValueType type) {
740     unboxNonDouble(tagOf(src), payloadOf(src), dest, type);
741   }
unboxNonDouble(const BaseIndex & src,Register dest,JSValueType type)742   void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType type) {
743     unboxNonDouble(tagOf(src), payloadOf(src), dest, type);
744   }
unboxInt32(const ValueOperand & src,Register dest)745   void unboxInt32(const ValueOperand& src, Register dest) {
746     unboxNonDouble(src, dest, JSVAL_TYPE_INT32);
747   }
unboxInt32(const Address & src,Register dest)748   void unboxInt32(const Address& src, Register dest) {
749     unboxNonDouble(src, dest, JSVAL_TYPE_INT32);
750   }
unboxInt32(const BaseIndex & src,Register dest)751   void unboxInt32(const BaseIndex& src, Register dest) {
752     unboxNonDouble(src, dest, JSVAL_TYPE_INT32);
753   }
unboxBoolean(const ValueOperand & src,Register dest)754   void unboxBoolean(const ValueOperand& src, Register dest) {
755     unboxNonDouble(src, dest, JSVAL_TYPE_BOOLEAN);
756   }
unboxBoolean(const Address & src,Register dest)757   void unboxBoolean(const Address& src, Register dest) {
758     unboxNonDouble(src, dest, JSVAL_TYPE_BOOLEAN);
759   }
unboxBoolean(const BaseIndex & src,Register dest)760   void unboxBoolean(const BaseIndex& src, Register dest) {
761     unboxNonDouble(src, dest, JSVAL_TYPE_BOOLEAN);
762   }
unboxString(const ValueOperand & src,Register dest)763   void unboxString(const ValueOperand& src, Register dest) {
764     unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
765   }
unboxString(const Address & src,Register dest)766   void unboxString(const Address& src, Register dest) {
767     unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
768   }
unboxSymbol(const ValueOperand & src,Register dest)769   void unboxSymbol(const ValueOperand& src, Register dest) {
770     unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
771   }
unboxSymbol(const Address & src,Register dest)772   void unboxSymbol(const Address& src, Register dest) {
773     unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
774   }
unboxBigInt(const ValueOperand & src,Register dest)775   void unboxBigInt(const ValueOperand& src, Register dest) {
776     unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT);
777   }
unboxBigInt(const Address & src,Register dest)778   void unboxBigInt(const Address& src, Register dest) {
779     unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT);
780   }
unboxObject(const ValueOperand & src,Register dest)781   void unboxObject(const ValueOperand& src, Register dest) {
782     unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
783   }
unboxObject(const Address & src,Register dest)784   void unboxObject(const Address& src, Register dest) {
785     unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
786   }
unboxObject(const BaseIndex & src,Register dest)787   void unboxObject(const BaseIndex& src, Register dest) {
788     unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
789   }
790   template <typename T>
unboxObjectOrNull(const T & src,Register dest)791   void unboxObjectOrNull(const T& src, Register dest) {
792     // Due to Spectre mitigation logic (see Value.h), if the value is an Object
793     // then this yields the object; otherwise it yields zero (null), as desired.
794     unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
795   }
796   template <typename T>
unboxDouble(const T & src,FloatRegister dest)797   void unboxDouble(const T& src, FloatRegister dest) {
798     loadDouble(Operand(src), dest);
799   }
unboxDouble(const ValueOperand & src,FloatRegister dest)800   void unboxDouble(const ValueOperand& src, FloatRegister dest) {
801     if (Assembler::HasSSE41()) {
802       vmovd(src.payloadReg(), dest);
803       vpinsrd(1, src.typeReg(), dest, dest);
804     } else {
805       ScratchDoubleScope fpscratch(asMasm());
806       vmovd(src.payloadReg(), dest);
807       vmovd(src.typeReg(), fpscratch);
808       vunpcklps(fpscratch, dest, dest);
809     }
810   }
unboxDouble(const Operand & payload,const Operand & type,Register scratch,FloatRegister dest)811   void unboxDouble(const Operand& payload, const Operand& type,
812                    Register scratch, FloatRegister dest) {
813     if (Assembler::HasSSE41()) {
814       movl(payload, scratch);
815       vmovd(scratch, dest);
816       movl(type, scratch);
817       vpinsrd(1, scratch, dest, dest);
818     } else {
819       ScratchDoubleScope fpscratch(asMasm());
820       movl(payload, scratch);
821       vmovd(scratch, dest);
822       movl(type, scratch);
823       vmovd(scratch, fpscratch);
824       vunpcklps(fpscratch, dest, dest);
825     }
826   }
827   inline void unboxValue(const ValueOperand& src, AnyRegister dest,
828                          JSValueType type);
829 
830   // See comment in MacroAssembler-x64.h.
unboxGCThingForGCBarrier(const Address & src,Register dest)831   void unboxGCThingForGCBarrier(const Address& src, Register dest) {
832     movl(payloadOf(src), dest);
833   }
834 
notBoolean(const ValueOperand & val)835   void notBoolean(const ValueOperand& val) { xorl(Imm32(1), val.payloadReg()); }
836 
837   template <typename T>
838   void fallibleUnboxPtrImpl(const T& src, Register dest, JSValueType type,
839                             Label* fail);
840 
841   // Extended unboxing API. If the payload is already in a register, returns
842   // that register. Otherwise, provides a move to the given scratch register,
843   // and returns that.
extractObject(const Address & address,Register dest)844   [[nodiscard]] Register extractObject(const Address& address, Register dest) {
845     unboxObject(address, dest);
846     return dest;
847   }
extractObject(const ValueOperand & value,Register scratch)848   [[nodiscard]] Register extractObject(const ValueOperand& value,
849                                        Register scratch) {
850     unboxNonDouble(value, value.payloadReg(), JSVAL_TYPE_OBJECT, scratch);
851     return value.payloadReg();
852   }
extractSymbol(const ValueOperand & value,Register scratch)853   [[nodiscard]] Register extractSymbol(const ValueOperand& value,
854                                        Register scratch) {
855     unboxNonDouble(value, value.payloadReg(), JSVAL_TYPE_SYMBOL, scratch);
856     return value.payloadReg();
857   }
extractInt32(const ValueOperand & value,Register scratch)858   [[nodiscard]] Register extractInt32(const ValueOperand& value,
859                                       Register scratch) {
860     return value.payloadReg();
861   }
extractBoolean(const ValueOperand & value,Register scratch)862   [[nodiscard]] Register extractBoolean(const ValueOperand& value,
863                                         Register scratch) {
864     return value.payloadReg();
865   }
extractTag(const Address & address,Register scratch)866   [[nodiscard]] Register extractTag(const Address& address, Register scratch) {
867     movl(tagOf(address), scratch);
868     return scratch;
869   }
extractTag(const ValueOperand & value,Register scratch)870   [[nodiscard]] Register extractTag(const ValueOperand& value,
871                                     Register scratch) {
872     return value.typeReg();
873   }
874 
875   void convertDoubleToPtr(FloatRegister src, Register dest, Label* fail,
876                           bool negativeZeroCheck = true) {
877     convertDoubleToInt32(src, dest, fail, negativeZeroCheck);
878   }
879 
boolValueToDouble(const ValueOperand & operand,FloatRegister dest)880   void boolValueToDouble(const ValueOperand& operand, FloatRegister dest) {
881     convertInt32ToDouble(operand.payloadReg(), dest);
882   }
boolValueToFloat32(const ValueOperand & operand,FloatRegister dest)883   void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
884     convertInt32ToFloat32(operand.payloadReg(), dest);
885   }
int32ValueToDouble(const ValueOperand & operand,FloatRegister dest)886   void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest) {
887     convertInt32ToDouble(operand.payloadReg(), dest);
888   }
int32ValueToFloat32(const ValueOperand & operand,FloatRegister dest)889   void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
890     convertInt32ToFloat32(operand.payloadReg(), dest);
891   }
892 
893   void loadConstantDouble(double d, FloatRegister dest);
894   void loadConstantFloat32(float f, FloatRegister dest);
895 
896   void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest);
897   void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest);
898   void vpaddbSimd128(const SimdConstant& v, FloatRegister srcDest);
899   void vpaddwSimd128(const SimdConstant& v, FloatRegister srcDest);
900   void vpadddSimd128(const SimdConstant& v, FloatRegister srcDest);
901   void vpaddqSimd128(const SimdConstant& v, FloatRegister srcDest);
902   void vpsubbSimd128(const SimdConstant& v, FloatRegister srcDest);
903   void vpsubwSimd128(const SimdConstant& v, FloatRegister srcDest);
904   void vpsubdSimd128(const SimdConstant& v, FloatRegister srcDest);
905   void vpsubqSimd128(const SimdConstant& v, FloatRegister srcDest);
906   void vpmullwSimd128(const SimdConstant& v, FloatRegister srcDest);
907   void vpmulldSimd128(const SimdConstant& v, FloatRegister srcDest);
908   void vpaddsbSimd128(const SimdConstant& v, FloatRegister srcDest);
909   void vpaddusbSimd128(const SimdConstant& v, FloatRegister srcDest);
910   void vpaddswSimd128(const SimdConstant& v, FloatRegister srcDest);
911   void vpadduswSimd128(const SimdConstant& v, FloatRegister srcDest);
912   void vpsubsbSimd128(const SimdConstant& v, FloatRegister srcDest);
913   void vpsubusbSimd128(const SimdConstant& v, FloatRegister srcDest);
914   void vpsubswSimd128(const SimdConstant& v, FloatRegister srcDest);
915   void vpsubuswSimd128(const SimdConstant& v, FloatRegister srcDest);
916   void vpminsbSimd128(const SimdConstant& v, FloatRegister srcDest);
917   void vpminubSimd128(const SimdConstant& v, FloatRegister srcDest);
918   void vpminswSimd128(const SimdConstant& v, FloatRegister srcDest);
919   void vpminuwSimd128(const SimdConstant& v, FloatRegister srcDest);
920   void vpminsdSimd128(const SimdConstant& v, FloatRegister srcDest);
921   void vpminudSimd128(const SimdConstant& v, FloatRegister srcDest);
922   void vpmaxsbSimd128(const SimdConstant& v, FloatRegister srcDest);
923   void vpmaxubSimd128(const SimdConstant& v, FloatRegister srcDest);
924   void vpmaxswSimd128(const SimdConstant& v, FloatRegister srcDest);
925   void vpmaxuwSimd128(const SimdConstant& v, FloatRegister srcDest);
926   void vpmaxsdSimd128(const SimdConstant& v, FloatRegister srcDest);
927   void vpmaxudSimd128(const SimdConstant& v, FloatRegister srcDest);
928   void vpandSimd128(const SimdConstant& v, FloatRegister srcDest);
929   void vpxorSimd128(const SimdConstant& v, FloatRegister srcDest);
930   void vporSimd128(const SimdConstant& v, FloatRegister srcDest);
931   void vaddpsSimd128(const SimdConstant& v, FloatRegister srcDest);
932   void vaddpdSimd128(const SimdConstant& v, FloatRegister srcDest);
933   void vsubpsSimd128(const SimdConstant& v, FloatRegister srcDest);
934   void vsubpdSimd128(const SimdConstant& v, FloatRegister srcDest);
935   void vdivpsSimd128(const SimdConstant& v, FloatRegister srcDest);
936   void vdivpdSimd128(const SimdConstant& v, FloatRegister srcDest);
937   void vmulpsSimd128(const SimdConstant& v, FloatRegister srcDest);
938   void vmulpdSimd128(const SimdConstant& v, FloatRegister srcDest);
939   void vpacksswbSimd128(const SimdConstant& v, FloatRegister srcDest);
940   void vpackuswbSimd128(const SimdConstant& v, FloatRegister srcDest);
941   void vpackssdwSimd128(const SimdConstant& v, FloatRegister srcDest);
942   void vpackusdwSimd128(const SimdConstant& v, FloatRegister srcDest);
943   void vpshufbSimd128(const SimdConstant& v, FloatRegister srcDest);
944   void vptestSimd128(const SimdConstant& v, FloatRegister src);
945   void vpmaddwdSimd128(const SimdConstant& v, FloatRegister src);
946   void vpcmpeqbSimd128(const SimdConstant& v, FloatRegister src);
947   void vpcmpgtbSimd128(const SimdConstant& v, FloatRegister src);
948   void vpcmpeqwSimd128(const SimdConstant& v, FloatRegister src);
949   void vpcmpgtwSimd128(const SimdConstant& v, FloatRegister src);
950   void vpcmpeqdSimd128(const SimdConstant& v, FloatRegister src);
951   void vpcmpgtdSimd128(const SimdConstant& v, FloatRegister src);
952   void vcmpeqpsSimd128(const SimdConstant& v, FloatRegister src);
953   void vcmpneqpsSimd128(const SimdConstant& v, FloatRegister src);
954   void vcmpltpsSimd128(const SimdConstant& v, FloatRegister src);
955   void vcmplepsSimd128(const SimdConstant& v, FloatRegister src);
956   void vcmpeqpdSimd128(const SimdConstant& v, FloatRegister src);
957   void vcmpneqpdSimd128(const SimdConstant& v, FloatRegister src);
958   void vcmpltpdSimd128(const SimdConstant& v, FloatRegister src);
959   void vcmplepdSimd128(const SimdConstant& v, FloatRegister src);
960 
testInt32Truthy(bool truthy,const ValueOperand & operand)961   Condition testInt32Truthy(bool truthy, const ValueOperand& operand) {
962     test32(operand.payloadReg(), operand.payloadReg());
963     return truthy ? NonZero : Zero;
964   }
testStringTruthy(bool truthy,const ValueOperand & value)965   Condition testStringTruthy(bool truthy, const ValueOperand& value) {
966     Register string = value.payloadReg();
967     cmp32(Operand(string, JSString::offsetOfLength()), Imm32(0));
968     return truthy ? Assembler::NotEqual : Assembler::Equal;
969   }
testBigIntTruthy(bool truthy,const ValueOperand & value)970   Condition testBigIntTruthy(bool truthy, const ValueOperand& value) {
971     Register bi = value.payloadReg();
972     cmp32(Operand(bi, BigInt::offsetOfDigitLength()), Imm32(0));
973     return truthy ? Assembler::NotEqual : Assembler::Equal;
974   }
975 
976   template <typename T>
977   inline void loadInt32OrDouble(const T& src, FloatRegister dest);
978 
979   template <typename T>
980   inline void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest);
981 
982   template <typename T>
storeUnboxedPayload(ValueOperand value,T address,size_t nbytes,JSValueType)983   void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes,
984                            JSValueType) {
985     switch (nbytes) {
986       case 4:
987         storePtr(value.payloadReg(), address);
988         return;
989       case 1:
990         store8(value.payloadReg(), address);
991         return;
992       default:
993         MOZ_CRASH("Bad payload width");
994     }
995   }
996 
loadInstructionPointerAfterCall(Register dest)997   void loadInstructionPointerAfterCall(Register dest) {
998     movl(Operand(StackPointer, 0x0), dest);
999   }
1000 
1001   // Note: this function clobbers the source register.
1002   inline void convertUInt32ToDouble(Register src, FloatRegister dest);
1003 
1004   // Note: this function clobbers the source register.
1005   inline void convertUInt32ToFloat32(Register src, FloatRegister dest);
1006 
incrementInt32Value(const Address & addr)1007   void incrementInt32Value(const Address& addr) {
1008     addl(Imm32(1), payloadOf(addr));
1009   }
1010 
1011   inline void ensureDouble(const ValueOperand& source, FloatRegister dest,
1012                            Label* failure);
1013 
loadWasmGlobalPtr(uint32_t globalDataOffset,Register dest)1014   void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) {
1015     loadPtr(Address(WasmTlsReg,
1016                     offsetof(wasm::TlsData, globalArea) + globalDataOffset),
1017             dest);
1018   }
loadWasmPinnedRegsFromTls()1019   void loadWasmPinnedRegsFromTls() {
1020     // x86 doesn't have any pinned registers.
1021   }
1022 
1023  public:
1024   // Used from within an Exit frame to handle a pending exception.
1025   void handleFailureWithHandlerTail(Label* profilerExitTail);
1026 
1027   // Instrumentation for entering and leaving the profiler.
1028   void profilerEnterFrame(Register framePtr, Register scratch);
1029   void profilerExitFrame();
1030 };
1031 
1032 typedef MacroAssemblerX86 MacroAssemblerSpecific;
1033 
1034 }  // namespace jit
1035 }  // namespace js
1036 
1037 #endif /* jit_x86_MacroAssembler_x86_h */
1038