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_x64_MacroAssembler_x64_h
8 #define jit_x64_MacroAssembler_x64_h
9 
10 #include "jit/x86-shared/MacroAssembler-x86-shared.h"
11 #include "js/HeapAPI.h"
12 #include "wasm/WasmBuiltins.h"
13 #include "wasm/WasmTlsData.h"
14 
15 namespace js {
16 namespace jit {
17 
18 struct ImmShiftedTag : public ImmWord {
ImmShiftedTagImmShiftedTag19   explicit ImmShiftedTag(JSValueShiftedTag shtag) : ImmWord((uintptr_t)shtag) {}
20 
ImmShiftedTagImmShiftedTag21   explicit ImmShiftedTag(JSValueType type)
22       : ImmWord(uintptr_t(JSVAL_TYPE_TO_SHIFTED_TAG(type))) {}
23 };
24 
25 struct ImmTag : public Imm32 {
ImmTagImmTag26   explicit ImmTag(JSValueTag tag) : Imm32(tag) {}
27 };
28 
29 // ScratchTagScope and ScratchTagScopeRelease are used to manage the tag
30 // register for splitTagForTest(), which has different register management on
31 // different platforms.  On 64-bit platforms it requires a scratch register that
32 // does not interfere with other operations; on 32-bit platforms it uses a
33 // register that is already part of the Value.
34 //
35 // The ScratchTagScope RAII type acquires the appropriate register; a reference
36 // to a variable of this type is then passed to splitTagForTest().
37 //
38 // On 64-bit platforms ScratchTagScopeRelease makes the owned scratch register
39 // available in a dynamic scope during compilation.  However it is important to
40 // remember that that does not preserve the register value in any way, so this
41 // RAII type should only be used along paths that eventually branch past further
42 // uses of the extracted tag value.
43 //
44 // On 32-bit platforms ScratchTagScopeRelease has no effect, since it does not
45 // manage a register, it only aliases a register in the ValueOperand.
46 
47 class ScratchTagScope : public ScratchRegisterScope {
48  public:
ScratchTagScope(MacroAssembler & masm,const ValueOperand &)49   ScratchTagScope(MacroAssembler& masm, const ValueOperand&)
50       : ScratchRegisterScope(masm) {}
51 };
52 
53 class ScratchTagScopeRelease {
54   ScratchTagScope* ts_;
55 
56  public:
ScratchTagScopeRelease(ScratchTagScope * ts)57   explicit ScratchTagScopeRelease(ScratchTagScope* ts) : ts_(ts) {
58     ts_->release();
59   }
~ScratchTagScopeRelease()60   ~ScratchTagScopeRelease() { ts_->reacquire(); }
61 };
62 
63 class MacroAssemblerX64 : public MacroAssemblerX86Shared {
64  private:
65   // Perform a downcast. Should be removed by Bug 996602.
66   MacroAssembler& asMasm();
67   const MacroAssembler& asMasm() const;
68 
69   void bindOffsets(const MacroAssemblerX86Shared::UsesVector&);
70 
71   void vpRiprOpSimd128(const SimdConstant& v, FloatRegister reg,
72                        JmpSrc (X86Encoding::BaseAssemblerX64::*op)(
73                            X86Encoding::XMMRegisterID id));
74 
75   void vpRiprOpSimd128(const SimdConstant& v, FloatRegister lhs,
76                        FloatRegister dest,
77                        JmpSrc (X86Encoding::BaseAssemblerX64::*op)(
78                            X86Encoding::XMMRegisterID srcId,
79                            X86Encoding::XMMRegisterID destId));
80 
81  public:
82   using MacroAssemblerX86Shared::load32;
83   using MacroAssemblerX86Shared::store16;
84   using MacroAssemblerX86Shared::store32;
85 
86   MacroAssemblerX64() = default;
87 
88   // The buffer is about to be linked, make sure any constant pools or excess
89   // bookkeeping has been flushed to the instruction stream.
90   void finish();
91 
92   /////////////////////////////////////////////////////////////////
93   // X64 helpers.
94   /////////////////////////////////////////////////////////////////
writeDataRelocation(const Value & val)95   void writeDataRelocation(const Value& val) {
96     // Raw GC pointer relocations and Value relocations both end up in
97     // Assembler::TraceDataRelocations.
98     if (val.isGCThing()) {
99       gc::Cell* cell = val.toGCThing();
100       if (cell && gc::IsInsideNursery(cell)) {
101         embedsNurseryPointers_ = true;
102       }
103       dataRelocations_.writeUnsigned(masm.currentOffset());
104     }
105   }
106 
107   // Refers to the upper 32 bits of a 64-bit Value operand.
108   // On x86_64, the upper 32 bits do not necessarily only contain the type.
ToUpper32(Operand base)109   Operand ToUpper32(Operand base) {
110     switch (base.kind()) {
111       case Operand::MEM_REG_DISP:
112         return Operand(Register::FromCode(base.base()), base.disp() + 4);
113 
114       case Operand::MEM_SCALE:
115         return Operand(Register::FromCode(base.base()),
116                        Register::FromCode(base.index()), base.scale(),
117                        base.disp() + 4);
118 
119       default:
120         MOZ_CRASH("unexpected operand kind");
121     }
122   }
ToUpper32(const Address & address)123   static inline Operand ToUpper32(const Address& address) {
124     return Operand(address.base, address.offset + 4);
125   }
ToUpper32(const BaseIndex & address)126   static inline Operand ToUpper32(const BaseIndex& address) {
127     return Operand(address.base, address.index, address.scale,
128                    address.offset + 4);
129   }
130 
Upper32Of(JSValueShiftedTag tag)131   uint32_t Upper32Of(JSValueShiftedTag tag) { return uint32_t(tag >> 32); }
132 
GetShiftedTag(JSValueType type)133   JSValueShiftedTag GetShiftedTag(JSValueType type) {
134     return (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type);
135   }
136 
137   /////////////////////////////////////////////////////////////////
138   // X86/X64-common interface.
139   /////////////////////////////////////////////////////////////////
ToPayload(Address value)140   Address ToPayload(Address value) { return value; }
141 
storeValue(ValueOperand val,Operand dest)142   void storeValue(ValueOperand val, Operand dest) {
143     movq(val.valueReg(), dest);
144   }
storeValue(ValueOperand val,const Address & dest)145   void storeValue(ValueOperand val, const Address& dest) {
146     storeValue(val, Operand(dest));
147   }
148   template <typename T>
storeValue(JSValueType type,Register reg,const T & dest)149   void storeValue(JSValueType type, Register reg, const T& dest) {
150     // Value types with 32-bit payloads can be emitted as two 32-bit moves.
151     if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
152       movl(reg, Operand(dest));
153       movl(Imm32(Upper32Of(GetShiftedTag(type))), ToUpper32(Operand(dest)));
154     } else {
155       ScratchRegisterScope scratch(asMasm());
156       boxValue(type, reg, scratch);
157       movq(scratch, Operand(dest));
158     }
159   }
160   template <typename T>
storeValue(const Value & val,const T & dest)161   void storeValue(const Value& val, const T& dest) {
162     ScratchRegisterScope scratch(asMasm());
163     if (val.isGCThing()) {
164       movWithPatch(ImmWord(val.asRawBits()), scratch);
165       writeDataRelocation(val);
166     } else {
167       mov(ImmWord(val.asRawBits()), scratch);
168     }
169     movq(scratch, Operand(dest));
170   }
storeValue(ValueOperand val,BaseIndex dest)171   void storeValue(ValueOperand val, BaseIndex dest) {
172     storeValue(val, Operand(dest));
173   }
storeValue(const Address & src,const Address & dest,Register temp)174   void storeValue(const Address& src, const Address& dest, Register temp) {
175     loadPtr(src, temp);
176     storePtr(temp, dest);
177   }
storePrivateValue(Register src,const Address & dest)178   void storePrivateValue(Register src, const Address& dest) {
179     storePtr(src, dest);
180   }
storePrivateValue(ImmGCPtr imm,const Address & dest)181   void storePrivateValue(ImmGCPtr imm, const Address& dest) {
182     storePtr(imm, dest);
183   }
loadValue(Operand src,ValueOperand val)184   void loadValue(Operand src, ValueOperand val) { movq(src, val.valueReg()); }
loadValue(Address src,ValueOperand val)185   void loadValue(Address src, ValueOperand val) {
186     loadValue(Operand(src), val);
187   }
loadValue(const BaseIndex & src,ValueOperand val)188   void loadValue(const BaseIndex& src, ValueOperand val) {
189     loadValue(Operand(src), val);
190   }
loadUnalignedValue(const Address & src,ValueOperand dest)191   void loadUnalignedValue(const Address& src, ValueOperand dest) {
192     loadValue(src, dest);
193   }
tagValue(JSValueType type,Register payload,ValueOperand dest)194   void tagValue(JSValueType type, Register payload, ValueOperand dest) {
195     ScratchRegisterScope scratch(asMasm());
196     MOZ_ASSERT(dest.valueReg() != scratch);
197     if (payload != dest.valueReg()) {
198       movq(payload, dest.valueReg());
199     }
200     mov(ImmShiftedTag(type), scratch);
201     orq(scratch, dest.valueReg());
202   }
pushValue(ValueOperand val)203   void pushValue(ValueOperand val) { push(val.valueReg()); }
popValue(ValueOperand val)204   void popValue(ValueOperand val) { pop(val.valueReg()); }
pushValue(const Value & val)205   void pushValue(const Value& val) {
206     if (val.isGCThing()) {
207       ScratchRegisterScope scratch(asMasm());
208       movWithPatch(ImmWord(val.asRawBits()), scratch);
209       writeDataRelocation(val);
210       push(scratch);
211     } else {
212       push(ImmWord(val.asRawBits()));
213     }
214   }
pushValue(JSValueType type,Register reg)215   void pushValue(JSValueType type, Register reg) {
216     ScratchRegisterScope scratch(asMasm());
217     boxValue(type, reg, scratch);
218     push(scratch);
219   }
pushValue(const Address & addr)220   void pushValue(const Address& addr) { push(Operand(addr)); }
221 
222   void boxValue(JSValueType type, Register src, Register dest);
223 
testUndefined(Condition cond,Register tag)224   Condition testUndefined(Condition cond, Register tag) {
225     MOZ_ASSERT(cond == Equal || cond == NotEqual);
226     cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED));
227     return cond;
228   }
testInt32(Condition cond,Register tag)229   Condition testInt32(Condition cond, Register tag) {
230     MOZ_ASSERT(cond == Equal || cond == NotEqual);
231     cmp32(tag, ImmTag(JSVAL_TAG_INT32));
232     return cond;
233   }
testBoolean(Condition cond,Register tag)234   Condition testBoolean(Condition cond, Register tag) {
235     MOZ_ASSERT(cond == Equal || cond == NotEqual);
236     cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN));
237     return cond;
238   }
testNull(Condition cond,Register tag)239   Condition testNull(Condition cond, Register tag) {
240     MOZ_ASSERT(cond == Equal || cond == NotEqual);
241     cmp32(tag, ImmTag(JSVAL_TAG_NULL));
242     return cond;
243   }
testString(Condition cond,Register tag)244   Condition testString(Condition cond, Register tag) {
245     MOZ_ASSERT(cond == Equal || cond == NotEqual);
246     cmp32(tag, ImmTag(JSVAL_TAG_STRING));
247     return cond;
248   }
testSymbol(Condition cond,Register tag)249   Condition testSymbol(Condition cond, Register tag) {
250     MOZ_ASSERT(cond == Equal || cond == NotEqual);
251     cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL));
252     return cond;
253   }
testBigInt(Condition cond,Register tag)254   Condition testBigInt(Condition cond, Register tag) {
255     MOZ_ASSERT(cond == Equal || cond == NotEqual);
256     cmp32(tag, ImmTag(JSVAL_TAG_BIGINT));
257     return cond;
258   }
testObject(Condition cond,Register tag)259   Condition testObject(Condition cond, Register tag) {
260     MOZ_ASSERT(cond == Equal || cond == NotEqual);
261     cmp32(tag, ImmTag(JSVAL_TAG_OBJECT));
262     return cond;
263   }
testDouble(Condition cond,Register tag)264   Condition testDouble(Condition cond, Register tag) {
265     MOZ_ASSERT(cond == Equal || cond == NotEqual);
266     cmp32(tag, Imm32(JSVAL_TAG_MAX_DOUBLE));
267     return cond == Equal ? BelowOrEqual : Above;
268   }
testNumber(Condition cond,Register tag)269   Condition testNumber(Condition cond, Register tag) {
270     MOZ_ASSERT(cond == Equal || cond == NotEqual);
271     cmp32(tag, Imm32(JS::detail::ValueUpperInclNumberTag));
272     return cond == Equal ? BelowOrEqual : Above;
273   }
testGCThing(Condition cond,Register tag)274   Condition testGCThing(Condition cond, Register tag) {
275     MOZ_ASSERT(cond == Equal || cond == NotEqual);
276     cmp32(tag, Imm32(JS::detail::ValueLowerInclGCThingTag));
277     return cond == Equal ? AboveOrEqual : Below;
278   }
279 
testMagic(Condition cond,Register tag)280   Condition testMagic(Condition cond, Register tag) {
281     MOZ_ASSERT(cond == Equal || cond == NotEqual);
282     cmp32(tag, ImmTag(JSVAL_TAG_MAGIC));
283     return cond;
284   }
testError(Condition cond,Register tag)285   Condition testError(Condition cond, Register tag) {
286     return testMagic(cond, tag);
287   }
testPrimitive(Condition cond,Register tag)288   Condition testPrimitive(Condition cond, Register tag) {
289     MOZ_ASSERT(cond == Equal || cond == NotEqual);
290     cmp32(tag, ImmTag(JS::detail::ValueUpperExclPrimitiveTag));
291     return cond == Equal ? Below : AboveOrEqual;
292   }
293 
testUndefined(Condition cond,const ValueOperand & src)294   Condition testUndefined(Condition cond, const ValueOperand& src) {
295     ScratchRegisterScope scratch(asMasm());
296     splitTag(src, scratch);
297     return testUndefined(cond, scratch);
298   }
testInt32(Condition cond,const ValueOperand & src)299   Condition testInt32(Condition cond, const ValueOperand& src) {
300     ScratchRegisterScope scratch(asMasm());
301     splitTag(src, scratch);
302     return testInt32(cond, scratch);
303   }
testBoolean(Condition cond,const ValueOperand & src)304   Condition testBoolean(Condition cond, const ValueOperand& src) {
305     ScratchRegisterScope scratch(asMasm());
306     splitTag(src, scratch);
307     return testBoolean(cond, scratch);
308   }
testDouble(Condition cond,const ValueOperand & src)309   Condition testDouble(Condition cond, const ValueOperand& src) {
310     ScratchRegisterScope scratch(asMasm());
311     splitTag(src, scratch);
312     return testDouble(cond, scratch);
313   }
testNumber(Condition cond,const ValueOperand & src)314   Condition testNumber(Condition cond, const ValueOperand& src) {
315     ScratchRegisterScope scratch(asMasm());
316     splitTag(src, scratch);
317     return testNumber(cond, scratch);
318   }
testNull(Condition cond,const ValueOperand & src)319   Condition testNull(Condition cond, const ValueOperand& src) {
320     ScratchRegisterScope scratch(asMasm());
321     splitTag(src, scratch);
322     return testNull(cond, scratch);
323   }
testString(Condition cond,const ValueOperand & src)324   Condition testString(Condition cond, const ValueOperand& src) {
325     ScratchRegisterScope scratch(asMasm());
326     splitTag(src, scratch);
327     return testString(cond, scratch);
328   }
testSymbol(Condition cond,const ValueOperand & src)329   Condition testSymbol(Condition cond, const ValueOperand& src) {
330     ScratchRegisterScope scratch(asMasm());
331     splitTag(src, scratch);
332     return testSymbol(cond, scratch);
333   }
testBigInt(Condition cond,const ValueOperand & src)334   Condition testBigInt(Condition cond, const ValueOperand& src) {
335     ScratchRegisterScope scratch(asMasm());
336     splitTag(src, scratch);
337     return testBigInt(cond, scratch);
338   }
testObject(Condition cond,const ValueOperand & src)339   Condition testObject(Condition cond, const ValueOperand& src) {
340     ScratchRegisterScope scratch(asMasm());
341     splitTag(src, scratch);
342     return testObject(cond, scratch);
343   }
testGCThing(Condition cond,const ValueOperand & src)344   Condition testGCThing(Condition cond, const ValueOperand& src) {
345     ScratchRegisterScope scratch(asMasm());
346     splitTag(src, scratch);
347     return testGCThing(cond, scratch);
348   }
testPrimitive(Condition cond,const ValueOperand & src)349   Condition testPrimitive(Condition cond, const ValueOperand& src) {
350     ScratchRegisterScope scratch(asMasm());
351     splitTag(src, scratch);
352     return testPrimitive(cond, scratch);
353   }
354 
testUndefined(Condition cond,const Address & src)355   Condition testUndefined(Condition cond, const Address& src) {
356     cmp32(ToUpper32(src),
357           Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_UNDEFINED))));
358     return cond;
359   }
testInt32(Condition cond,const Address & src)360   Condition testInt32(Condition cond, const Address& src) {
361     cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_INT32))));
362     return cond;
363   }
testBoolean(Condition cond,const Address & src)364   Condition testBoolean(Condition cond, const Address& src) {
365     cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_BOOLEAN))));
366     return cond;
367   }
testDouble(Condition cond,const Address & src)368   Condition testDouble(Condition cond, const Address& src) {
369     ScratchRegisterScope scratch(asMasm());
370     splitTag(src, scratch);
371     return testDouble(cond, scratch);
372   }
testNumber(Condition cond,const Address & src)373   Condition testNumber(Condition cond, const Address& src) {
374     ScratchRegisterScope scratch(asMasm());
375     splitTag(src, scratch);
376     return testNumber(cond, scratch);
377   }
testNull(Condition cond,const Address & src)378   Condition testNull(Condition cond, const Address& src) {
379     cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_NULL))));
380     return cond;
381   }
testString(Condition cond,const Address & src)382   Condition testString(Condition cond, const Address& src) {
383     ScratchRegisterScope scratch(asMasm());
384     splitTag(src, scratch);
385     return testString(cond, scratch);
386   }
testSymbol(Condition cond,const Address & src)387   Condition testSymbol(Condition cond, const Address& src) {
388     ScratchRegisterScope scratch(asMasm());
389     splitTag(src, scratch);
390     return testSymbol(cond, scratch);
391   }
testBigInt(Condition cond,const Address & src)392   Condition testBigInt(Condition cond, const Address& src) {
393     ScratchRegisterScope scratch(asMasm());
394     splitTag(src, scratch);
395     return testBigInt(cond, scratch);
396   }
testObject(Condition cond,const Address & src)397   Condition testObject(Condition cond, const Address& src) {
398     ScratchRegisterScope scratch(asMasm());
399     splitTag(src, scratch);
400     return testObject(cond, scratch);
401   }
testPrimitive(Condition cond,const Address & src)402   Condition testPrimitive(Condition cond, const Address& src) {
403     ScratchRegisterScope scratch(asMasm());
404     splitTag(src, scratch);
405     return testPrimitive(cond, scratch);
406   }
testGCThing(Condition cond,const Address & src)407   Condition testGCThing(Condition cond, const Address& src) {
408     ScratchRegisterScope scratch(asMasm());
409     splitTag(src, scratch);
410     return testGCThing(cond, scratch);
411   }
testMagic(Condition cond,const Address & src)412   Condition testMagic(Condition cond, const Address& src) {
413     ScratchRegisterScope scratch(asMasm());
414     splitTag(src, scratch);
415     return testMagic(cond, scratch);
416   }
417 
testUndefined(Condition cond,const BaseIndex & src)418   Condition testUndefined(Condition cond, const BaseIndex& src) {
419     ScratchRegisterScope scratch(asMasm());
420     splitTag(src, scratch);
421     return testUndefined(cond, scratch);
422   }
testNull(Condition cond,const BaseIndex & src)423   Condition testNull(Condition cond, const BaseIndex& src) {
424     ScratchRegisterScope scratch(asMasm());
425     splitTag(src, scratch);
426     return testNull(cond, scratch);
427   }
testBoolean(Condition cond,const BaseIndex & src)428   Condition testBoolean(Condition cond, const BaseIndex& src) {
429     ScratchRegisterScope scratch(asMasm());
430     splitTag(src, scratch);
431     return testBoolean(cond, scratch);
432   }
testString(Condition cond,const BaseIndex & src)433   Condition testString(Condition cond, const BaseIndex& src) {
434     ScratchRegisterScope scratch(asMasm());
435     splitTag(src, scratch);
436     return testString(cond, scratch);
437   }
testSymbol(Condition cond,const BaseIndex & src)438   Condition testSymbol(Condition cond, const BaseIndex& src) {
439     ScratchRegisterScope scratch(asMasm());
440     splitTag(src, scratch);
441     return testSymbol(cond, scratch);
442   }
testBigInt(Condition cond,const BaseIndex & src)443   Condition testBigInt(Condition cond, const BaseIndex& src) {
444     ScratchRegisterScope scratch(asMasm());
445     splitTag(src, scratch);
446     return testBigInt(cond, scratch);
447   }
testInt32(Condition cond,const BaseIndex & src)448   Condition testInt32(Condition cond, const BaseIndex& src) {
449     ScratchRegisterScope scratch(asMasm());
450     splitTag(src, scratch);
451     return testInt32(cond, scratch);
452   }
testObject(Condition cond,const BaseIndex & src)453   Condition testObject(Condition cond, const BaseIndex& src) {
454     ScratchRegisterScope scratch(asMasm());
455     splitTag(src, scratch);
456     return testObject(cond, scratch);
457   }
testDouble(Condition cond,const BaseIndex & src)458   Condition testDouble(Condition cond, const BaseIndex& src) {
459     ScratchRegisterScope scratch(asMasm());
460     splitTag(src, scratch);
461     return testDouble(cond, scratch);
462   }
testMagic(Condition cond,const BaseIndex & src)463   Condition testMagic(Condition cond, const BaseIndex& src) {
464     ScratchRegisterScope scratch(asMasm());
465     splitTag(src, scratch);
466     return testMagic(cond, scratch);
467   }
testGCThing(Condition cond,const BaseIndex & src)468   Condition testGCThing(Condition cond, const BaseIndex& src) {
469     ScratchRegisterScope scratch(asMasm());
470     splitTag(src, scratch);
471     return testGCThing(cond, scratch);
472   }
473 
isMagic(Condition cond,const ValueOperand & src,JSWhyMagic why)474   Condition isMagic(Condition cond, const ValueOperand& src, JSWhyMagic why) {
475     uint64_t magic = MagicValue(why).asRawBits();
476     cmpPtr(src.valueReg(), ImmWord(magic));
477     return cond;
478   }
479 
cmpPtr(Register lhs,const ImmWord rhs)480   void cmpPtr(Register lhs, const ImmWord rhs) {
481     ScratchRegisterScope scratch(asMasm());
482     MOZ_ASSERT(lhs != scratch);
483     if (intptr_t(rhs.value) <= INT32_MAX && intptr_t(rhs.value) >= INT32_MIN) {
484       cmpPtr(lhs, Imm32(int32_t(rhs.value)));
485     } else {
486       movePtr(rhs, scratch);
487       cmpPtr(lhs, scratch);
488     }
489   }
cmpPtr(Register lhs,const ImmPtr rhs)490   void cmpPtr(Register lhs, const ImmPtr rhs) {
491     cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
492   }
cmpPtr(Register lhs,const ImmGCPtr rhs)493   void cmpPtr(Register lhs, const ImmGCPtr rhs) {
494     ScratchRegisterScope scratch(asMasm());
495     MOZ_ASSERT(lhs != scratch);
496     movePtr(rhs, scratch);
497     cmpPtr(lhs, scratch);
498   }
cmpPtr(Register lhs,const Imm32 rhs)499   void cmpPtr(Register lhs, const Imm32 rhs) { cmpq(rhs, lhs); }
cmpPtr(const Operand & lhs,const ImmGCPtr rhs)500   void cmpPtr(const Operand& lhs, const ImmGCPtr rhs) {
501     ScratchRegisterScope scratch(asMasm());
502     MOZ_ASSERT(!lhs.containsReg(scratch));
503     movePtr(rhs, scratch);
504     cmpPtr(lhs, scratch);
505   }
cmpPtr(const Operand & lhs,const ImmWord rhs)506   void cmpPtr(const Operand& lhs, const ImmWord rhs) {
507     if ((intptr_t)rhs.value <= INT32_MAX && (intptr_t)rhs.value >= INT32_MIN) {
508       cmpPtr(lhs, Imm32((int32_t)rhs.value));
509     } else {
510       ScratchRegisterScope scratch(asMasm());
511       movePtr(rhs, scratch);
512       cmpPtr(lhs, scratch);
513     }
514   }
cmpPtr(const Operand & lhs,const ImmPtr rhs)515   void cmpPtr(const Operand& lhs, const ImmPtr rhs) {
516     cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
517   }
cmpPtr(const Address & lhs,const ImmGCPtr rhs)518   void cmpPtr(const Address& lhs, const ImmGCPtr rhs) {
519     cmpPtr(Operand(lhs), rhs);
520   }
cmpPtr(const Address & lhs,const ImmWord rhs)521   void cmpPtr(const Address& lhs, const ImmWord rhs) {
522     cmpPtr(Operand(lhs), rhs);
523   }
cmpPtr(const Address & lhs,const ImmPtr rhs)524   void cmpPtr(const Address& lhs, const ImmPtr rhs) {
525     cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
526   }
cmpPtr(const Operand & lhs,Register rhs)527   void cmpPtr(const Operand& lhs, Register rhs) { cmpq(rhs, lhs); }
cmpPtr(Register lhs,const Operand & rhs)528   void cmpPtr(Register lhs, const Operand& rhs) { cmpq(rhs, lhs); }
cmpPtr(const Operand & lhs,const Imm32 rhs)529   void cmpPtr(const Operand& lhs, const Imm32 rhs) { cmpq(rhs, lhs); }
cmpPtr(const Address & lhs,Register rhs)530   void cmpPtr(const Address& lhs, Register rhs) { cmpPtr(Operand(lhs), rhs); }
cmpPtr(Register lhs,Register rhs)531   void cmpPtr(Register lhs, Register rhs) { cmpq(rhs, lhs); }
testPtr(Register lhs,Register rhs)532   void testPtr(Register lhs, Register rhs) { testq(rhs, lhs); }
testPtr(Register lhs,Imm32 rhs)533   void testPtr(Register lhs, Imm32 rhs) { testq(rhs, lhs); }
testPtr(const Operand & lhs,Imm32 rhs)534   void testPtr(const Operand& lhs, Imm32 rhs) { testq(rhs, lhs); }
test64(Register lhs,Register rhs)535   void test64(Register lhs, Register rhs) { testq(rhs, lhs); }
test64(Register lhs,const Imm64 rhs)536   void test64(Register lhs, const Imm64 rhs) {
537     if ((intptr_t)rhs.value <= INT32_MAX && (intptr_t)rhs.value >= INT32_MIN) {
538       testq(Imm32((int32_t)rhs.value), lhs);
539     } else {
540       ScratchRegisterScope scratch(asMasm());
541       movq(ImmWord(rhs.value), scratch);
542       testq(scratch, lhs);
543     }
544   }
545 
546   // Compare-then-conditionally-move/load, for integer types
547   template <size_t CmpSize, size_t MoveSize>
548   void cmpMove(Condition cond, Register lhs, Register rhs, Register falseVal,
549                Register trueValAndDest);
550 
551   template <size_t CmpSize, size_t MoveSize>
552   void cmpMove(Condition cond, Register lhs, const Address& rhs,
553                Register falseVal, Register trueValAndDest);
554 
555   template <size_t CmpSize, size_t LoadSize>
556   void cmpLoad(Condition cond, Register lhs, Register rhs,
557                const Address& falseVal, Register trueValAndDest);
558 
559   template <size_t CmpSize, size_t LoadSize>
560   void cmpLoad(Condition cond, Register lhs, const Address& rhs,
561                const Address& falseVal, Register trueValAndDest);
562 
563   /////////////////////////////////////////////////////////////////
564   // Common interface.
565   /////////////////////////////////////////////////////////////////
566 
movePtr(Register src,Register dest)567   void movePtr(Register src, Register dest) { movq(src, dest); }
movePtr(Register src,const Operand & dest)568   void movePtr(Register src, const Operand& dest) { movq(src, dest); }
movePtr(ImmWord imm,Register dest)569   void movePtr(ImmWord imm, Register dest) { mov(imm, dest); }
movePtr(ImmPtr imm,Register dest)570   void movePtr(ImmPtr imm, Register dest) { mov(imm, dest); }
movePtr(wasm::SymbolicAddress imm,Register dest)571   void movePtr(wasm::SymbolicAddress imm, Register dest) { mov(imm, dest); }
movePtr(ImmGCPtr imm,Register dest)572   void movePtr(ImmGCPtr imm, Register dest) { movq(imm, dest); }
loadPtr(AbsoluteAddress address,Register dest)573   void loadPtr(AbsoluteAddress address, Register dest) {
574     if (X86Encoding::IsAddressImmediate(address.addr)) {
575       movq(Operand(address), dest);
576     } else {
577       ScratchRegisterScope scratch(asMasm());
578       mov(ImmPtr(address.addr), scratch);
579       loadPtr(Address(scratch, 0x0), dest);
580     }
581   }
loadPtr(const Address & address,Register dest)582   void loadPtr(const Address& address, Register dest) {
583     movq(Operand(address), dest);
584   }
load64(const Address & address,Register dest)585   void load64(const Address& address, Register dest) {
586     movq(Operand(address), dest);
587   }
loadPtr(const Operand & src,Register dest)588   void loadPtr(const Operand& src, Register dest) { movq(src, dest); }
loadPtr(const BaseIndex & src,Register dest)589   void loadPtr(const BaseIndex& src, Register dest) {
590     movq(Operand(src), dest);
591   }
loadPrivate(const Address & src,Register dest)592   void loadPrivate(const Address& src, Register dest) { loadPtr(src, dest); }
load32(AbsoluteAddress address,Register dest)593   void load32(AbsoluteAddress address, Register dest) {
594     if (X86Encoding::IsAddressImmediate(address.addr)) {
595       movl(Operand(address), dest);
596     } else {
597       ScratchRegisterScope scratch(asMasm());
598       mov(ImmPtr(address.addr), scratch);
599       load32(Address(scratch, 0x0), dest);
600     }
601   }
load64(const Operand & address,Register64 dest)602   void load64(const Operand& address, Register64 dest) {
603     movq(address, dest.reg);
604   }
load64(const Address & address,Register64 dest)605   void load64(const Address& address, Register64 dest) {
606     movq(Operand(address), dest.reg);
607   }
load64(const BaseIndex & address,Register64 dest)608   void load64(const BaseIndex& address, Register64 dest) {
609     movq(Operand(address), dest.reg);
610   }
611   template <typename S>
load64Unaligned(const S & src,Register64 dest)612   void load64Unaligned(const S& src, Register64 dest) {
613     load64(src, dest);
614   }
615   template <typename T>
storePtr(ImmWord imm,T address)616   void storePtr(ImmWord imm, T address) {
617     if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) {
618       movq(Imm32((int32_t)imm.value), Operand(address));
619     } else {
620       ScratchRegisterScope scratch(asMasm());
621       mov(imm, scratch);
622       movq(scratch, Operand(address));
623     }
624   }
625   template <typename T>
storePtr(ImmPtr imm,T address)626   void storePtr(ImmPtr imm, T address) {
627     storePtr(ImmWord(uintptr_t(imm.value)), address);
628   }
629   template <typename T>
storePtr(ImmGCPtr imm,T address)630   void storePtr(ImmGCPtr imm, T address) {
631     ScratchRegisterScope scratch(asMasm());
632     movq(imm, scratch);
633     movq(scratch, Operand(address));
634   }
storePtr(Register src,const Address & address)635   void storePtr(Register src, const Address& address) {
636     movq(src, Operand(address));
637   }
store64(Register src,const Address & address)638   void store64(Register src, const Address& address) {
639     movq(src, Operand(address));
640   }
store64(Register64 src,const Operand & address)641   void store64(Register64 src, const Operand& address) {
642     movq(src.reg, address);
643   }
storePtr(Register src,const BaseIndex & address)644   void storePtr(Register src, const BaseIndex& address) {
645     movq(src, Operand(address));
646   }
storePtr(Register src,const Operand & dest)647   void storePtr(Register src, const Operand& dest) { movq(src, dest); }
storePtr(Register src,AbsoluteAddress address)648   void storePtr(Register src, AbsoluteAddress address) {
649     if (X86Encoding::IsAddressImmediate(address.addr)) {
650       movq(src, Operand(address));
651     } else {
652       ScratchRegisterScope scratch(asMasm());
653       mov(ImmPtr(address.addr), scratch);
654       storePtr(src, Address(scratch, 0x0));
655     }
656   }
store32(Register src,AbsoluteAddress address)657   void store32(Register src, AbsoluteAddress address) {
658     if (X86Encoding::IsAddressImmediate(address.addr)) {
659       movl(src, Operand(address));
660     } else {
661       ScratchRegisterScope scratch(asMasm());
662       mov(ImmPtr(address.addr), scratch);
663       store32(src, Address(scratch, 0x0));
664     }
665   }
store16(Register src,AbsoluteAddress address)666   void store16(Register src, AbsoluteAddress address) {
667     if (X86Encoding::IsAddressImmediate(address.addr)) {
668       movw(src, Operand(address));
669     } else {
670       ScratchRegisterScope scratch(asMasm());
671       mov(ImmPtr(address.addr), scratch);
672       store16(src, Address(scratch, 0x0));
673     }
674   }
store64(Register64 src,Address address)675   void store64(Register64 src, Address address) { storePtr(src.reg, address); }
store64(Register64 src,const BaseIndex & address)676   void store64(Register64 src, const BaseIndex& address) {
677     storePtr(src.reg, address);
678   }
store64(Imm64 imm,Address address)679   void store64(Imm64 imm, Address address) {
680     storePtr(ImmWord(imm.value), address);
681   }
store64(Imm64 imm,const BaseIndex & address)682   void store64(Imm64 imm, const BaseIndex& address) {
683     storePtr(ImmWord(imm.value), address);
684   }
685   template <typename S, typename T>
store64Unaligned(const S & src,const T & dest)686   void store64Unaligned(const S& src, const T& dest) {
687     store64(src, dest);
688   }
689 
splitTag(Register src,Register dest)690   void splitTag(Register src, Register dest) {
691     if (src != dest) {
692       movq(src, dest);
693     }
694     shrq(Imm32(JSVAL_TAG_SHIFT), dest);
695   }
splitTag(const ValueOperand & operand,Register dest)696   void splitTag(const ValueOperand& operand, Register dest) {
697     splitTag(operand.valueReg(), dest);
698   }
splitTag(const Operand & operand,Register dest)699   void splitTag(const Operand& operand, Register dest) {
700     movq(operand, dest);
701     shrq(Imm32(JSVAL_TAG_SHIFT), dest);
702   }
splitTag(const Address & operand,Register dest)703   void splitTag(const Address& operand, Register dest) {
704     splitTag(Operand(operand), dest);
705   }
splitTag(const BaseIndex & operand,Register dest)706   void splitTag(const BaseIndex& operand, Register dest) {
707     splitTag(Operand(operand), dest);
708   }
709 
710   // Extracts the tag of a value and places it in tag.
splitTagForTest(const ValueOperand & value,ScratchTagScope & tag)711   void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag) {
712     splitTag(value, tag);
713   }
cmpTag(const ValueOperand & operand,ImmTag tag)714   void cmpTag(const ValueOperand& operand, ImmTag tag) {
715     ScratchTagScope reg(asMasm(), operand);
716     splitTagForTest(operand, reg);
717     cmp32(reg, tag);
718   }
719 
testMagic(Condition cond,const ValueOperand & src)720   Condition testMagic(Condition cond, const ValueOperand& src) {
721     ScratchTagScope scratch(asMasm(), src);
722     splitTagForTest(src, scratch);
723     return testMagic(cond, scratch);
724   }
testError(Condition cond,const ValueOperand & src)725   Condition testError(Condition cond, const ValueOperand& src) {
726     return testMagic(cond, src);
727   }
728 
testNullSet(Condition cond,const ValueOperand & value,Register dest)729   void testNullSet(Condition cond, const ValueOperand& value, Register dest) {
730     cond = testNull(cond, value);
731     emitSet(cond, dest);
732   }
733 
testObjectSet(Condition cond,const ValueOperand & value,Register dest)734   void testObjectSet(Condition cond, const ValueOperand& value, Register dest) {
735     cond = testObject(cond, value);
736     emitSet(cond, dest);
737   }
738 
testUndefinedSet(Condition cond,const ValueOperand & value,Register dest)739   void testUndefinedSet(Condition cond, const ValueOperand& value,
740                         Register dest) {
741     cond = testUndefined(cond, value);
742     emitSet(cond, dest);
743   }
744 
boxDouble(FloatRegister src,const ValueOperand & dest,FloatRegister)745   void boxDouble(FloatRegister src, const ValueOperand& dest, FloatRegister) {
746     vmovq(src, dest.valueReg());
747   }
boxNonDouble(JSValueType type,Register src,const ValueOperand & dest)748   void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) {
749     MOZ_ASSERT(src != dest.valueReg());
750     boxValue(type, src, dest.valueReg());
751   }
752 
753   // Note that the |dest| register here may be ScratchReg, so we shouldn't
754   // use it.
unboxInt32(const ValueOperand & src,Register dest)755   void unboxInt32(const ValueOperand& src, Register dest) {
756     movl(src.valueReg(), dest);
757   }
unboxInt32(const Operand & src,Register dest)758   void unboxInt32(const Operand& src, Register dest) { movl(src, dest); }
unboxInt32(const Address & src,Register dest)759   void unboxInt32(const Address& src, Register dest) {
760     unboxInt32(Operand(src), dest);
761   }
unboxInt32(const BaseIndex & src,Register dest)762   void unboxInt32(const BaseIndex& src, Register dest) {
763     unboxInt32(Operand(src), dest);
764   }
765   template <typename T>
unboxDouble(const T & src,FloatRegister dest)766   void unboxDouble(const T& src, FloatRegister dest) {
767     loadDouble(Operand(src), dest);
768   }
769 
unboxArgObjMagic(const ValueOperand & src,Register dest)770   void unboxArgObjMagic(const ValueOperand& src, Register dest) {
771     unboxArgObjMagic(Operand(src.valueReg()), dest);
772   }
unboxArgObjMagic(const Operand & src,Register dest)773   void unboxArgObjMagic(const Operand& src, Register dest) {
774     mov(ImmWord(0), dest);
775   }
unboxArgObjMagic(const Address & src,Register dest)776   void unboxArgObjMagic(const Address& src, Register dest) {
777     unboxArgObjMagic(Operand(src), dest);
778   }
779 
unboxBoolean(const ValueOperand & src,Register dest)780   void unboxBoolean(const ValueOperand& src, Register dest) {
781     movl(src.valueReg(), dest);
782   }
unboxBoolean(const Operand & src,Register dest)783   void unboxBoolean(const Operand& src, Register dest) { movl(src, dest); }
unboxBoolean(const Address & src,Register dest)784   void unboxBoolean(const Address& src, Register dest) {
785     unboxBoolean(Operand(src), dest);
786   }
unboxBoolean(const BaseIndex & src,Register dest)787   void unboxBoolean(const BaseIndex& src, Register dest) {
788     unboxBoolean(Operand(src), dest);
789   }
790 
unboxMagic(const ValueOperand & src,Register dest)791   void unboxMagic(const ValueOperand& src, Register dest) {
792     movl(src.valueReg(), dest);
793   }
794 
unboxDouble(const ValueOperand & src,FloatRegister dest)795   void unboxDouble(const ValueOperand& src, FloatRegister dest) {
796     vmovq(src.valueReg(), dest);
797   }
798 
notBoolean(const ValueOperand & val)799   void notBoolean(const ValueOperand& val) { xorq(Imm32(1), val.valueReg()); }
800 
unboxNonDouble(const ValueOperand & src,Register dest,JSValueType type)801   void unboxNonDouble(const ValueOperand& src, Register dest,
802                       JSValueType type) {
803     MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
804     if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
805       movl(src.valueReg(), dest);
806       return;
807     }
808     if (src.valueReg() == dest) {
809       ScratchRegisterScope scratch(asMasm());
810       mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), scratch);
811       xorq(scratch, dest);
812     } else {
813       mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), dest);
814       xorq(src.valueReg(), dest);
815     }
816   }
unboxNonDouble(const Operand & src,Register dest,JSValueType type)817   void unboxNonDouble(const Operand& src, Register dest, JSValueType type) {
818     MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
819     if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
820       movl(src, dest);
821       return;
822     }
823     // Explicitly permits |dest| to be used in |src|.
824     ScratchRegisterScope scratch(asMasm());
825     MOZ_ASSERT(dest != scratch);
826     if (src.containsReg(dest)) {
827       mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), scratch);
828       // If src is already a register, then src and dest are the same
829       // thing and we don't need to move anything into dest.
830       if (src.kind() != Operand::REG) {
831         movq(src, dest);
832       }
833       xorq(scratch, dest);
834     } else {
835       mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), dest);
836       xorq(src, dest);
837     }
838   }
unboxNonDouble(const Address & src,Register dest,JSValueType type)839   void unboxNonDouble(const Address& src, Register dest, JSValueType type) {
840     unboxNonDouble(Operand(src), dest, type);
841   }
unboxNonDouble(const BaseIndex & src,Register dest,JSValueType type)842   void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType type) {
843     unboxNonDouble(Operand(src), dest, type);
844   }
845 
unboxString(const ValueOperand & src,Register dest)846   void unboxString(const ValueOperand& src, Register dest) {
847     unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
848   }
unboxString(const Operand & src,Register dest)849   void unboxString(const Operand& src, Register dest) {
850     unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
851   }
unboxString(const Address & src,Register dest)852   void unboxString(const Address& src, Register dest) {
853     unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
854   }
855 
unboxSymbol(const ValueOperand & src,Register dest)856   void unboxSymbol(const ValueOperand& src, Register dest) {
857     unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
858   }
unboxSymbol(const Operand & src,Register dest)859   void unboxSymbol(const Operand& src, Register dest) {
860     unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
861   }
862 
unboxBigInt(const ValueOperand & src,Register dest)863   void unboxBigInt(const ValueOperand& src, Register dest) {
864     unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT);
865   }
unboxBigInt(const Operand & src,Register dest)866   void unboxBigInt(const Operand& src, Register dest) {
867     unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT);
868   }
unboxBigInt(const Address & src,Register dest)869   void unboxBigInt(const Address& src, Register dest) {
870     unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT);
871   }
872 
unboxObject(const ValueOperand & src,Register dest)873   void unboxObject(const ValueOperand& src, Register dest) {
874     unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
875   }
unboxObject(const Operand & src,Register dest)876   void unboxObject(const Operand& src, Register dest) {
877     unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
878   }
unboxObject(const Address & src,Register dest)879   void unboxObject(const Address& src, Register dest) {
880     unboxNonDouble(Operand(src), dest, JSVAL_TYPE_OBJECT);
881   }
unboxObject(const BaseIndex & src,Register dest)882   void unboxObject(const BaseIndex& src, Register dest) {
883     unboxNonDouble(Operand(src), dest, JSVAL_TYPE_OBJECT);
884   }
885 
886   template <typename T>
unboxObjectOrNull(const T & src,Register dest)887   void unboxObjectOrNull(const T& src, Register dest) {
888     unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
889     ScratchRegisterScope scratch(asMasm());
890     mov(ImmWord(~JS::detail::ValueObjectOrNullBit), scratch);
891     andq(scratch, dest);
892   }
893 
894   // This should only be used for GC barrier code, to unbox a GC thing Value.
895   // It's fine there because we don't depend on the actual Value type (all Cells
896   // are treated the same way). In almost all other cases this would be
897   // Spectre-unsafe - use unboxNonDouble and friends instead.
unboxGCThingForGCBarrier(const Address & src,Register dest)898   void unboxGCThingForGCBarrier(const Address& src, Register dest) {
899     movq(ImmWord(JS::detail::ValueGCThingPayloadMask), dest);
900     andq(Operand(src), dest);
901   }
unboxGCThingForGCBarrier(const ValueOperand & src,Register dest)902   void unboxGCThingForGCBarrier(const ValueOperand& src, Register dest) {
903     MOZ_ASSERT(src.valueReg() != dest);
904     movq(ImmWord(JS::detail::ValueGCThingPayloadMask), dest);
905     andq(src.valueReg(), dest);
906   }
907 
908   inline void fallibleUnboxPtrImpl(const Operand& src, Register dest,
909                                    JSValueType type, Label* fail);
910 
911   // Extended unboxing API. If the payload is already in a register, returns
912   // that register. Otherwise, provides a move to the given scratch register,
913   // and returns that.
extractObject(const Address & address,Register scratch)914   [[nodiscard]] Register extractObject(const Address& address,
915                                        Register scratch) {
916     MOZ_ASSERT(scratch != ScratchReg);
917     unboxObject(address, scratch);
918     return scratch;
919   }
extractObject(const ValueOperand & value,Register scratch)920   [[nodiscard]] Register extractObject(const ValueOperand& value,
921                                        Register scratch) {
922     MOZ_ASSERT(scratch != ScratchReg);
923     unboxObject(value, scratch);
924     return scratch;
925   }
extractSymbol(const ValueOperand & value,Register scratch)926   [[nodiscard]] Register extractSymbol(const ValueOperand& value,
927                                        Register scratch) {
928     MOZ_ASSERT(scratch != ScratchReg);
929     unboxSymbol(value, scratch);
930     return scratch;
931   }
extractInt32(const ValueOperand & value,Register scratch)932   [[nodiscard]] Register extractInt32(const ValueOperand& value,
933                                       Register scratch) {
934     MOZ_ASSERT(scratch != ScratchReg);
935     unboxInt32(value, scratch);
936     return scratch;
937   }
extractBoolean(const ValueOperand & value,Register scratch)938   [[nodiscard]] Register extractBoolean(const ValueOperand& value,
939                                         Register scratch) {
940     MOZ_ASSERT(scratch != ScratchReg);
941     unboxBoolean(value, scratch);
942     return scratch;
943   }
extractTag(const Address & address,Register scratch)944   [[nodiscard]] Register extractTag(const Address& address, Register scratch) {
945     MOZ_ASSERT(scratch != ScratchReg);
946     loadPtr(address, scratch);
947     splitTag(scratch, scratch);
948     return scratch;
949   }
extractTag(const ValueOperand & value,Register scratch)950   [[nodiscard]] Register extractTag(const ValueOperand& value,
951                                     Register scratch) {
952     MOZ_ASSERT(scratch != ScratchReg);
953     splitTag(value, scratch);
954     return scratch;
955   }
956 
957   inline void unboxValue(const ValueOperand& src, AnyRegister dest,
958                          JSValueType type);
959 
960   // These two functions use the low 32-bits of the full value register.
boolValueToDouble(const ValueOperand & operand,FloatRegister dest)961   void boolValueToDouble(const ValueOperand& operand, FloatRegister dest) {
962     convertInt32ToDouble(operand.valueReg(), dest);
963   }
int32ValueToDouble(const ValueOperand & operand,FloatRegister dest)964   void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest) {
965     convertInt32ToDouble(operand.valueReg(), dest);
966   }
967 
boolValueToFloat32(const ValueOperand & operand,FloatRegister dest)968   void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
969     convertInt32ToFloat32(operand.valueReg(), dest);
970   }
int32ValueToFloat32(const ValueOperand & operand,FloatRegister dest)971   void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
972     convertInt32ToFloat32(operand.valueReg(), dest);
973   }
974 
975   void loadConstantDouble(double d, FloatRegister dest);
976   void loadConstantFloat32(float f, FloatRegister dest);
977 
978   void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest);
979   void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest);
980   void vpaddbSimd128(const SimdConstant& v, FloatRegister lhs,
981                      FloatRegister dest);
982   void vpaddwSimd128(const SimdConstant& v, FloatRegister lhs,
983                      FloatRegister dest);
984   void vpadddSimd128(const SimdConstant& v, FloatRegister lhs,
985                      FloatRegister dest);
986   void vpaddqSimd128(const SimdConstant& v, FloatRegister lhs,
987                      FloatRegister dest);
988   void vpsubbSimd128(const SimdConstant& v, FloatRegister lhs,
989                      FloatRegister dest);
990   void vpsubwSimd128(const SimdConstant& v, FloatRegister lhs,
991                      FloatRegister dest);
992   void vpsubdSimd128(const SimdConstant& v, FloatRegister lhs,
993                      FloatRegister dest);
994   void vpsubqSimd128(const SimdConstant& v, FloatRegister lhs,
995                      FloatRegister dest);
996   void vpmullwSimd128(const SimdConstant& v, FloatRegister lhs,
997                       FloatRegister dest);
998   void vpmulldSimd128(const SimdConstant& v, FloatRegister lhs,
999                       FloatRegister dest);
1000   void vpaddsbSimd128(const SimdConstant& v, FloatRegister lhs,
1001                       FloatRegister dest);
1002   void vpaddusbSimd128(const SimdConstant& v, FloatRegister lhs,
1003                        FloatRegister dest);
1004   void vpaddswSimd128(const SimdConstant& v, FloatRegister lhs,
1005                       FloatRegister dest);
1006   void vpadduswSimd128(const SimdConstant& v, FloatRegister lhs,
1007                        FloatRegister dest);
1008   void vpsubsbSimd128(const SimdConstant& v, FloatRegister lhs,
1009                       FloatRegister dest);
1010   void vpsubusbSimd128(const SimdConstant& v, FloatRegister lhs,
1011                        FloatRegister dest);
1012   void vpsubswSimd128(const SimdConstant& v, FloatRegister lhs,
1013                       FloatRegister dest);
1014   void vpsubuswSimd128(const SimdConstant& v, FloatRegister lhs,
1015                        FloatRegister dest);
1016   void vpminsbSimd128(const SimdConstant& v, FloatRegister lhs,
1017                       FloatRegister dest);
1018   void vpminubSimd128(const SimdConstant& v, FloatRegister lhs,
1019                       FloatRegister dest);
1020   void vpminswSimd128(const SimdConstant& v, FloatRegister lhs,
1021                       FloatRegister dest);
1022   void vpminuwSimd128(const SimdConstant& v, FloatRegister lhs,
1023                       FloatRegister dest);
1024   void vpminsdSimd128(const SimdConstant& v, FloatRegister lhs,
1025                       FloatRegister dest);
1026   void vpminudSimd128(const SimdConstant& v, FloatRegister lhs,
1027                       FloatRegister dest);
1028   void vpmaxsbSimd128(const SimdConstant& v, FloatRegister lhs,
1029                       FloatRegister dest);
1030   void vpmaxubSimd128(const SimdConstant& v, FloatRegister lhs,
1031                       FloatRegister dest);
1032   void vpmaxswSimd128(const SimdConstant& v, FloatRegister lhs,
1033                       FloatRegister dest);
1034   void vpmaxuwSimd128(const SimdConstant& v, FloatRegister lhs,
1035                       FloatRegister dest);
1036   void vpmaxsdSimd128(const SimdConstant& v, FloatRegister lhs,
1037                       FloatRegister dest);
1038   void vpmaxudSimd128(const SimdConstant& v, FloatRegister lhs,
1039                       FloatRegister dest);
1040   void vpandSimd128(const SimdConstant& v, FloatRegister lhs,
1041                     FloatRegister dest);
1042   void vpxorSimd128(const SimdConstant& v, FloatRegister lhs,
1043                     FloatRegister dest);
1044   void vporSimd128(const SimdConstant& v, FloatRegister lhs,
1045                    FloatRegister dest);
1046   void vaddpsSimd128(const SimdConstant& v, FloatRegister lhs,
1047                      FloatRegister dest);
1048   void vaddpdSimd128(const SimdConstant& v, FloatRegister lhs,
1049                      FloatRegister dest);
1050   void vsubpsSimd128(const SimdConstant& v, FloatRegister lhs,
1051                      FloatRegister dest);
1052   void vsubpdSimd128(const SimdConstant& v, FloatRegister lhs,
1053                      FloatRegister dest);
1054   void vdivpsSimd128(const SimdConstant& v, FloatRegister lhs,
1055                      FloatRegister dest);
1056   void vdivpdSimd128(const SimdConstant& v, FloatRegister lhs,
1057                      FloatRegister dest);
1058   void vmulpsSimd128(const SimdConstant& v, FloatRegister lhs,
1059                      FloatRegister dest);
1060   void vmulpdSimd128(const SimdConstant& v, FloatRegister lhs,
1061                      FloatRegister dest);
1062   void vpacksswbSimd128(const SimdConstant& v, FloatRegister lhs,
1063                         FloatRegister dest);
1064   void vpackuswbSimd128(const SimdConstant& v, FloatRegister lhs,
1065                         FloatRegister dest);
1066   void vpackssdwSimd128(const SimdConstant& v, FloatRegister lhs,
1067                         FloatRegister dest);
1068   void vpackusdwSimd128(const SimdConstant& v, FloatRegister lhs,
1069                         FloatRegister dest);
1070   void vpshufbSimd128(const SimdConstant& v, FloatRegister lhs,
1071                       FloatRegister dest);
1072   void vptestSimd128(const SimdConstant& v, FloatRegister lhs);
1073   void vpmaddwdSimd128(const SimdConstant& v, FloatRegister lhs,
1074                        FloatRegister dest);
1075   void vpcmpeqbSimd128(const SimdConstant& v, FloatRegister lhs,
1076                        FloatRegister dest);
1077   void vpcmpgtbSimd128(const SimdConstant& v, FloatRegister lhs,
1078                        FloatRegister dest);
1079   void vpcmpeqwSimd128(const SimdConstant& v, FloatRegister lhs,
1080                        FloatRegister dest);
1081   void vpcmpgtwSimd128(const SimdConstant& v, FloatRegister lhs,
1082                        FloatRegister dest);
1083   void vpcmpeqdSimd128(const SimdConstant& v, FloatRegister lhs,
1084                        FloatRegister dest);
1085   void vpcmpgtdSimd128(const SimdConstant& v, FloatRegister lhs,
1086                        FloatRegister dest);
1087   void vcmpeqpsSimd128(const SimdConstant& v, FloatRegister lhs,
1088                        FloatRegister dest);
1089   void vcmpneqpsSimd128(const SimdConstant& v, FloatRegister lhs,
1090                         FloatRegister dest);
1091   void vcmpltpsSimd128(const SimdConstant& v, FloatRegister lhs,
1092                        FloatRegister dest);
1093   void vcmplepsSimd128(const SimdConstant& v, FloatRegister lhs,
1094                        FloatRegister dest);
1095   void vcmpeqpdSimd128(const SimdConstant& v, FloatRegister lhs,
1096                        FloatRegister dest);
1097   void vcmpneqpdSimd128(const SimdConstant& v, FloatRegister lhs,
1098                         FloatRegister dest);
1099   void vcmpltpdSimd128(const SimdConstant& v, FloatRegister lhs,
1100                        FloatRegister dest);
1101   void vcmplepdSimd128(const SimdConstant& v, FloatRegister lhs,
1102                        FloatRegister dest);
1103   void vpmaddubswSimd128(const SimdConstant& v, FloatRegister lhs,
1104                          FloatRegister dest);
1105 
1106  public:
testInt32Truthy(bool truthy,const ValueOperand & operand)1107   Condition testInt32Truthy(bool truthy, const ValueOperand& operand) {
1108     test32(operand.valueReg(), operand.valueReg());
1109     return truthy ? NonZero : Zero;
1110   }
1111   Condition testStringTruthy(bool truthy, const ValueOperand& value);
1112   Condition testBigIntTruthy(bool truthy, const ValueOperand& value);
1113 
1114   template <typename T>
1115   inline void loadInt32OrDouble(const T& src, FloatRegister dest);
1116 
1117   template <typename T>
loadUnboxedValue(const T & src,MIRType type,AnyRegister dest)1118   void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) {
1119     if (dest.isFloat()) {
1120       loadInt32OrDouble(src, dest.fpu());
1121     } else {
1122       unboxNonDouble(Operand(src), dest.gpr(), ValueTypeFromMIRType(type));
1123     }
1124   }
1125 
1126   template <typename T>
storeUnboxedPayload(ValueOperand value,T address,size_t nbytes,JSValueType type)1127   void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes,
1128                            JSValueType type) {
1129     switch (nbytes) {
1130       case 8: {
1131         ScratchRegisterScope scratch(asMasm());
1132         unboxNonDouble(value, scratch, type);
1133         storePtr(scratch, address);
1134         if (type == JSVAL_TYPE_OBJECT) {
1135           // Ideally we would call unboxObjectOrNull, but we need an extra
1136           // scratch register for that. So unbox as object, then clear the
1137           // object-or-null bit.
1138           mov(ImmWord(~JS::detail::ValueObjectOrNullBit), scratch);
1139           andq(scratch, Operand(address));
1140         }
1141         return;
1142       }
1143       case 4:
1144         store32(value.valueReg(), address);
1145         return;
1146       case 1:
1147         store8(value.valueReg(), address);
1148         return;
1149       default:
1150         MOZ_CRASH("Bad payload width");
1151     }
1152   }
1153 
loadInstructionPointerAfterCall(Register dest)1154   void loadInstructionPointerAfterCall(Register dest) {
1155     loadPtr(Address(StackPointer, 0x0), dest);
1156   }
1157 
1158   // Checks whether a double is representable as a 64-bit integer. If so, the
1159   // integer is written to the output register. Otherwise, a bailout is taken to
1160   // the given snapshot. This function overwrites the scratch float register.
1161   void convertDoubleToPtr(FloatRegister src, Register dest, Label* fail,
1162                           bool negativeZeroCheck = true);
1163 
convertUInt32ToDouble(Register src,FloatRegister dest)1164   void convertUInt32ToDouble(Register src, FloatRegister dest) {
1165     // Zero the output register to break dependencies, see convertInt32ToDouble.
1166     zeroDouble(dest);
1167 
1168     vcvtsq2sd(src, dest, dest);
1169   }
1170 
convertUInt32ToFloat32(Register src,FloatRegister dest)1171   void convertUInt32ToFloat32(Register src, FloatRegister dest) {
1172     // Zero the output register to break dependencies, see convertInt32ToDouble.
1173     zeroDouble(dest);
1174 
1175     vcvtsq2ss(src, dest, dest);
1176   }
1177 
1178   inline void incrementInt32Value(const Address& addr);
1179 
1180   inline void ensureDouble(const ValueOperand& source, FloatRegister dest,
1181                            Label* failure);
1182 
1183  public:
1184   void handleFailureWithHandlerTail(Label* profilerExitTail);
1185 
1186   // Instrumentation for entering and leaving the profiler.
1187   void profilerEnterFrame(Register framePtr, Register scratch);
1188   void profilerExitFrame();
1189 };
1190 
1191 using MacroAssemblerSpecific = MacroAssemblerX64;
1192 
1193 }  // namespace jit
1194 }  // namespace js
1195 
1196 #endif /* jit_x64_MacroAssembler_x64_h */
1197