Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/js/src/jit/x64/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 45 kB image not shown  

Quelle  MacroAssembler-x64.h   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/. */


#ifndef jit_x64_MacroAssembler_x64_h
#define jit_x64_MacroAssembler_x64_h

#include "jit/x86-shared/MacroAssembler-x86-shared.h"
#include "js/HeapAPI.h"
#include "wasm/WasmBuiltins.h"

namespace js {
namespace jit {

struct ImmShiftedTag : public ImmWord {
  explicit ImmShiftedTag(JSValueType type)
      : ImmWord(uintptr_t(JSVAL_TYPE_TO_SHIFTED_TAG(type))) {}
};

struct ImmTag : public Imm32 {
  explicit ImmTag(JSValueTag tag) : Imm32(tag) {}
};

// ScratchTagScope and ScratchTagScopeRelease are used to manage the tag
// register for splitTagForTest(), which has different register management on
// different platforms.  On 64-bit platforms it requires a scratch register that
// does not interfere with other operations; on 32-bit platforms it uses a
// register that is already part of the Value.
//
// The ScratchTagScope RAII type acquires the appropriate register; a reference
// to a variable of this type is then passed to splitTagForTest().
//
// On 64-bit platforms ScratchTagScopeRelease makes the owned scratch register
// available in a dynamic scope during compilation.  However it is important to
// remember that that does not preserve the register value in any way, so this
// RAII type should only be used along paths that eventually branch past further
// uses of the extracted tag value.
//
// On 32-bit platforms ScratchTagScopeRelease has no effect, since it does not
// manage a register, it only aliases a register in the ValueOperand.

class ScratchTagScope : public ScratchRegisterScope {
 public:
  ScratchTagScope(MacroAssembler& masm, const ValueOperand&)
      : ScratchRegisterScope(masm) {}
};

class ScratchTagScopeRelease {
  ScratchTagScope* ts_;

 public:
  explicit ScratchTagScopeRelease(ScratchTagScope* ts) : ts_(ts) {
    ts_->release();
  }
  ~ScratchTagScopeRelease() { ts_->reacquire(); }
};

class MacroAssemblerX64 : public MacroAssemblerX86Shared {
 private:
  // Perform a downcast. Should be removed by Bug 996602.
  MacroAssembler& asMasm();
  const MacroAssembler& asMasm() const;

  void bindOffsets(const MacroAssemblerX86Shared::UsesVector&);

  void vpRiprOpSimd128(const SimdConstant& v, FloatRegister reg,
                       JmpSrc (X86Encoding::BaseAssemblerX64::*op)(
                           X86Encoding::XMMRegisterID id));

  void vpRiprOpSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest,
                       JmpSrc (X86Encoding::BaseAssemblerX64::*op)(
                           X86Encoding::XMMRegisterID srcId,
                           X86Encoding::XMMRegisterID destId));

 protected:
  void flexibleDivMod64(Register rhs, Register lhsOutput, bool isUnsigned,
                        bool isDiv);

 public:
  using MacroAssemblerX86Shared::load32;
  using MacroAssemblerX86Shared::store16;
  using MacroAssemblerX86Shared::store32;

  MacroAssemblerX64() = default;

  // The buffer is about to be linked, make sure any constant pools or excess
  // bookkeeping has been flushed to the instruction stream.
  void finish();

  /////////////////////////////////////////////////////////////////
  // X64 helpers.
  /////////////////////////////////////////////////////////////////
  void writeDataRelocation(const Value& val) {
    // Raw GC pointer relocations and Value relocations both end up in
    // Assembler::TraceDataRelocations.
    if (val.isGCThing()) {
      gc::Cell* cell = val.toGCThing();
      if (cell && gc::IsInsideNursery(cell)) {
        embedsNurseryPointers_ = true;
      }
      dataRelocations_.writeUnsigned(masm.currentOffset());
    }
  }

  // Refers to the upper 32 bits of a 64-bit Value operand.
  // On x86_64, the upper 32 bits do not necessarily only contain the type.
  Operand ToUpper32(Operand base) {
    switch (base.kind()) {
      case Operand::MEM_REG_DISP:
        return Operand(Register::FromCode(base.base()), base.disp() + 4);

      case Operand::MEM_SCALE:
        return Operand(Register::FromCode(base.base()),
                       Register::FromCode(base.index()), base.scale(),
                       base.disp() + 4);

      default:
        MOZ_CRASH("unexpected operand kind");
    }
  }
  static inline Operand ToUpper32(const Address& address) {
    return Operand(address.base, address.offset + 4);
  }
  static inline Operand ToUpper32(const BaseIndex& address) {
    return Operand(address.base, address.index, address.scale,
                   address.offset + 4);
  }

  uint32_t Upper32Of(JSValueShiftedTag tag) { return uint32_t(tag >> 32); }

  JSValueShiftedTag GetShiftedTag(JSValueType type) {
    return (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type);
  }

  /////////////////////////////////////////////////////////////////
  // X86/X64-common interface.
  /////////////////////////////////////////////////////////////////

  void storeValue(ValueOperand val, Operand dest) {
    movq(val.valueReg(), dest);
  }
  void storeValue(ValueOperand val, const Address& dest) {
    storeValue(val, Operand(dest));
  }
  template <typename T>
  void storeValue(JSValueType type, Register reg, const T& dest) {
    // Value types with 32-bit payloads can be emitted as two 32-bit moves.
    if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
      movl(reg, Operand(dest));
      movl(Imm32(Upper32Of(GetShiftedTag(type))), ToUpper32(Operand(dest)));
    } else {
      ScratchRegisterScope scratch(asMasm());
      boxValue(type, reg, scratch);
      movq(scratch, Operand(dest));
    }
  }
  template <typename T>
  void storeValue(const Value& val, const T& dest) {
    ScratchRegisterScope scratch(asMasm());
    if (val.isGCThing()) {
      movWithPatch(ImmWord(val.asRawBits()), scratch);
      writeDataRelocation(val);
    } else {
      mov(ImmWord(val.asRawBits()), scratch);
    }
    movq(scratch, Operand(dest));
  }
  void storeValue(ValueOperand val, BaseIndex dest) {
    storeValue(val, Operand(dest));
  }
  void storeValue(const Address& src, const Address& dest, Register temp) {
    loadPtr(src, temp);
    storePtr(temp, dest);
  }
  void storePrivateValue(Register src, const Address& dest) {
    storePtr(src, dest);
  }
  void storePrivateValue(ImmGCPtr imm, const Address& dest) {
    storePtr(imm, dest);
  }
  void loadValue(Operand src, ValueOperand val) { movq(src, val.valueReg()); }
  void loadValue(Address src, ValueOperand val) {
    loadValue(Operand(src), val);
  }
  void loadValue(const BaseIndex& src, ValueOperand val) {
    loadValue(Operand(src), val);
  }
  void loadUnalignedValue(const Address& src, ValueOperand dest) {
    loadValue(src, dest);
  }
  void tagValue(JSValueType type, Register payload, ValueOperand dest) {
    ScratchRegisterScope scratch(asMasm());
    MOZ_ASSERT(dest.valueReg() != scratch);
    if (payload != dest.valueReg()) {
      movq(payload, dest.valueReg());
    }
    mov(ImmShiftedTag(type), scratch);
    orq(scratch, dest.valueReg());
  }
  void pushValue(ValueOperand val) { push(val.valueReg()); }
  void popValue(ValueOperand val) { pop(val.valueReg()); }
  void pushValue(const Value& val) {
    if (val.isGCThing()) {
      ScratchRegisterScope scratch(asMasm());
      movWithPatch(ImmWord(val.asRawBits()), scratch);
      writeDataRelocation(val);
      push(scratch);
    } else {
      push(ImmWord(val.asRawBits()));
    }
  }
  void pushValue(JSValueType type, Register reg) {
    ScratchRegisterScope scratch(asMasm());
    boxValue(type, reg, scratch);
    push(scratch);
  }
  void pushValue(const Address& addr) { push(Operand(addr)); }

  void pushValue(const BaseIndex& addr, Register scratch) {
    push(Operand(addr));
  }

  void boxValue(JSValueType type, Register src, Register dest);

  Condition testUndefined(Condition cond, Register tag) {
    MOZ_ASSERT(cond == Equal || cond == NotEqual);
    cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED));
    return cond;
  }
  Condition testInt32(Condition cond, Register tag) {
    MOZ_ASSERT(cond == Equal || cond == NotEqual);
    cmp32(tag, ImmTag(JSVAL_TAG_INT32));
    return cond;
  }
  Condition testBoolean(Condition cond, Register tag) {
    MOZ_ASSERT(cond == Equal || cond == NotEqual);
    cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN));
    return cond;
  }
  Condition testNull(Condition cond, Register tag) {
    MOZ_ASSERT(cond == Equal || cond == NotEqual);
    cmp32(tag, ImmTag(JSVAL_TAG_NULL));
    return cond;
  }
  Condition testString(Condition cond, Register tag) {
    MOZ_ASSERT(cond == Equal || cond == NotEqual);
    cmp32(tag, ImmTag(JSVAL_TAG_STRING));
    return cond;
  }
  Condition testSymbol(Condition cond, Register tag) {
    MOZ_ASSERT(cond == Equal || cond == NotEqual);
    cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL));
    return cond;
  }
  Condition testBigInt(Condition cond, Register tag) {
    MOZ_ASSERT(cond == Equal || cond == NotEqual);
    cmp32(tag, ImmTag(JSVAL_TAG_BIGINT));
    return cond;
  }
  Condition testObject(Condition cond, Register tag) {
    MOZ_ASSERT(cond == Equal || cond == NotEqual);
    cmp32(tag, ImmTag(JSVAL_TAG_OBJECT));
    return cond;
  }
  Condition testDouble(Condition cond, Register tag) {
    MOZ_ASSERT(cond == Equal || cond == NotEqual);
    cmp32(tag, Imm32(JSVAL_TAG_MAX_DOUBLE));
    return cond == Equal ? BelowOrEqual : Above;
  }
  Condition testNumber(Condition cond, Register tag) {
    MOZ_ASSERT(cond == Equal || cond == NotEqual);
    cmp32(tag, Imm32(JS::detail::ValueUpperInclNumberTag));
    return cond == Equal ? BelowOrEqual : Above;
  }
  Condition testGCThing(Condition cond, Register tag) {
    MOZ_ASSERT(cond == Equal || cond == NotEqual);
    cmp32(tag, Imm32(JS::detail::ValueLowerInclGCThingTag));
    return cond == Equal ? AboveOrEqual : Below;
  }

  Condition testMagic(Condition cond, Register tag) {
    MOZ_ASSERT(cond == Equal || cond == NotEqual);
    cmp32(tag, ImmTag(JSVAL_TAG_MAGIC));
    return cond;
  }
  Condition testError(Condition cond, Register tag) {
    return testMagic(cond, tag);
  }
  Condition testPrimitive(Condition cond, Register tag) {
    MOZ_ASSERT(cond == Equal || cond == NotEqual);
    cmp32(tag, ImmTag(JS::detail::ValueUpperExclPrimitiveTag));
    return cond == Equal ? Below : AboveOrEqual;
  }

  Condition testUndefined(Condition cond, const ValueOperand& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testUndefined(cond, scratch);
  }
  Condition testInt32(Condition cond, const ValueOperand& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testInt32(cond, scratch);
  }
  Condition testBoolean(Condition cond, const ValueOperand& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testBoolean(cond, scratch);
  }
  Condition testDouble(Condition cond, const ValueOperand& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testDouble(cond, scratch);
  }
  Condition testNumber(Condition cond, const ValueOperand& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testNumber(cond, scratch);
  }
  Condition testNull(Condition cond, const ValueOperand& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testNull(cond, scratch);
  }
  Condition testString(Condition cond, const ValueOperand& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testString(cond, scratch);
  }
  Condition testSymbol(Condition cond, const ValueOperand& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testSymbol(cond, scratch);
  }
  Condition testBigInt(Condition cond, const ValueOperand& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testBigInt(cond, scratch);
  }
  Condition testObject(Condition cond, const ValueOperand& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testObject(cond, scratch);
  }
  Condition testGCThing(Condition cond, const ValueOperand& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testGCThing(cond, scratch);
  }
  Condition testPrimitive(Condition cond, const ValueOperand& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testPrimitive(cond, scratch);
  }

  Condition testUndefined(Condition cond, const Address& src) {
    cmp32(ToUpper32(src),
          Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_UNDEFINED))));
    return cond;
  }
  Condition testInt32(Condition cond, const Address& src) {
    cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_INT32))));
    return cond;
  }
  Condition testBoolean(Condition cond, const Address& src) {
    cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_BOOLEAN))));
    return cond;
  }
  Condition testDouble(Condition cond, const Address& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testDouble(cond, scratch);
  }
  Condition testNumber(Condition cond, const Address& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testNumber(cond, scratch);
  }
  Condition testNull(Condition cond, const Address& src) {
    cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_NULL))));
    return cond;
  }
  Condition testString(Condition cond, const Address& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testString(cond, scratch);
  }
  Condition testSymbol(Condition cond, const Address& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testSymbol(cond, scratch);
  }
  Condition testBigInt(Condition cond, const Address& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testBigInt(cond, scratch);
  }
  Condition testObject(Condition cond, const Address& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testObject(cond, scratch);
  }
  Condition testPrimitive(Condition cond, const Address& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testPrimitive(cond, scratch);
  }
  Condition testGCThing(Condition cond, const Address& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testGCThing(cond, scratch);
  }
  Condition testMagic(Condition cond, const Address& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testMagic(cond, scratch);
  }

  Condition testUndefined(Condition cond, const BaseIndex& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testUndefined(cond, scratch);
  }
  Condition testNull(Condition cond, const BaseIndex& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testNull(cond, scratch);
  }
  Condition testBoolean(Condition cond, const BaseIndex& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testBoolean(cond, scratch);
  }
  Condition testString(Condition cond, const BaseIndex& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testString(cond, scratch);
  }
  Condition testSymbol(Condition cond, const BaseIndex& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testSymbol(cond, scratch);
  }
  Condition testBigInt(Condition cond, const BaseIndex& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testBigInt(cond, scratch);
  }
  Condition testInt32(Condition cond, const BaseIndex& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testInt32(cond, scratch);
  }
  Condition testObject(Condition cond, const BaseIndex& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testObject(cond, scratch);
  }
  Condition testDouble(Condition cond, const BaseIndex& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testDouble(cond, scratch);
  }
  Condition testMagic(Condition cond, const BaseIndex& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testMagic(cond, scratch);
  }
  Condition testGCThing(Condition cond, const BaseIndex& src) {
    ScratchRegisterScope scratch(asMasm());
    splitTag(src, scratch);
    return testGCThing(cond, scratch);
  }

  Condition isMagic(Condition cond, const ValueOperand& src, JSWhyMagic why) {
    uint64_t magic = MagicValue(why).asRawBits();
    cmpPtr(src.valueReg(), ImmWord(magic));
    return cond;
  }

  void cmpPtr(Register lhs, const ImmWord rhs) {
    ScratchRegisterScope scratch(asMasm());
    MOZ_ASSERT(lhs != scratch);
    if (intptr_t(rhs.value) <= INT32_MAX && intptr_t(rhs.value) >= INT32_MIN) {
      cmpPtr(lhs, Imm32(int32_t(rhs.value)));
    } else {
      movePtr(rhs, scratch);
      cmpPtr(lhs, scratch);
    }
  }
  void cmpPtr(Register lhs, const ImmPtr rhs) {
    cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
  }
  void cmpPtr(Register lhs, const ImmGCPtr rhs) {
    ScratchRegisterScope scratch(asMasm());
    MOZ_ASSERT(lhs != scratch);
    movePtr(rhs, scratch);
    cmpPtr(lhs, scratch);
  }
  void cmpPtr(Register lhs, const Imm32 rhs) { cmpq(rhs, lhs); }
  void cmpPtr(const Operand& lhs, const ImmGCPtr rhs) {
    ScratchRegisterScope scratch(asMasm());
    MOZ_ASSERT(!lhs.containsReg(scratch));
    movePtr(rhs, scratch);
    cmpPtr(lhs, scratch);
  }
  void cmpPtr(const Operand& lhs, const ImmWord rhs) {
    if ((intptr_t)rhs.value <= INT32_MAX && (intptr_t)rhs.value >= INT32_MIN) {
      cmpPtr(lhs, Imm32((int32_t)rhs.value));
    } else {
      ScratchRegisterScope scratch(asMasm());
      movePtr(rhs, scratch);
      cmpPtr(lhs, scratch);
    }
  }
  void cmpPtr(const Operand& lhs, const ImmPtr rhs) {
    cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
  }
  void cmpPtr(const Address& lhs, const ImmGCPtr rhs) {
    cmpPtr(Operand(lhs), rhs);
  }
  void cmpPtr(const Address& lhs, const ImmWord rhs) {
    cmpPtr(Operand(lhs), rhs);
  }
  void cmpPtr(const Address& lhs, const ImmPtr rhs) {
    cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
  }
  void cmpPtr(const Operand& lhs, Register rhs) { cmpq(rhs, lhs); }
  void cmpPtr(Register lhs, const Operand& rhs) { cmpq(rhs, lhs); }
  void cmpPtr(const Operand& lhs, const Imm32 rhs) { cmpq(rhs, lhs); }
  void cmpPtr(const Address& lhs, Register rhs) { cmpPtr(Operand(lhs), rhs); }
  void cmpPtr(Register lhs, Register rhs) { cmpq(rhs, lhs); }
  void testPtr(Register lhs, Register rhs) { testq(rhs, lhs); }
  void testPtr(Register lhs, Imm32 rhs) { testq(rhs, lhs); }
  void testPtr(Register lhs, ImmWord rhs) { test64(lhs, Imm64(rhs.value)); }
  void testPtr(const Operand& lhs, Imm32 rhs) { testq(rhs, lhs); }
  void test64(Register lhs, Register rhs) { testq(rhs, lhs); }
  void test64(Register lhs, const Imm64 rhs) {
    if ((intptr_t)rhs.value <= INT32_MAX && (intptr_t)rhs.value >= INT32_MIN) {
      testq(Imm32((int32_t)rhs.value), lhs);
    } else {
      ScratchRegisterScope scratch(asMasm());
      movq(ImmWord(rhs.value), scratch);
      testq(scratch, lhs);
    }
  }

  // Compare-then-conditionally-move/load, for integer types
  template <size_t CmpSize, size_t MoveSize>
  void cmpMove(Condition cond, Register lhs, Register rhs, Register falseVal,
               Register trueValAndDest);

  template <size_t CmpSize, size_t MoveSize>
  void cmpMove(Condition cond, Register lhs, const Address& rhs,
               Register falseVal, Register trueValAndDest);

  template <size_t CmpSize, size_t LoadSize>
  void cmpLoad(Condition cond, Register lhs, Register rhs,
               const Address& falseVal, Register trueValAndDest);

  template <size_t CmpSize, size_t LoadSize>
  void cmpLoad(Condition cond, Register lhs, const Address& rhs,
               const Address& falseVal, Register trueValAndDest);

  /////////////////////////////////////////////////////////////////
  // Common interface.
  /////////////////////////////////////////////////////////////////

  void movePtr(Register src, Register dest) { movq(src, dest); }
  void movePtr(Register src, const Operand& dest) { movq(src, dest); }
  void movePtr(ImmWord imm, Register dest) { mov(imm, dest); }
  void movePtr(ImmPtr imm, Register dest) { mov(imm, dest); }
  void movePtr(wasm::SymbolicAddress imm, Register dest) { mov(imm, dest); }
  void movePtr(ImmGCPtr imm, Register dest) { movq(imm, dest); }
  void loadPtr(AbsoluteAddress address, Register dest) {
    if (X86Encoding::IsAddressImmediate(address.addr)) {
      movq(Operand(address), dest);
    } else {
      ScratchRegisterScope scratch(asMasm());
      mov(ImmPtr(address.addr), scratch);
      loadPtr(Address(scratch, 0x0), dest);
    }
  }
  FaultingCodeOffset loadPtr(const Address& address, Register dest) {
    FaultingCodeOffset fco = FaultingCodeOffset(currentOffset());
    movq(Operand(address), dest);
    return fco;
  }
  void load64(const Address& address, Register dest) {
    movq(Operand(address), dest);
  }
  void loadPtr(const Operand& src, Register dest) { movq(src, dest); }
  FaultingCodeOffset loadPtr(const BaseIndex& src, Register dest) {
    FaultingCodeOffset fco = FaultingCodeOffset(currentOffset());
    movq(Operand(src), dest);
    return fco;
  }
  void loadPrivate(const Address& src, Register dest) { loadPtr(src, dest); }
  void load32(AbsoluteAddress address, Register dest) {
    if (X86Encoding::IsAddressImmediate(address.addr)) {
      movl(Operand(address), dest);
    } else {
      ScratchRegisterScope scratch(asMasm());
      mov(ImmPtr(address.addr), scratch);
      load32(Address(scratch, 0x0), dest);
    }
  }
  void load64(const Operand& address, Register64 dest) {
    movq(address, dest.reg);
  }
  FaultingCodeOffset load64(const Address& address, Register64 dest) {
    FaultingCodeOffset fco = FaultingCodeOffset(currentOffset());
    movq(Operand(address), dest.reg);
    return fco;
  }
  FaultingCodeOffset load64(const BaseIndex& address, Register64 dest) {
    FaultingCodeOffset fco = FaultingCodeOffset(currentOffset());
    movq(Operand(address), dest.reg);
    return fco;
  }
  template <typename S>
  void load64Unaligned(const S& src, Register64 dest) {
    load64(src, dest);
  }
  template <typename T>
  void storePtr(ImmWord imm, T address) {
    if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) {
      movq(Imm32((int32_t)imm.value), Operand(address));
    } else {
      ScratchRegisterScope scratch(asMasm());
      mov(imm, scratch);
      movq(scratch, Operand(address));
    }
  }
  template <typename T>
  void storePtr(ImmPtr imm, T address) {
    storePtr(ImmWord(uintptr_t(imm.value)), address);
  }
  template <typename T>
  void storePtr(ImmGCPtr imm, T address) {
    ScratchRegisterScope scratch(asMasm());
    movq(imm, scratch);
    movq(scratch, Operand(address));
  }
  FaultingCodeOffset storePtr(Register src, const Address& address) {
    FaultingCodeOffset fco = FaultingCodeOffset(currentOffset());
    movq(src, Operand(address));
    return fco;
  }
  void store64(Register src, const Address& address) {
    movq(src, Operand(address));
  }
  void store64(Register64 src, const Operand& address) {
    movq(src.reg, address);
  }
  FaultingCodeOffset storePtr(Register src, const BaseIndex& address) {
    FaultingCodeOffset fco = FaultingCodeOffset(currentOffset());
    movq(src, Operand(address));
    return fco;
  }
  void storePtr(Register src, const Operand& dest) { movq(src, dest); }
  void storePtr(Register src, AbsoluteAddress address) {
    if (X86Encoding::IsAddressImmediate(address.addr)) {
      movq(src, Operand(address));
    } else {
      ScratchRegisterScope scratch(asMasm());
      mov(ImmPtr(address.addr), scratch);
      storePtr(src, Address(scratch, 0x0));
    }
  }
  void store32(Register src, AbsoluteAddress address) {
    if (X86Encoding::IsAddressImmediate(address.addr)) {
      movl(src, Operand(address));
    } else {
      ScratchRegisterScope scratch(asMasm());
      mov(ImmPtr(address.addr), scratch);
      store32(src, Address(scratch, 0x0));
    }
  }
  void store16(Register src, AbsoluteAddress address) {
    if (X86Encoding::IsAddressImmediate(address.addr)) {
      movw(src, Operand(address));
    } else {
      ScratchRegisterScope scratch(asMasm());
      mov(ImmPtr(address.addr), scratch);
      store16(src, Address(scratch, 0x0));
    }
  }
  FaultingCodeOffset store64(Register64 src, Address address) {
    FaultingCodeOffset fco = FaultingCodeOffset(currentOffset());
    storePtr(src.reg, address);
    return fco;
  }
  FaultingCodeOffset store64(Register64 src, const BaseIndex& address) {
    return storePtr(src.reg, address);
  }
  void store64(Imm64 imm, Address address) {
    storePtr(ImmWord(imm.value), address);
  }
  void store64(Imm64 imm, const BaseIndex& address) {
    storePtr(ImmWord(imm.value), address);
  }
  template <typename S, typename T>
  void store64Unaligned(const S& src, const T& dest) {
    store64(src, dest);
  }

  void splitTag(Register src, Register dest) {
    if (src != dest) {
      movq(src, dest);
    }
    shrq(Imm32(JSVAL_TAG_SHIFT), dest);
  }
  void splitTag(const ValueOperand& operand, Register dest) {
    splitTag(operand.valueReg(), dest);
  }
  void splitTag(const Operand& operand, Register dest) {
    movq(operand, dest);
    shrq(Imm32(JSVAL_TAG_SHIFT), dest);
  }
  void splitTag(const Address& operand, Register dest) {
    splitTag(Operand(operand), dest);
  }
  void splitTag(const BaseIndex& operand, Register dest) {
    splitTag(Operand(operand), dest);
  }

  // Extracts the tag of a value and places it in tag.
  void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag) {
    splitTag(value, tag);
  }
  void cmpTag(const ValueOperand& operand, ImmTag tag) {
    ScratchTagScope reg(asMasm(), operand);
    splitTagForTest(operand, reg);
    cmp32(reg, tag);
  }

  Condition testMagic(Condition cond, const ValueOperand& src) {
    ScratchTagScope scratch(asMasm(), src);
    splitTagForTest(src, scratch);
    return testMagic(cond, scratch);
  }
  Condition testError(Condition cond, const ValueOperand& src) {
    return testMagic(cond, src);
  }

  void testNullSet(Condition cond, const ValueOperand& value, Register dest) {
    bool destIsZero = maybeEmitSetZeroByteRegister(value, dest);
    cond = testNull(cond, value);
    emitSet(cond, dest, destIsZero);
  }

  void testObjectSet(Condition cond, const ValueOperand& value, Register dest) {
    bool destIsZero = maybeEmitSetZeroByteRegister(value, dest);
    cond = testObject(cond, value);
    emitSet(cond, dest, destIsZero);
  }

  void testUndefinedSet(Condition cond, const ValueOperand& value,
                        Register dest) {
    bool destIsZero = maybeEmitSetZeroByteRegister(value, dest);
    cond = testUndefined(cond, value);
    emitSet(cond, dest, destIsZero);
  }

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

  // Note that the |dest| register here may be ScratchReg, so we shouldn't
  // use it.
  void unboxInt32(const ValueOperand& src, Register dest) {
    movl(src.valueReg(), dest);
  }
  void unboxInt32(const Operand& src, Register dest) { movl(src, dest); }
  void unboxInt32(const Address& src, Register dest) {
    unboxInt32(Operand(src), dest);
  }
  void unboxInt32(const BaseIndex& src, Register dest) {
    unboxInt32(Operand(src), dest);
  }
  template <typename T>
  void unboxDouble(const T& src, FloatRegister dest) {
    loadDouble(Operand(src), dest);
  }

  void unboxArgObjMagic(const ValueOperand& src, Register dest) {
    unboxArgObjMagic(Operand(src.valueReg()), dest);
  }
  void unboxArgObjMagic(const Operand& src, Register dest) {
    mov(ImmWord(0), dest);
  }
  void unboxArgObjMagic(const Address& src, Register dest) {
    unboxArgObjMagic(Operand(src), dest);
  }

  void unboxBoolean(const ValueOperand& src, Register dest) {
    movl(src.valueReg(), dest);
  }
  void unboxBoolean(const Operand& src, Register dest) { movl(src, dest); }
  void unboxBoolean(const Address& src, Register dest) {
    unboxBoolean(Operand(src), dest);
  }
  void unboxBoolean(const BaseIndex& src, Register dest) {
    unboxBoolean(Operand(src), dest);
  }

  void unboxMagic(const ValueOperand& src, Register dest) {
    movl(src.valueReg(), dest);
  }

  void unboxDouble(const ValueOperand& src, FloatRegister dest) {
    vmovq(src.valueReg(), dest);
  }

  void notBoolean(const ValueOperand& val) { xorq(Imm32(1), val.valueReg()); }

  void unboxNonDouble(const ValueOperand& src, Register dest,
                      JSValueType type) {
    MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
    if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
      movl(src.valueReg(), dest);
      return;
    }
    if (src.valueReg() == dest) {
      ScratchRegisterScope scratch(asMasm());
      mov(ImmShiftedTag(type), scratch);
      xorq(scratch, dest);
    } else {
      mov(ImmShiftedTag(type), dest);
      xorq(src.valueReg(), dest);
    }
  }
  void unboxNonDouble(const Operand& src, Register dest, JSValueType type) {
    MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
    if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
      movl(src, dest);
      return;
    }
    // Explicitly permits |dest| to be used in |src|.
    ScratchRegisterScope scratch(asMasm());
    MOZ_ASSERT(dest != scratch);
    if (src.containsReg(dest)) {
      mov(ImmShiftedTag(type), scratch);
      // If src is already a register, then src and dest are the same
      // thing and we don't need to move anything into dest.
      if (src.kind() != Operand::REG) {
        movq(src, dest);
      }
      xorq(scratch, dest);
    } else {
      mov(ImmShiftedTag(type), dest);
      xorq(src, dest);
    }
  }
  void unboxNonDouble(const Address& src, Register dest, JSValueType type) {
    unboxNonDouble(Operand(src), dest, type);
  }
  void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType type) {
    unboxNonDouble(Operand(src), dest, type);
  }

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

  void unboxSymbol(const ValueOperand& src, Register dest) {
    unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
  }
  void unboxSymbol(const Operand& src, Register dest) {
    unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
  }

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

  void unboxObject(const ValueOperand& src, Register dest) {
    unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
  }
  void unboxObject(const Operand& src, Register dest) {
    unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
  }
  void unboxObject(const Address& src, Register dest) {
    unboxNonDouble(Operand(src), dest, JSVAL_TYPE_OBJECT);
  }
  void unboxObject(const BaseIndex& src, Register dest) {
    unboxNonDouble(Operand(src), dest, JSVAL_TYPE_OBJECT);
  }

  template <typename T>
  void unboxObjectOrNull(const T& src, Register dest) {
    unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
    ScratchRegisterScope scratch(asMasm());
    mov(ImmWord(~JS::detail::ValueObjectOrNullBit), scratch);
    andq(scratch, dest);
  }

  // This should only be used for GC barrier code, to unbox a GC thing Value.
  // It's fine there because we don't depend on the actual Value type (all Cells
  // are treated the same way). In almost all other cases this would be
  // Spectre-unsafe - use unboxNonDouble and friends instead.
  void unboxGCThingForGCBarrier(const Address& src, Register dest) {
    movq(ImmWord(JS::detail::ValueGCThingPayloadMask), dest);
    andq(Operand(src), dest);
  }
  void unboxGCThingForGCBarrier(const ValueOperand& src, Register dest) {
    MOZ_ASSERT(src.valueReg() != dest);
    movq(ImmWord(JS::detail::ValueGCThingPayloadMask), dest);
    andq(src.valueReg(), dest);
  }

  void unboxWasmAnyRefGCThingForGCBarrier(const Address& src, Register dest) {
    movq(ImmWord(wasm::AnyRef::GCThingMask), dest);
    andq(Operand(src), dest);
  }

  // Like unboxGCThingForGCBarrier, but loads the GC thing's chunk base.
  void getGCThingValueChunk(const Address& src, Register dest) {
    movq(ImmWord(JS::detail::ValueGCThingPayloadChunkMask), dest);
    andq(Operand(src), dest);
  }
  void getGCThingValueChunk(const ValueOperand& src, Register dest) {
    MOZ_ASSERT(src.valueReg() != dest);
    movq(ImmWord(JS::detail::ValueGCThingPayloadChunkMask), dest);
    andq(src.valueReg(), dest);
  }

  void getWasmAnyRefGCThingChunk(Register src, Register dest) {
    MOZ_ASSERT(src != dest);
    movq(ImmWord(wasm::AnyRef::GCThingChunkMask), dest);
    andq(src, dest);
  }

  inline void fallibleUnboxPtrImpl(const Operand& src, Register dest,
                                   JSValueType type, Label* fail);

  // Extended unboxing API. If the payload is already in a register, returns
  // that register. Otherwise, provides a move to the given scratch register,
  // and returns that.
  [[nodiscard]] Register extractObject(const Address& address,
                                       Register scratch) {
    MOZ_ASSERT(scratch != ScratchReg);
    unboxObject(address, scratch);
    return scratch;
  }
  [[nodiscard]] Register extractObject(const ValueOperand& value,
                                       Register scratch) {
    MOZ_ASSERT(scratch != ScratchReg);
    unboxObject(value, scratch);
    return scratch;
  }
  [[nodiscard]] Register extractSymbol(const ValueOperand& value,
                                       Register scratch) {
    MOZ_ASSERT(scratch != ScratchReg);
    unboxSymbol(value, scratch);
    return scratch;
  }
  [[nodiscard]] Register extractInt32(const ValueOperand& value,
                                      Register scratch) {
    MOZ_ASSERT(scratch != ScratchReg);
    unboxInt32(value, scratch);
    return scratch;
  }
  [[nodiscard]] Register extractBoolean(const ValueOperand& value,
                                        Register scratch) {
    MOZ_ASSERT(scratch != ScratchReg);
    unboxBoolean(value, scratch);
    return scratch;
  }
  [[nodiscard]] Register extractTag(const Address& address, Register scratch) {
    MOZ_ASSERT(scratch != ScratchReg);
    loadPtr(address, scratch);
    splitTag(scratch, scratch);
    return scratch;
  }
  [[nodiscard]] Register extractTag(const ValueOperand& value,
                                    Register scratch) {
    MOZ_ASSERT(scratch != ScratchReg);
    splitTag(value, scratch);
    return scratch;
  }

  inline void unboxValue(const ValueOperand& src, AnyRegister dest,
                         JSValueType type);

  void loadConstantDouble(double d, FloatRegister dest);
  void loadConstantFloat32(float f, FloatRegister dest);

  void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest);
  void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest);
  void vpaddbSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vpaddwSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vpadddSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vpaddqSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vpsubbSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vpsubwSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vpsubdSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vpsubqSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vpmullwSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpmulldSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpaddsbSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpaddusbSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vpaddswSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpadduswSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vpsubsbSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpsubusbSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vpsubswSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpsubuswSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vpminsbSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpminubSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpminswSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpminuwSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpminsdSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpminudSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpmaxsbSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpmaxubSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpmaxswSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpmaxuwSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpmaxsdSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpmaxudSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vpandSimd128(const SimdConstant& v, FloatRegister lhs,
                    FloatRegister dest);
  void vpxorSimd128(const SimdConstant& v, FloatRegister lhs,
                    FloatRegister dest);
  void vporSimd128(const SimdConstant& v, FloatRegister lhs,
                   FloatRegister dest);
  void vaddpsSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vaddpdSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vsubpsSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vsubpdSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vdivpsSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vdivpdSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vmulpsSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vmulpdSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vandpdSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vminpdSimd128(const SimdConstant& v, FloatRegister lhs,
                     FloatRegister dest);
  void vpacksswbSimd128(const SimdConstant& v, FloatRegister lhs,
                        FloatRegister dest);
  void vpackuswbSimd128(const SimdConstant& v, FloatRegister lhs,
                        FloatRegister dest);
  void vpackssdwSimd128(const SimdConstant& v, FloatRegister lhs,
                        FloatRegister dest);
  void vpackusdwSimd128(const SimdConstant& v, FloatRegister lhs,
                        FloatRegister dest);
  void vpunpckldqSimd128(const SimdConstant& v, FloatRegister lhs,
                         FloatRegister dest);
  void vunpcklpsSimd128(const SimdConstant& v, FloatRegister lhs,
                        FloatRegister dest);
  void vpshufbSimd128(const SimdConstant& v, FloatRegister lhs,
                      FloatRegister dest);
  void vptestSimd128(const SimdConstant& v, FloatRegister lhs);
  void vpmaddwdSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vpcmpeqbSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vpcmpgtbSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vpcmpeqwSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vpcmpgtwSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vpcmpeqdSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vpcmpgtdSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vcmpeqpsSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vcmpneqpsSimd128(const SimdConstant& v, FloatRegister lhs,
                        FloatRegister dest);
  void vcmpltpsSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vcmplepsSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vcmpgepsSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vcmpeqpdSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vcmpneqpdSimd128(const SimdConstant& v, FloatRegister lhs,
                        FloatRegister dest);
  void vcmpltpdSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vcmplepdSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);
  void vpmaddubswSimd128(const SimdConstant& v, FloatRegister lhs,
                         FloatRegister dest);
  void vpmuludqSimd128(const SimdConstant& v, FloatRegister lhs,
                       FloatRegister dest);

 public:
  Condition testInt32Truthy(bool truthy, const ValueOperand& operand) {
    test32(operand.valueReg(), operand.valueReg());
    return truthy ? NonZero : Zero;
  }
  Condition testStringTruthy(bool truthy, const ValueOperand& value);
  Condition testBigIntTruthy(bool truthy, const ValueOperand& value);

  template <typename T>
  inline void loadInt32OrDouble(const T& src, FloatRegister dest);

  template <typename T>
  void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) {
    if (dest.isFloat()) {
      loadInt32OrDouble(src, dest.fpu());
    } else {
      unboxNonDouble(Operand(src), dest.gpr(), ValueTypeFromMIRType(type));
    }
  }

  template <typename T>
  void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes,
                           JSValueType type) {
    switch (nbytes) {
      case 8: {
        ScratchRegisterScope scratch(asMasm());
        unboxNonDouble(value, scratch, type);
        storePtr(scratch, address);
        if (type == JSVAL_TYPE_OBJECT) {
          // Ideally we would call unboxObjectOrNull, but we need an extra
          // scratch register for that. So unbox as object, then clear the
          // object-or-null bit.
          mov(ImmWord(~JS::detail::ValueObjectOrNullBit), scratch);
          andq(scratch, Operand(address));
        }
        return;
      }
      case 4:
        store32(value.valueReg(), address);
        return;
      case 1:
        store8(value.valueReg(), address);
        return;
      default:
        MOZ_CRASH("Bad payload width");
    }
  }

  // Checks whether a double is representable as a 64-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 convertDoubleToPtr(FloatRegister src, Register dest, Label* fail,
                          bool negativeZeroCheck = true);

  void convertUInt32ToDouble(Register src, FloatRegister dest) {
    // Zero the output register to break dependencies, see convertInt32ToDouble.
    zeroDouble(dest);

    vcvtsq2sd(src, dest, dest);
  }

  void convertUInt32ToFloat32(Register src, FloatRegister dest) {
    // Zero the output register to break dependencies, see convertInt32ToDouble.
    zeroDouble(dest);

    vcvtsq2ss(src, dest, dest);
  }

  void truncateFloat32ModUint32(FloatRegister src, Register dest) {
    // vcvttss2sq returns 0x8000000000000000 on failure. It fails if
    // 1. The input is non-finite (NaN or ±Infinity).
    // 2. The input's exponent is at least 63.
    //
    // In both cases the input is too large for an int32 and the truncated
    // result is zero. So unconditionally zeroing the upper 32-bits gives the
    // correct result for all inputs.

    vcvttss2sq(src, dest);
    movl(dest, dest);  // Zero upper 32-bits.
  }

  inline void incrementInt32Value(const Address& addr);

 public:
  void handleFailureWithHandlerTail(Label* profilerExitTail, Label* bailoutTail,
                                    uint32_t* returnValueCheckOffset);

  // Instrumentation for entering and leaving the profiler.
  void profilerEnterFrame(Register framePtr, Register scratch);
  void profilerExitFrame();
};

using MacroAssemblerSpecific = MacroAssemblerX64;

}  // namespace jit
}  // namespace js

#endif /* jit_x64_MacroAssembler_x64_h */

Messung V0.5
C=95 H=99 G=96

¤ Dauer der Verarbeitung: 0.14 Sekunden  ¤

*© 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.