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