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_arm_MacroAssembler_arm_h
8 #define jit_arm_MacroAssembler_arm_h
9 
10 #include "mozilla/DebugOnly.h"
11 
12 #include "jit/arm/Assembler-arm.h"
13 #include "jit/JitFrames.h"
14 #include "jit/MoveResolver.h"
15 #include "vm/BytecodeUtil.h"
16 
17 using mozilla::DebugOnly;
18 
19 namespace js {
20 namespace jit {
21 
22 static Register CallReg = ip;
23 static const int defaultShift = 3;
24 JS_STATIC_ASSERT(1 << defaultShift == sizeof(JS::Value));
25 
26 // See documentation for ScratchTagScope and ScratchTagScopeRelease in
27 // MacroAssembler-x64.h.
28 
29 class ScratchTagScope {
30   const ValueOperand& v_;
31 
32  public:
ScratchTagScope(MacroAssembler &,const ValueOperand & v)33   ScratchTagScope(MacroAssembler&, const ValueOperand& v) : v_(v) {}
Register()34   operator Register() { return v_.typeReg(); }
release()35   void release() {}
reacquire()36   void reacquire() {}
37 };
38 
39 class ScratchTagScopeRelease {
40  public:
ScratchTagScopeRelease(ScratchTagScope *)41   explicit ScratchTagScopeRelease(ScratchTagScope*) {}
42 };
43 
44 // MacroAssemblerARM is inheriting form Assembler defined in
45 // Assembler-arm.{h,cpp}
46 class MacroAssemblerARM : public Assembler {
47  private:
48   // Perform a downcast. Should be removed by Bug 996602.
49   MacroAssembler& asMasm();
50   const MacroAssembler& asMasm() const;
51 
52  protected:
53   // On ARM, some instructions require a second scratch register. This
54   // register defaults to lr, since it's non-allocatable (as it can be
55   // clobbered by some instructions). Allow the baseline compiler to override
56   // this though, since baseline IC stubs rely on lr holding the return
57   // address.
58   Register secondScratchReg_;
59 
60  public:
getSecondScratchReg()61   Register getSecondScratchReg() const { return secondScratchReg_; }
62 
63  public:
64   // Higher level tag testing code.
65   // TODO: Can probably remove the Operand versions.
ToPayload(Operand base)66   Operand ToPayload(Operand base) const {
67     return Operand(Register::FromCode(base.base()), base.disp());
68   }
ToPayload(const Address & base)69   Address ToPayload(const Address& base) const { return base; }
70 
71  protected:
ToType(Operand base)72   Operand ToType(Operand base) const {
73     return Operand(Register::FromCode(base.base()),
74                    base.disp() + sizeof(void*));
75   }
ToType(const Address & base)76   Address ToType(const Address& base) const {
77     return ToType(Operand(base)).toAddress();
78   }
79 
ToPayloadAfterStackPush(const Address & base)80   Address ToPayloadAfterStackPush(const Address& base) const {
81     // If we are based on StackPointer, pass over the type tag just pushed.
82     if (base.base == StackPointer)
83       return Address(base.base, base.offset + sizeof(void*));
84     return ToPayload(base);
85   }
86 
87  public:
MacroAssemblerARM()88   MacroAssemblerARM() : secondScratchReg_(lr) {}
89 
setSecondScratchReg(Register reg)90   void setSecondScratchReg(Register reg) {
91     MOZ_ASSERT(reg != ScratchRegister);
92     secondScratchReg_ = reg;
93   }
94 
95   void convertBoolToInt32(Register source, Register dest);
96   void convertInt32ToDouble(Register src, FloatRegister dest);
97   void convertInt32ToDouble(const Address& src, FloatRegister dest);
98   void convertInt32ToDouble(const BaseIndex& src, FloatRegister dest);
99   void convertUInt32ToFloat32(Register src, FloatRegister dest);
100   void convertUInt32ToDouble(Register src, FloatRegister dest);
101   void convertDoubleToFloat32(FloatRegister src, FloatRegister dest,
102                               Condition c = Always);
103   void convertDoubleToInt32(FloatRegister src, Register dest, Label* fail,
104                             bool negativeZeroCheck = true);
105   void convertFloat32ToInt32(FloatRegister src, Register dest, Label* fail,
106                              bool negativeZeroCheck = true);
107 
108   void convertFloat32ToDouble(FloatRegister src, FloatRegister dest);
109   void convertInt32ToFloat32(Register src, FloatRegister dest);
110   void convertInt32ToFloat32(const Address& src, FloatRegister dest);
111 
112   void wasmTruncateToInt32(FloatRegister input, Register output,
113                            MIRType fromType, bool isUnsigned, bool isSaturating,
114                            Label* oolEntry);
115   void outOfLineWasmTruncateToIntCheck(FloatRegister input, MIRType fromType,
116                                        MIRType toType, TruncFlags flags,
117                                        Label* rejoin,
118                                        wasm::BytecodeOffset trapOffset);
119 
120   // Somewhat direct wrappers for the low-level assembler funcitons
121   // bitops. Attempt to encode a virtual alu instruction using two real
122   // instructions.
123  private:
124   bool alu_dbl(Register src1, Imm32 imm, Register dest, ALUOp op, SBit s,
125                Condition c);
126 
127  public:
128   void ma_alu(Register src1, Imm32 imm, Register dest,
129               AutoRegisterScope& scratch, ALUOp op, SBit s = LeaveCC,
130               Condition c = Always);
131   void ma_alu(Register src1, Operand2 op2, Register dest, ALUOp op,
132               SBit s = LeaveCC, Condition c = Always);
133   void ma_alu(Register src1, Operand op2, Register dest, ALUOp op,
134               SBit s = LeaveCC, Condition c = Always);
135   void ma_nop();
136 
137   BufferOffset ma_movPatchable(Imm32 imm, Register dest,
138                                Assembler::Condition c);
139   BufferOffset ma_movPatchable(ImmPtr imm, Register dest,
140                                Assembler::Condition c);
141 
142   // To be used with Iter := InstructionIterator or BufferInstructionIterator.
143   template <class Iter>
144   static void ma_mov_patch(Imm32 imm, Register dest, Assembler::Condition c,
145                            RelocStyle rs, Iter iter);
146 
147   // ALU based ops
148   // mov
149   void ma_mov(Register src, Register dest, SBit s = LeaveCC,
150               Condition c = Always);
151 
152   void ma_mov(Imm32 imm, Register dest, Condition c = Always);
153   void ma_mov(ImmWord imm, Register dest, Condition c = Always);
154 
155   void ma_mov(ImmGCPtr ptr, Register dest);
156 
157   // Shifts (just a move with a shifting op2)
158   void ma_lsl(Imm32 shift, Register src, Register dst);
159   void ma_lsr(Imm32 shift, Register src, Register dst);
160   void ma_asr(Imm32 shift, Register src, Register dst);
161   void ma_ror(Imm32 shift, Register src, Register dst);
162   void ma_rol(Imm32 shift, Register src, Register dst);
163 
164   void ma_lsl(Register shift, Register src, Register dst);
165   void ma_lsr(Register shift, Register src, Register dst);
166   void ma_asr(Register shift, Register src, Register dst);
167   void ma_ror(Register shift, Register src, Register dst);
168   void ma_rol(Register shift, Register src, Register dst,
169               AutoRegisterScope& scratch);
170 
171   // Move not (dest <- ~src)
172   void ma_mvn(Register src1, Register dest, SBit s = LeaveCC,
173               Condition c = Always);
174 
175   // Negate (dest <- -src) implemented as rsb dest, src, 0
176   void ma_neg(Register src, Register dest, SBit s = LeaveCC,
177               Condition c = Always);
178 
179   // And
180   void ma_and(Register src, Register dest, SBit s = LeaveCC,
181               Condition c = Always);
182 
183   void ma_and(Register src1, Register src2, Register dest, SBit s = LeaveCC,
184               Condition c = Always);
185 
186   void ma_and(Imm32 imm, Register dest, AutoRegisterScope& scratch,
187               SBit s = LeaveCC, Condition c = Always);
188 
189   void ma_and(Imm32 imm, Register src1, Register dest,
190               AutoRegisterScope& scratch, SBit s = LeaveCC,
191               Condition c = Always);
192 
193   // Bit clear (dest <- dest & ~imm) or (dest <- src1 & ~src2)
194   void ma_bic(Imm32 imm, Register dest, AutoRegisterScope& scratch,
195               SBit s = LeaveCC, Condition c = Always);
196 
197   // Exclusive or
198   void ma_eor(Register src, Register dest, SBit s = LeaveCC,
199               Condition c = Always);
200 
201   void ma_eor(Register src1, Register src2, Register dest, SBit s = LeaveCC,
202               Condition c = Always);
203 
204   void ma_eor(Imm32 imm, Register dest, AutoRegisterScope& scratch,
205               SBit s = LeaveCC, Condition c = Always);
206 
207   void ma_eor(Imm32 imm, Register src1, Register dest,
208               AutoRegisterScope& scratch, SBit s = LeaveCC,
209               Condition c = Always);
210 
211   // Or
212   void ma_orr(Register src, Register dest, SBit s = LeaveCC,
213               Condition c = Always);
214 
215   void ma_orr(Register src1, Register src2, Register dest, SBit s = LeaveCC,
216               Condition c = Always);
217 
218   void ma_orr(Imm32 imm, Register dest, AutoRegisterScope& scratch,
219               SBit s = LeaveCC, Condition c = Always);
220 
221   void ma_orr(Imm32 imm, Register src1, Register dest,
222               AutoRegisterScope& scratch, SBit s = LeaveCC,
223               Condition c = Always);
224 
225   // Arithmetic based ops.
226   // Add with carry:
227   void ma_adc(Imm32 imm, Register dest, AutoRegisterScope& scratch,
228               SBit s = LeaveCC, Condition c = Always);
229   void ma_adc(Register src, Register dest, SBit s = LeaveCC,
230               Condition c = Always);
231   void ma_adc(Register src1, Register src2, Register dest, SBit s = LeaveCC,
232               Condition c = Always);
233 
234   // Add:
235   void ma_add(Imm32 imm, Register dest, AutoRegisterScope& scratch,
236               SBit s = LeaveCC, Condition c = Always);
237   void ma_add(Register src1, Register dest, SBit s = LeaveCC,
238               Condition c = Always);
239   void ma_add(Register src1, Register src2, Register dest, SBit s = LeaveCC,
240               Condition c = Always);
241   void ma_add(Register src1, Operand op, Register dest, SBit s = LeaveCC,
242               Condition c = Always);
243   void ma_add(Register src1, Imm32 op, Register dest,
244               AutoRegisterScope& scratch, SBit s = LeaveCC,
245               Condition c = Always);
246 
247   // Subtract with carry:
248   void ma_sbc(Imm32 imm, Register dest, AutoRegisterScope& scratch,
249               SBit s = LeaveCC, Condition c = Always);
250   void ma_sbc(Register src1, Register dest, SBit s = LeaveCC,
251               Condition c = Always);
252   void ma_sbc(Register src1, Register src2, Register dest, SBit s = LeaveCC,
253               Condition c = Always);
254 
255   // Subtract:
256   void ma_sub(Imm32 imm, Register dest, AutoRegisterScope& scratch,
257               SBit s = LeaveCC, Condition c = Always);
258   void ma_sub(Register src1, Register dest, SBit s = LeaveCC,
259               Condition c = Always);
260   void ma_sub(Register src1, Register src2, Register dest, SBit s = LeaveCC,
261               Condition c = Always);
262   void ma_sub(Register src1, Operand op, Register dest, SBit s = LeaveCC,
263               Condition c = Always);
264   void ma_sub(Register src1, Imm32 op, Register dest,
265               AutoRegisterScope& scratch, SBit s = LeaveCC,
266               Condition c = Always);
267 
268   // Reverse subtract:
269   void ma_rsb(Imm32 imm, Register dest, AutoRegisterScope& scratch,
270               SBit s = LeaveCC, Condition c = Always);
271   void ma_rsb(Register src1, Register dest, SBit s = LeaveCC,
272               Condition c = Always);
273   void ma_rsb(Register src1, Register src2, Register dest, SBit s = LeaveCC,
274               Condition c = Always);
275   void ma_rsb(Register src1, Imm32 op2, Register dest,
276               AutoRegisterScope& scratch, SBit s = LeaveCC,
277               Condition c = Always);
278 
279   // Reverse subtract with carry:
280   void ma_rsc(Imm32 imm, Register dest, AutoRegisterScope& scratch,
281               SBit s = LeaveCC, Condition c = Always);
282   void ma_rsc(Register src1, Register dest, SBit s = LeaveCC,
283               Condition c = Always);
284   void ma_rsc(Register src1, Register src2, Register dest, SBit s = LeaveCC,
285               Condition c = Always);
286 
287   // Compares/tests.
288   // Compare negative (sets condition codes as src1 + src2 would):
289   void ma_cmn(Register src1, Imm32 imm, AutoRegisterScope& scratch,
290               Condition c = Always);
291   void ma_cmn(Register src1, Register src2, Condition c = Always);
292   void ma_cmn(Register src1, Operand op, Condition c = Always);
293 
294   // Compare (src - src2):
295   void ma_cmp(Register src1, Imm32 imm, AutoRegisterScope& scratch,
296               Condition c = Always);
297   void ma_cmp(Register src1, ImmTag tag, Condition c = Always);
298   void ma_cmp(Register src1, ImmWord ptr, AutoRegisterScope& scratch,
299               Condition c = Always);
300   void ma_cmp(Register src1, ImmGCPtr ptr, AutoRegisterScope& scratch,
301               Condition c = Always);
302   void ma_cmp(Register src1, Operand op, AutoRegisterScope& scratch,
303               AutoRegisterScope& scratch2, Condition c = Always);
304   void ma_cmp(Register src1, Register src2, Condition c = Always);
305 
306   // Test for equality, (src1 ^ src2):
307   void ma_teq(Register src1, Imm32 imm, AutoRegisterScope& scratch,
308               Condition c = Always);
309   void ma_teq(Register src1, Register src2, Condition c = Always);
310   void ma_teq(Register src1, Operand op, Condition c = Always);
311 
312   // Test (src1 & src2):
313   void ma_tst(Register src1, Imm32 imm, AutoRegisterScope& scratch,
314               Condition c = Always);
315   void ma_tst(Register src1, Register src2, Condition c = Always);
316   void ma_tst(Register src1, Operand op, Condition c = Always);
317 
318   // Multiplies. For now, there are only two that we care about.
319   void ma_mul(Register src1, Register src2, Register dest);
320   void ma_mul(Register src1, Imm32 imm, Register dest,
321               AutoRegisterScope& scratch);
322   Condition ma_check_mul(Register src1, Register src2, Register dest,
323                          AutoRegisterScope& scratch, Condition cond);
324   Condition ma_check_mul(Register src1, Imm32 imm, Register dest,
325                          AutoRegisterScope& scratch, Condition cond);
326 
327   void ma_umull(Register src1, Imm32 imm, Register destHigh, Register destLow,
328                 AutoRegisterScope& scratch);
329   void ma_umull(Register src1, Register src2, Register destHigh,
330                 Register destLow);
331 
332   // Fast mod, uses scratch registers, and thus needs to be in the assembler
333   // implicitly assumes that we can overwrite dest at the beginning of the
334   // sequence.
335   void ma_mod_mask(Register src, Register dest, Register hold, Register tmp,
336                    AutoRegisterScope& scratch, AutoRegisterScope& scratch2,
337                    int32_t shift);
338 
339   // Mod - depends on integer divide instructions being supported.
340   void ma_smod(Register num, Register div, Register dest,
341                AutoRegisterScope& scratch);
342   void ma_umod(Register num, Register div, Register dest,
343                AutoRegisterScope& scratch);
344 
345   // Division - depends on integer divide instructions being supported.
346   void ma_sdiv(Register num, Register div, Register dest,
347                Condition cond = Always);
348   void ma_udiv(Register num, Register div, Register dest,
349                Condition cond = Always);
350   // Misc operations
351   void ma_clz(Register src, Register dest, Condition cond = Always);
352   void ma_ctz(Register src, Register dest, AutoRegisterScope& scratch);
353   // Memory:
354   // Shortcut for when we know we're transferring 32 bits of data.
355   void ma_dtr(LoadStore ls, Register rn, Imm32 offset, Register rt,
356               AutoRegisterScope& scratch, Index mode = Offset,
357               Condition cc = Always);
358   void ma_dtr(LoadStore ls, Register rt, const Address& addr,
359               AutoRegisterScope& scratch, Index mode, Condition cc);
360 
361   void ma_str(Register rt, DTRAddr addr, Index mode = Offset,
362               Condition cc = Always);
363   void ma_str(Register rt, const Address& addr, AutoRegisterScope& scratch,
364               Index mode = Offset, Condition cc = Always);
365 
366   void ma_ldr(DTRAddr addr, Register rt, Index mode = Offset,
367               Condition cc = Always);
368   void ma_ldr(const Address& addr, Register rt, AutoRegisterScope& scratch,
369               Index mode = Offset, Condition cc = Always);
370 
371   void ma_ldrb(DTRAddr addr, Register rt, Index mode = Offset,
372                Condition cc = Always);
373   void ma_ldrh(EDtrAddr addr, Register rt, Index mode = Offset,
374                Condition cc = Always);
375   void ma_ldrsh(EDtrAddr addr, Register rt, Index mode = Offset,
376                 Condition cc = Always);
377   void ma_ldrsb(EDtrAddr addr, Register rt, Index mode = Offset,
378                 Condition cc = Always);
379   void ma_ldrd(EDtrAddr addr, Register rt, DebugOnly<Register> rt2,
380                Index mode = Offset, Condition cc = Always);
381   void ma_strb(Register rt, DTRAddr addr, Index mode = Offset,
382                Condition cc = Always);
383   void ma_strh(Register rt, EDtrAddr addr, Index mode = Offset,
384                Condition cc = Always);
385   void ma_strd(Register rt, DebugOnly<Register> rt2, EDtrAddr addr,
386                Index mode = Offset, Condition cc = Always);
387 
388   // Specialty for moving N bits of data, where n == 8,16,32,64.
389   BufferOffset ma_dataTransferN(LoadStore ls, int size, bool IsSigned,
390                                 Register rn, Register rm, Register rt,
391                                 AutoRegisterScope& scratch, Index mode = Offset,
392                                 Condition cc = Always, Scale scale = TimesOne);
393 
394   BufferOffset ma_dataTransferN(LoadStore ls, int size, bool IsSigned,
395                                 Register rn, Register rm, Register rt,
396                                 Index mode = Offset, Condition cc = Always);
397 
398   BufferOffset ma_dataTransferN(LoadStore ls, int size, bool IsSigned,
399                                 Register rn, Imm32 offset, Register rt,
400                                 AutoRegisterScope& scratch, Index mode = Offset,
401                                 Condition cc = Always);
402 
403   void ma_pop(Register r);
404   void ma_popn_pc(Imm32 n, AutoRegisterScope& scratch,
405                   AutoRegisterScope& scratch2);
406   void ma_push(Register r);
407   void ma_push_sp(Register r, AutoRegisterScope& scratch);
408 
409   void ma_vpop(VFPRegister r);
410   void ma_vpush(VFPRegister r);
411 
412   // Barriers.
413   void ma_dmb(BarrierOption option = BarrierSY);
414   void ma_dsb(BarrierOption option = BarrierSY);
415 
416   // Branches when done from within arm-specific code.
417   BufferOffset ma_b(Label* dest, Condition c = Always);
418   BufferOffset ma_b(wasm::OldTrapDesc target, Condition c = Always);
419   void ma_b(void* target, Condition c = Always);
420   void ma_bx(Register dest, Condition c = Always);
421 
422   // This is almost NEVER necessary, we'll basically never be calling a label
423   // except, possibly in the crazy bailout-table case.
424   void ma_bl(Label* dest, Condition c = Always);
425 
426   void ma_blx(Register dest, Condition c = Always);
427 
428   // VFP/ALU:
429   void ma_vadd(FloatRegister src1, FloatRegister src2, FloatRegister dst);
430   void ma_vsub(FloatRegister src1, FloatRegister src2, FloatRegister dst);
431 
432   void ma_vmul(FloatRegister src1, FloatRegister src2, FloatRegister dst);
433   void ma_vdiv(FloatRegister src1, FloatRegister src2, FloatRegister dst);
434 
435   void ma_vneg(FloatRegister src, FloatRegister dest, Condition cc = Always);
436   void ma_vmov(FloatRegister src, FloatRegister dest, Condition cc = Always);
437   void ma_vmov_f32(FloatRegister src, FloatRegister dest,
438                    Condition cc = Always);
439   void ma_vabs(FloatRegister src, FloatRegister dest, Condition cc = Always);
440   void ma_vabs_f32(FloatRegister src, FloatRegister dest,
441                    Condition cc = Always);
442 
443   void ma_vsqrt(FloatRegister src, FloatRegister dest, Condition cc = Always);
444   void ma_vsqrt_f32(FloatRegister src, FloatRegister dest,
445                     Condition cc = Always);
446 
447   void ma_vimm(double value, FloatRegister dest, Condition cc = Always);
448   void ma_vimm_f32(float value, FloatRegister dest, Condition cc = Always);
449 
450   void ma_vcmp(FloatRegister src1, FloatRegister src2, Condition cc = Always);
451   void ma_vcmp_f32(FloatRegister src1, FloatRegister src2,
452                    Condition cc = Always);
453   void ma_vcmpz(FloatRegister src1, Condition cc = Always);
454   void ma_vcmpz_f32(FloatRegister src1, Condition cc = Always);
455 
456   void ma_vadd_f32(FloatRegister src1, FloatRegister src2, FloatRegister dst);
457   void ma_vsub_f32(FloatRegister src1, FloatRegister src2, FloatRegister dst);
458 
459   void ma_vmul_f32(FloatRegister src1, FloatRegister src2, FloatRegister dst);
460   void ma_vdiv_f32(FloatRegister src1, FloatRegister src2, FloatRegister dst);
461 
462   void ma_vneg_f32(FloatRegister src, FloatRegister dest,
463                    Condition cc = Always);
464 
465   // Source is F64, dest is I32:
466   void ma_vcvt_F64_I32(FloatRegister src, FloatRegister dest,
467                        Condition cc = Always);
468   void ma_vcvt_F64_U32(FloatRegister src, FloatRegister dest,
469                        Condition cc = Always);
470 
471   // Source is I32, dest is F64:
472   void ma_vcvt_I32_F64(FloatRegister src, FloatRegister dest,
473                        Condition cc = Always);
474   void ma_vcvt_U32_F64(FloatRegister src, FloatRegister dest,
475                        Condition cc = Always);
476 
477   // Source is F32, dest is I32:
478   void ma_vcvt_F32_I32(FloatRegister src, FloatRegister dest,
479                        Condition cc = Always);
480   void ma_vcvt_F32_U32(FloatRegister src, FloatRegister dest,
481                        Condition cc = Always);
482 
483   // Source is I32, dest is F32:
484   void ma_vcvt_I32_F32(FloatRegister src, FloatRegister dest,
485                        Condition cc = Always);
486   void ma_vcvt_U32_F32(FloatRegister src, FloatRegister dest,
487                        Condition cc = Always);
488 
489   // Transfer (do not coerce) a float into a gpr.
490   void ma_vxfer(VFPRegister src, Register dest, Condition cc = Always);
491   // Transfer (do not coerce) a double into a couple of gpr.
492   void ma_vxfer(VFPRegister src, Register dest1, Register dest2,
493                 Condition cc = Always);
494 
495   // Transfer (do not coerce) a gpr into a float
496   void ma_vxfer(Register src, FloatRegister dest, Condition cc = Always);
497   // Transfer (do not coerce) a couple of gpr into a double
498   void ma_vxfer(Register src1, Register src2, FloatRegister dest,
499                 Condition cc = Always);
500 
501   BufferOffset ma_vdtr(LoadStore ls, const Address& addr, VFPRegister dest,
502                        AutoRegisterScope& scratch, Condition cc = Always);
503 
504   BufferOffset ma_vldr(VFPAddr addr, VFPRegister dest, Condition cc = Always);
505   BufferOffset ma_vldr(const Address& addr, VFPRegister dest,
506                        AutoRegisterScope& scratch, Condition cc = Always);
507   BufferOffset ma_vldr(VFPRegister src, Register base, Register index,
508                        AutoRegisterScope& scratch, int32_t shift = defaultShift,
509                        Condition cc = Always);
510 
511   BufferOffset ma_vstr(VFPRegister src, VFPAddr addr, Condition cc = Always);
512   BufferOffset ma_vstr(VFPRegister src, const Address& addr,
513                        AutoRegisterScope& scratch, Condition cc = Always);
514   BufferOffset ma_vstr(VFPRegister src, Register base, Register index,
515                        AutoRegisterScope& scratch, AutoRegisterScope& scratch2,
516                        int32_t shift, int32_t offset, Condition cc = Always);
517   BufferOffset ma_vstr(VFPRegister src, Register base, Register index,
518                        AutoRegisterScope& scratch, int32_t shift,
519                        Condition cc = Always);
520 
521   void ma_call(ImmPtr dest);
522 
523   // Float registers can only be loaded/stored in continuous runs when using
524   // vstm/vldm. This function breaks set into continuous runs and loads/stores
525   // them at [rm]. rm will be modified and left in a state logically suitable
526   // for the next load/store. Returns the offset from [dm] for the logical
527   // next load/store.
transferMultipleByRuns(FloatRegisterSet set,LoadStore ls,Register rm,DTMMode mode)528   int32_t transferMultipleByRuns(FloatRegisterSet set, LoadStore ls,
529                                  Register rm, DTMMode mode) {
530     if (mode == IA) {
531       return transferMultipleByRunsImpl<FloatRegisterForwardIterator>(
532           set, ls, rm, mode, 1);
533     }
534     if (mode == DB) {
535       return transferMultipleByRunsImpl<FloatRegisterBackwardIterator>(
536           set, ls, rm, mode, -1);
537     }
538     MOZ_CRASH("Invalid data transfer addressing mode");
539   }
540 
541   // `outAny` is valid if and only if `out64` == Register64::Invalid().
542   void wasmLoadImpl(const wasm::MemoryAccessDesc& access, Register memoryBase,
543                     Register ptr, Register ptrScratch, AnyRegister outAny,
544                     Register64 out64);
545 
546   // `valAny` is valid if and only if `val64` == Register64::Invalid().
547   void wasmStoreImpl(const wasm::MemoryAccessDesc& access, AnyRegister valAny,
548                      Register64 val64, Register memoryBase, Register ptr,
549                      Register ptrScratch);
550 
551  protected:
552   // `outAny` is valid if and only if `out64` == Register64::Invalid().
553   void wasmUnalignedLoadImpl(const wasm::MemoryAccessDesc& access,
554                              Register memoryBase, Register ptr,
555                              Register ptrScratch, AnyRegister outAny,
556                              Register64 out64, Register tmp1, Register tmp2,
557                              Register tmp3);
558 
559   // The value to be stored is in `floatValue` (if not invalid), `val64` (if not
560   // invalid), or in `valOrTmp` (if `floatValue` and `val64` are both invalid).
561   // Note `valOrTmp` must always be valid.
562   void wasmUnalignedStoreImpl(const wasm::MemoryAccessDesc& access,
563                               FloatRegister floatValue, Register64 val64,
564                               Register memoryBase, Register ptr,
565                               Register ptrScratch, Register valOrTmp);
566 
567  private:
568   // Loads `byteSize` bytes, byte by byte, by reading from ptr[offset],
569   // applying the indicated signedness (defined by isSigned).
570   // - all three registers must be different.
571   // - tmp and dest will get clobbered, ptr will remain intact.
572   // - byteSize can be up to 4 bytes and no more (GPR are 32 bits on ARM).
573   void emitUnalignedLoad(bool isSigned, unsigned byteSize, Register ptr,
574                          Register tmp, Register dest, unsigned offset = 0);
575 
576   // Ditto, for a store. Note stores don't care about signedness.
577   // - the two registers must be different.
578   // - val will get clobbered, ptr will remain intact.
579   // - byteSize can be up to 4 bytes and no more (GPR are 32 bits on ARM).
580   void emitUnalignedStore(unsigned byteSize, Register ptr, Register val,
581                           unsigned offset = 0);
582 
583   // Implementation for transferMultipleByRuns so we can use different
584   // iterators for forward/backward traversals. The sign argument should be 1
585   // if we traverse forwards, -1 if we traverse backwards.
586   template <typename RegisterIterator>
transferMultipleByRunsImpl(FloatRegisterSet set,LoadStore ls,Register rm,DTMMode mode,int32_t sign)587   int32_t transferMultipleByRunsImpl(FloatRegisterSet set, LoadStore ls,
588                                      Register rm, DTMMode mode, int32_t sign) {
589     MOZ_ASSERT(sign == 1 || sign == -1);
590 
591     int32_t delta = sign * sizeof(float);
592     int32_t offset = 0;
593     // Build up a new set, which is the sum of all of the single and double
594     // registers. This set can have up to 48 registers in it total
595     // s0-s31 and d16-d31
596     FloatRegisterSet mod = set.reduceSetForPush();
597 
598     RegisterIterator iter(mod);
599     while (iter.more()) {
600       startFloatTransferM(ls, rm, mode, WriteBack);
601       int32_t reg = (*iter).code();
602       do {
603         offset += delta;
604         if ((*iter).isDouble()) offset += delta;
605         transferFloatReg(*iter);
606       } while ((++iter).more() && int32_t((*iter).code()) == (reg += sign));
607       finishFloatTransfer();
608     }
609     return offset;
610   }
611 };
612 
613 class MacroAssembler;
614 
615 class MacroAssemblerARMCompat : public MacroAssemblerARM {
616  private:
617   // Perform a downcast. Should be removed by Bug 996602.
618   MacroAssembler& asMasm();
619   const MacroAssembler& asMasm() const;
620 
621  public:
MacroAssemblerARMCompat()622   MacroAssemblerARMCompat() {}
623 
624  public:
625   // Jumps + other functions that should be called from non-arm specific
626   // code. Basically, an x86 front end on top of the ARM code.
j(Condition code,Label * dest)627   void j(Condition code, Label* dest) { as_b(dest, code); }
j(Label * dest)628   void j(Label* dest) { as_b(dest, Always); }
629 
mov(Register src,Register dest)630   void mov(Register src, Register dest) { ma_mov(src, dest); }
mov(ImmWord imm,Register dest)631   void mov(ImmWord imm, Register dest) { ma_mov(Imm32(imm.value), dest); }
mov(ImmPtr imm,Register dest)632   void mov(ImmPtr imm, Register dest) {
633     mov(ImmWord(uintptr_t(imm.value)), dest);
634   }
635 
branch(JitCode * c)636   void branch(JitCode* c) {
637     BufferOffset bo = m_buffer.nextOffset();
638     addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
639     ScratchRegisterScope scratch(asMasm());
640     ma_movPatchable(ImmPtr(c->raw()), scratch, Always);
641     ma_bx(scratch);
642   }
branch(const Register reg)643   void branch(const Register reg) { ma_bx(reg); }
nop()644   void nop() { ma_nop(); }
shortJumpSizedNop()645   void shortJumpSizedNop() { ma_nop(); }
ret()646   void ret() { ma_pop(pc); }
retn(Imm32 n)647   void retn(Imm32 n) {
648     ScratchRegisterScope scratch(asMasm());
649     SecondScratchRegisterScope scratch2(asMasm());
650     ma_popn_pc(n, scratch, scratch2);
651   }
push(Imm32 imm)652   void push(Imm32 imm) {
653     ScratchRegisterScope scratch(asMasm());
654     ma_mov(imm, scratch);
655     ma_push(scratch);
656   }
push(ImmWord imm)657   void push(ImmWord imm) { push(Imm32(imm.value)); }
push(ImmGCPtr imm)658   void push(ImmGCPtr imm) {
659     ScratchRegisterScope scratch(asMasm());
660     ma_mov(imm, scratch);
661     ma_push(scratch);
662   }
push(const Address & addr)663   void push(const Address& addr) {
664     ScratchRegisterScope scratch(asMasm());
665     SecondScratchRegisterScope scratch2(asMasm());
666     ma_ldr(addr, scratch, scratch2);
667     ma_push(scratch);
668   }
push(Register reg)669   void push(Register reg) {
670     if (reg == sp) {
671       ScratchRegisterScope scratch(asMasm());
672       ma_push_sp(reg, scratch);
673     } else {
674       ma_push(reg);
675     }
676   }
push(FloatRegister reg)677   void push(FloatRegister reg) { ma_vpush(VFPRegister(reg)); }
pushWithPadding(Register reg,const Imm32 extraSpace)678   void pushWithPadding(Register reg, const Imm32 extraSpace) {
679     ScratchRegisterScope scratch(asMasm());
680     Imm32 totSpace = Imm32(extraSpace.value + 4);
681     ma_dtr(IsStore, sp, totSpace, reg, scratch, PreIndex);
682   }
pushWithPadding(Imm32 imm,const Imm32 extraSpace)683   void pushWithPadding(Imm32 imm, const Imm32 extraSpace) {
684     ScratchRegisterScope scratch(asMasm());
685     SecondScratchRegisterScope scratch2(asMasm());
686     Imm32 totSpace = Imm32(extraSpace.value + 4);
687     ma_mov(imm, scratch);
688     ma_dtr(IsStore, sp, totSpace, scratch, scratch2, PreIndex);
689   }
690 
pop(Register reg)691   void pop(Register reg) { ma_pop(reg); }
pop(FloatRegister reg)692   void pop(FloatRegister reg) { ma_vpop(VFPRegister(reg)); }
693 
popN(Register reg,Imm32 extraSpace)694   void popN(Register reg, Imm32 extraSpace) {
695     ScratchRegisterScope scratch(asMasm());
696     Imm32 totSpace = Imm32(extraSpace.value + 4);
697     ma_dtr(IsLoad, sp, totSpace, reg, scratch, PostIndex);
698   }
699 
700   CodeOffset toggledJump(Label* label);
701 
702   // Emit a BLX or NOP instruction. ToggleCall can be used to patch this
703   // instruction.
704   CodeOffset toggledCall(JitCode* target, bool enabled);
705 
pushWithPatch(ImmWord imm)706   CodeOffset pushWithPatch(ImmWord imm) {
707     ScratchRegisterScope scratch(asMasm());
708     CodeOffset label = movWithPatch(imm, scratch);
709     ma_push(scratch);
710     return label;
711   }
712 
movWithPatch(ImmWord imm,Register dest)713   CodeOffset movWithPatch(ImmWord imm, Register dest) {
714     CodeOffset label = CodeOffset(currentOffset());
715     ma_movPatchable(Imm32(imm.value), dest, Always);
716     return label;
717   }
movWithPatch(ImmPtr imm,Register dest)718   CodeOffset movWithPatch(ImmPtr imm, Register dest) {
719     return movWithPatch(ImmWord(uintptr_t(imm.value)), dest);
720   }
721 
jump(Label * label)722   void jump(Label* label) { as_b(label); }
jump(JitCode * code)723   void jump(JitCode* code) { branch(code); }
jump(TrampolinePtr code)724   void jump(TrampolinePtr code) {
725     ScratchRegisterScope scratch(asMasm());
726     movePtr(ImmPtr(code.value), scratch);
727     ma_bx(scratch);
728   }
jump(Register reg)729   void jump(Register reg) { ma_bx(reg); }
jump(const Address & addr)730   void jump(const Address& addr) {
731     ScratchRegisterScope scratch(asMasm());
732     SecondScratchRegisterScope scratch2(asMasm());
733     ma_ldr(addr, scratch, scratch2);
734     ma_bx(scratch);
735   }
jump(wasm::OldTrapDesc target)736   void jump(wasm::OldTrapDesc target) { as_b(target); }
737 
negl(Register reg)738   void negl(Register reg) { ma_neg(reg, reg, SetCC); }
test32(Register lhs,Register rhs)739   void test32(Register lhs, Register rhs) { ma_tst(lhs, rhs); }
test32(Register lhs,Imm32 imm)740   void test32(Register lhs, Imm32 imm) {
741     ScratchRegisterScope scratch(asMasm());
742     ma_tst(lhs, imm, scratch);
743   }
test32(const Address & addr,Imm32 imm)744   void test32(const Address& addr, Imm32 imm) {
745     ScratchRegisterScope scratch(asMasm());
746     SecondScratchRegisterScope scratch2(asMasm());
747     ma_ldr(addr, scratch, scratch2);
748     ma_tst(scratch, imm, scratch2);
749   }
testPtr(Register lhs,Register rhs)750   void testPtr(Register lhs, Register rhs) { test32(lhs, rhs); }
751 
splitTagForTest(const ValueOperand & value,ScratchTagScope & tag)752   void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag) {
753     MOZ_ASSERT(value.typeReg() == tag);
754   }
755 
756   // Higher level tag testing code.
757   Condition testInt32(Condition cond, const ValueOperand& value);
758   Condition testBoolean(Condition cond, const ValueOperand& value);
759   Condition testDouble(Condition cond, const ValueOperand& value);
760   Condition testNull(Condition cond, const ValueOperand& value);
761   Condition testUndefined(Condition cond, const ValueOperand& value);
762   Condition testString(Condition cond, const ValueOperand& value);
763   Condition testSymbol(Condition cond, const ValueOperand& value);
764   Condition testObject(Condition cond, const ValueOperand& value);
765   Condition testNumber(Condition cond, const ValueOperand& value);
766   Condition testMagic(Condition cond, const ValueOperand& value);
767 
768   Condition testPrimitive(Condition cond, const ValueOperand& value);
769 
770   // Register-based tests.
771   Condition testInt32(Condition cond, Register tag);
772   Condition testBoolean(Condition cond, Register tag);
773   Condition testNull(Condition cond, Register tag);
774   Condition testUndefined(Condition cond, Register tag);
775   Condition testString(Condition cond, Register tag);
776   Condition testSymbol(Condition cond, Register tag);
777   Condition testObject(Condition cond, Register tag);
778   Condition testDouble(Condition cond, Register tag);
779   Condition testNumber(Condition cond, Register tag);
780   Condition testMagic(Condition cond, Register tag);
781   Condition testPrimitive(Condition cond, Register tag);
782 
783   Condition testGCThing(Condition cond, const Address& address);
784   Condition testMagic(Condition cond, const Address& address);
785   Condition testInt32(Condition cond, const Address& address);
786   Condition testDouble(Condition cond, const Address& address);
787   Condition testBoolean(Condition cond, const Address& address);
788   Condition testNull(Condition cond, const Address& address);
789   Condition testUndefined(Condition cond, const Address& address);
790   Condition testString(Condition cond, const Address& address);
791   Condition testSymbol(Condition cond, const Address& address);
792   Condition testObject(Condition cond, const Address& address);
793   Condition testNumber(Condition cond, const Address& address);
794 
795   Condition testUndefined(Condition cond, const BaseIndex& src);
796   Condition testNull(Condition cond, const BaseIndex& src);
797   Condition testBoolean(Condition cond, const BaseIndex& src);
798   Condition testString(Condition cond, const BaseIndex& src);
799   Condition testSymbol(Condition cond, const BaseIndex& src);
800   Condition testInt32(Condition cond, const BaseIndex& src);
801   Condition testObject(Condition cond, const BaseIndex& src);
802   Condition testDouble(Condition cond, const BaseIndex& src);
803   Condition testMagic(Condition cond, const BaseIndex& src);
804   Condition testGCThing(Condition cond, const BaseIndex& src);
805 
806   // Unboxing code.
807   void unboxNonDouble(const ValueOperand& operand, Register dest,
808                       JSValueType type);
809   void unboxNonDouble(const Address& src, Register dest, JSValueType type);
810   void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType type);
unboxInt32(const ValueOperand & src,Register dest)811   void unboxInt32(const ValueOperand& src, Register dest) {
812     unboxNonDouble(src, dest, JSVAL_TYPE_INT32);
813   }
unboxInt32(const Address & src,Register dest)814   void unboxInt32(const Address& src, Register dest) {
815     unboxNonDouble(src, dest, JSVAL_TYPE_INT32);
816   }
unboxBoolean(const ValueOperand & src,Register dest)817   void unboxBoolean(const ValueOperand& src, Register dest) {
818     unboxNonDouble(src, dest, JSVAL_TYPE_BOOLEAN);
819   }
unboxBoolean(const Address & src,Register dest)820   void unboxBoolean(const Address& src, Register dest) {
821     unboxNonDouble(src, dest, JSVAL_TYPE_BOOLEAN);
822   }
unboxString(const ValueOperand & src,Register dest)823   void unboxString(const ValueOperand& src, Register dest) {
824     unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
825   }
unboxString(const Address & src,Register dest)826   void unboxString(const Address& src, Register dest) {
827     unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
828   }
unboxSymbol(const ValueOperand & src,Register dest)829   void unboxSymbol(const ValueOperand& src, Register dest) {
830     unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
831   }
unboxSymbol(const Address & src,Register dest)832   void unboxSymbol(const Address& src, Register dest) {
833     unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
834   }
unboxObject(const ValueOperand & src,Register dest)835   void unboxObject(const ValueOperand& src, Register dest) {
836     unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
837   }
unboxObject(const Address & src,Register dest)838   void unboxObject(const Address& src, Register dest) {
839     unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
840   }
unboxObject(const BaseIndex & src,Register dest)841   void unboxObject(const BaseIndex& src, Register dest) {
842     unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
843   }
844   void unboxDouble(const ValueOperand& src, FloatRegister dest);
845   void unboxDouble(const Address& src, FloatRegister dest);
846   void unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType type);
847   void unboxPrivate(const ValueOperand& src, Register dest);
848 
849   // See comment in MacroAssembler-x64.h.
unboxGCThingForPreBarrierTrampoline(const Address & src,Register dest)850   void unboxGCThingForPreBarrierTrampoline(const Address& src, Register dest) {
851     load32(ToPayload(src), dest);
852   }
853 
notBoolean(const ValueOperand & val)854   void notBoolean(const ValueOperand& val) {
855     as_eor(val.payloadReg(), val.payloadReg(), Imm8(1));
856   }
857 
858   // Boxing code.
859   void boxDouble(FloatRegister src, const ValueOperand& dest, FloatRegister);
860   void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest);
861 
862   // Extended unboxing API. If the payload is already in a register, returns
863   // that register. Otherwise, provides a move to the given scratch register,
864   // and returns that.
865   Register extractObject(const Address& address, Register scratch);
extractObject(const ValueOperand & value,Register scratch)866   Register extractObject(const ValueOperand& value, Register scratch) {
867     unboxNonDouble(value, value.payloadReg(), JSVAL_TYPE_OBJECT);
868     return value.payloadReg();
869   }
extractString(const ValueOperand & value,Register scratch)870   Register extractString(const ValueOperand& value, Register scratch) {
871     unboxNonDouble(value, value.payloadReg(), JSVAL_TYPE_STRING);
872     return value.payloadReg();
873   }
extractSymbol(const ValueOperand & value,Register scratch)874   Register extractSymbol(const ValueOperand& value, Register scratch) {
875     unboxNonDouble(value, value.payloadReg(), JSVAL_TYPE_SYMBOL);
876     return value.payloadReg();
877   }
extractInt32(const ValueOperand & value,Register scratch)878   Register extractInt32(const ValueOperand& value, Register scratch) {
879     return value.payloadReg();
880   }
extractBoolean(const ValueOperand & value,Register scratch)881   Register extractBoolean(const ValueOperand& value, Register scratch) {
882     return value.payloadReg();
883   }
884   Register extractTag(const Address& address, Register scratch);
885   Register extractTag(const BaseIndex& address, Register scratch);
extractTag(const ValueOperand & value,Register scratch)886   Register extractTag(const ValueOperand& value, Register scratch) {
887     return value.typeReg();
888   }
889 
890   void boolValueToDouble(const ValueOperand& operand, FloatRegister dest);
891   void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest);
892   void loadInt32OrDouble(const Address& src, FloatRegister dest);
893   void loadInt32OrDouble(Register base, Register index, FloatRegister dest,
894                          int32_t shift = defaultShift);
895   void loadConstantDouble(double dp, FloatRegister dest);
896 
897   // Treat the value as a boolean, and set condition codes accordingly.
898   Condition testInt32Truthy(bool truthy, const ValueOperand& operand);
899   Condition testBooleanTruthy(bool truthy, const ValueOperand& operand);
900   Condition testDoubleTruthy(bool truthy, FloatRegister reg);
901   Condition testStringTruthy(bool truthy, const ValueOperand& value);
902 
903   void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest);
904   void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest);
905   void loadConstantFloat32(float f, FloatRegister dest);
906 
907   CodeOffsetJump jumpWithPatch(RepatchLabel* label, Condition cond = Always,
908                                Label* documentation = nullptr);
backedgeJump(RepatchLabel * label,Label * documentation)909   CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation) {
910     return jumpWithPatch(label, Always, documentation);
911   }
912 
loadUnboxedValue(Address address,MIRType type,AnyRegister dest)913   void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) {
914     if (dest.isFloat()) {
915       loadInt32OrDouble(address, dest.fpu());
916     } else {
917       ScratchRegisterScope scratch(asMasm());
918       ma_ldr(address, dest.gpr(), scratch);
919     }
920   }
921 
loadUnboxedValue(BaseIndex address,MIRType type,AnyRegister dest)922   void loadUnboxedValue(BaseIndex address, MIRType type, AnyRegister dest) {
923     if (dest.isFloat())
924       loadInt32OrDouble(address.base, address.index, dest.fpu(), address.scale);
925     else
926       load32(address, dest.gpr());
927   }
928 
929   template <typename T>
storeUnboxedPayload(ValueOperand value,T address,size_t nbytes,JSValueType)930   void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes,
931                            JSValueType) {
932     switch (nbytes) {
933       case 4:
934         storePtr(value.payloadReg(), address);
935         return;
936       case 1:
937         store8(value.payloadReg(), address);
938         return;
939       default:
940         MOZ_CRASH("Bad payload width");
941     }
942   }
943 
944   void storeValue(ValueOperand val, const Address& dst);
945   void storeValue(ValueOperand val, const BaseIndex& dest);
storeValue(JSValueType type,Register reg,BaseIndex dest)946   void storeValue(JSValueType type, Register reg, BaseIndex dest) {
947     ScratchRegisterScope scratch(asMasm());
948     SecondScratchRegisterScope scratch2(asMasm());
949 
950     int32_t payloadoffset = dest.offset + NUNBOX32_PAYLOAD_OFFSET;
951     int32_t typeoffset = dest.offset + NUNBOX32_TYPE_OFFSET;
952 
953     ma_alu(dest.base, lsl(dest.index, dest.scale), scratch, OpAdd);
954 
955     // Store the payload.
956     if (payloadoffset < 4096 && payloadoffset > -4096)
957       ma_str(reg, DTRAddr(scratch, DtrOffImm(payloadoffset)));
958     else
959       ma_str(reg, Address(scratch, payloadoffset), scratch2);
960 
961     // Store the type.
962     if (typeoffset < 4096 && typeoffset > -4096) {
963       // Encodable as DTRAddr, so only two instructions needed.
964       ma_mov(ImmTag(JSVAL_TYPE_TO_TAG(type)), scratch2);
965       ma_str(scratch2, DTRAddr(scratch, DtrOffImm(typeoffset)));
966     } else {
967       // Since there are only two scratch registers, the offset must be
968       // applied early using a third instruction to be safe.
969       ma_add(Imm32(typeoffset), scratch, scratch2);
970       ma_mov(ImmTag(JSVAL_TYPE_TO_TAG(type)), scratch2);
971       ma_str(scratch2, DTRAddr(scratch, DtrOffImm(0)));
972     }
973   }
storeValue(JSValueType type,Register reg,Address dest)974   void storeValue(JSValueType type, Register reg, Address dest) {
975     ScratchRegisterScope scratch(asMasm());
976     SecondScratchRegisterScope scratch2(asMasm());
977 
978     ma_str(reg, dest, scratch2);
979     ma_mov(ImmTag(JSVAL_TYPE_TO_TAG(type)), scratch);
980     ma_str(scratch, Address(dest.base, dest.offset + NUNBOX32_TYPE_OFFSET),
981            scratch2);
982   }
storeValue(const Value & val,const Address & dest)983   void storeValue(const Value& val, const Address& dest) {
984     ScratchRegisterScope scratch(asMasm());
985     SecondScratchRegisterScope scratch2(asMasm());
986 
987     ma_mov(Imm32(val.toNunboxTag()), scratch);
988     ma_str(scratch, ToType(dest), scratch2);
989     if (val.isGCThing())
990       ma_mov(ImmGCPtr(val.toGCThing()), scratch);
991     else
992       ma_mov(Imm32(val.toNunboxPayload()), scratch);
993     ma_str(scratch, ToPayload(dest), scratch2);
994   }
storeValue(const Value & val,BaseIndex dest)995   void storeValue(const Value& val, BaseIndex dest) {
996     ScratchRegisterScope scratch(asMasm());
997     SecondScratchRegisterScope scratch2(asMasm());
998 
999     int32_t typeoffset = dest.offset + NUNBOX32_TYPE_OFFSET;
1000     int32_t payloadoffset = dest.offset + NUNBOX32_PAYLOAD_OFFSET;
1001 
1002     ma_alu(dest.base, lsl(dest.index, dest.scale), scratch, OpAdd);
1003 
1004     // Store the type.
1005     if (typeoffset < 4096 && typeoffset > -4096) {
1006       ma_mov(Imm32(val.toNunboxTag()), scratch2);
1007       ma_str(scratch2, DTRAddr(scratch, DtrOffImm(typeoffset)));
1008     } else {
1009       ma_add(Imm32(typeoffset), scratch, scratch2);
1010       ma_mov(Imm32(val.toNunboxTag()), scratch2);
1011       ma_str(scratch2, DTRAddr(scratch, DtrOffImm(0)));
1012       // Restore scratch for the payload store.
1013       ma_alu(dest.base, lsl(dest.index, dest.scale), scratch, OpAdd);
1014     }
1015 
1016     // Store the payload, marking if necessary.
1017     if (payloadoffset < 4096 && payloadoffset > -4096) {
1018       if (val.isGCThing())
1019         ma_mov(ImmGCPtr(val.toGCThing()), scratch2);
1020       else
1021         ma_mov(Imm32(val.toNunboxPayload()), scratch2);
1022       ma_str(scratch2, DTRAddr(scratch, DtrOffImm(payloadoffset)));
1023     } else {
1024       ma_add(Imm32(payloadoffset), scratch, scratch2);
1025       if (val.isGCThing())
1026         ma_mov(ImmGCPtr(val.toGCThing()), scratch2);
1027       else
1028         ma_mov(Imm32(val.toNunboxPayload()), scratch2);
1029       ma_str(scratch2, DTRAddr(scratch, DtrOffImm(0)));
1030     }
1031   }
storeValue(const Address & src,const Address & dest,Register temp)1032   void storeValue(const Address& src, const Address& dest, Register temp) {
1033     load32(ToType(src), temp);
1034     store32(temp, ToType(dest));
1035 
1036     load32(ToPayload(src), temp);
1037     store32(temp, ToPayload(dest));
1038   }
1039 
1040   void loadValue(Address src, ValueOperand val);
loadValue(Operand dest,ValueOperand val)1041   void loadValue(Operand dest, ValueOperand val) {
1042     loadValue(dest.toAddress(), val);
1043   }
1044   void loadValue(const BaseIndex& addr, ValueOperand val);
1045   void tagValue(JSValueType type, Register payload, ValueOperand dest);
1046 
1047   void pushValue(ValueOperand val);
1048   void popValue(ValueOperand val);
pushValue(const Value & val)1049   void pushValue(const Value& val) {
1050     push(Imm32(val.toNunboxTag()));
1051     if (val.isGCThing())
1052       push(ImmGCPtr(val.toGCThing()));
1053     else
1054       push(Imm32(val.toNunboxPayload()));
1055   }
pushValue(JSValueType type,Register reg)1056   void pushValue(JSValueType type, Register reg) {
1057     push(ImmTag(JSVAL_TYPE_TO_TAG(type)));
1058     ma_push(reg);
1059   }
1060   void pushValue(const Address& addr);
1061 
1062   void storePayload(const Value& val, const Address& dest);
1063   void storePayload(Register src, const Address& dest);
1064   void storePayload(const Value& val, const BaseIndex& dest);
1065   void storePayload(Register src, const BaseIndex& dest);
1066   void storeTypeTag(ImmTag tag, const Address& dest);
1067   void storeTypeTag(ImmTag tag, const BaseIndex& dest);
1068 
1069   void handleFailureWithHandlerTail(void* handler, Label* profilerExitTail);
1070 
1071   /////////////////////////////////////////////////////////////////
1072   // Common interface.
1073   /////////////////////////////////////////////////////////////////
1074  public:
1075   void not32(Register reg);
1076 
1077   void move32(Imm32 imm, Register dest);
1078   void move32(Register src, Register dest);
1079 
1080   void movePtr(Register src, Register dest);
1081   void movePtr(ImmWord imm, Register dest);
1082   void movePtr(ImmPtr imm, Register dest);
1083   void movePtr(wasm::SymbolicAddress imm, Register dest);
1084   void movePtr(ImmGCPtr imm, Register dest);
1085 
1086   void load8SignExtend(const Address& address, Register dest);
1087   void load8SignExtend(const BaseIndex& src, Register dest);
1088 
1089   void load8ZeroExtend(const Address& address, Register dest);
1090   void load8ZeroExtend(const BaseIndex& src, Register dest);
1091 
1092   void load16SignExtend(const Address& address, Register dest);
1093   void load16SignExtend(const BaseIndex& src, Register dest);
1094 
1095   void load16ZeroExtend(const Address& address, Register dest);
1096   void load16ZeroExtend(const BaseIndex& src, Register dest);
1097 
1098   void load32(const Address& address, Register dest);
1099   void load32(const BaseIndex& address, Register dest);
1100   void load32(AbsoluteAddress address, Register dest);
load64(const Address & address,Register64 dest)1101   void load64(const Address& address, Register64 dest) {
1102     load32(LowWord(address), dest.low);
1103     load32(HighWord(address), dest.high);
1104   }
1105 
1106   void loadPtr(const Address& address, Register dest);
1107   void loadPtr(const BaseIndex& src, Register dest);
1108   void loadPtr(AbsoluteAddress address, Register dest);
1109   void loadPtr(wasm::SymbolicAddress address, Register dest);
1110 
1111   void loadPrivate(const Address& address, Register dest);
1112 
loadInt32x1(const Address & addr,FloatRegister dest)1113   void loadInt32x1(const Address& addr, FloatRegister dest) {
1114     MOZ_CRASH("NYI");
1115   }
loadInt32x1(const BaseIndex & addr,FloatRegister dest)1116   void loadInt32x1(const BaseIndex& addr, FloatRegister dest) {
1117     MOZ_CRASH("NYI");
1118   }
loadInt32x2(const Address & addr,FloatRegister dest)1119   void loadInt32x2(const Address& addr, FloatRegister dest) {
1120     MOZ_CRASH("NYI");
1121   }
loadInt32x2(const BaseIndex & addr,FloatRegister dest)1122   void loadInt32x2(const BaseIndex& addr, FloatRegister dest) {
1123     MOZ_CRASH("NYI");
1124   }
loadInt32x3(const Address & src,FloatRegister dest)1125   void loadInt32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); }
loadInt32x3(const BaseIndex & src,FloatRegister dest)1126   void loadInt32x3(const BaseIndex& src, FloatRegister dest) {
1127     MOZ_CRASH("NYI");
1128   }
loadInt32x4(const Address & addr,FloatRegister dest)1129   void loadInt32x4(const Address& addr, FloatRegister dest) {
1130     MOZ_CRASH("NYI");
1131   }
storeInt32x1(FloatRegister src,const Address & dest)1132   void storeInt32x1(FloatRegister src, const Address& dest) {
1133     MOZ_CRASH("NYI");
1134   }
storeInt32x1(FloatRegister src,const BaseIndex & dest)1135   void storeInt32x1(FloatRegister src, const BaseIndex& dest) {
1136     MOZ_CRASH("NYI");
1137   }
storeInt32x2(FloatRegister src,const Address & dest)1138   void storeInt32x2(FloatRegister src, const Address& dest) {
1139     MOZ_CRASH("NYI");
1140   }
storeInt32x2(FloatRegister src,const BaseIndex & dest)1141   void storeInt32x2(FloatRegister src, const BaseIndex& dest) {
1142     MOZ_CRASH("NYI");
1143   }
storeInt32x3(FloatRegister src,const Address & dest)1144   void storeInt32x3(FloatRegister src, const Address& dest) {
1145     MOZ_CRASH("NYI");
1146   }
storeInt32x3(FloatRegister src,const BaseIndex & dest)1147   void storeInt32x3(FloatRegister src, const BaseIndex& dest) {
1148     MOZ_CRASH("NYI");
1149   }
storeInt32x4(FloatRegister src,const Address & addr)1150   void storeInt32x4(FloatRegister src, const Address& addr) {
1151     MOZ_CRASH("NYI");
1152   }
loadAlignedSimd128Int(const Address & addr,FloatRegister dest)1153   void loadAlignedSimd128Int(const Address& addr, FloatRegister dest) {
1154     MOZ_CRASH("NYI");
1155   }
storeAlignedSimd128Int(FloatRegister src,Address addr)1156   void storeAlignedSimd128Int(FloatRegister src, Address addr) {
1157     MOZ_CRASH("NYI");
1158   }
loadUnalignedSimd128Int(const Address & addr,FloatRegister dest)1159   void loadUnalignedSimd128Int(const Address& addr, FloatRegister dest) {
1160     MOZ_CRASH("NYI");
1161   }
loadUnalignedSimd128Int(const BaseIndex & addr,FloatRegister dest)1162   void loadUnalignedSimd128Int(const BaseIndex& addr, FloatRegister dest) {
1163     MOZ_CRASH("NYI");
1164   }
storeUnalignedSimd128Int(FloatRegister src,Address addr)1165   void storeUnalignedSimd128Int(FloatRegister src, Address addr) {
1166     MOZ_CRASH("NYI");
1167   }
storeUnalignedSimd128Int(FloatRegister src,BaseIndex addr)1168   void storeUnalignedSimd128Int(FloatRegister src, BaseIndex addr) {
1169     MOZ_CRASH("NYI");
1170   }
1171 
loadFloat32x3(const Address & src,FloatRegister dest)1172   void loadFloat32x3(const Address& src, FloatRegister dest) {
1173     MOZ_CRASH("NYI");
1174   }
loadFloat32x3(const BaseIndex & src,FloatRegister dest)1175   void loadFloat32x3(const BaseIndex& src, FloatRegister dest) {
1176     MOZ_CRASH("NYI");
1177   }
loadFloat32x4(const Address & addr,FloatRegister dest)1178   void loadFloat32x4(const Address& addr, FloatRegister dest) {
1179     MOZ_CRASH("NYI");
1180   }
storeFloat32x4(FloatRegister src,const Address & addr)1181   void storeFloat32x4(FloatRegister src, const Address& addr) {
1182     MOZ_CRASH("NYI");
1183   }
1184 
loadAlignedSimd128Float(const Address & addr,FloatRegister dest)1185   void loadAlignedSimd128Float(const Address& addr, FloatRegister dest) {
1186     MOZ_CRASH("NYI");
1187   }
storeAlignedSimd128Float(FloatRegister src,Address addr)1188   void storeAlignedSimd128Float(FloatRegister src, Address addr) {
1189     MOZ_CRASH("NYI");
1190   }
loadUnalignedSimd128Float(const Address & addr,FloatRegister dest)1191   void loadUnalignedSimd128Float(const Address& addr, FloatRegister dest) {
1192     MOZ_CRASH("NYI");
1193   }
loadUnalignedSimd128Float(const BaseIndex & addr,FloatRegister dest)1194   void loadUnalignedSimd128Float(const BaseIndex& addr, FloatRegister dest) {
1195     MOZ_CRASH("NYI");
1196   }
storeUnalignedSimd128Float(FloatRegister src,Address addr)1197   void storeUnalignedSimd128Float(FloatRegister src, Address addr) {
1198     MOZ_CRASH("NYI");
1199   }
storeUnalignedSimd128Float(FloatRegister src,BaseIndex addr)1200   void storeUnalignedSimd128Float(FloatRegister src, BaseIndex addr) {
1201     MOZ_CRASH("NYI");
1202   }
1203 
1204   void loadDouble(const Address& addr, FloatRegister dest);
1205   void loadDouble(const BaseIndex& src, FloatRegister dest);
1206 
1207   // Load a float value into a register, then expand it to a double.
1208   void loadFloatAsDouble(const Address& addr, FloatRegister dest);
1209   void loadFloatAsDouble(const BaseIndex& src, FloatRegister dest);
1210 
1211   void loadFloat32(const Address& addr, FloatRegister dest);
1212   void loadFloat32(const BaseIndex& src, FloatRegister dest);
1213 
1214   void store8(Register src, const Address& address);
1215   void store8(Imm32 imm, const Address& address);
1216   void store8(Register src, const BaseIndex& address);
1217   void store8(Imm32 imm, const BaseIndex& address);
1218 
1219   void store16(Register src, const Address& address);
1220   void store16(Imm32 imm, const Address& address);
1221   void store16(Register src, const BaseIndex& address);
1222   void store16(Imm32 imm, const BaseIndex& address);
1223 
1224   void store32(Register src, AbsoluteAddress address);
1225   void store32(Register src, const Address& address);
1226   void store32(Register src, const BaseIndex& address);
1227   void store32(Imm32 src, const Address& address);
1228   void store32(Imm32 src, const BaseIndex& address);
1229 
store64(Register64 src,Address address)1230   void store64(Register64 src, Address address) {
1231     store32(src.low, LowWord(address));
1232     store32(src.high, HighWord(address));
1233   }
1234 
store64(Imm64 imm,Address address)1235   void store64(Imm64 imm, Address address) {
1236     store32(imm.low(), LowWord(address));
1237     store32(imm.hi(), HighWord(address));
1238   }
1239 
1240   void storePtr(ImmWord imm, const Address& address);
1241   void storePtr(ImmWord imm, const BaseIndex& address);
1242   void storePtr(ImmPtr imm, const Address& address);
1243   void storePtr(ImmPtr imm, const BaseIndex& address);
1244   void storePtr(ImmGCPtr imm, const Address& address);
1245   void storePtr(ImmGCPtr imm, const BaseIndex& address);
1246   void storePtr(Register src, const Address& address);
1247   void storePtr(Register src, const BaseIndex& address);
1248   void storePtr(Register src, AbsoluteAddress dest);
1249 
1250   void moveDouble(FloatRegister src, FloatRegister dest,
1251                   Condition cc = Always) {
1252     ma_vmov(src, dest, cc);
1253   }
1254 
1255   inline void incrementInt32Value(const Address& addr);
1256 
1257   void cmp32(Register lhs, Imm32 rhs);
1258   void cmp32(Register lhs, Register rhs);
cmp32(const Address & lhs,Imm32 rhs)1259   void cmp32(const Address& lhs, Imm32 rhs) { MOZ_CRASH("NYI"); }
cmp32(const Address & lhs,Register rhs)1260   void cmp32(const Address& lhs, Register rhs) { MOZ_CRASH("NYI"); }
1261 
1262   void cmpPtr(Register lhs, Register rhs);
1263   void cmpPtr(Register lhs, ImmWord rhs);
1264   void cmpPtr(Register lhs, ImmPtr rhs);
1265   void cmpPtr(Register lhs, ImmGCPtr rhs);
1266   void cmpPtr(Register lhs, Imm32 rhs);
1267   void cmpPtr(const Address& lhs, Register rhs);
1268   void cmpPtr(const Address& lhs, ImmWord rhs);
1269   void cmpPtr(const Address& lhs, ImmPtr rhs);
1270   void cmpPtr(const Address& lhs, ImmGCPtr rhs);
1271   void cmpPtr(const Address& lhs, Imm32 rhs);
1272 
1273   void setStackArg(Register reg, uint32_t arg);
1274 
1275   void breakpoint();
1276   // Conditional breakpoint.
1277   void breakpoint(Condition cc);
1278 
1279   // Trigger the simulator's interactive read-eval-print loop.
1280   // The message will be printed at the stopping point.
1281   // (On non-simulator builds, does nothing.)
1282   void simulatorStop(const char* msg);
1283 
1284   // Evaluate srcDest = minmax<isMax>{Float32,Double}(srcDest, other).
1285   // Checks for NaN if canBeNaN is true.
1286   void minMaxDouble(FloatRegister srcDest, FloatRegister other, bool canBeNaN,
1287                     bool isMax);
1288   void minMaxFloat32(FloatRegister srcDest, FloatRegister other, bool canBeNaN,
1289                      bool isMax);
1290 
1291   void compareDouble(FloatRegister lhs, FloatRegister rhs);
1292 
1293   void compareFloat(FloatRegister lhs, FloatRegister rhs);
1294 
1295   void checkStackAlignment();
1296 
1297   // If source is a double, load it into dest. If source is int32, convert it
1298   // to double. Else, branch to failure.
1299   void ensureDouble(const ValueOperand& source, FloatRegister dest,
1300                     Label* failure);
1301 
emitSet(Assembler::Condition cond,Register dest)1302   void emitSet(Assembler::Condition cond, Register dest) {
1303     ma_mov(Imm32(0), dest);
1304     ma_mov(Imm32(1), dest, cond);
1305   }
1306 
testNullSet(Condition cond,const ValueOperand & value,Register dest)1307   void testNullSet(Condition cond, const ValueOperand& value, Register dest) {
1308     cond = testNull(cond, value);
1309     emitSet(cond, dest);
1310   }
1311 
testObjectSet(Condition cond,const ValueOperand & value,Register dest)1312   void testObjectSet(Condition cond, const ValueOperand& value, Register dest) {
1313     cond = testObject(cond, value);
1314     emitSet(cond, dest);
1315   }
1316 
testUndefinedSet(Condition cond,const ValueOperand & value,Register dest)1317   void testUndefinedSet(Condition cond, const ValueOperand& value,
1318                         Register dest) {
1319     cond = testUndefined(cond, value);
1320     emitSet(cond, dest);
1321   }
1322 
1323  protected:
1324   bool buildOOLFakeExitFrame(void* fakeReturnAddr);
1325 
1326  public:
labelForPatch()1327   CodeOffset labelForPatch() { return CodeOffset(nextOffset().getOffset()); }
1328 
computeEffectiveAddress(const Address & address,Register dest)1329   void computeEffectiveAddress(const Address& address, Register dest) {
1330     ScratchRegisterScope scratch(asMasm());
1331     ma_add(address.base, Imm32(address.offset), dest, scratch, LeaveCC);
1332   }
computeEffectiveAddress(const BaseIndex & address,Register dest)1333   void computeEffectiveAddress(const BaseIndex& address, Register dest) {
1334     ScratchRegisterScope scratch(asMasm());
1335     ma_alu(address.base, lsl(address.index, address.scale), dest, OpAdd,
1336            LeaveCC);
1337     if (address.offset)
1338       ma_add(dest, Imm32(address.offset), dest, scratch, LeaveCC);
1339   }
1340   void floor(FloatRegister input, Register output, Label* handleNotAnInt);
1341   void floorf(FloatRegister input, Register output, Label* handleNotAnInt);
1342   void ceil(FloatRegister input, Register output, Label* handleNotAnInt);
1343   void ceilf(FloatRegister input, Register output, Label* handleNotAnInt);
1344   void round(FloatRegister input, Register output, Label* handleNotAnInt,
1345              FloatRegister tmp);
1346   void roundf(FloatRegister input, Register output, Label* handleNotAnInt,
1347               FloatRegister tmp);
1348 
clampCheck(Register r,Label * handleNotAnInt)1349   void clampCheck(Register r, Label* handleNotAnInt) {
1350     // Check explicitly for r == INT_MIN || r == INT_MAX
1351     // This is the instruction sequence that gcc generated for this
1352     // operation.
1353     ScratchRegisterScope scratch(asMasm());
1354     SecondScratchRegisterScope scratch2(asMasm());
1355     ma_sub(r, Imm32(0x80000001), scratch, scratch2);
1356     as_cmn(scratch, Imm8(3));
1357     ma_b(handleNotAnInt, Above);
1358   }
1359 
lea(Operand addr,Register dest)1360   void lea(Operand addr, Register dest) {
1361     ScratchRegisterScope scratch(asMasm());
1362     ma_add(addr.baseReg(), Imm32(addr.disp()), dest, scratch);
1363   }
1364 
abiret()1365   void abiret() { as_bx(lr); }
1366 
1367   void moveFloat32(FloatRegister src, FloatRegister dest,
1368                    Condition cc = Always) {
1369     as_vmov(VFPRegister(dest).singleOverlay(), VFPRegister(src).singleOverlay(),
1370             cc);
1371   }
1372 
loadWasmGlobalPtr(uint32_t globalDataOffset,Register dest)1373   void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) {
1374     loadPtr(Address(WasmTlsReg,
1375                     offsetof(wasm::TlsData, globalArea) + globalDataOffset),
1376             dest);
1377   }
loadWasmPinnedRegsFromTls()1378   void loadWasmPinnedRegsFromTls() {
1379     ScratchRegisterScope scratch(asMasm());
1380     ma_ldr(Address(WasmTlsReg, offsetof(wasm::TlsData, memoryBase)), HeapReg,
1381            scratch);
1382   }
1383 
1384   // Instrumentation for entering and leaving the profiler.
1385   void profilerEnterFrame(Register framePtr, Register scratch);
1386   void profilerExitFrame();
1387 };
1388 
1389 typedef MacroAssemblerARMCompat MacroAssemblerSpecific;
1390 
1391 }  // namespace jit
1392 }  // namespace js
1393 
1394 #endif /* jit_arm_MacroAssembler_arm_h */
1395