Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  MacroAssembler-mips64.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "jit/mips64/MacroAssembler-mips64.h"

#include "mozilla/DebugOnly.h"
#include "mozilla/MathAlgorithms.h"

#include "jit/Bailouts.h"
#include "jit/BaselineFrame.h"
#include "jit/JitFrames.h"
#include "jit/JitRuntime.h"
#include "jit/MacroAssembler.h"
#include "jit/mips64/Simulator-mips64.h"
#include "jit/MoveEmitter.h"
#include "jit/SharedICRegisters.h"
#include "util/Memory.h"
#include "vm/JitActivation.h"  // js::jit::JitActivation
#include "vm/JSContext.h"
#include "wasm/WasmStubs.h"

#include "jit/MacroAssembler-inl.h"

using namespace js;
using namespace jit;

using mozilla::Abs;

static_assert(sizeof(intptr_t) == 8, "Not 32-bit clean.");

void MacroAssemblerMIPS64Compat::convertBoolToInt32(Register src,
                                                    Register dest) {
  // Note that C++ bool is only 1 byte, so zero extend it to clear the
  // higher-order bits.
  ma_and(dest, src, Imm32(0xff));
}

void MacroAssemblerMIPS64Compat::convertInt32ToDouble(Register src,
                                                      FloatRegister dest) {
  as_mtc1(src, dest);
  as_cvtdw(dest, dest);
}

void MacroAssemblerMIPS64Compat::convertInt32ToDouble(const Address& src,
                                                      FloatRegister dest) {
  ma_ls(dest, src);
  as_cvtdw(dest, dest);
}

void MacroAssemblerMIPS64Compat::convertInt32ToDouble(const BaseIndex& src,
                                                      FloatRegister dest) {
  computeScaledAddress(src, ScratchRegister);
  convertInt32ToDouble(Address(ScratchRegister, src.offset), dest);
}

void MacroAssemblerMIPS64Compat::convertUInt32ToDouble(Register src,
                                                       FloatRegister dest) {
  ma_dext(ScratchRegister, src, Imm32(0), Imm32(32));
  asMasm().convertInt64ToDouble(Register64(ScratchRegister), dest);
}

void MacroAssemblerMIPS64Compat::convertUInt64ToDouble(Register src,
                                                       FloatRegister dest) {
  Label positive, done;
  ma_b(src, src, &positive, NotSigned, ShortJump);

  MOZ_ASSERT(src != ScratchRegister);
  MOZ_ASSERT(src != SecondScratchReg);

  ma_and(ScratchRegister, src, Imm32(1));
  ma_dsrl(SecondScratchReg, src, Imm32(1));
  ma_or(ScratchRegister, SecondScratchReg);
  as_dmtc1(ScratchRegister, dest);
  as_cvtdl(dest, dest);
  asMasm().addDouble(dest, dest);
  ma_b(&done, ShortJump);

  bind(&positive);
  as_dmtc1(src, dest);
  as_cvtdl(dest, dest);

  bind(&done);
}

void MacroAssemblerMIPS64Compat::convertUInt32ToFloat32(Register src,
                                                        FloatRegister dest) {
  ma_dext(ScratchRegister, src, Imm32(0), Imm32(32));
  asMasm().convertInt64ToFloat32(Register64(ScratchRegister), dest);
}

void MacroAssemblerMIPS64Compat::convertDoubleToFloat32(FloatRegister src,
                                                        FloatRegister dest) {
  as_cvtsd(dest, src);
}

const int CauseBitPos = int(Assembler::CauseI);
const int CauseBitCount = 1 + int(Assembler::CauseV) - int(Assembler::CauseI);
const int CauseIOrVMask = ((1 << int(Assembler::CauseI)) |
                           (1 << int(Assembler::CauseV))) >>
                          int(Assembler::CauseI);

// Checks whether a double is representable as a 32-bit integer. If so, the
// integer is written to the output register. Otherwise, a bailout is taken to
// the given snapshot. This function overwrites the scratch float register.
void MacroAssemblerMIPS64Compat::convertDoubleToInt32(FloatRegister src,
                                                      Register dest,
                                                      Label* fail,
                                                      bool negativeZeroCheck) {
  if (negativeZeroCheck) {
    moveFromDouble(src, dest);
    ma_drol(dest, dest, Imm32(1));
    ma_b(dest, Imm32(1), fail, Assembler::Equal);
  }

  // Truncate double to int ; if result is inexact or invalid fail.
  as_truncwd(ScratchFloat32Reg, src);
  as_cfc1(ScratchRegister, Assembler::FCSR);
  moveFromFloat32(ScratchFloat32Reg, dest);
  ma_ext(ScratchRegister, ScratchRegister, CauseBitPos, CauseBitCount);
  as_andi(ScratchRegister, ScratchRegister,
          CauseIOrVMask);  // masking for Inexact and Invalid flag.
  ma_b(ScratchRegister, Imm32(0), fail, Assembler::NotEqual);
}

void MacroAssemblerMIPS64Compat::convertDoubleToPtr(FloatRegister src,
                                                    Register dest, Label* fail,
                                                    bool negativeZeroCheck) {
  if (negativeZeroCheck) {
    moveFromDouble(src, dest);
    ma_drol(dest, dest, Imm32(1));
    ma_b(dest, Imm32(1), fail, Assembler::Equal);
  }
  as_truncld(ScratchDoubleReg, src);
  as_cfc1(ScratchRegister, Assembler::FCSR);
  moveFromDouble(ScratchDoubleReg, dest);
  ma_ext(ScratchRegister, ScratchRegister, CauseBitPos, CauseBitCount);
  as_andi(ScratchRegister, ScratchRegister, CauseIOrVMask);
  ma_b(ScratchRegister, Imm32(0), fail, Assembler::NotEqual);
}

// Checks whether a float32 is representable as a 32-bit integer. If so, the
// integer is written to the output register. Otherwise, a bailout is taken to
// the given snapshot. This function overwrites the scratch float register.
void MacroAssemblerMIPS64Compat::convertFloat32ToInt32(FloatRegister src,
                                                       Register dest,
                                                       Label* fail,
                                                       bool negativeZeroCheck) {
  if (negativeZeroCheck) {
    moveFromFloat32(src, dest);
    ma_b(dest, Imm32(INT32_MIN), fail, Assembler::Equal);
  }

  as_truncws(ScratchFloat32Reg, src);
  as_cfc1(ScratchRegister, Assembler::FCSR);
  moveFromFloat32(ScratchFloat32Reg, dest);
  ma_ext(ScratchRegister, ScratchRegister, CauseBitPos, CauseBitCount);
  as_andi(ScratchRegister, ScratchRegister, CauseIOrVMask);
  ma_b(ScratchRegister, Imm32(0), fail, Assembler::NotEqual);
}

void MacroAssemblerMIPS64Compat::convertFloat32ToDouble(FloatRegister src,
                                                        FloatRegister dest) {
  as_cvtds(dest, src);
}

void MacroAssemblerMIPS64Compat::convertInt32ToFloat32(Register src,
                                                       FloatRegister dest) {
  as_mtc1(src, dest);
  as_cvtsw(dest, dest);
}

void MacroAssemblerMIPS64Compat::convertInt32ToFloat32(const Address& src,
                                                       FloatRegister dest) {
  ma_ls(dest, src);
  as_cvtsw(dest, dest);
}

void MacroAssembler::convertIntPtrToDouble(Register src, FloatRegister dest) {
  convertInt64ToDouble(Register64(src), dest);
}

void MacroAssemblerMIPS64Compat::movq(Register rs, Register rd) {
  ma_move(rd, rs);
}

void MacroAssemblerMIPS64::ma_li(Register dest, CodeLabel* label) {
  BufferOffset bo = m_buffer.nextOffset();
  ma_liPatchable(dest, ImmWord(/* placeholder */ 0));
  label->patchAt()->bind(bo.getOffset());
  label->setLinkMode(CodeLabel::MoveImmediate);
}

void MacroAssemblerMIPS64::ma_li(Register dest, ImmWord imm) {
  int64_t value = imm.value;

  if (-1 == (value >> 15) || 0 == (value >> 15)) {
    as_addiu(dest, zero, value);
    return;
  }
  if (0 == (value >> 16)) {
    as_ori(dest, zero, value);
    return;
  }

  if (-1 == (value >> 31) || 0 == (value >> 31)) {
    as_lui(dest, uint16_t(value >> 16));
  } else if (0 == (value >> 32)) {
    as_lui(dest, uint16_t(value >> 16));
    as_dinsu(dest, zero, 32, 32);
  } else if (-1 == (value >> 47) || 0 == (value >> 47)) {
    as_lui(dest, uint16_t(value >> 32));
    if (uint16_t(value >> 16)) {
      as_ori(dest, dest, uint16_t(value >> 16));
    }
    as_dsll(dest, dest, 16);
  } else if (0 == (value >> 48)) {
    as_lui(dest, uint16_t(value >> 32));
    as_dinsu(dest, zero, 32, 32);
    if (uint16_t(value >> 16)) {
      as_ori(dest, dest, uint16_t(value >> 16));
    }
    as_dsll(dest, dest, 16);
  } else {
    as_lui(dest, uint16_t(value >> 48));
    if (uint16_t(value >> 32)) {
      as_ori(dest, dest, uint16_t(value >> 32));
    }
    if (uint16_t(value >> 16)) {
      as_dsll(dest, dest, 16);
      as_ori(dest, dest, uint16_t(value >> 16));
      as_dsll(dest, dest, 16);
    } else {
      as_dsll32(dest, dest, 32);
    }
  }
  if (uint16_t(value)) {
    as_ori(dest, dest, uint16_t(value));
  }
}

// This method generates lui, dsll and ori instruction block that can be
// modified by UpdateLoad64Value, either during compilation (eg.
// Assembler::bind), or during execution (eg. jit::PatchJump).
void MacroAssemblerMIPS64::ma_liPatchable(Register dest, ImmPtr imm) {
  return ma_liPatchable(dest, ImmWord(uintptr_t(imm.value)));
}

void MacroAssemblerMIPS64::ma_liPatchable(Register dest, ImmWord imm,
                                          LiFlags flags) {
  if (Li64 == flags) {
    m_buffer.ensureSpace(6 * sizeof(uint32_t));
    as_lui(dest, Imm16::Upper(Imm32(imm.value >> 32)).encode());
    as_ori(dest, dest, Imm16::Lower(Imm32(imm.value >> 32)).encode());
    as_dsll(dest, dest, 16);
    as_ori(dest, dest, Imm16::Upper(Imm32(imm.value)).encode());
    as_dsll(dest, dest, 16);
    as_ori(dest, dest, Imm16::Lower(Imm32(imm.value)).encode());
  } else {
    m_buffer.ensureSpace(4 * sizeof(uint32_t));
    as_lui(dest, Imm16::Lower(Imm32(imm.value >> 32)).encode());
    as_ori(dest, dest, Imm16::Upper(Imm32(imm.value)).encode());
    as_drotr32(dest, dest, 48);
    as_ori(dest, dest, Imm16::Lower(Imm32(imm.value)).encode());
  }
}

void MacroAssemblerMIPS64::ma_dnegu(Register rd, Register rs) {
  as_dsubu(rd, zero, rs);
}

// Shifts
void MacroAssemblerMIPS64::ma_dsll(Register rd, Register rt, Imm32 shift) {
  if (31 < shift.value) {
    as_dsll32(rd, rt, shift.value);
  } else {
    as_dsll(rd, rt, shift.value);
  }
}

void MacroAssemblerMIPS64::ma_dsrl(Register rd, Register rt, Imm32 shift) {
  if (31 < shift.value) {
    as_dsrl32(rd, rt, shift.value);
  } else {
    as_dsrl(rd, rt, shift.value);
  }
}

void MacroAssemblerMIPS64::ma_dsra(Register rd, Register rt, Imm32 shift) {
  if (31 < shift.value) {
    as_dsra32(rd, rt, shift.value);
  } else {
    as_dsra(rd, rt, shift.value);
  }
}

void MacroAssemblerMIPS64::ma_dror(Register rd, Register rt, Imm32 shift) {
  if (31 < shift.value) {
    as_drotr32(rd, rt, shift.value);
  } else {
    as_drotr(rd, rt, shift.value);
  }
}

void MacroAssemblerMIPS64::ma_drol(Register rd, Register rt, Imm32 shift) {
  uint32_t s = 64 - shift.value;

  if (31 < s) {
    as_drotr32(rd, rt, s);
  } else {
    as_drotr(rd, rt, s);
  }
}

void MacroAssemblerMIPS64::ma_dsll(Register rd, Register rt, Register shift) {
  as_dsllv(rd, rt, shift);
}

void MacroAssemblerMIPS64::ma_dsrl(Register rd, Register rt, Register shift) {
  as_dsrlv(rd, rt, shift);
}

void MacroAssemblerMIPS64::ma_dsra(Register rd, Register rt, Register shift) {
  as_dsrav(rd, rt, shift);
}

void MacroAssemblerMIPS64::ma_dror(Register rd, Register rt, Register shift) {
  as_drotrv(rd, rt, shift);
}

void MacroAssemblerMIPS64::ma_drol(Register rd, Register rt, Register shift) {
  as_dsubu(ScratchRegister, zero, shift);
  as_drotrv(rd, rt, ScratchRegister);
}

void MacroAssemblerMIPS64::ma_dins(Register rt, Register rs, Imm32 pos,
                                   Imm32 size) {
  if (pos.value >= 0 && pos.value < 32) {
    if (pos.value + size.value > 32) {
      as_dinsm(rt, rs, pos.value, size.value);
    } else {
      as_dins(rt, rs, pos.value, size.value);
    }
  } else {
    as_dinsu(rt, rs, pos.value, size.value);
  }
}

void MacroAssemblerMIPS64::ma_dext(Register rt, Register rs, Imm32 pos,
                                   Imm32 size) {
  if (pos.value >= 0 && pos.value < 32) {
    if (size.value > 32) {
      as_dextm(rt, rs, pos.value, size.value);
    } else {
      as_dext(rt, rs, pos.value, size.value);
    }
  } else {
    as_dextu(rt, rs, pos.value, size.value);
  }
}

void MacroAssemblerMIPS64::ma_dsbh(Register rd, Register rt) {
  as_dsbh(rd, rt);
}

void MacroAssemblerMIPS64::ma_dshd(Register rd, Register rt) {
  as_dshd(rd, rt);
}

void MacroAssemblerMIPS64::ma_dctz(Register rd, Register rs) {
  ma_dnegu(ScratchRegister, rs);
  as_and(rd, ScratchRegister, rs);
  as_dclz(rd, rd);
  ma_dnegu(SecondScratchReg, rd);
  ma_daddu(SecondScratchReg, Imm32(0x3f));
#ifdef MIPS64
  as_selnez(SecondScratchReg, SecondScratchReg, ScratchRegister);
  as_seleqz(rd, rd, ScratchRegister);
  as_or(rd, rd, SecondScratchReg);
#else
  as_movn(rd, SecondScratchReg, ScratchRegister);
#endif
}

// Arithmetic-based ops.

// Add.
void MacroAssemblerMIPS64::ma_daddu(Register rd, Register rs, Imm32 imm) {
  if (Imm16::IsInSignedRange(imm.value)) {
    as_daddiu(rd, rs, imm.value);
  } else {
    ma_li(ScratchRegister, imm);
    as_daddu(rd, rs, ScratchRegister);
  }
}

void MacroAssemblerMIPS64::ma_daddu(Register rd, Register rs) {
  as_daddu(rd, rd, rs);
}

void MacroAssemblerMIPS64::ma_daddu(Register rd, Imm32 imm) {
  ma_daddu(rd, rd, imm);
}

void MacroAssemblerMIPS64::ma_add32TestOverflow(Register rd, Register rs,
                                                Register rt, Label* overflow) {
  as_daddu(SecondScratchReg, rs, rt);
  as_addu(rd, rs, rt);
  ma_b(rd, SecondScratchReg, overflow, Assembler::NotEqual);
}

void MacroAssemblerMIPS64::ma_add32TestOverflow(Register rd, Register rs,
                                                Imm32 imm, Label* overflow) {
  // Check for signed range because of as_daddiu
  if (Imm16::IsInSignedRange(imm.value)) {
    as_daddiu(SecondScratchReg, rs, imm.value);
    as_addiu(rd, rs, imm.value);
    ma_b(rd, SecondScratchReg, overflow, Assembler::NotEqual);
  } else {
    ma_li(ScratchRegister, imm);
    ma_add32TestOverflow(rd, rs, ScratchRegister, overflow);
  }
}

void MacroAssemblerMIPS64::ma_addPtrTestOverflow(Register rd, Register rs,
                                                 Register rt, Label* overflow) {
  SecondScratchRegisterScope scratch2(asMasm());
  MOZ_ASSERT(rd != rt);
  MOZ_ASSERT(rd != scratch2);

  if (rs == rt) {
    as_daddu(rd, rs, rs);
    as_xor(scratch2, rs, rd);
  } else {
    ScratchRegisterScope scratch(asMasm());
    MOZ_ASSERT(rs != scratch2);
    MOZ_ASSERT(rt != scratch2);

    // If the sign of rs and rt are different, no overflow
    as_xor(scratch2, rs, rt);
    as_nor(scratch2, scratch2, zero);

    as_daddu(rd, rs, rt);
    as_xor(scratch, rd, rt);
    as_and(scratch, scratch, scratch2);
  }

  ma_b(scratch2, zero, overflow, Assembler::LessThan);
}

void MacroAssemblerMIPS64::ma_addPtrTestOverflow(Register rd, Register rs,
                                                 Imm32 imm, Label* overflow) {
  ma_li(ScratchRegister, imm);
  ma_addPtrTestOverflow(rd, rs, ScratchRegister, overflow);
}

void MacroAssemblerMIPS64::ma_addPtrTestOverflow(Register rd, Register rs,
                                                 ImmWord imm, Label* overflow) {
  ScratchRegisterScope scratch(asMasm());
  ma_li(scratch, imm);
  ma_addPtrTestOverflow(rd, rs, scratch, overflow);
}

void MacroAssemblerMIPS64::ma_addPtrTestCarry(Condition cond, Register rd,
                                              Register rs, Register rt,
                                              Label* overflow) {
  SecondScratchRegisterScope scratch2(asMasm());
  as_daddu(rd, rs, rt);
  as_sltu(scratch2, rd, rt);
  ma_b(scratch2, scratch2, overflow,
       cond == Assembler::CarrySet ? Assembler::NonZero : Assembler::Zero);
}

void MacroAssemblerMIPS64::ma_addPtrTestCarry(Condition cond, Register rd,
                                              Register rs, Imm32 imm,
                                              Label* overflow) {
  // Check for signed range because of as_daddiu
  if (Imm16::IsInSignedRange(imm.value)) {
    SecondScratchRegisterScope scratch2(asMasm());
    as_daddiu(rd, rs, imm.value);
    as_sltiu(scratch2, rd, imm.value);
    ma_b(scratch2, scratch2, overflow,
         cond == Assembler::CarrySet ? Assembler::NonZero : Assembler::Zero);
  } else {
    ma_li(ScratchRegister, imm);
    ma_addPtrTestCarry(cond, rd, rs, ScratchRegister, overflow);
  }
}

void MacroAssemblerMIPS64::ma_addPtrTestCarry(Condition cond, Register rd,
                                              Register rs, ImmWord imm,
                                              Label* overflow) {
  // Check for signed range because of as_daddiu
  if (Imm16::IsInSignedRange(imm.value)) {
    SecondScratchRegisterScope scratch2(asMasm());
    as_daddiu(rd, rs, imm.value);
    as_sltiu(scratch2, rd, imm.value);
    ma_b(scratch2, scratch2, overflow,
         cond == Assembler::CarrySet ? Assembler::NonZero : Assembler::Zero);
  } else {
    ScratchRegisterScope scratch(asMasm());
    ma_li(scratch, imm);
    ma_addPtrTestCarry(cond, rd, rs, scratch, overflow);
  }
}

// Subtract.
void MacroAssemblerMIPS64::ma_dsubu(Register rd, Register rs, Imm32 imm) {
  if (Imm16::IsInSignedRange(-imm.value)) {
    as_daddiu(rd, rs, -imm.value);
  } else {
    ma_li(ScratchRegister, imm);
    as_dsubu(rd, rs, ScratchRegister);
  }
}

void MacroAssemblerMIPS64::ma_dsubu(Register rd, Register rs) {
  as_dsubu(rd, rd, rs);
}

void MacroAssemblerMIPS64::ma_dsubu(Register rd, Imm32 imm) {
  ma_dsubu(rd, rd, imm);
}

void MacroAssemblerMIPS64::ma_sub32TestOverflow(Register rd, Register rs,
                                                Register rt, Label* overflow) {
  as_dsubu(SecondScratchReg, rs, rt);
  as_subu(rd, rs, rt);
  ma_b(rd, SecondScratchReg, overflow, Assembler::NotEqual);
}

void MacroAssemblerMIPS64::ma_subPtrTestOverflow(Register rd, Register rs,
                                                 Register rt, Label* overflow) {
  SecondScratchRegisterScope scratch2(asMasm());
  MOZ_ASSERT_IF(rs == rd, rs != rt);
  MOZ_ASSERT(rd != rt);
  MOZ_ASSERT(rs != scratch2);
  MOZ_ASSERT(rt != scratch2);
  MOZ_ASSERT(rd != scratch2);

  Register rs_copy = rs;

  if (rs == rd) {
    ma_move(scratch2, rs);
    rs_copy = scratch2;
  }

  {
    ScratchRegisterScope scratch(asMasm());
    MOZ_ASSERT(rd != scratch);

    as_dsubu(rd, rs, rt);
    // If the sign of rs and rt are the same, no overflow
    as_xor(scratch, rs_copy, rt);
    // Check if the sign of rd and rs are the same
    as_xor(scratch2, rd, rs_copy);
    as_and(scratch2, scratch2, scratch);
  }

  ma_b(scratch2, zero, overflow, Assembler::LessThan);
}

void MacroAssemblerMIPS64::ma_subPtrTestOverflow(Register rd, Register rs,
                                                 Imm32 imm, Label* overflow) {
  ma_li(ScratchRegister, imm);
  ma_subPtrTestOverflow(rd, rs, ScratchRegister, overflow);
}

void MacroAssemblerMIPS64::ma_dmult(Register rs, Imm32 imm) {
  ma_li(ScratchRegister, imm);
#ifdef MIPSR6
  as_dmul(rs, ScratchRegister, SecondScratchReg);
  as_dmuh(rs, ScratchRegister, rs);
  ma_move(rs, SecondScratchReg);
#else
  as_dmult(rs, ScratchRegister);
#endif
}

void MacroAssemblerMIPS64::ma_mulPtrTestOverflow(Register rd, Register rs,
                                                 Register rt, Label* overflow) {
#ifdef MIPSR6
  if (rd == rs) {
    ma_move(SecondScratchReg, rs);
    rs = SecondScratchReg;
  }
  as_dmul(rd, rs, rt);
  as_dmuh(SecondScratchReg, rs, rt);
#else
  as_dmult(rs, rt);
  as_mflo(rd);
  as_mfhi(SecondScratchReg);
#endif
  as_dsra32(ScratchRegister, rd, 63);
  ma_b(ScratchRegister, SecondScratchReg, overflow, Assembler::NotEqual);
}

// Memory.
FaultingCodeOffset MacroAssemblerMIPS64::ma_load(Register dest, Address address,
                                                 LoadStoreSize size,
                                                 LoadStoreExtension extension) {
  int16_t encodedOffset;
  Register base;
  FaultingCodeOffset fco;

  if (isLoongson() && ZeroExtend != extension &&
      !Imm16::IsInSignedRange(address.offset)) {
    ma_li(ScratchRegister, Imm32(address.offset));
    base = address.base;

    fco = FaultingCodeOffset(currentOffset());
    switch (size) {
      case SizeByte:
        as_gslbx(dest, base, ScratchRegister, 0);
        break;
      case SizeHalfWord:
        as_gslhx(dest, base, ScratchRegister, 0);
        break;
      case SizeWord:
        as_gslwx(dest, base, ScratchRegister, 0);
        break;
      case SizeDouble:
        as_gsldx(dest, base, ScratchRegister, 0);
        break;
      default:
        MOZ_CRASH("Invalid argument for ma_load");
    }
    return fco;
  }

  if (!Imm16::IsInSignedRange(address.offset)) {
    ma_li(ScratchRegister, Imm32(address.offset));
    as_daddu(ScratchRegister, address.base, ScratchRegister);
    base = ScratchRegister;
    encodedOffset = Imm16(0).encode();
  } else {
    encodedOffset = Imm16(address.offset).encode();
    base = address.base;
  }

  fco = FaultingCodeOffset(currentOffset());
  switch (size) {
    case SizeByte:
      if (ZeroExtend == extension) {
        as_lbu(dest, base, encodedOffset);
      } else {
        as_lb(dest, base, encodedOffset);
      }
      break;
    case SizeHalfWord:
      if (ZeroExtend == extension) {
        as_lhu(dest, base, encodedOffset);
      } else {
        as_lh(dest, base, encodedOffset);
      }
      break;
    case SizeWord:
      if (ZeroExtend == extension) {
        as_lwu(dest, base, encodedOffset);
      } else {
        as_lw(dest, base, encodedOffset);
      }
      break;
    case SizeDouble:
      as_ld(dest, base, encodedOffset);
      break;
    default:
      MOZ_CRASH("Invalid argument for ma_load");
  }
  return fco;
}

FaultingCodeOffset MacroAssemblerMIPS64::ma_store(
    Register data, Address address, LoadStoreSize size,
    LoadStoreExtension extension) {
  int16_t encodedOffset;
  Register base;
  FaultingCodeOffset fco;

  if (isLoongson() && !Imm16::IsInSignedRange(address.offset)) {
    ma_li(ScratchRegister, Imm32(address.offset));
    base = address.base;

    fco = FaultingCodeOffset(currentOffset());
    switch (size) {
      case SizeByte:
        as_gssbx(data, base, ScratchRegister, 0);
        break;
      case SizeHalfWord:
        as_gsshx(data, base, ScratchRegister, 0);
        break;
      case SizeWord:
        as_gsswx(data, base, ScratchRegister, 0);
        break;
      case SizeDouble:
        as_gssdx(data, base, ScratchRegister, 0);
        break;
      default:
        MOZ_CRASH("Invalid argument for ma_store");
    }
    return fco;
  }

  if (!Imm16::IsInSignedRange(address.offset)) {
    ma_li(ScratchRegister, Imm32(address.offset));
    as_daddu(ScratchRegister, address.base, ScratchRegister);
    base = ScratchRegister;
    encodedOffset = Imm16(0).encode();
  } else {
    encodedOffset = Imm16(address.offset).encode();
    base = address.base;
  }

  fco = FaultingCodeOffset(currentOffset());
  switch (size) {
    case SizeByte:
      as_sb(data, base, encodedOffset);
      break;
    case SizeHalfWord:
      as_sh(data, base, encodedOffset);
      break;
    case SizeWord:
      as_sw(data, base, encodedOffset);
      break;
    case SizeDouble:
      as_sd(data, base, encodedOffset);
      break;
    default:
      MOZ_CRASH("Invalid argument for ma_store");
  }
  return fco;
}

void MacroAssemblerMIPS64Compat::computeScaledAddress(const BaseIndex& address,
                                                      Register dest) {
  int32_t shift = Imm32::ShiftOf(address.scale).value;
  if (shift) {
    ma_dsll(ScratchRegister, address.index, Imm32(shift));
    as_daddu(dest, address.base, ScratchRegister);
  } else {
    as_daddu(dest, address.base, address.index);
  }
}

void MacroAssemblerMIPS64Compat::computeEffectiveAddress(
    const BaseIndex& address, Register dest) {
  computeScaledAddress(address, dest);
  if (address.offset) {
    asMasm().addPtr(Imm32(address.offset), dest);
  }
}

// Shortcut for when we know we're transferring 32 bits of data.
void MacroAssemblerMIPS64::ma_pop(Register r) {
  as_ld(r, StackPointer, 0);
  as_daddiu(StackPointer, StackPointer, sizeof(intptr_t));
}

void MacroAssemblerMIPS64::ma_push(Register r) {
  if (r == sp) {
    // Pushing sp requires one more instruction.
    ma_move(ScratchRegister, sp);
    r = ScratchRegister;
  }

  as_daddiu(StackPointer, StackPointer, (int32_t)-sizeof(intptr_t));
  as_sd(r, StackPointer, 0);
}

// Branches when done from within mips-specific code.
void MacroAssemblerMIPS64::ma_b(Register lhs, ImmWord imm, Label* label,
                                Condition c, JumpKind jumpKind) {
  if (imm.value <= INT32_MAX) {
    ma_b(lhs, Imm32(uint32_t(imm.value)), label, c, jumpKind);
  } else {
    MOZ_ASSERT(lhs != ScratchRegister);
    ma_li(ScratchRegister, imm);
    ma_b(lhs, ScratchRegister, label, c, jumpKind);
  }
}

void MacroAssemblerMIPS64::ma_b(Register lhs, Address addr, Label* label,
                                Condition c, JumpKind jumpKind) {
  MOZ_ASSERT(lhs != ScratchRegister);
  ma_load(ScratchRegister, addr, SizeDouble);
  ma_b(lhs, ScratchRegister, label, c, jumpKind);
}

void MacroAssemblerMIPS64::ma_b(Address addr, Imm32 imm, Label* label,
                                Condition c, JumpKind jumpKind) {
  ma_load(SecondScratchReg, addr, SizeDouble);
  ma_b(SecondScratchReg, imm, label, c, jumpKind);
}

void MacroAssemblerMIPS64::ma_b(Address addr, ImmGCPtr imm, Label* label,
                                Condition c, JumpKind jumpKind) {
  ma_load(SecondScratchReg, addr, SizeDouble);
  ma_b(SecondScratchReg, imm, label, c, jumpKind);
}

void MacroAssemblerMIPS64::ma_bal(Label* label, DelaySlotFill delaySlotFill) {
  spew("branch .Llabel %p\n", label);
  if (label->bound()) {
    // Generate the long jump for calls because return address has to be
    // the address after the reserved block.
    addLongJump(nextOffset(), BufferOffset(label->offset()));
    ma_liPatchable(ScratchRegister, ImmWord(LabelBase::INVALID_OFFSET));
    as_jalr(ScratchRegister);
    if (delaySlotFill == FillDelaySlot) {
      as_nop();
    }
    return;
  }

  // Second word holds a pointer to the next branch in label's chain.
  uint32_t nextInChain =
      label->used() ? label->offset() : LabelBase::INVALID_OFFSET;

  // Make the whole branch continous in the buffer. The '6'
  // instructions are writing at below (contain delay slot).
  m_buffer.ensureSpace(6 * sizeof(uint32_t));

  spew("bal .Llabel %p\n", label);
  BufferOffset bo = writeInst(getBranchCode(BranchIsCall).encode());
  writeInst(nextInChain);
  if (!oom()) {
    label->use(bo.getOffset());
  }
  // Leave space for long jump.
  as_nop();
  as_nop();
  as_nop();
  if (delaySlotFill == FillDelaySlot) {
    as_nop();
  }
}

void MacroAssemblerMIPS64::branchWithCode(InstImm code, Label* label,
                                          JumpKind jumpKind) {
  // simply output the pointer of one label as its id,
  // notice that after one label destructor, the pointer will be reused.
  spew("branch .Llabel %p", label);
  MOZ_ASSERT(code.encode() !=
             InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0)).encode());
  InstImm inst_beq = InstImm(op_beq, zero, zero, BOffImm16(0));

  if (label->bound()) {
    int32_t offset = label->offset() - m_buffer.nextOffset().getOffset();

    if (BOffImm16::IsInRange(offset)) {
      jumpKind = ShortJump;
    }

    if (jumpKind == ShortJump) {
      MOZ_ASSERT(BOffImm16::IsInRange(offset));
      code.setBOffImm16(BOffImm16(offset));
#ifdef JS_JITSPEW
      decodeBranchInstAndSpew(code);
#endif
      writeInst(code.encode());
      as_nop();
      return;
    }

    if (code.encode() == inst_beq.encode()) {
      // Handle long jump
      addLongJump(nextOffset(), BufferOffset(label->offset()));
      ma_liPatchable(ScratchRegister, ImmWord(LabelBase::INVALID_OFFSET));
      as_jr(ScratchRegister);
      as_nop();
      return;
    }

    // Handle long conditional branch, the target offset is based on self,
    // point to next instruction of nop at below.
    spew("invert branch .Llabel %p", label);
    InstImm code_r = invertBranch(code, BOffImm16(7 * sizeof(uint32_t)));
#ifdef JS_JITSPEW
    decodeBranchInstAndSpew(code_r);
#endif
    writeInst(code_r.encode());
    // No need for a "nop" here because we can clobber scratch.
    addLongJump(nextOffset(), BufferOffset(label->offset()));
    ma_liPatchable(ScratchRegister, ImmWord(LabelBase::INVALID_OFFSET));
    as_jr(ScratchRegister);
    as_nop();
    return;
  }

  // Generate open jump and link it to a label.

  // Second word holds a pointer to the next branch in label's chain.
  uint32_t nextInChain =
      label->used() ? label->offset() : LabelBase::INVALID_OFFSET;

  if (jumpKind == ShortJump) {
    // Make the whole branch continous in the buffer.
    m_buffer.ensureSpace(2 * sizeof(uint32_t));

    // Indicate that this is short jump with offset 4.
    code.setBOffImm16(BOffImm16(4));
#ifdef JS_JITSPEW
    decodeBranchInstAndSpew(code);
#endif
    BufferOffset bo = writeInst(code.encode());
    writeInst(nextInChain);
    if (!oom()) {
      label->use(bo.getOffset());
    }
    return;
  }

  bool conditional = code.encode() != inst_beq.encode();

  // Make the whole branch continous in the buffer. The '7'
  // instructions are writing at below (contain conditional nop).
  m_buffer.ensureSpace(7 * sizeof(uint32_t));

#ifdef JS_JITSPEW
  decodeBranchInstAndSpew(code);
#endif
  BufferOffset bo = writeInst(code.encode());
  writeInst(nextInChain);
  if (!oom()) {
    label->use(bo.getOffset());
  }
  // Leave space for potential long jump.
  as_nop();
  as_nop();
  as_nop();
  as_nop();
  if (conditional) {
    as_nop();
  }
}

void MacroAssemblerMIPS64::ma_cmp_set(Register rd, Register rs, ImmWord imm,
                                      Condition c) {
  if (imm.value <= INT32_MAX) {
    ma_cmp_set(rd, rs, Imm32(uint32_t(imm.value)), c);
  } else {
    ma_li(ScratchRegister, imm);
    ma_cmp_set(rd, rs, ScratchRegister, c);
  }
}

void MacroAssemblerMIPS64::ma_cmp_set(Register rd, Register rs, ImmPtr imm,
                                      Condition c) {
  ma_cmp_set(rd, rs, ImmWord(uintptr_t(imm.value)), c);
}

void MacroAssemblerMIPS64::ma_cmp_set(Register rd, Address address, Register rt,
                                      Condition c) {
  SecondScratchRegisterScope scratch2(asMasm());
  ma_load(scratch2, address, SizeDouble);
  ma_cmp_set(rd, scratch2, rt, c);
}

void MacroAssemblerMIPS64::ma_cmp_set(Register rd, Address address, ImmWord imm,
                                      Condition c) {
  SecondScratchRegisterScope scratch2(asMasm());
  ma_load(scratch2, address, SizeDouble);
  ma_cmp_set(rd, scratch2, imm, c);
}

void MacroAssemblerMIPS64::ma_cmp_set(Register rd, Address address, Imm32 imm,
                                      Condition c) {
  SecondScratchRegisterScope scratch2(asMasm());
  ma_load(scratch2, address, SizeWord, SignExtend);
  ma_cmp_set(rd, scratch2, imm, c);
}

// fp instructions
void MacroAssemblerMIPS64::ma_lid(FloatRegister dest, double value) {
  ImmWord imm(mozilla::BitwiseCast<uint64_t>(value));

  if (imm.value != 0) {
    ma_li(ScratchRegister, imm);
    moveToDouble(ScratchRegister, dest);
  } else {
    moveToDouble(zero, dest);
  }
}

void MacroAssemblerMIPS64::ma_mv(FloatRegister src, ValueOperand dest) {
  as_dmfc1(dest.valueReg(), src);
}

void MacroAssemblerMIPS64::ma_mv(ValueOperand src, FloatRegister dest) {
  as_dmtc1(src.valueReg(), dest);
}

FaultingCodeOffset MacroAssemblerMIPS64::ma_ls(FloatRegister ft,
                                               Address address) {
  FaultingCodeOffset fco;
  if (Imm16::IsInSignedRange(address.offset)) {
    fco = FaultingCodeOffset(currentOffset());
    as_lwc1(ft, address.base, address.offset);
  } else {
    MOZ_ASSERT(address.base != ScratchRegister);
    ma_li(ScratchRegister, Imm32(address.offset));
    if (isLoongson()) {
      fco = FaultingCodeOffset(currentOffset());
      as_gslsx(ft, address.base, ScratchRegister, 0);
    } else {
      as_daddu(ScratchRegister, address.base, ScratchRegister);
      fco = FaultingCodeOffset(currentOffset());
      as_lwc1(ft, ScratchRegister, 0);
    }
  }
  return fco;
}

FaultingCodeOffset MacroAssemblerMIPS64::ma_ld(FloatRegister ft,
                                               Address address) {
  FaultingCodeOffset fco;
  if (Imm16::IsInSignedRange(address.offset)) {
    fco = FaultingCodeOffset(currentOffset());
    as_ldc1(ft, address.base, address.offset);
  } else {
    MOZ_ASSERT(address.base != ScratchRegister);
    ma_li(ScratchRegister, Imm32(address.offset));
    if (isLoongson()) {
      fco = FaultingCodeOffset(currentOffset());
      as_gsldx(ft, address.base, ScratchRegister, 0);
    } else {
      as_daddu(ScratchRegister, address.base, ScratchRegister);
      fco = FaultingCodeOffset(currentOffset());
      as_ldc1(ft, ScratchRegister, 0);
    }
  }
  return fco;
}

FaultingCodeOffset MacroAssemblerMIPS64::ma_sd(FloatRegister ft,
                                               Address address) {
  FaultingCodeOffset fco;
  if (Imm16::IsInSignedRange(address.offset)) {
    fco = FaultingCodeOffset(currentOffset());
    as_sdc1(ft, address.base, address.offset);
  } else {
    MOZ_ASSERT(address.base != ScratchRegister);
    ma_li(ScratchRegister, Imm32(address.offset));
    if (isLoongson()) {
      fco = FaultingCodeOffset(currentOffset());
      as_gssdx(ft, address.base, ScratchRegister, 0);
    } else {
      as_daddu(ScratchRegister, address.base, ScratchRegister);
      fco = FaultingCodeOffset(currentOffset());
      as_sdc1(ft, ScratchRegister, 0);
    }
  }
  return fco;
}

FaultingCodeOffset MacroAssemblerMIPS64::ma_ss(FloatRegister ft,
                                               Address address) {
  FaultingCodeOffset fco;
  if (Imm16::IsInSignedRange(address.offset)) {
    fco = FaultingCodeOffset(currentOffset());
    as_swc1(ft, address.base, address.offset);
  } else {
    MOZ_ASSERT(address.base != ScratchRegister);
    ma_li(ScratchRegister, Imm32(address.offset));
    if (isLoongson()) {
      fco = FaultingCodeOffset(currentOffset());
      as_gsssx(ft, address.base, ScratchRegister, 0);
    } else {
      as_daddu(ScratchRegister, address.base, ScratchRegister);
      fco = FaultingCodeOffset(currentOffset());
      as_swc1(ft, ScratchRegister, 0);
    }
  }
  return fco;
}

void MacroAssemblerMIPS64::ma_pop(FloatRegister f) {
  as_ldc1(f, StackPointer, 0);
  as_daddiu(StackPointer, StackPointer, sizeof(double));
}

void MacroAssemblerMIPS64::ma_push(FloatRegister f) {
  as_daddiu(StackPointer, StackPointer, (int32_t)-sizeof(double));
  as_sdc1(f, StackPointer, 0);
}

bool MacroAssemblerMIPS64Compat::buildOOLFakeExitFrame(void* fakeReturnAddr) {
  asMasm().PushFrameDescriptor(FrameType::IonJS);  // descriptor_
  asMasm().Push(ImmPtr(fakeReturnAddr));
  asMasm().Push(FramePointer);
  return true;
}

void MacroAssemblerMIPS64Compat::move32(Imm32 imm, Register dest) {
  ma_li(dest, imm);
}

void MacroAssemblerMIPS64Compat::move32(Register src, Register dest) {
  ma_sll(dest, src, Imm32(0));
}

void MacroAssemblerMIPS64Compat::movePtr(Register src, Register dest) {
  ma_move(dest, src);
}
void MacroAssemblerMIPS64Compat::movePtr(ImmWord imm, Register dest) {
  ma_li(dest, imm);
}

void MacroAssemblerMIPS64Compat::movePtr(ImmGCPtr imm, Register dest) {
  ma_li(dest, imm);
}

void MacroAssemblerMIPS64Compat::movePtr(ImmPtr imm, Register dest) {
  movePtr(ImmWord(uintptr_t(imm.value)), dest);
}
void MacroAssemblerMIPS64Compat::movePtr(wasm::SymbolicAddress imm,
                                         Register dest) {
  append(wasm::SymbolicAccess(CodeOffset(nextOffset().getOffset()), imm));
  ma_liPatchable(dest, ImmWord(-1));
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::load8ZeroExtend(
    const Address& address, Register dest) {
  return ma_load(dest, address, SizeByte, ZeroExtend);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::load8ZeroExtend(
    const BaseIndex& src, Register dest) {
  return ma_load(dest, src, SizeByte, ZeroExtend);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::load8SignExtend(
    const Address& address, Register dest) {
  return ma_load(dest, address, SizeByte, SignExtend);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::load8SignExtend(
    const BaseIndex& src, Register dest) {
  return ma_load(dest, src, SizeByte, SignExtend);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::load16ZeroExtend(
    const Address& address, Register dest) {
  return ma_load(dest, address, SizeHalfWord, ZeroExtend);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::load16ZeroExtend(
    const BaseIndex& src, Register dest) {
  return ma_load(dest, src, SizeHalfWord, ZeroExtend);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::load16SignExtend(
    const Address& address, Register dest) {
  return ma_load(dest, address, SizeHalfWord, SignExtend);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::load16SignExtend(
    const BaseIndex& src, Register dest) {
  return ma_load(dest, src, SizeHalfWord, SignExtend);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::load32(const Address& address,
                                                      Register dest) {
  return ma_load(dest, address, SizeWord);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::load32(const BaseIndex& address,
                                                      Register dest) {
  return ma_load(dest, address, SizeWord);
}

void MacroAssemblerMIPS64Compat::load32(AbsoluteAddress address,
                                        Register dest) {
  movePtr(ImmPtr(address.addr), ScratchRegister);
  load32(Address(ScratchRegister, 0), dest);
}

void MacroAssemblerMIPS64Compat::load32(wasm::SymbolicAddress address,
                                        Register dest) {
  movePtr(address, ScratchRegister);
  load32(Address(ScratchRegister, 0), dest);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::loadPtr(const Address& address,
                                                       Register dest) {
  return ma_load(dest, address, SizeDouble);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::loadPtr(const BaseIndex& src,
                                                       Register dest) {
  return ma_load(dest, src, SizeDouble);
}

void MacroAssemblerMIPS64Compat::loadPtr(AbsoluteAddress address,
                                         Register dest) {
  movePtr(ImmPtr(address.addr), ScratchRegister);
  loadPtr(Address(ScratchRegister, 0), dest);
}

void MacroAssemblerMIPS64Compat::loadPtr(wasm::SymbolicAddress address,
                                         Register dest) {
  movePtr(address, ScratchRegister);
  loadPtr(Address(ScratchRegister, 0), dest);
}

void MacroAssemblerMIPS64Compat::loadPrivate(const Address& address,
                                             Register dest) {
  loadPtr(address, dest);
}

void MacroAssemblerMIPS64Compat::loadUnalignedDouble(
    const wasm::MemoryAccessDesc& access, const BaseIndex& src, Register temp,
    FloatRegister dest) {
  computeScaledAddress(src, SecondScratchReg);
  BufferOffset load;
  if (Imm16::IsInSignedRange(src.offset) &&
      Imm16::IsInSignedRange(src.offset + 7)) {
    load = as_ldl(temp, SecondScratchReg, src.offset + 7);
    as_ldr(temp, SecondScratchReg, src.offset);
  } else {
    ma_li(ScratchRegister, Imm32(src.offset));
    as_daddu(ScratchRegister, SecondScratchReg, ScratchRegister);
    load = as_ldl(temp, ScratchRegister, 7);
    as_ldr(temp, ScratchRegister, 0);
  }
  append(access, wasm::TrapMachineInsnForLoad(Scalar::byteSize(access.type())),
         FaultingCodeOffset(load.getOffset()));
  moveToDouble(temp, dest);
}

void MacroAssemblerMIPS64Compat::loadUnalignedFloat32(
    const wasm::MemoryAccessDesc& access, const BaseIndex& src, Register temp,
    FloatRegister dest) {
  computeScaledAddress(src, SecondScratchReg);
  BufferOffset load;
  if (Imm16::IsInSignedRange(src.offset) &&
      Imm16::IsInSignedRange(src.offset + 3)) {
    load = as_lwl(temp, SecondScratchReg, src.offset + 3);
    as_lwr(temp, SecondScratchReg, src.offset);
  } else {
    ma_li(ScratchRegister, Imm32(src.offset));
    as_daddu(ScratchRegister, SecondScratchReg, ScratchRegister);
    load = as_lwl(temp, ScratchRegister, 3);
    as_lwr(temp, ScratchRegister, 0);
  }
  append(access, wasm::TrapMachineInsnForLoad(Scalar::byteSize(access.type())),
         FaultingCodeOffset(load.getOffset()));
  moveToFloat32(temp, dest);
}

void MacroAssemblerMIPS64Compat::store8(Imm32 imm, const Address& address) {
  ma_li(SecondScratchReg, imm);
  ma_store(SecondScratchReg, address, SizeByte);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::store8(Register src,
                                                      const Address& address) {
  return ma_store(src, address, SizeByte);
}

void MacroAssemblerMIPS64Compat::store8(Imm32 imm, const BaseIndex& dest) {
  ma_store(imm, dest, SizeByte);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::store8(Register src,
                                                      const BaseIndex& dest) {
  return ma_store(src, dest, SizeByte);
}

void MacroAssemblerMIPS64Compat::store16(Imm32 imm, const Address& address) {
  ma_li(SecondScratchReg, imm);
  ma_store(SecondScratchReg, address, SizeHalfWord);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::store16(Register src,
                                                       const Address& address) {
  return ma_store(src, address, SizeHalfWord);
}

void MacroAssemblerMIPS64Compat::store16(Imm32 imm, const BaseIndex& dest) {
  ma_store(imm, dest, SizeHalfWord);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::store16(
    Register src, const BaseIndex& address) {
  return ma_store(src, address, SizeHalfWord);
}

void MacroAssemblerMIPS64Compat::store32(Register src,
                                         AbsoluteAddress address) {
  movePtr(ImmPtr(address.addr), ScratchRegister);
  store32(src, Address(ScratchRegister, 0));
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::store32(Register src,
                                                       const Address& address) {
  return ma_store(src, address, SizeWord);
}

void MacroAssemblerMIPS64Compat::store32(Imm32 src, const Address& address) {
  move32(src, SecondScratchReg);
  ma_store(SecondScratchReg, address, SizeWord);
}

void MacroAssemblerMIPS64Compat::store32(Imm32 imm, const BaseIndex& dest) {
  ma_store(imm, dest, SizeWord);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::store32(Register src,
                                                       const BaseIndex& dest) {
  return ma_store(src, dest, SizeWord);
}

template <typename T>
void MacroAssemblerMIPS64Compat::storePtr(ImmWord imm, T address) {
  ma_li(SecondScratchReg, imm);
  ma_store(SecondScratchReg, address, SizeDouble);
}

template void MacroAssemblerMIPS64Compat::storePtr<Address>(ImmWord imm,
                                                            Address address);
template void MacroAssemblerMIPS64Compat::storePtr<BaseIndex>(
    ImmWord imm, BaseIndex address);

template <typename T>
void MacroAssemblerMIPS64Compat::storePtr(ImmPtr imm, T address) {
  storePtr(ImmWord(uintptr_t(imm.value)), address);
}

template void MacroAssemblerMIPS64Compat::storePtr<Address>(ImmPtr imm,
                                                            Address address);
template void MacroAssemblerMIPS64Compat::storePtr<BaseIndex>(
    ImmPtr imm, BaseIndex address);

template <typename T>
void MacroAssemblerMIPS64Compat::storePtr(ImmGCPtr imm, T address) {
  movePtr(imm, SecondScratchReg);
  storePtr(SecondScratchReg, address);
}

template void MacroAssemblerMIPS64Compat::storePtr<Address>(ImmGCPtr imm,
                                                            Address address);
template void MacroAssemblerMIPS64Compat::storePtr<BaseIndex>(
    ImmGCPtr imm, BaseIndex address);

FaultingCodeOffset MacroAssemblerMIPS64Compat::storePtr(
    Register src, const Address& address) {
  return ma_store(src, address, SizeDouble);
}

FaultingCodeOffset MacroAssemblerMIPS64Compat::storePtr(
    Register src, const BaseIndex& address) {
  return ma_store(src, address, SizeDouble);
}

void MacroAssemblerMIPS64Compat::storePtr(Register src, AbsoluteAddress dest) {
  movePtr(ImmPtr(dest.addr), ScratchRegister);
  storePtr(src, Address(ScratchRegister, 0));
}

void MacroAssemblerMIPS64Compat::storeUnalignedFloat32(
    const wasm::MemoryAccessDesc& access, FloatRegister src, Register temp,
    const BaseIndex& dest) {
  computeScaledAddress(dest, SecondScratchReg);
  moveFromFloat32(src, temp);
  BufferOffset store;
  if (Imm16::IsInSignedRange(dest.offset) &&
      Imm16::IsInSignedRange(dest.offset + 3)) {
    store = as_swl(temp, SecondScratchReg, dest.offset + 3);
    as_swr(temp, SecondScratchReg, dest.offset);
  } else {
    ma_li(ScratchRegister, Imm32(dest.offset));
    as_daddu(ScratchRegister, SecondScratchReg, ScratchRegister);
    store = as_swl(temp, ScratchRegister, 3);
    as_swr(temp, ScratchRegister, 0);
  }
  append(access, wasm::TrapMachineInsnForStore(Scalar::byteSize(access.type())),
         FaultingCodeOffset(store.getOffset()));
}

void MacroAssemblerMIPS64Compat::storeUnalignedDouble(
    const wasm::MemoryAccessDesc& access, FloatRegister src, Register temp,
    const BaseIndex& dest) {
  computeScaledAddress(dest, SecondScratchReg);
  moveFromDouble(src, temp);

  BufferOffset store;
  if (Imm16::IsInSignedRange(dest.offset) &&
      Imm16::IsInSignedRange(dest.offset + 7)) {
    store = as_sdl(temp, SecondScratchReg, dest.offset + 7);
    as_sdr(temp, SecondScratchReg, dest.offset);
  } else {
    ma_li(ScratchRegister, Imm32(dest.offset));
    as_daddu(ScratchRegister, SecondScratchReg, ScratchRegister);
    store = as_sdl(temp, ScratchRegister, 7);
    as_sdr(temp, ScratchRegister, 0);
  }
  append(access, wasm::TrapMachineInsnForStore(Scalar::byteSize(access.type())),
         FaultingCodeOffset(store.getOffset()));
}

void MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output) {
  as_roundwd(ScratchDoubleReg, input);
  ma_li(ScratchRegister, Imm32(255));
  as_mfc1(output, ScratchDoubleReg);
#ifdef MIPSR6
  as_slti(SecondScratchReg, output, 0);
  as_seleqz(output, output, SecondScratchReg);
  as_sltiu(SecondScratchReg, output, 255);
  as_selnez(output, output, SecondScratchReg);
  as_seleqz(ScratchRegister, ScratchRegister, SecondScratchReg);
  as_or(output, output, ScratchRegister);
#else
  zeroDouble(ScratchDoubleReg);
  as_sltiu(SecondScratchReg, output, 255);
  as_colt(DoubleFloat, ScratchDoubleReg, input);
  // if res > 255; res = 255;
  as_movz(output, ScratchRegister, SecondScratchReg);
  // if !(input > 0); res = 0;
  as_movf(output, zero);
#endif
}

void MacroAssemblerMIPS64Compat::testNullSet(Condition cond,
                                             const ValueOperand& value,
                                             Register dest) {
  MOZ_ASSERT(cond == Equal || cond == NotEqual);
  splitTag(value, SecondScratchReg);
  ma_cmp_set(dest, SecondScratchReg, ImmTag(JSVAL_TAG_NULL), cond);
}

void MacroAssemblerMIPS64Compat::testObjectSet(Condition cond,
                                               const ValueOperand& value,
                                               Register dest) {
  MOZ_ASSERT(cond == Equal || cond == NotEqual);
  splitTag(value, SecondScratchReg);
  ma_cmp_set(dest, SecondScratchReg, ImmTag(JSVAL_TAG_OBJECT), cond);
}

void MacroAssemblerMIPS64Compat::testUndefinedSet(Condition cond,
                                                  const ValueOperand& value,
                                                  Register dest) {
  MOZ_ASSERT(cond == Equal || cond == NotEqual);
  splitTag(value, SecondScratchReg);
  ma_cmp_set(dest, SecondScratchReg, ImmTag(JSVAL_TAG_UNDEFINED), cond);
}

void MacroAssemblerMIPS64Compat::unboxInt32(const ValueOperand& operand,
                                            Register dest) {
  ma_sll(dest, operand.valueReg(), Imm32(0));
}

void MacroAssemblerMIPS64Compat::unboxInt32(Register src, Register dest) {
  ma_sll(dest, src, Imm32(0));
}

void MacroAssemblerMIPS64Compat::unboxInt32(const Address& src, Register dest) {
  load32(Address(src.base, src.offset), dest);
}

void MacroAssemblerMIPS64Compat::unboxInt32(const BaseIndex& src,
                                            Register dest) {
  computeScaledAddress(src, SecondScratchReg);
  load32(Address(SecondScratchReg, src.offset), dest);
}

void MacroAssemblerMIPS64Compat::unboxBoolean(const ValueOperand& operand,
                                              Register dest) {
  ma_dext(dest, operand.valueReg(), Imm32(0), Imm32(32));
}

void MacroAssemblerMIPS64Compat::unboxBoolean(Register src, Register dest) {
  ma_dext(dest, src, Imm32(0), Imm32(32));
}

void MacroAssemblerMIPS64Compat::unboxBoolean(const Address& src,
                                              Register dest) {
  ma_load(dest, Address(src.base, src.offset), SizeWord, ZeroExtend);
}

void MacroAssemblerMIPS64Compat::unboxBoolean(const BaseIndex& src,
                                              Register dest) {
  computeScaledAddress(src, SecondScratchReg);
  ma_load(dest, Address(SecondScratchReg, src.offset), SizeWord, ZeroExtend);
}

void MacroAssemblerMIPS64Compat::unboxDouble(const ValueOperand& operand,
                                             FloatRegister dest) {
  as_dmtc1(operand.valueReg(), dest);
}

void MacroAssemblerMIPS64Compat::unboxDouble(const Address& src,
                                             FloatRegister dest) {
  ma_ld(dest, Address(src.base, src.offset));
}
void MacroAssemblerMIPS64Compat::unboxDouble(const BaseIndex& src,
                                             FloatRegister dest) {
  SecondScratchRegisterScope scratch(asMasm());
  loadPtr(src, scratch);
  unboxDouble(ValueOperand(scratch), dest);
}

void MacroAssemblerMIPS64Compat::unboxString(const ValueOperand& operand,
                                             Register dest) {
  unboxNonDouble(operand, dest, JSVAL_TYPE_STRING);
}

void MacroAssemblerMIPS64Compat::unboxString(Register src, Register dest) {
  unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
}

void MacroAssemblerMIPS64Compat::unboxString(const Address& src,
                                             Register dest) {
  unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
}

void MacroAssemblerMIPS64Compat::unboxSymbol(const ValueOperand& operand,
                                             Register dest) {
  unboxNonDouble(operand, dest, JSVAL_TYPE_SYMBOL);
}

void MacroAssemblerMIPS64Compat::unboxSymbol(Register src, Register dest) {
  unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
}

void MacroAssemblerMIPS64Compat::unboxSymbol(const Address& src,
                                             Register dest) {
  unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
}

void MacroAssemblerMIPS64Compat::unboxBigInt(const ValueOperand& operand,
                                             Register dest) {
  unboxNonDouble(operand, dest, JSVAL_TYPE_BIGINT);
}

void MacroAssemblerMIPS64Compat::unboxBigInt(Register src, Register dest) {
  unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT);
}

void MacroAssemblerMIPS64Compat::unboxBigInt(const Address& src,
                                             Register dest) {
  unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT);
}

void MacroAssemblerMIPS64Compat::unboxObject(const ValueOperand& src,
                                             Register dest) {
  unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}

void MacroAssemblerMIPS64Compat::unboxObject(Register src, Register dest) {
  unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}

void MacroAssemblerMIPS64Compat::unboxObject(const Address& src,
                                             Register dest) {
  unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}

void MacroAssemblerMIPS64Compat::unboxValue(const ValueOperand& src,
                                            AnyRegister dest,
                                            JSValueType type) {
  if (dest.isFloat()) {
    Label notInt32, end;
    asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32);
    convertInt32ToDouble(src.valueReg(), dest.fpu());
    ma_b(&end, ShortJump);
    bind(¬Int32);
    unboxDouble(src, dest.fpu());
    bind(&end);
  } else {
    unboxNonDouble(src, dest.gpr(), type);
  }
}

void MacroAssemblerMIPS64Compat::boxDouble(FloatRegister src,
                                           const ValueOperand& dest,
                                           FloatRegister) {
  as_dmfc1(dest.valueReg(), src);
}

void MacroAssemblerMIPS64Compat::boxNonDouble(JSValueType type, Register src,
                                              const ValueOperand& dest) {
  MOZ_ASSERT(src != dest.valueReg());
  boxValue(type, src, dest.valueReg());
}

void MacroAssemblerMIPS64Compat::loadConstantFloat32(float f,
                                                     FloatRegister dest) {
  ma_lis(dest, f);
}

void MacroAssemblerMIPS64Compat::loadInt32OrDouble(const Address& src,
                                                   FloatRegister dest) {
  Label notInt32, end;
  // If it's an int, convert it to double.
  loadPtr(Address(src.base, src.offset), ScratchRegister);
  ma_dsrl(SecondScratchReg, ScratchRegister, Imm32(JSVAL_TAG_SHIFT));
  asMasm().branchTestInt32(Assembler::NotEqual, SecondScratchReg, ¬Int32);
  loadPtr(Address(src.base, src.offset), SecondScratchReg);
  convertInt32ToDouble(SecondScratchReg, dest);
  ma_b(&end, ShortJump);

  // Not an int, just load as double.
  bind(¬Int32);
  unboxDouble(src, dest);
  bind(&end);
}

void MacroAssemblerMIPS64Compat::loadInt32OrDouble(const BaseIndex& addr,
                                                   FloatRegister dest) {
  Label notInt32, end;

  // If it's an int, convert it to double.
  computeScaledAddress(addr, SecondScratchReg);
  // Since we only have one scratch, we need to stomp over it with the tag.
  loadPtr(Address(SecondScratchReg, 0), ScratchRegister);
  ma_dsrl(SecondScratchReg, ScratchRegister, Imm32(JSVAL_TAG_SHIFT));
  asMasm().branchTestInt32(Assembler::NotEqual, SecondScratchReg, ¬Int32);

  computeScaledAddress(addr, SecondScratchReg);
  loadPtr(Address(SecondScratchReg, 0), SecondScratchReg);
  convertInt32ToDouble(SecondScratchReg, dest);
  ma_b(&end, ShortJump);

  // Not an int, just load as double.
  bind(¬Int32);
  // First, recompute the offset that had been stored in the scratch register
  // since the scratch register was overwritten loading in the type.
  computeScaledAddress(addr, SecondScratchReg);
  unboxDouble(Address(SecondScratchReg, 0), dest);
  bind(&end);
}

void MacroAssemblerMIPS64Compat::loadConstantDouble(double dp,
                                                    FloatRegister dest) {
  ma_lid(dest, dp);
}

Register MacroAssemblerMIPS64Compat::extractObject(const Address& address,
                                                   Register scratch) {
  loadPtr(Address(address.base, address.offset), scratch);
  ma_dext(scratch, scratch, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
  return scratch;
}

Register MacroAssemblerMIPS64Compat::extractTag(const Address& address,
                                                Register scratch) {
  loadPtr(Address(address.base, address.offset), scratch);
  ma_dext(scratch, scratch, Imm32(JSVAL_TAG_SHIFT),
          Imm32(64 - JSVAL_TAG_SHIFT));
  return scratch;
}

Register MacroAssemblerMIPS64Compat::extractTag(const BaseIndex& address,
                                                Register scratch) {
  computeScaledAddress(address, scratch);
  return extractTag(Address(scratch, address.offset), scratch);
}

/////////////////////////////////////////////////////////////////
// X86/X64-common/ARM/MIPS interface.
/////////////////////////////////////////////////////////////////
void MacroAssemblerMIPS64Compat::storeValue(ValueOperand val, Operand dst) {
  storeValue(val, Address(Register::FromCode(dst.base()), dst.disp()));
}

void MacroAssemblerMIPS64Compat::storeValue(ValueOperand val,
                                            const BaseIndex& dest) {
  computeScaledAddress(dest, SecondScratchReg);
  storeValue(val, Address(SecondScratchReg, dest.offset));
}

void MacroAssemblerMIPS64Compat::storeValue(JSValueType type, Register reg,
                                            BaseIndex dest) {
  computeScaledAddress(dest, ScratchRegister);

  int32_t offset = dest.offset;
  if (!Imm16::IsInSignedRange(offset)) {
    ma_li(SecondScratchReg, Imm32(offset));
    as_daddu(ScratchRegister, ScratchRegister, SecondScratchReg);
    offset = 0;
  }

  storeValue(type, reg, Address(ScratchRegister, offset));
}

void MacroAssemblerMIPS64Compat::storeValue(ValueOperand val,
                                            const Address& dest) {
  storePtr(val.valueReg(), Address(dest.base, dest.offset));
}

void MacroAssemblerMIPS64Compat::storeValue(JSValueType type, Register reg,
                                            Address dest) {
  MOZ_ASSERT(dest.base != SecondScratchReg);

  if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
    store32(reg, dest);
    JSValueShiftedTag tag = (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type);
    store32(((Imm64(tag)).hi()), Address(dest.base, dest.offset + 4));
  } else {
    ma_li(SecondScratchReg, ImmTag(JSVAL_TYPE_TO_TAG(type)));
    ma_dsll(SecondScratchReg, SecondScratchReg, Imm32(JSVAL_TAG_SHIFT));
    ma_dins(SecondScratchReg, reg, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
    storePtr(SecondScratchReg, Address(dest.base, dest.offset));
  }
}

void MacroAssemblerMIPS64Compat::storeValue(const Value& val, Address dest) {
  if (val.isGCThing()) {
    writeDataRelocation(val);
    movWithPatch(ImmWord(val.asRawBits()), SecondScratchReg);
  } else {
    ma_li(SecondScratchReg, ImmWord(val.asRawBits()));
  }
  storePtr(SecondScratchReg, Address(dest.base, dest.offset));
}

void MacroAssemblerMIPS64Compat::storeValue(const Value& val, BaseIndex dest) {
  computeScaledAddress(dest, ScratchRegister);

  int32_t offset = dest.offset;
  if (!Imm16::IsInSignedRange(offset)) {
    ma_li(SecondScratchReg, Imm32(offset));
    as_daddu(ScratchRegister, ScratchRegister, SecondScratchReg);
    offset = 0;
  }
  storeValue(val, Address(ScratchRegister, offset));
}

void MacroAssemblerMIPS64Compat::loadValue(const BaseIndex& addr,
                                           ValueOperand val) {
  computeScaledAddress(addr, SecondScratchReg);
  loadValue(Address(SecondScratchReg, addr.offset), val);
}

void MacroAssemblerMIPS64Compat::loadValue(Address src, ValueOperand val) {
  loadPtr(Address(src.base, src.offset), val.valueReg());
}

void MacroAssemblerMIPS64Compat::tagValue(JSValueType type, Register payload,
                                          ValueOperand dest) {
  MOZ_ASSERT(dest.valueReg() != ScratchRegister);
  if (payload != dest.valueReg()) {
    ma_move(dest.valueReg(), payload);
  }
  ma_li(ScratchRegister, ImmTag(JSVAL_TYPE_TO_TAG(type)));
  ma_dins(dest.valueReg(), ScratchRegister, Imm32(JSVAL_TAG_SHIFT),
          Imm32(64 - JSVAL_TAG_SHIFT));
  if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
    ma_dins(dest.valueReg(), zero, Imm32(32), Imm32(JSVAL_TAG_SHIFT - 32));
  }
}

void MacroAssemblerMIPS64Compat::pushValue(ValueOperand val) {
  // Allocate stack slots for Value. One for each.
  asMasm().subPtr(Imm32(sizeof(Value)), StackPointer);
  // Store Value
  storeValue(val, Address(StackPointer, 0));
}

void MacroAssemblerMIPS64Compat::pushValue(const Address& addr) {
  // Load value before allocate stack, addr.base may be is sp.
  loadPtr(Address(addr.base, addr.offset), ScratchRegister);
  ma_dsubu(StackPointer, StackPointer, Imm32(sizeof(Value)));
  storePtr(ScratchRegister, Address(StackPointer, 0));
}

void MacroAssemblerMIPS64Compat::popValue(ValueOperand val) {
  as_ld(val.valueReg(), StackPointer, 0);
  as_daddiu(StackPointer, StackPointer, sizeof(Value));
}

void MacroAssemblerMIPS64Compat::breakpoint() { as_break(0); }

void MacroAssemblerMIPS64Compat::checkStackAlignment() {
#ifdef DEBUG
  Label aligned;
  as_andi(ScratchRegister, sp, ABIStackAlignment - 1);
  ma_b(ScratchRegister, zero, &aligned, Equal, ShortJump);
  as_break(BREAK_STACK_UNALIGNED);
  bind(&aligned);
#endif
}

void MacroAssemblerMIPS64Compat::handleFailureWithHandlerTail(
    Label* profilerExitTail, Label* bailoutTail,
    uint32_t* returnValueCheckOffset) {
  // Reserve space for exception information.
  int size = (sizeof(ResumeFromException) + ABIStackAlignment) &
             ~(ABIStackAlignment - 1);
  asMasm().subPtr(Imm32(size), StackPointer);
  ma_move(a0, StackPointer);  // Use a0 since it is a first function argument

  // Call the handler.
  using Fn = void (*)(ResumeFromException* rfe);
  asMasm().setupUnalignedABICall(a1);
  asMasm().passABIArg(a0);
  asMasm().callWithABI<Fn, HandleException>(
      ABIType::General, CheckUnsafeCallWithABI::DontCheckHasExitFrame);

  *returnValueCheckOffset = asMasm().currentOffset();

  Label entryFrame;
  Label catch_;
  Label finally;
  Label returnBaseline;
  Label returnIon;
  Label bailout;
  Label wasmInterpEntry;
  Label wasmCatch;

  // Already clobbered a0, so use it...
  load32(Address(StackPointer, ResumeFromException::offsetOfKind()), a0);
  asMasm().branch32(Assembler::Equal, a0,
                    Imm32(ExceptionResumeKind::EntryFrame), &entryFrame);
  asMasm().branch32(Assembler::Equal, a0, Imm32(ExceptionResumeKind::Catch),
                    &catch_);
  asMasm().branch32(Assembler::Equal, a0, Imm32(ExceptionResumeKind::Finally),
                    &finally);
  asMasm().branch32(Assembler::Equal, a0,
                    Imm32(ExceptionResumeKind::ForcedReturnBaseline),
                    &returnBaseline);
  asMasm().branch32(Assembler::Equal, a0,
                    Imm32(ExceptionResumeKind::ForcedReturnIon), &returnIon);
  asMasm().branch32(Assembler::Equal, a0, Imm32(ExceptionResumeKind::Bailout),
                    &bailout);
  asMasm().branch32(Assembler::Equal, a0,
                    Imm32(ExceptionResumeKind::WasmInterpEntry),
                    &wasmInterpEntry);
  asMasm().branch32(Assembler::Equal, a0, Imm32(ExceptionResumeKind::WasmCatch),
                    &wasmCatch);

  breakpoint();  // Invalid kind.

  // No exception handler. Load the error value, restore state and return from
  // the entry frame.
  bind(&entryFrame);
  asMasm().moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
  loadPtr(Address(StackPointer, ResumeFromException::offsetOfFramePointer()),
          FramePointer);
  loadPtr(Address(StackPointer, ResumeFromException::offsetOfStackPointer()),
          StackPointer);

  // We're going to be returning by the ion calling convention
  ma_pop(ra);
  as_jr(ra);
  as_nop();

  // If we found a catch handler, this must be a baseline frame. Restore
  // state and jump to the catch block.
  bind(&catch_);
  loadPtr(Address(StackPointer, ResumeFromException::offsetOfTarget()), a0);
  loadPtr(Address(StackPointer, ResumeFromException::offsetOfFramePointer()),
          FramePointer);
  loadPtr(Address(StackPointer, ResumeFromException::offsetOfStackPointer()),
          StackPointer);
  jump(a0);

  // If we found a finally block, this must be a baseline frame. Push three
  // values expected by the finally block: the exception, the exception stack,
  // and BooleanValue(true).
  bind(&finally);
  ValueOperand exception = ValueOperand(a1);
  loadValue(Address(sp, ResumeFromException::offsetOfException()), exception);

  ValueOperand exceptionStack = ValueOperand(a2);
  loadValue(Address(sp, ResumeFromException::offsetOfExceptionStack()),
            exceptionStack);

  loadPtr(Address(sp, ResumeFromException::offsetOfTarget()), a0);
  loadPtr(Address(sp, ResumeFromException::offsetOfFramePointer()),
          FramePointer);
  loadPtr(Address(sp, ResumeFromException::offsetOfStackPointer()), sp);

  pushValue(exception);
  pushValue(exceptionStack);
  pushValue(BooleanValue(true));
  jump(a0);

  // Return BaselineFrame->returnValue() to the caller.
  // Used in debug mode and for GeneratorReturn.
  Label profilingInstrumentation;
  bind(&returnBaseline);
  loadPtr(Address(StackPointer, ResumeFromException::offsetOfFramePointer()),
          FramePointer);
  loadPtr(Address(StackPointer, ResumeFromException::offsetOfStackPointer()),
          StackPointer);
  loadValue(Address(FramePointer, BaselineFrame::reverseOffsetOfReturnValue()),
            JSReturnOperand);
  jump(&profilingInstrumentation);

  // Return the given value to the caller.
  bind(&returnIon);
  loadValue(Address(StackPointer, ResumeFromException::offsetOfException()),
            JSReturnOperand);
  loadPtr(Address(StackPointer, ResumeFromException::offsetOfFramePointer()),
          FramePointer);
  loadPtr(Address(StackPointer, ResumeFromException::offsetOfStackPointer()),
          StackPointer);

  // If profiling is enabled, then update the lastProfilingFrame to refer to
  // caller frame before returning. This code is shared by ForcedReturnIon
  // and ForcedReturnBaseline.
  bind(&profilingInstrumentation);
  {
    Label skipProfilingInstrumentation;
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=92 H=97 G=94

¤ Dauer der Verarbeitung: 0.97 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge