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_mips32_MacroAssembler_mips32_h
8 #define jit_mips32_MacroAssembler_mips32_h
9 
10 #include "mozilla/EndianUtils.h"
11 
12 #include "jit/JitFrames.h"
13 #include "jit/mips-shared/MacroAssembler-mips-shared.h"
14 #include "jit/MoveResolver.h"
15 #include "vm/BytecodeUtil.h"
16 
17 namespace js {
18 namespace jit {
19 
20 struct ImmTag : public Imm32 {
ImmTagImmTag21   ImmTag(JSValueTag mask) : Imm32(int32_t(mask)) {}
22 };
23 
24 struct ImmType : public ImmTag {
ImmTypeImmType25   ImmType(JSValueType type) : ImmTag(JSVAL_TYPE_TO_TAG(type)) {}
26 };
27 
28 static constexpr ValueOperand JSReturnOperand{JSReturnReg_Type,
29                                               JSReturnReg_Data};
30 static const ValueOperand softfpReturnOperand = ValueOperand(v1, v0);
31 
32 static const int defaultShift = 3;
33 static_assert(1 << defaultShift == sizeof(JS::Value),
34               "The defaultShift is wrong");
35 
36 static const uint32_t LOW_32_MASK = (1LL << 32) - 1;
37 #if MOZ_LITTLE_ENDIAN()
38 static const int32_t LOW_32_OFFSET = 0;
39 static const int32_t HIGH_32_OFFSET = 4;
40 #else
41 static const int32_t LOW_32_OFFSET = 4;
42 static const int32_t HIGH_32_OFFSET = 0;
43 #endif
44 
45 // See documentation for ScratchTagScope and ScratchTagScopeRelease in
46 // MacroAssembler-x64.h.
47 
48 class ScratchTagScope {
49   const ValueOperand& v_;
50 
51  public:
ScratchTagScope(MacroAssembler &,const ValueOperand & v)52   ScratchTagScope(MacroAssembler&, const ValueOperand& v) : v_(v) {}
Register()53   operator Register() { return v_.typeReg(); }
release()54   void release() {}
reacquire()55   void reacquire() {}
56 };
57 
58 class ScratchTagScopeRelease {
59  public:
ScratchTagScopeRelease(ScratchTagScope *)60   explicit ScratchTagScopeRelease(ScratchTagScope*) {}
61 };
62 
63 class MacroAssemblerMIPS : public MacroAssemblerMIPSShared {
64  public:
65   using MacroAssemblerMIPSShared::ma_b;
66   using MacroAssemblerMIPSShared::ma_cmp_set;
67   using MacroAssemblerMIPSShared::ma_ld;
68   using MacroAssemblerMIPSShared::ma_li;
69   using MacroAssemblerMIPSShared::ma_liPatchable;
70   using MacroAssemblerMIPSShared::ma_load;
71   using MacroAssemblerMIPSShared::ma_ls;
72   using MacroAssemblerMIPSShared::ma_sd;
73   using MacroAssemblerMIPSShared::ma_ss;
74   using MacroAssemblerMIPSShared::ma_store;
75   using MacroAssemblerMIPSShared::ma_subTestOverflow;
76 
77   void ma_li(Register dest, CodeLabel* label);
78 
79   void ma_li(Register dest, ImmWord imm);
80   void ma_liPatchable(Register dest, ImmPtr imm);
81   void ma_liPatchable(Register dest, ImmWord imm);
82 
83   // load
84   void ma_load(Register dest, Address address, LoadStoreSize size = SizeWord,
85                LoadStoreExtension extension = SignExtend);
86 
87   // store
88   void ma_store(Register data, Address address, LoadStoreSize size = SizeWord,
89                 LoadStoreExtension extension = SignExtend);
90 
91   // arithmetic based ops
92   // add
93   void ma_addTestOverflow(Register rd, Register rs, Register rt,
94                           Label* overflow);
95   void ma_addTestOverflow(Register rd, Register rs, Imm32 imm, Label* overflow);
96 
97   // subtract
98   void ma_subTestOverflow(Register rd, Register rs, Register rt,
99                           Label* overflow);
100 
101   // memory
102   // shortcut for when we know we're transferring 32 bits of data
103   void ma_lw(Register data, Address address);
104 
105   void ma_sw(Register data, Address address);
106   void ma_sw(Imm32 imm, Address address);
107   void ma_sw(Register data, BaseIndex& address);
108 
109   void ma_pop(Register r);
110   void ma_push(Register r);
111 
112   void branchWithCode(InstImm code, Label* label, JumpKind jumpKind);
113   // branches when done from within mips-specific code
114   void ma_b(Register lhs, ImmWord imm, Label* l, Condition c,
115             JumpKind jumpKind = LongJump) {
116     ma_b(lhs, Imm32(uint32_t(imm.value)), l, c, jumpKind);
117   }
118   void ma_b(Address addr, ImmWord imm, Label* l, Condition c,
119             JumpKind jumpKind = LongJump) {
120     ma_b(addr, Imm32(uint32_t(imm.value)), l, c, jumpKind);
121   }
122 
123   void ma_b(Register lhs, Address addr, Label* l, Condition c,
124             JumpKind jumpKind = LongJump);
125   void ma_b(Address addr, Imm32 imm, Label* l, Condition c,
126             JumpKind jumpKind = LongJump);
127   void ma_b(Address addr, ImmGCPtr imm, Label* l, Condition c,
128             JumpKind jumpKind = LongJump);
129   void ma_b(Address addr, Register rhs, Label* l, Condition c,
130             JumpKind jumpKind = LongJump) {
131     MOZ_ASSERT(rhs != ScratchRegister);
132     ma_lw(ScratchRegister, addr);
133     ma_b(ScratchRegister, rhs, l, c, jumpKind);
134   }
135 
136   void ma_bal(Label* l, DelaySlotFill delaySlotFill = FillDelaySlot);
137 
138   // fp instructions
139   void ma_lid(FloatRegister dest, double value);
140 
141   void ma_mv(FloatRegister src, ValueOperand dest);
142   void ma_mv(ValueOperand src, FloatRegister dest);
143 
144   void ma_ls(FloatRegister ft, Address address);
145   void ma_ld(FloatRegister ft, Address address);
146   void ma_sd(FloatRegister ft, Address address);
147   void ma_ss(FloatRegister ft, Address address);
148 
149   void ma_ldc1WordAligned(FloatRegister ft, Register base, int32_t off);
150   void ma_sdc1WordAligned(FloatRegister ft, Register base, int32_t off);
151 
152   void ma_pop(FloatRegister f);
153   void ma_push(FloatRegister f);
154 
ma_cmp_set(Register dst,Register lhs,ImmWord imm,Condition c)155   void ma_cmp_set(Register dst, Register lhs, ImmWord imm, Condition c) {
156     ma_cmp_set(dst, lhs, Imm32(uint32_t(imm.value)), c);
157   }
ma_cmp_set(Register dst,Register lhs,ImmPtr imm,Condition c)158   void ma_cmp_set(Register dst, Register lhs, ImmPtr imm, Condition c) {
159     ma_cmp_set(dst, lhs, ImmWord(uintptr_t(imm.value)), c);
160   }
ma_cmp_set(Register dst,Register lhs,Address addr,Condition c)161   void ma_cmp_set(Register dst, Register lhs, Address addr, Condition c) {
162     MOZ_ASSERT(lhs != ScratchRegister);
163     ma_lw(ScratchRegister, addr);
164     ma_cmp_set(dst, lhs, ScratchRegister, c);
165   }
ma_cmp_set(Register dst,Address lhs,Register rhs,Condition c)166   void ma_cmp_set(Register dst, Address lhs, Register rhs, Condition c) {
167     MOZ_ASSERT(rhs != ScratchRegister);
168     ma_lw(ScratchRegister, lhs);
169     ma_cmp_set(dst, ScratchRegister, rhs, c);
170   }
ma_cmp_set(Register dst,Address lhs,ImmPtr imm,Condition c)171   void ma_cmp_set(Register dst, Address lhs, ImmPtr imm, Condition c) {
172     ma_lw(SecondScratchReg, lhs);
173     ma_cmp_set(dst, SecondScratchReg, imm, c);
174   }
175 
176   // These fuctions abstract the access to high part of the double precision
177   // float register. It is intended to work on both 32 bit and 64 bit
178   // floating point coprocessor.
179   // :TODO: (Bug 985881) Modify this for N32 ABI to use mthc1 and mfhc1
moveToDoubleHi(Register src,FloatRegister dest)180   void moveToDoubleHi(Register src, FloatRegister dest) {
181     as_mtc1(src, getOddPair(dest));
182   }
moveFromDoubleHi(FloatRegister src,Register dest)183   void moveFromDoubleHi(FloatRegister src, Register dest) {
184     as_mfc1(dest, getOddPair(src));
185   }
186 };
187 
188 class MacroAssembler;
189 
190 class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS {
191  public:
192   using MacroAssemblerMIPS::call;
193 
MacroAssemblerMIPSCompat()194   MacroAssemblerMIPSCompat() {}
195 
196   void convertBoolToInt32(Register source, Register dest);
197   void convertInt32ToDouble(Register src, FloatRegister dest);
198   void convertInt32ToDouble(const Address& src, FloatRegister dest);
199   void convertInt32ToDouble(const BaseIndex& src, FloatRegister dest);
200   void convertUInt32ToDouble(Register src, FloatRegister dest);
201   void convertUInt32ToFloat32(Register src, FloatRegister dest);
202   void convertDoubleToFloat32(FloatRegister src, FloatRegister dest);
203   void convertDoubleToInt32(FloatRegister src, Register dest, Label* fail,
204                             bool negativeZeroCheck = true);
205   void convertFloat32ToInt32(FloatRegister src, Register dest, Label* fail,
206                              bool negativeZeroCheck = true);
207 
208   void convertFloat32ToDouble(FloatRegister src, FloatRegister dest);
209   void convertInt32ToFloat32(Register src, FloatRegister dest);
210   void convertInt32ToFloat32(const Address& src, FloatRegister dest);
211 
212   void computeScaledAddress(const BaseIndex& address, Register dest);
213 
computeEffectiveAddress(const Address & address,Register dest)214   void computeEffectiveAddress(const Address& address, Register dest) {
215     ma_addu(dest, address.base, Imm32(address.offset));
216   }
217 
218   inline void computeEffectiveAddress(const BaseIndex& address, Register dest);
219 
j(Label * dest)220   void j(Label* dest) { ma_b(dest); }
221 
mov(Register src,Register dest)222   void mov(Register src, Register dest) { as_ori(dest, src, 0); }
mov(ImmWord imm,Register dest)223   void mov(ImmWord imm, Register dest) { ma_li(dest, imm); }
mov(ImmPtr imm,Register dest)224   void mov(ImmPtr imm, Register dest) {
225     mov(ImmWord(uintptr_t(imm.value)), dest);
226   }
mov(CodeLabel * label,Register dest)227   void mov(CodeLabel* label, Register dest) { ma_li(dest, label); }
mov(Register src,Address dest)228   void mov(Register src, Address dest) { MOZ_CRASH("NYI-IC"); }
mov(Address src,Register dest)229   void mov(Address src, Register dest) { MOZ_CRASH("NYI-IC"); }
230 
branch(JitCode * c)231   void branch(JitCode* c) {
232     BufferOffset bo = m_buffer.nextOffset();
233     addPendingJump(bo, ImmPtr(c->raw()), RelocationKind::JITCODE);
234     ma_liPatchable(ScratchRegister, ImmPtr(c->raw()));
235     as_jr(ScratchRegister);
236     as_nop();
237   }
branch(const Register reg)238   void branch(const Register reg) {
239     as_jr(reg);
240     as_nop();
241   }
nop()242   void nop() { as_nop(); }
ret()243   void ret() {
244     ma_pop(ra);
245     as_jr(ra);
246     as_nop();
247   }
248   inline void retn(Imm32 n);
push(Imm32 imm)249   void push(Imm32 imm) {
250     ma_li(ScratchRegister, imm);
251     ma_push(ScratchRegister);
252   }
push(ImmWord imm)253   void push(ImmWord imm) {
254     ma_li(ScratchRegister, imm);
255     ma_push(ScratchRegister);
256   }
push(ImmGCPtr imm)257   void push(ImmGCPtr imm) {
258     ma_li(ScratchRegister, imm);
259     ma_push(ScratchRegister);
260   }
push(const Address & address)261   void push(const Address& address) {
262     loadPtr(address, ScratchRegister);
263     ma_push(ScratchRegister);
264   }
push(Register reg)265   void push(Register reg) { ma_push(reg); }
push(FloatRegister reg)266   void push(FloatRegister reg) { ma_push(reg); }
pop(Register reg)267   void pop(Register reg) { ma_pop(reg); }
pop(FloatRegister reg)268   void pop(FloatRegister reg) { ma_pop(reg); }
269 
270   // Emit a branch that can be toggled to a non-operation. On MIPS we use
271   // "andi" instruction to toggle the branch.
272   // See ToggleToJmp(), ToggleToCmp().
273   CodeOffset toggledJump(Label* label);
274 
275   // Emit a "jalr" or "nop" instruction. ToggleCall can be used to patch
276   // this instruction.
277   CodeOffset toggledCall(JitCode* target, bool enabled);
278 
ToggledCallSize(uint8_t * code)279   static size_t ToggledCallSize(uint8_t* code) {
280     // Four instructions used in: MacroAssemblerMIPSCompat::toggledCall
281     return 4 * sizeof(uint32_t);
282   }
283 
pushWithPatch(ImmWord imm)284   CodeOffset pushWithPatch(ImmWord imm) {
285     CodeOffset label = movWithPatch(imm, ScratchRegister);
286     ma_push(ScratchRegister);
287     return label;
288   }
289 
movWithPatch(ImmWord imm,Register dest)290   CodeOffset movWithPatch(ImmWord imm, Register dest) {
291     CodeOffset label = CodeOffset(currentOffset());
292     ma_liPatchable(dest, imm);
293     return label;
294   }
movWithPatch(ImmPtr imm,Register dest)295   CodeOffset movWithPatch(ImmPtr imm, Register dest) {
296     return movWithPatch(ImmWord(uintptr_t(imm.value)), dest);
297   }
298 
writeCodePointer(CodeLabel * label)299   void writeCodePointer(CodeLabel* label) {
300     BufferOffset off = writeInst(-1);
301     label->patchAt()->bind(off.getOffset());
302     label->setLinkMode(CodeLabel::RawPointer);
303   }
304 
jump(Label * label)305   void jump(Label* label) { ma_b(label); }
jump(Register reg)306   void jump(Register reg) {
307     as_jr(reg);
308     as_nop();
309   }
jump(const Address & address)310   void jump(const Address& address) {
311     loadPtr(address, ScratchRegister);
312     as_jr(ScratchRegister);
313     as_nop();
314   }
315 
jump(JitCode * code)316   void jump(JitCode* code) { branch(code); }
317 
jump(ImmPtr ptr)318   void jump(ImmPtr ptr) {
319     BufferOffset bo = m_buffer.nextOffset();
320     addPendingJump(bo, ptr, RelocationKind::HARDCODED);
321     ma_jump(ptr);
322   }
323 
jump(TrampolinePtr code)324   void jump(TrampolinePtr code) { jump(ImmPtr(code.value)); }
325 
negl(Register reg)326   void negl(Register reg) { ma_negu(reg, reg); }
327 
splitTagForTest(const ValueOperand & value,ScratchTagScope & tag)328   void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag) {
329     MOZ_ASSERT(value.typeReg() == tag);
330   }
331 
332   // unboxing code
333   void unboxNonDouble(const ValueOperand& operand, Register dest, JSValueType);
334   void unboxNonDouble(const Address& src, Register dest, JSValueType);
335   void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType);
336   void unboxInt32(const ValueOperand& operand, Register dest);
337   void unboxInt32(const Address& src, Register dest);
338   void unboxBoolean(const ValueOperand& operand, Register dest);
339   void unboxBoolean(const Address& src, Register dest);
340   void unboxDouble(const ValueOperand& operand, FloatRegister dest);
341   void unboxDouble(const Address& src, FloatRegister dest);
342   void unboxDouble(const BaseIndex& src, FloatRegister dest);
343   void unboxString(const ValueOperand& operand, Register dest);
344   void unboxString(const Address& src, Register dest);
345   void unboxBigInt(const ValueOperand& operand, Register dest);
346   void unboxBigInt(const Address& src, Register dest);
347   void unboxObject(const ValueOperand& src, Register dest);
348   void unboxObject(const Address& src, Register dest);
unboxObject(const BaseIndex & src,Register dest)349   void unboxObject(const BaseIndex& src, Register dest) {
350     unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
351   }
352   void unboxObjectOrNull(const Address& src, Register dest);
353   void unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType);
354 
unboxGCThingForGCBarrier(const Address & src,Register dest)355   void unboxGCThingForGCBarrier(const Address& src, Register dest) {
356     unboxObject(src, dest);
357   }
unboxGCThingForGCBarrier(const ValueOperand & src,Register dest)358   void unboxGCThingForGCBarrier(const ValueOperand& src, Register dest) {
359     unboxObject(src, dest);
360   }
361 
notBoolean(const ValueOperand & val)362   void notBoolean(const ValueOperand& val) {
363     as_xori(val.payloadReg(), val.payloadReg(), 1);
364   }
365 
366   // boxing code
367   void boxDouble(FloatRegister src, const ValueOperand& dest, FloatRegister);
368   void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest);
369 
370   // Extended unboxing API. If the payload is already in a register, returns
371   // that register. Otherwise, provides a move to the given scratch register,
372   // and returns that.
373   MOZ_MUST_USE Register extractObject(const Address& address, Register scratch);
extractObject(const ValueOperand & value,Register scratch)374   MOZ_MUST_USE Register extractObject(const ValueOperand& value,
375                                       Register scratch) {
376     return value.payloadReg();
377   }
extractString(const ValueOperand & value,Register scratch)378   MOZ_MUST_USE Register extractString(const ValueOperand& value,
379                                       Register scratch) {
380     return value.payloadReg();
381   }
extractSymbol(const ValueOperand & value,Register scratch)382   MOZ_MUST_USE Register extractSymbol(const ValueOperand& value,
383                                       Register scratch) {
384     return value.payloadReg();
385   }
extractInt32(const ValueOperand & value,Register scratch)386   MOZ_MUST_USE Register extractInt32(const ValueOperand& value,
387                                      Register scratch) {
388     return value.payloadReg();
389   }
extractBoolean(const ValueOperand & value,Register scratch)390   MOZ_MUST_USE Register extractBoolean(const ValueOperand& value,
391                                        Register scratch) {
392     return value.payloadReg();
393   }
394   MOZ_MUST_USE Register extractTag(const Address& address, Register scratch);
395   MOZ_MUST_USE Register extractTag(const BaseIndex& address, Register scratch);
extractTag(const ValueOperand & value,Register scratch)396   MOZ_MUST_USE Register extractTag(const ValueOperand& value,
397                                    Register scratch) {
398     return value.typeReg();
399   }
400 
401   void boolValueToDouble(const ValueOperand& operand, FloatRegister dest);
402   void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest);
403   void loadInt32OrDouble(const Address& address, FloatRegister dest);
404   void loadInt32OrDouble(Register base, Register index, FloatRegister dest,
405                          int32_t shift = defaultShift);
406   void loadConstantDouble(double dp, FloatRegister dest);
407 
408   void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest);
409   void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest);
410   void loadConstantFloat32(float f, FloatRegister dest);
411 
412   void testNullSet(Condition cond, const ValueOperand& value, Register dest);
413 
414   void testObjectSet(Condition cond, const ValueOperand& value, Register dest);
415 
416   void testUndefinedSet(Condition cond, const ValueOperand& value,
417                         Register dest);
418 
419   // higher level tag testing code
420   Operand ToPayload(Operand base);
ToPayload(Address base)421   Address ToPayload(Address base) {
422     return ToPayload(Operand(base)).toAddress();
423   }
424 
ToPayload(BaseIndex base)425   BaseIndex ToPayload(BaseIndex base) {
426     return BaseIndex(base.base, base.index, base.scale,
427                      base.offset + NUNBOX32_PAYLOAD_OFFSET);
428   }
429 
430  protected:
431   Operand ToType(Operand base);
ToType(Address base)432   Address ToType(Address base) { return ToType(Operand(base)).toAddress(); }
433 
434   uint32_t getType(const Value& val);
435   void moveData(const Value& val, Register data);
436 
437  public:
438   void moveValue(const Value& val, Register type, Register data);
439 
loadUnboxedValue(Address address,MIRType type,AnyRegister dest)440   void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) {
441     if (dest.isFloat()) {
442       loadInt32OrDouble(address, dest.fpu());
443     } else {
444       ma_lw(dest.gpr(), ToPayload(address));
445     }
446   }
447 
loadUnboxedValue(BaseIndex address,MIRType type,AnyRegister dest)448   void loadUnboxedValue(BaseIndex address, MIRType type, AnyRegister dest) {
449     if (dest.isFloat()) {
450       loadInt32OrDouble(address.base, address.index, dest.fpu(), address.scale);
451     } else {
452       load32(ToPayload(address), dest.gpr());
453     }
454   }
455 
456   template <typename T>
457   void storeUnboxedValue(ConstantOrRegister value, MIRType valueType,
458                          const T& dest, MIRType slotType);
459 
460   template <typename T>
storeUnboxedPayload(ValueOperand value,T address,size_t nbytes,JSValueType)461   void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes,
462                            JSValueType) {
463     switch (nbytes) {
464       case 4:
465         store32(value.payloadReg(), address);
466         return;
467       case 1:
468         store8(value.payloadReg(), address);
469         return;
470       default:
471         MOZ_CRASH("Bad payload width");
472     }
473   }
474 
475   void moveValue(const Value& val, const ValueOperand& dest);
476 
moveValue(const ValueOperand & src,const ValueOperand & dest)477   void moveValue(const ValueOperand& src, const ValueOperand& dest) {
478     Register s0 = src.typeReg(), d0 = dest.typeReg(), s1 = src.payloadReg(),
479              d1 = dest.payloadReg();
480 
481     // Either one or both of the source registers could be the same as a
482     // destination register.
483     if (s1 == d0) {
484       if (s0 == d1) {
485         // If both are, this is just a swap of two registers.
486         MOZ_ASSERT(d1 != ScratchRegister);
487         MOZ_ASSERT(d0 != ScratchRegister);
488         move32(d1, ScratchRegister);
489         move32(d0, d1);
490         move32(ScratchRegister, d0);
491         return;
492       }
493       // If only one is, copy that source first.
494       std::swap(s0, s1);
495       std::swap(d0, d1);
496     }
497 
498     if (s0 != d0) {
499       move32(s0, d0);
500     }
501     if (s1 != d1) {
502       move32(s1, d1);
503     }
504   }
505 
506   void storeValue(ValueOperand val, Operand dst);
507   void storeValue(ValueOperand val, const BaseIndex& dest);
508   void storeValue(JSValueType type, Register reg, BaseIndex dest);
509   void storeValue(ValueOperand val, const Address& dest);
510   void storeValue(JSValueType type, Register reg, Address dest);
511   void storeValue(const Value& val, Address dest);
512   void storeValue(const Value& val, BaseIndex dest);
storeValue(const Address & src,const Address & dest,Register temp)513   void storeValue(const Address& src, const Address& dest, Register temp) {
514     load32(ToType(src), temp);
515     store32(temp, ToType(dest));
516 
517     load32(ToPayload(src), temp);
518     store32(temp, ToPayload(dest));
519   }
520 
521   void loadValue(Address src, ValueOperand val);
loadValue(Operand dest,ValueOperand val)522   void loadValue(Operand dest, ValueOperand val) {
523     loadValue(dest.toAddress(), val);
524   }
525   void loadValue(const BaseIndex& addr, ValueOperand val);
526 
loadUnalignedValue(const Address & src,ValueOperand dest)527   void loadUnalignedValue(const Address& src, ValueOperand dest) {
528     loadValue(src, dest);
529   }
530 
531   void tagValue(JSValueType type, Register payload, ValueOperand dest);
532 
533   void pushValue(ValueOperand val);
534   void popValue(ValueOperand val);
535 #if MOZ_LITTLE_ENDIAN()
pushValue(const Value & val)536   void pushValue(const Value& val) {
537     push(Imm32(val.toNunboxTag()));
538     if (val.isGCThing()) {
539       push(ImmGCPtr(val.toGCThing()));
540     } else {
541       push(Imm32(val.toNunboxPayload()));
542     }
543   }
pushValue(JSValueType type,Register reg)544   void pushValue(JSValueType type, Register reg) {
545     push(ImmTag(JSVAL_TYPE_TO_TAG(type)));
546     ma_push(reg);
547   }
548 #else
pushValue(const Value & val)549   void pushValue(const Value& val) {
550     if (val.isGCThing()) {
551       push(ImmGCPtr(val.toGCThing()));
552     } else {
553       push(Imm32(val.toNunboxPayload()));
554     }
555     push(Imm32(val.toNunboxTag()));
556   }
pushValue(JSValueType type,Register reg)557   void pushValue(JSValueType type, Register reg) {
558     ma_push(reg);
559     push(ImmTag(JSVAL_TYPE_TO_TAG(type)));
560   }
561 #endif
562   void pushValue(const Address& addr);
563 
564   void storePayload(const Value& val, Address dest);
565   void storePayload(Register src, Address dest);
566   void storePayload(const Value& val, const BaseIndex& dest);
567   void storePayload(Register src, const BaseIndex& dest);
568   void storeTypeTag(ImmTag tag, Address dest);
569   void storeTypeTag(ImmTag tag, const BaseIndex& dest);
570 
571   void handleFailureWithHandlerTail(void* handler, Label* profilerExitTail);
572 
573   template <typename T>
574   void wasmAtomicStore64(const wasm::MemoryAccessDesc& access, const T& mem,
575                          Register temp, Register64 value);
576 
577   /////////////////////////////////////////////////////////////////
578   // Common interface.
579   /////////////////////////////////////////////////////////////////
580  public:
581   // The following functions are exposed for use in platform-shared code.
582 
583   inline void incrementInt32Value(const Address& addr);
584 
585   void move32(Imm32 imm, Register dest);
586   void move32(Register src, Register dest);
587 
588   void movePtr(Register src, Register dest);
589   void movePtr(ImmWord imm, Register dest);
590   void movePtr(ImmPtr imm, Register dest);
591   void movePtr(wasm::SymbolicAddress imm, Register dest);
592   void movePtr(ImmGCPtr imm, Register dest);
593 
594   void load8SignExtend(const Address& address, Register dest);
595   void load8SignExtend(const BaseIndex& src, Register dest);
596 
597   void load8ZeroExtend(const Address& address, Register dest);
598   void load8ZeroExtend(const BaseIndex& src, Register dest);
599 
600   void load16SignExtend(const Address& address, Register dest);
601   void load16SignExtend(const BaseIndex& src, Register dest);
602 
603   template <typename S>
load16UnalignedSignExtend(const S & src,Register dest)604   void load16UnalignedSignExtend(const S& src, Register dest) {
605     ma_load_unaligned(dest, src, SizeHalfWord, SignExtend);
606   }
607 
608   void load16ZeroExtend(const Address& address, Register dest);
609   void load16ZeroExtend(const BaseIndex& src, Register dest);
610 
611   template <typename S>
load16UnalignedZeroExtend(const S & src,Register dest)612   void load16UnalignedZeroExtend(const S& src, Register dest) {
613     ma_load_unaligned(dest, src, SizeHalfWord, ZeroExtend);
614   }
615 
616   void load32(const Address& address, Register dest);
617   void load32(const BaseIndex& address, Register dest);
618   void load32(AbsoluteAddress address, Register dest);
619   void load32(wasm::SymbolicAddress address, Register dest);
620 
621   template <typename S>
load32Unaligned(const S & src,Register dest)622   void load32Unaligned(const S& src, Register dest) {
623     ma_load_unaligned(dest, src);
624   }
625 
load64(const Address & address,Register64 dest)626   void load64(const Address& address, Register64 dest) {
627     load32(LowWord(address), dest.low);
628     load32(HighWord(address), dest.high);
629   }
load64(const BaseIndex & address,Register64 dest)630   void load64(const BaseIndex& address, Register64 dest) {
631     load32(LowWord(address), dest.low);
632     load32(HighWord(address), dest.high);
633   }
634 
635   template <typename S>
load64Unaligned(const S & src,Register64 dest)636   void load64Unaligned(const S& src, Register64 dest) {
637     ma_load_unaligned(dest.low, LowWord(src));
638     ma_load_unaligned(dest.high, HighWord(src));
639   }
640 
641   void loadPtr(const Address& address, Register dest);
642   void loadPtr(const BaseIndex& src, Register dest);
643   void loadPtr(AbsoluteAddress address, Register dest);
644   void loadPtr(wasm::SymbolicAddress address, Register dest);
645 
646   void loadPrivate(const Address& address, Register dest);
647 
648   void loadUnalignedDouble(const wasm::MemoryAccessDesc& access,
649                            const BaseIndex& src, Register temp,
650                            FloatRegister dest);
651 
652   void loadUnalignedFloat32(const wasm::MemoryAccessDesc& access,
653                             const BaseIndex& src, Register temp,
654                             FloatRegister dest);
655 
656   void store8(Register src, const Address& address);
657   void store8(Imm32 imm, const Address& address);
658   void store8(Register src, const BaseIndex& address);
659   void store8(Imm32 imm, const BaseIndex& address);
660 
661   void store16(Register src, const Address& address);
662   void store16(Imm32 imm, const Address& address);
663   void store16(Register src, const BaseIndex& address);
664   void store16(Imm32 imm, const BaseIndex& address);
665 
666   template <typename T>
store16Unaligned(Register src,const T & dest)667   void store16Unaligned(Register src, const T& dest) {
668     ma_store_unaligned(src, dest, SizeHalfWord);
669   }
670 
671   void store32(Register src, AbsoluteAddress address);
672   void store32(Register src, const Address& address);
673   void store32(Register src, const BaseIndex& address);
674   void store32(Imm32 src, const Address& address);
675   void store32(Imm32 src, const BaseIndex& address);
676 
677   // NOTE: This will use second scratch on MIPS. Only ARM needs the
678   // implementation without second scratch.
store32_NoSecondScratch(Imm32 src,const Address & address)679   void store32_NoSecondScratch(Imm32 src, const Address& address) {
680     store32(src, address);
681   }
682 
683   template <typename T>
store32Unaligned(Register src,const T & dest)684   void store32Unaligned(Register src, const T& dest) {
685     ma_store_unaligned(src, dest);
686   }
687 
store64(Register64 src,Address address)688   void store64(Register64 src, Address address) {
689     store32(src.low, Address(address.base, address.offset + LOW_32_OFFSET));
690     store32(src.high, Address(address.base, address.offset + HIGH_32_OFFSET));
691   }
store64(Register64 src,const BaseIndex & address)692   void store64(Register64 src, const BaseIndex& address) {
693     store32(src.low, Address(address.base, address.offset + LOW_32_OFFSET));
694     store32(src.high, Address(address.base, address.offset + HIGH_32_OFFSET));
695   }
696 
store64(Imm64 imm,Address address)697   void store64(Imm64 imm, Address address) {
698     store32(imm.low(), Address(address.base, address.offset + LOW_32_OFFSET));
699     store32(imm.hi(), Address(address.base, address.offset + HIGH_32_OFFSET));
700   }
store64(Imm64 imm,const BaseIndex & address)701   void store64(Imm64 imm, const BaseIndex& address) {
702     store32(imm.low(), Address(address.base, address.offset + LOW_32_OFFSET));
703     store32(imm.hi(), Address(address.base, address.offset + HIGH_32_OFFSET));
704   }
705 
706   template <typename T>
store64Unaligned(Register64 src,const T & dest)707   void store64Unaligned(Register64 src, const T& dest) {
708     ma_store_unaligned(src.low, LowWord(dest));
709     ma_store_unaligned(src.high, HighWord(dest));
710   }
711 
712   template <typename T>
713   void storePtr(ImmWord imm, T address);
714   template <typename T>
715   void storePtr(ImmPtr imm, T address);
716   template <typename T>
717   void storePtr(ImmGCPtr imm, T address);
718   void storePtr(Register src, const Address& address);
719   void storePtr(Register src, const BaseIndex& address);
720   void storePtr(Register src, AbsoluteAddress dest);
721 
722   void storeUnalignedFloat32(const wasm::MemoryAccessDesc& access,
723                              FloatRegister src, Register temp,
724                              const BaseIndex& dest);
725   void storeUnalignedDouble(const wasm::MemoryAccessDesc& access,
726                             FloatRegister src, Register temp,
727                             const BaseIndex& dest);
728 
moveDouble(FloatRegister src,FloatRegister dest)729   void moveDouble(FloatRegister src, FloatRegister dest) { as_movd(dest, src); }
730 
zeroDouble(FloatRegister reg)731   void zeroDouble(FloatRegister reg) {
732     moveToDoubleLo(zero, reg);
733     moveToDoubleHi(zero, reg);
734   }
735 
736   void breakpoint();
737 
738   void checkStackAlignment();
739 
740   void alignStackPointer();
741   void restoreStackPointer();
742   static void calculateAlignedStackPointer(void** stackPointer);
743 
744   // If source is a double, load it into dest. If source is int32,
745   // convert it to double. Else, branch to failure.
746   void ensureDouble(const ValueOperand& source, FloatRegister dest,
747                     Label* failure);
748 
749   void cmp64Set(Condition cond, Register64 lhs, Register64 rhs, Register dest);
750   void cmp64Set(Condition cond, Register64 lhs, Imm64 val, Register dest);
751 
752  protected:
753   bool buildOOLFakeExitFrame(void* fakeReturnAddr);
754 
755   void enterAtomic64Region(Register addr, Register spinlock, Register tmp);
756   void exitAtomic64Region(Register spinlock);
757   void wasmLoadI64Impl(const wasm::MemoryAccessDesc& access,
758                        Register memoryBase, Register ptr, Register ptrScratch,
759                        Register64 output, Register tmp);
760   void wasmStoreI64Impl(const wasm::MemoryAccessDesc& access, Register64 value,
761                         Register memoryBase, Register ptr, Register ptrScratch,
762                         Register tmp);
763   Condition ma_cmp64(Condition cond, Register64 lhs, Register64 rhs,
764                      Register dest);
765   Condition ma_cmp64(Condition cond, Register64 lhs, Imm64 val, Register dest);
766 
767  public:
lea(Operand addr,Register dest)768   void lea(Operand addr, Register dest) {
769     ma_addu(dest, addr.baseReg(), Imm32(addr.disp()));
770   }
771 
abiret()772   void abiret() {
773     as_jr(ra);
774     as_nop();
775   }
776 
ma_storeImm(Imm32 imm,const Address & addr)777   void ma_storeImm(Imm32 imm, const Address& addr) { ma_sw(imm, addr); }
778 
moveFloat32(FloatRegister src,FloatRegister dest)779   void moveFloat32(FloatRegister src, FloatRegister dest) {
780     as_movs(dest, src);
781   }
loadWasmGlobalPtr(uint32_t globalDataOffset,Register dest)782   void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) {
783     loadPtr(Address(WasmTlsReg,
784                     offsetof(wasm::TlsData, globalArea) + globalDataOffset),
785             dest);
786   }
loadWasmPinnedRegsFromTls()787   void loadWasmPinnedRegsFromTls() {
788     loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, memoryBase)), HeapReg);
789   }
790 
791   // Instrumentation for entering and leaving the profiler.
792   void profilerEnterFrame(Register framePtr, Register scratch);
793   void profilerExitFrame();
794 };
795 
796 typedef MacroAssemblerMIPSCompat MacroAssemblerSpecific;
797 
798 }  // namespace jit
799 }  // namespace js
800 
801 #endif /* jit_mips32_MacroAssembler_mips32_h */
802