tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MacroAssembler-mips64.h (32215B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef jit_mips64_MacroAssembler_mips64_h
      8 #define jit_mips64_MacroAssembler_mips64_h
      9 
     10 #include "jit/mips-shared/MacroAssembler-mips-shared.h"
     11 #include "jit/MoveResolver.h"
     12 #include "vm/BytecodeUtil.h"
     13 #include "wasm/WasmBuiltins.h"
     14 
     15 namespace js {
     16 namespace jit {
     17 
     18 enum LiFlags {
     19  Li64 = 0,
     20  Li48 = 1,
     21 };
     22 
     23 struct ImmShiftedTag : public ImmWord {
     24  explicit ImmShiftedTag(JSValueType type)
     25      : ImmWord(uintptr_t(JSValueShiftedTag(JSVAL_TYPE_TO_SHIFTED_TAG(type)))) {
     26  }
     27 };
     28 
     29 struct ImmTag : public Imm32 {
     30  explicit ImmTag(JSValueTag mask) : Imm32(int32_t(mask)) {}
     31 };
     32 
     33 static constexpr ValueOperand JSReturnOperand{JSReturnReg};
     34 
     35 static const int defaultShift = 3;
     36 static_assert(1 << defaultShift == sizeof(JS::Value),
     37              "The defaultShift is wrong");
     38 
     39 // See documentation for ScratchTagScope and ScratchTagScopeRelease in
     40 // MacroAssembler-x64.h.
     41 
     42 class ScratchTagScope {
     43  UseScratchRegisterScope temps_;
     44  Register scratch_;
     45  bool owned_;
     46  mozilla::DebugOnly<bool> released_;
     47 
     48 public:
     49  ScratchTagScope(Assembler& masm, const ValueOperand&)
     50      : temps_(masm), owned_(true), released_(false) {
     51    scratch_ = temps_.Acquire();
     52  }
     53 
     54  operator Register() {
     55    MOZ_ASSERT(!released_);
     56    return scratch_;
     57  }
     58 
     59  void release() {
     60    MOZ_ASSERT(!released_);
     61    released_ = true;
     62    if (owned_) {
     63      temps_.Release(scratch_);
     64      owned_ = false;
     65    }
     66  }
     67 
     68  void reacquire() {
     69    MOZ_ASSERT(released_);
     70    released_ = false;
     71    if (!owned_) {
     72      scratch_ = temps_.Acquire();
     73      owned_ = true;
     74    }
     75  }
     76 };
     77 
     78 class ScratchTagScopeRelease {
     79  ScratchTagScope* ts_;
     80 
     81 public:
     82  explicit ScratchTagScopeRelease(ScratchTagScope* ts) : ts_(ts) {
     83    ts_->release();
     84  }
     85  ~ScratchTagScopeRelease() { ts_->reacquire(); }
     86 };
     87 
     88 class MacroAssemblerMIPS64 : public MacroAssemblerMIPSShared {
     89 public:
     90  using MacroAssemblerMIPSShared::ma_b;
     91  using MacroAssemblerMIPSShared::ma_cmp_set;
     92  using MacroAssemblerMIPSShared::ma_ld;
     93  using MacroAssemblerMIPSShared::ma_li;
     94  using MacroAssemblerMIPSShared::ma_liPatchable;
     95  using MacroAssemblerMIPSShared::ma_load;
     96  using MacroAssemblerMIPSShared::ma_ls;
     97  using MacroAssemblerMIPSShared::ma_sd;
     98  using MacroAssemblerMIPSShared::ma_ss;
     99  using MacroAssemblerMIPSShared::ma_store;
    100  using MacroAssemblerMIPSShared::ma_sub32TestOverflow;
    101 
    102  void ma_li(Register dest, CodeLabel* label);
    103  void ma_li(Register dest, ImmWord imm);
    104  void ma_liPatchable(Register dest, ImmPtr imm);
    105  void ma_liPatchable(Register dest, ImmWord imm, LiFlags flags = Li48);
    106 
    107  // Negate
    108  void ma_dnegu(Register rd, Register rs);
    109 
    110  // Shift operations
    111  void ma_dsll(Register rd, Register rt, Imm32 shift);
    112  void ma_dsrl(Register rd, Register rt, Imm32 shift);
    113  void ma_dsra(Register rd, Register rt, Imm32 shift);
    114  void ma_dror(Register rd, Register rt, Imm32 shift);
    115  void ma_drol(Register rd, Register rt, Imm32 shift);
    116 
    117  void ma_dsll(Register rd, Register rt, Register shift);
    118  void ma_dsrl(Register rd, Register rt, Register shift);
    119  void ma_dsra(Register rd, Register rt, Register shift);
    120  void ma_dror(Register rd, Register rt, Register shift);
    121  void ma_drol(Register rd, Register rt, Register shift);
    122 
    123  void ma_dins(Register rt, Register rs, Imm32 pos, Imm32 size);
    124  void ma_dext(Register rt, Register rs, Imm32 pos, Imm32 size);
    125 
    126  // doubleword swap bytes
    127  void ma_dsbh(Register rd, Register rt);
    128  void ma_dshd(Register rd, Register rt);
    129 
    130  void ma_dctz(Register rd, Register rs);
    131 
    132  // load
    133  FaultingCodeOffset ma_load(Register dest, Address address,
    134                             LoadStoreSize size = SizeWord,
    135                             LoadStoreExtension extension = SignExtend);
    136 
    137  // store
    138  FaultingCodeOffset ma_store(Register data, Address address,
    139                              LoadStoreSize size = SizeWord,
    140                              LoadStoreExtension extension = SignExtend);
    141  void ma_store(ImmWord imm, const BaseIndex& dest,
    142                LoadStoreSize size = SizeWord,
    143                LoadStoreExtension extension = SignExtend);
    144  void ma_store(ImmWord imm, Address address, LoadStoreSize size = SizeWord,
    145                LoadStoreExtension extension = SignExtend);
    146  // arithmetic based ops
    147  // add
    148  void ma_daddu(Register rd, Register rs, Imm32 imm);
    149  void ma_daddu(Register rd, Register rs, ImmWord imm);
    150  void ma_daddu(Register rd, Register rs);
    151  void ma_daddu(Register rd, Imm32 imm);
    152  void ma_add32TestOverflow(Register rd, Register rs, Register rt,
    153                            Label* overflow);
    154  void ma_add32TestOverflow(Register rd, Register rs, Imm32 imm,
    155                            Label* overflow);
    156  void ma_addPtrTestOverflow(Register rd, Register rs, Register rt,
    157                             Label* overflow);
    158  void ma_addPtrTestOverflow(Register rd, Register rs, Imm32 imm,
    159                             Label* overflow);
    160  void ma_addPtrTestOverflow(Register rd, Register rs, ImmWord imm,
    161                             Label* overflow);
    162  void ma_addPtrTestCarry(Condition cond, Register rd, Register rs, Register rt,
    163                          Label* overflow);
    164  void ma_addPtrTestCarry(Condition cond, Register rd, Register rs, Imm32 imm,
    165                          Label* overflow);
    166  void ma_addPtrTestCarry(Condition cond, Register rd, Register rs, ImmWord imm,
    167                          Label* overflow);
    168  void ma_addPtrTestSigned(Condition cond, Register rd, Register rj,
    169                           Register rk, Label* taken);
    170  void ma_addPtrTestSigned(Condition cond, Register rd, Register rj, Imm32 imm,
    171                           Label* taken);
    172  void ma_addPtrTestSigned(Condition cond, Register rd, Register rj,
    173                           ImmWord imm, Label* taken);
    174  // subtract
    175  void ma_dsubu(Register rd, Register rs, Imm32 imm);
    176  void ma_dsubu(Register rd, Register rs, ImmWord imm);
    177  void ma_dsubu(Register rd, Register rs);
    178  void ma_dsubu(Register rd, Imm32 imm);
    179  void ma_sub32TestOverflow(Register rd, Register rs, Register rt,
    180                            Label* overflow);
    181  void ma_subPtrTestOverflow(Register rd, Register rs, Register rt,
    182                             Label* overflow);
    183  void ma_subPtrTestOverflow(Register rd, Register rs, Imm32 imm,
    184                             Label* overflow);
    185 
    186  // multiplies.  For now, there are only few that we care about.
    187  void ma_dmulu(Register rd, Register rs, Register rt);
    188  void ma_dmulu(Register rd, Register rs, ImmWord imm);
    189  void ma_mulPtrTestOverflow(Register rd, Register rs, Register rt,
    190                             Label* overflow);
    191 
    192  // stack
    193  void ma_pop(Register r);
    194  void ma_push(Register r);
    195 
    196  void branchWithCode(InstImm code, Label* label, JumpKind jumpKind,
    197                      Register branchCodeScratch = InvalidReg);
    198  // branches when done from within mips-specific code
    199  void ma_b(Register lhs, ImmWord imm, Label* l, Condition c,
    200            JumpKind jumpKind = LongJump);
    201  void ma_b(Register lhs, Address addr, Label* l, Condition c,
    202            JumpKind jumpKind = LongJump);
    203  void ma_b(Address addr, Imm32 imm, Label* l, Condition c,
    204            JumpKind jumpKind = LongJump);
    205  void ma_b(Address addr, ImmGCPtr imm, Label* l, Condition c,
    206            JumpKind jumpKind = LongJump);
    207  void ma_b(Address addr, Register rhs, Label* l, Condition c,
    208            JumpKind jumpKind = LongJump) {
    209    UseScratchRegisterScope temps(*this);
    210    Register scratch = temps.Acquire();
    211    MOZ_ASSERT(rhs != scratch);
    212    ma_load(scratch, addr, SizeDouble);
    213    ma_b(scratch, rhs, l, c, jumpKind);
    214  }
    215 
    216  void ma_bal(Label* l, DelaySlotFill delaySlotFill = FillDelaySlot);
    217 
    218  // fp instructions
    219  void ma_lid(FloatRegister dest, double value);
    220 
    221  void ma_mv(FloatRegister src, ValueOperand dest);
    222  void ma_mv(ValueOperand src, FloatRegister dest);
    223 
    224  FaultingCodeOffset ma_ls(FloatRegister ft, Address address);
    225  FaultingCodeOffset ma_ld(FloatRegister ft, Address address);
    226  FaultingCodeOffset ma_sd(FloatRegister ft, Address address);
    227  FaultingCodeOffset ma_ss(FloatRegister ft, Address address);
    228 
    229  void ma_pop(FloatRegister f);
    230  void ma_push(FloatRegister f);
    231 
    232  void ma_cmp_set(Register dst, Register lhs, ImmWord imm, Condition c);
    233  void ma_cmp_set(Register dst, Register lhs, ImmPtr imm, Condition c);
    234  void ma_cmp_set(Register dst, Register lhs, ImmGCPtr imm, Condition c);
    235  void ma_cmp_set(Register dst, Address address, Register rhs, Condition c);
    236  void ma_cmp_set(Register dst, Address address, ImmWord imm, Condition c);
    237  void ma_cmp_set(Register dst, Address address, Imm32 imm, Condition c);
    238 
    239  // These functions abstract the access to high part of the double precision
    240  // float register. They are intended to work on both 32 bit and 64 bit
    241  // floating point coprocessor.
    242  void moveToDoubleHi(Register src, FloatRegister dest) { as_mthc1(src, dest); }
    243  void moveFromDoubleHi(FloatRegister src, Register dest) {
    244    as_mfhc1(dest, src);
    245  }
    246 
    247  void moveToDouble(Register src, FloatRegister dest) { as_dmtc1(src, dest); }
    248  void moveFromDouble(FloatRegister src, Register dest) { as_dmfc1(dest, src); }
    249 };
    250 
    251 class MacroAssembler;
    252 
    253 class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 {
    254 public:
    255  using MacroAssemblerMIPS64::call;
    256 
    257  MacroAssemblerMIPS64Compat() {}
    258 
    259  void convertBoolToInt32(Register source, Register dest);
    260  void convertInt32ToDouble(Register src, FloatRegister dest);
    261  void convertInt32ToDouble(const Address& src, FloatRegister dest);
    262  void convertInt32ToDouble(const BaseIndex& src, FloatRegister dest);
    263  void convertUInt32ToDouble(Register src, FloatRegister dest);
    264  void convertUInt32ToFloat32(Register src, FloatRegister dest);
    265  void convertDoubleToFloat32(FloatRegister src, FloatRegister dest);
    266  void convertDoubleToInt32(FloatRegister src, Register dest, Label* fail,
    267                            bool negativeZeroCheck = true);
    268  void convertDoubleToPtr(FloatRegister src, Register dest, Label* fail,
    269                          bool negativeZeroCheck = true);
    270  void convertFloat32ToInt32(FloatRegister src, Register dest, Label* fail,
    271                             bool negativeZeroCheck = true);
    272 
    273  void convertFloat32ToDouble(FloatRegister src, FloatRegister dest);
    274  void convertInt32ToFloat32(Register src, FloatRegister dest);
    275  void convertInt32ToFloat32(const Address& src, FloatRegister dest);
    276 
    277  void convertDoubleToFloat16(FloatRegister src, FloatRegister dest) {
    278    MOZ_CRASH("Not supported for this target");
    279  }
    280  void convertFloat16ToDouble(FloatRegister src, FloatRegister dest) {
    281    MOZ_CRASH("Not supported for this target");
    282  }
    283  void convertFloat32ToFloat16(FloatRegister src, FloatRegister dest) {
    284    MOZ_CRASH("Not supported for this target");
    285  }
    286  void convertFloat16ToFloat32(FloatRegister src, FloatRegister dest) {
    287    MOZ_CRASH("Not supported for this target");
    288  }
    289  void convertInt32ToFloat16(Register src, FloatRegister dest) {
    290    MOZ_CRASH("Not supported for this target");
    291  }
    292 
    293  void computeScaledAddress(const BaseIndex& address, Register dest);
    294  void computeScaledAddress32(const BaseIndex& address, Register dest);
    295 
    296  void computeEffectiveAddress(const Address& address, Register dest) {
    297    ma_daddu(dest, address.base, Imm32(address.offset));
    298  }
    299 
    300  void computeEffectiveAddress(const BaseIndex& address, Register dest);
    301 
    302  void computeEffectiveAddress32(const Address& address, Register dest) {
    303    ma_addu(dest, address.base, Imm32(address.offset));
    304  }
    305 
    306  void computeEffectiveAddress32(const BaseIndex& address, Register dest) {
    307    computeScaledAddress32(address, dest);
    308    if (address.offset) {
    309      ma_addu(dest, dest, Imm32(address.offset));
    310    }
    311  }
    312 
    313  void j(Label* dest) { ma_b(dest); }
    314 
    315  void mov(Register src, Register dest) { as_ori(dest, src, 0); }
    316  void mov(ImmWord imm, Register dest) { ma_li(dest, imm); }
    317  void mov(ImmPtr imm, Register dest) {
    318    mov(ImmWord(uintptr_t(imm.value)), dest);
    319  }
    320  void mov(CodeLabel* label, Register dest) { ma_li(dest, label); }
    321  void mov(Register src, Address dest) { MOZ_CRASH("NYI-IC"); }
    322  void mov(Address src, Register dest) { MOZ_CRASH("NYI-IC"); }
    323 
    324  void writeDataRelocation(const Value& val) {
    325    MOZ_ASSERT(val.isGCThing(), "only called for gc-things");
    326 
    327    // Raw GC pointer relocations and Value relocations both end up in
    328    // TraceOneDataRelocation.
    329    gc::Cell* cell = val.toGCThing();
    330    if (cell && gc::IsInsideNursery(cell)) {
    331      embedsNurseryPointers_ = true;
    332    }
    333    dataRelocations_.writeUnsigned(currentOffset());
    334  }
    335 
    336  void branch(JitCode* c) {
    337    UseScratchRegisterScope temps(*this);
    338    BufferOffset bo = m_buffer.nextOffset();
    339    addPendingJump(bo, ImmPtr(c->raw()), RelocationKind::JITCODE);
    340    Register scratch = temps.Acquire();
    341    ma_liPatchable(scratch, ImmPtr(c->raw()));
    342    as_jr(scratch);
    343    as_nop();
    344  }
    345  void branch(const Register reg) {
    346    as_jr(reg);
    347    as_nop();
    348  }
    349  void nop() { as_nop(); }
    350  BufferOffset ret() {
    351    ma_pop(ra);
    352    BufferOffset offset = as_jr(ra);
    353    as_nop();
    354    return offset;
    355  }
    356  inline void retn(Imm32 n);
    357  void push(Imm32 imm) {
    358    UseScratchRegisterScope temps(*this);
    359    Register scratch = temps.Acquire();
    360    ma_li(scratch, imm);
    361    ma_push(scratch);
    362  }
    363  void push(ImmWord imm) {
    364    UseScratchRegisterScope temps(*this);
    365    Register scratch = temps.Acquire();
    366    ma_li(scratch, imm);
    367    ma_push(scratch);
    368  }
    369  void push(ImmGCPtr imm) {
    370    UseScratchRegisterScope temps(*this);
    371    Register scratch = temps.Acquire();
    372    ma_li(scratch, imm);
    373    ma_push(scratch);
    374  }
    375  void push(const Address& address) {
    376    UseScratchRegisterScope temps(*this);
    377    Register scratch = temps.Acquire();
    378    loadPtr(address, scratch);
    379    ma_push(scratch);
    380  }
    381  void push(Register reg) { ma_push(reg); }
    382  void push(FloatRegister reg) { ma_push(reg); }
    383  void pop(Register reg) { ma_pop(reg); }
    384  void pop(FloatRegister reg) { ma_pop(reg); }
    385 
    386  // Emit a branch that can be toggled to a non-operation. On MIPS64 we use
    387  // "andi" instruction to toggle the branch.
    388  // See ToggleToJmp(), ToggleToCmp().
    389  CodeOffset toggledJump(Label* label);
    390 
    391  // Emit a "jalr" or "nop" instruction. ToggleCall can be used to patch
    392  // this instruction.
    393  CodeOffset toggledCall(JitCode* target, bool enabled);
    394 
    395  static size_t ToggledCallSize(uint8_t* code) {
    396    // Six instructions used in: MacroAssemblerMIPS64Compat::toggledCall
    397    return 6 * sizeof(uint32_t);
    398  }
    399 
    400  CodeOffset pushWithPatch(ImmWord imm) {
    401    UseScratchRegisterScope temps(*this);
    402    Register scratch = temps.Acquire();
    403    CodeOffset offset = movWithPatch(imm, scratch);
    404    ma_push(scratch);
    405    return offset;
    406  }
    407 
    408  CodeOffset movWithPatch(ImmWord imm, Register dest) {
    409    CodeOffset offset = CodeOffset(currentOffset());
    410    ma_liPatchable(dest, imm, Li64);
    411    return offset;
    412  }
    413  CodeOffset movWithPatch(ImmPtr imm, Register dest) {
    414    CodeOffset offset = CodeOffset(currentOffset());
    415    ma_liPatchable(dest, imm);
    416    return offset;
    417  }
    418 
    419  void writeCodePointer(CodeLabel* label) {
    420    label->patchAt()->bind(currentOffset());
    421    label->setLinkMode(CodeLabel::RawPointer);
    422    m_buffer.ensureSpace(sizeof(void*));
    423    writeInst(-1);
    424    writeInst(-1);
    425  }
    426 
    427  void jump(Label* label) { ma_b(label); }
    428  void jump(Register reg) {
    429    as_jr(reg);
    430    as_nop();
    431  }
    432  void jump(const Address& address) {
    433    UseScratchRegisterScope temps(*this);
    434    Register scratch = temps.Acquire();
    435    loadPtr(address, scratch);
    436    as_jr(scratch);
    437    as_nop();
    438  }
    439 
    440  void jump(JitCode* code) { branch(code); }
    441 
    442  void jump(ImmPtr ptr) {
    443    BufferOffset bo = m_buffer.nextOffset();
    444    addPendingJump(bo, ptr, RelocationKind::HARDCODED);
    445    ma_jump(ptr);
    446  }
    447 
    448  void jump(TrampolinePtr code) { jump(ImmPtr(code.value)); }
    449 
    450  void splitTag(Register src, Register dest) {
    451    ma_dsrl(dest, src, Imm32(JSVAL_TAG_SHIFT));
    452  }
    453 
    454  void splitTag(const ValueOperand& operand, Register dest) {
    455    splitTag(operand.valueReg(), dest);
    456  }
    457 
    458  void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag) {
    459    splitTag(value, tag);
    460  }
    461 
    462  // unboxing code
    463  void unboxNonDouble(const ValueOperand& operand, Register dest,
    464                      JSValueType type) {
    465    unboxNonDouble(operand.valueReg(), dest, type);
    466  }
    467 
    468  template <typename T>
    469  void unboxNonDouble(T src, Register dest, JSValueType type) {
    470    MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
    471    if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
    472      load32(src, dest);
    473      return;
    474    }
    475    loadPtr(src, dest);
    476    unboxNonDouble(dest, dest, type);
    477  }
    478 
    479  void unboxNonDouble(Register src, Register dest, JSValueType type) {
    480    UseScratchRegisterScope temps(*this);
    481    MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
    482    if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
    483      ma_sll(dest, src, Imm32(0));
    484      return;
    485    }
    486    Register scratch = temps.Acquire();
    487    MOZ_ASSERT(scratch != src);
    488    mov(ImmShiftedTag(type), scratch);
    489    as_xor(dest, src, scratch);
    490  }
    491 
    492  void unboxGCThingForGCBarrier(const Address& src, Register dest) {
    493    loadPtr(src, dest);
    494    ma_dext(dest, dest, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
    495  }
    496  void unboxGCThingForGCBarrier(const ValueOperand& src, Register dest) {
    497    ma_dext(dest, src.valueReg(), Imm32(0), Imm32(JSVAL_TAG_SHIFT));
    498  }
    499 
    500  void unboxWasmAnyRefGCThingForGCBarrier(const Address& src, Register dest) {
    501    UseScratchRegisterScope temps(*this);
    502    Register scratch = temps.Acquire();
    503    MOZ_ASSERT(scratch != dest);
    504    movePtr(ImmWord(wasm::AnyRef::GCThingMask), scratch);
    505    loadPtr(src, dest);
    506    as_and(dest, dest, scratch);
    507  }
    508 
    509  // Like unboxGCThingForGCBarrier, but loads the GC thing's chunk base.
    510  void getGCThingValueChunk(const Address& src, Register dest) {
    511    UseScratchRegisterScope temps(*this);
    512    Register scratch = temps.Acquire();
    513    MOZ_ASSERT(scratch != dest);
    514    loadPtr(src, dest);
    515    movePtr(ImmWord(JS::detail::ValueGCThingPayloadChunkMask), scratch);
    516    as_and(dest, dest, scratch);
    517  }
    518  void getGCThingValueChunk(const ValueOperand& src, Register dest) {
    519    MOZ_ASSERT(src.valueReg() != dest);
    520    movePtr(ImmWord(JS::detail::ValueGCThingPayloadChunkMask), dest);
    521    as_and(dest, dest, src.valueReg());
    522  }
    523 
    524  void getWasmAnyRefGCThingChunk(Register src, Register dest) {
    525    MOZ_ASSERT(src != dest);
    526    movePtr(ImmWord(wasm::AnyRef::GCThingChunkMask), dest);
    527    as_and(dest, dest, src);
    528  }
    529 
    530  void unboxInt32(const ValueOperand& operand, Register dest);
    531  void unboxInt32(Register src, Register dest);
    532  void unboxInt32(const Address& src, Register dest);
    533  void unboxInt32(const BaseIndex& src, Register dest);
    534  void unboxBoolean(const ValueOperand& operand, Register dest);
    535  void unboxBoolean(Register src, Register dest);
    536  void unboxBoolean(const Address& src, Register dest);
    537  void unboxBoolean(const BaseIndex& src, Register dest);
    538  void unboxDouble(const ValueOperand& operand, FloatRegister dest);
    539  void unboxDouble(Register src, Register dest);
    540  void unboxDouble(const Address& src, FloatRegister dest);
    541  void unboxDouble(const BaseIndex& src, FloatRegister dest);
    542  void unboxString(const ValueOperand& operand, Register dest);
    543  void unboxString(Register src, Register dest);
    544  void unboxString(const Address& src, Register dest);
    545  void unboxSymbol(const ValueOperand& src, Register dest);
    546  void unboxSymbol(Register src, Register dest);
    547  void unboxSymbol(const Address& src, Register dest);
    548  void unboxBigInt(const ValueOperand& operand, Register dest);
    549  void unboxBigInt(Register src, Register dest);
    550  void unboxBigInt(const Address& src, Register dest);
    551  void unboxObject(const ValueOperand& src, Register dest);
    552  void unboxObject(Register src, Register dest);
    553  void unboxObject(const Address& src, Register dest);
    554  void unboxObject(const BaseIndex& src, Register dest) {
    555    unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
    556  }
    557  void unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType type);
    558 
    559  void notBoolean(const ValueOperand& val) {
    560    as_xori(val.valueReg(), val.valueReg(), 1);
    561  }
    562 
    563  // boxing code
    564  void boxDouble(FloatRegister src, const ValueOperand& dest, FloatRegister);
    565  void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) {
    566    boxValue(type, src, dest.valueReg());
    567  }
    568  void boxNonDouble(Register type, Register src, const ValueOperand& dest) {
    569    boxValue(type, src, dest.valueReg());
    570  }
    571 
    572  // Extended unboxing API. If the payload is already in a register, returns
    573  // that register. Otherwise, provides a move to the given scratch register,
    574  // and returns that.
    575  [[nodiscard]] Register extractObject(const Address& address,
    576                                       Register scratch);
    577  [[nodiscard]] Register extractObject(const ValueOperand& value,
    578                                       Register scratch) {
    579    unboxObject(value, scratch);
    580    return scratch;
    581  }
    582  [[nodiscard]] Register extractString(const ValueOperand& value,
    583                                       Register scratch) {
    584    unboxString(value, scratch);
    585    return scratch;
    586  }
    587  [[nodiscard]] Register extractSymbol(const ValueOperand& value,
    588                                       Register scratch) {
    589    unboxSymbol(value, scratch);
    590    return scratch;
    591  }
    592  [[nodiscard]] Register extractInt32(const ValueOperand& value,
    593                                      Register scratch) {
    594    unboxInt32(value, scratch);
    595    return scratch;
    596  }
    597  [[nodiscard]] Register extractBoolean(const ValueOperand& value,
    598                                        Register scratch) {
    599    unboxBoolean(value, scratch);
    600    return scratch;
    601  }
    602  [[nodiscard]] Register extractTag(const Address& address, Register scratch);
    603  [[nodiscard]] Register extractTag(const BaseIndex& address, Register scratch);
    604  [[nodiscard]] Register extractTag(const ValueOperand& value,
    605                                    Register scratch) {
    606    splitTag(value, scratch);
    607    return scratch;
    608  }
    609 
    610  void loadInt32OrDouble(const Address& src, FloatRegister dest);
    611  void loadInt32OrDouble(const BaseIndex& addr, FloatRegister dest);
    612  void loadConstantDouble(double dp, FloatRegister dest);
    613  void loadConstantFloat32(float f, FloatRegister dest);
    614 
    615  void testNullSet(Condition cond, const ValueOperand& value, Register dest);
    616 
    617  void testObjectSet(Condition cond, const ValueOperand& value, Register dest);
    618 
    619  void testUndefinedSet(Condition cond, const ValueOperand& value,
    620                        Register dest);
    621 
    622  template <typename T>
    623  void loadUnboxedValue(const T& address, MIRType type, AnyRegister dest) {
    624    if (dest.isFloat()) {
    625      loadInt32OrDouble(address, dest.fpu());
    626    } else {
    627      unboxNonDouble(address, dest.gpr(), ValueTypeFromMIRType(type));
    628    }
    629  }
    630 
    631  void boxValue(JSValueType type, Register src, Register dest);
    632  void boxValue(Register type, Register src, Register dest);
    633 
    634  void storeValue(ValueOperand val, Operand dst);
    635  void storeValue(ValueOperand val, const BaseIndex& dest);
    636  void storeValue(JSValueType type, Register reg, BaseIndex dest);
    637  void storeValue(ValueOperand val, const Address& dest);
    638  void storeValue(JSValueType type, Register reg, Address dest);
    639  void storeValue(const Value& val, Address dest);
    640  void storeValue(const Value& val, BaseIndex dest);
    641  void storeValue(const Address& src, const Address& dest, Register temp) {
    642    loadPtr(src, temp);
    643    storePtr(temp, dest);
    644  }
    645 
    646  void storePrivateValue(Register src, const Address& dest) {
    647    storePtr(src, dest);
    648  }
    649  void storePrivateValue(ImmGCPtr imm, const Address& dest) {
    650    storePtr(imm, dest);
    651  }
    652 
    653  void loadValue(Address src, ValueOperand val);
    654  void loadValue(Operand dest, ValueOperand val) {
    655    loadValue(dest.toAddress(), val);
    656  }
    657  void loadValue(const BaseIndex& addr, ValueOperand val);
    658 
    659  void loadUnalignedValue(const Address& src, ValueOperand dest) {
    660    loadValue(src, dest);
    661  }
    662 
    663  void tagValue(JSValueType type, Register payload, ValueOperand dest);
    664 
    665  void pushValue(ValueOperand val);
    666  void popValue(ValueOperand val);
    667  void pushValue(const Value& val) {
    668    if (val.isGCThing()) {
    669      UseScratchRegisterScope temps(*this);
    670      writeDataRelocation(val);
    671      Register scratch = temps.Acquire();
    672      movWithPatch(ImmWord(val.asRawBits()), scratch);
    673      push(scratch);
    674    } else {
    675      push(ImmWord(val.asRawBits()));
    676    }
    677  }
    678  void pushValue(JSValueType type, Register reg) {
    679    UseScratchRegisterScope temps(*this);
    680    Register scratch = temps.Acquire();
    681    boxValue(type, reg, scratch);
    682    push(scratch);
    683  }
    684  void pushValue(const Address& addr);
    685  void pushValue(const BaseIndex& addr, Register scratch) {
    686    loadValue(addr, ValueOperand(scratch));
    687    pushValue(ValueOperand(scratch));
    688  }
    689 
    690  void handleFailureWithHandlerTail(Label* profilerExitTail, Label* bailoutTail,
    691                                    uint32_t* returnValueCheckOffset);
    692 
    693  /////////////////////////////////////////////////////////////////
    694  // Common interface.
    695  /////////////////////////////////////////////////////////////////
    696 public:
    697  // The following functions are exposed for use in platform-shared code.
    698 
    699  inline void incrementInt32Value(const Address& addr);
    700 
    701  void move32(Imm32 imm, Register dest);
    702  void move32(Register src, Register dest);
    703 
    704  void movePtr(Register src, Register dest);
    705  void movePtr(ImmWord imm, Register dest);
    706  void movePtr(ImmPtr imm, Register dest);
    707  void movePtr(wasm::SymbolicAddress imm, Register dest);
    708  void movePtr(ImmGCPtr imm, Register dest);
    709 
    710  FaultingCodeOffset load8SignExtend(const Address& address, Register dest);
    711  FaultingCodeOffset load8SignExtend(const BaseIndex& src, Register dest);
    712 
    713  FaultingCodeOffset load8ZeroExtend(const Address& address, Register dest);
    714  FaultingCodeOffset load8ZeroExtend(const BaseIndex& src, Register dest);
    715 
    716  FaultingCodeOffset load16SignExtend(const Address& address, Register dest);
    717  FaultingCodeOffset load16SignExtend(const BaseIndex& src, Register dest);
    718 
    719  template <typename S>
    720  void load16UnalignedSignExtend(const S& src, Register dest) {
    721    ma_load_unaligned(dest, src, SizeHalfWord, SignExtend);
    722  }
    723 
    724  FaultingCodeOffset load16ZeroExtend(const Address& address, Register dest);
    725  FaultingCodeOffset load16ZeroExtend(const BaseIndex& src, Register dest);
    726 
    727  template <typename S>
    728  void load16UnalignedZeroExtend(const S& src, Register dest) {
    729    ma_load_unaligned(dest, src, SizeHalfWord, ZeroExtend);
    730  }
    731 
    732  FaultingCodeOffset load32(const Address& address, Register dest);
    733  FaultingCodeOffset load32(const BaseIndex& address, Register dest);
    734  void load32(AbsoluteAddress address, Register dest);
    735  void load32(wasm::SymbolicAddress address, Register dest);
    736 
    737  template <typename S>
    738  void load32Unaligned(const S& src, Register dest) {
    739    ma_load_unaligned(dest, src, SizeWord, SignExtend);
    740  }
    741 
    742  FaultingCodeOffset load64(const Address& address, Register64 dest) {
    743    return loadPtr(address, dest.reg);
    744  }
    745  FaultingCodeOffset load64(const BaseIndex& address, Register64 dest) {
    746    return loadPtr(address, dest.reg);
    747  }
    748 
    749  template <typename S>
    750  void load64Unaligned(const S& src, Register64 dest) {
    751    ma_load_unaligned(dest.reg, src, SizeDouble, ZeroExtend);
    752  }
    753 
    754  FaultingCodeOffset loadPtr(const Address& address, Register dest);
    755  FaultingCodeOffset loadPtr(const BaseIndex& src, Register dest);
    756  void loadPtr(AbsoluteAddress address, Register dest);
    757  void loadPtr(wasm::SymbolicAddress address, Register dest);
    758 
    759  void loadPrivate(const Address& address, Register dest);
    760 
    761  void loadUnalignedDouble(const wasm::MemoryAccessDesc& access,
    762                           const BaseIndex& src, Register temp,
    763                           FloatRegister dest);
    764  void loadUnalignedFloat32(const wasm::MemoryAccessDesc& access,
    765                            const BaseIndex& src, Register temp,
    766                            FloatRegister dest);
    767 
    768  FaultingCodeOffset store8(Register src, const Address& address);
    769  FaultingCodeOffset store8(Register src, const BaseIndex& address);
    770  void store8(Imm32 imm, const Address& address);
    771  void store8(Imm32 imm, const BaseIndex& address);
    772 
    773  FaultingCodeOffset store16(Register src, const Address& address);
    774  FaultingCodeOffset store16(Register src, const BaseIndex& address);
    775  void store16(Imm32 imm, const Address& address);
    776  void store16(Imm32 imm, const BaseIndex& address);
    777 
    778  template <typename T>
    779  void store16Unaligned(Register src, const T& dest) {
    780    ma_store_unaligned(src, dest, SizeHalfWord);
    781  }
    782 
    783  FaultingCodeOffset store32(Register src, const Address& address);
    784  FaultingCodeOffset store32(Register src, const BaseIndex& address);
    785  void store32(Register src, AbsoluteAddress address);
    786  void store32(Imm32 src, const Address& address);
    787  void store32(Imm32 src, const BaseIndex& address);
    788 
    789  template <typename T>
    790  void store32Unaligned(Register src, const T& dest) {
    791    ma_store_unaligned(src, dest, SizeWord);
    792  }
    793 
    794  void store64(Imm64 imm, Address address) {
    795    storePtr(ImmWord(imm.value), address);
    796  }
    797  void store64(Imm64 imm, const BaseIndex& address) {
    798    storePtr(ImmWord(imm.value), address);
    799  }
    800 
    801  FaultingCodeOffset store64(Register64 src, Address address) {
    802    return storePtr(src.reg, address);
    803  }
    804  FaultingCodeOffset store64(Register64 src, const BaseIndex& address) {
    805    return storePtr(src.reg, address);
    806  }
    807 
    808  template <typename T>
    809  void store64Unaligned(Register64 src, const T& dest) {
    810    ma_store_unaligned(src.reg, dest, SizeDouble);
    811  }
    812 
    813  template <typename T>
    814  void storePtr(ImmWord imm, T address);
    815  template <typename T>
    816  void storePtr(ImmPtr imm, T address);
    817  template <typename T>
    818  void storePtr(ImmGCPtr imm, T address);
    819  FaultingCodeOffset storePtr(Register src, const Address& address);
    820  FaultingCodeOffset storePtr(Register src, const BaseIndex& address);
    821  void storePtr(Register src, AbsoluteAddress dest);
    822 
    823  void storeUnalignedFloat32(const wasm::MemoryAccessDesc& access,
    824                             FloatRegister src, Register temp,
    825                             const BaseIndex& dest);
    826  void storeUnalignedDouble(const wasm::MemoryAccessDesc& access,
    827                            FloatRegister src, Register temp,
    828                            const BaseIndex& dest);
    829 
    830  void moveDouble(FloatRegister src, FloatRegister dest) { as_movd(dest, src); }
    831 
    832  void zeroDouble(FloatRegister reg) { moveToDouble(zero, reg); }
    833 
    834  void convertUInt64ToDouble(Register src, FloatRegister dest);
    835 
    836  void breakpoint();
    837 
    838  void checkStackAlignment();
    839 
    840  static void calculateAlignedStackPointer(void** stackPointer);
    841 
    842  void cmpPtrSet(Assembler::Condition cond, Address lhs, ImmPtr rhs,
    843                 Register dest);
    844  void cmpPtrSet(Assembler::Condition cond, Register lhs, Address rhs,
    845                 Register dest);
    846  void cmpPtrSet(Assembler::Condition cond, Address lhs, Register rhs,
    847                 Register dest);
    848 
    849  void cmp32Set(Assembler::Condition cond, Register lhs, Address rhs,
    850                Register dest);
    851 
    852 protected:
    853  bool buildOOLFakeExitFrame(void* fakeReturnAddr);
    854 
    855  void wasmLoadI64Impl(const wasm::MemoryAccessDesc& access,
    856                       Register memoryBase, Register ptr, Register ptrScratch,
    857                       Register64 output, Register tmp);
    858  void wasmStoreI64Impl(const wasm::MemoryAccessDesc& access, Register64 value,
    859                        Register memoryBase, Register ptr, Register ptrScratch,
    860                        Register tmp);
    861 
    862 public:
    863  void lea(Operand addr, Register dest) {
    864    ma_daddu(dest, addr.baseReg(), Imm32(addr.disp()));
    865  }
    866 
    867  void abiret() {
    868    as_jr(ra);
    869    as_nop();
    870  }
    871 
    872  void moveFloat32(FloatRegister src, FloatRegister dest) {
    873    as_movs(dest, src);
    874  }
    875 
    876  // Instrumentation for entering and leaving the profiler.
    877  void profilerEnterFrame(Register framePtr, Register scratch);
    878  void profilerExitFrame();
    879 };
    880 
    881 typedef MacroAssemblerMIPS64Compat MacroAssemblerSpecific;
    882 
    883 }  // namespace jit
    884 }  // namespace js
    885 
    886 #endif /* jit_mips64_MacroAssembler_mips64_h */