tor-browser

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

RegisterSets.h (45036B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef jit_RegisterSets_h
      8 #define jit_RegisterSets_h
      9 
     10 #include "mozilla/Assertions.h"
     11 #include "mozilla/Attributes.h"
     12 
     13 #include <new>
     14 #include <stddef.h>
     15 #include <stdint.h>
     16 
     17 #include "jit/IonTypes.h"
     18 #include "jit/Registers.h"
     19 #include "js/Value.h"
     20 
     21 /*
     22 * [SMDOC] Allocating registers by hand
     23 *
     24 * To reduce our maintenance burden, much of our codegen is written using an
     25 * architecture-independent macroassembler layer. All abstractions are leaky;
     26 * one of the main ways that the masm abstraction leaks is when it comes to
     27 * finding registers.
     28 *
     29 * The main constraint is 32-bit x86. There are eight general purpose registers
     30 * on 32-bit x86, but two of those (esp and ebp) are permanently claimed for the
     31 * stack pointer and the frame pointer, leaving six useful registers. JS::Value
     32 * is eight bytes, so 32-bit architectures require two registers to store Values
     33 * (one for the tag and one for the payload). Therefore, the most that
     34 * architecture-independent codegen can keep alive at one time is:
     35 *
     36 *      +------+---------+
     37 *      | GPRs |  Values |
     38 *      +------+---------+
     39 *      |  6   |    0    |
     40 *      |  4   |    1    |
     41 *      |  2   |    2    |
     42 *      |  0   |    3    |
     43 *      +------+---------+
     44 *
     45 * Hand-written masm (eg trampolines, stubs) often requires agreement between
     46 * the caller and the code itself about which values will be passed in which
     47 * registers. In such cases, we usually define a named register in a header:
     48 * either an arch-specific header, like RegExpMatcherRegExpReg in
     49 * jit/<arch>/Assembler-<arch>.h, or an arch-independent header like the
     50 * registers in jit/IonGenericCallStub.h.  For scratch registers in such code,
     51 * AllocatableGeneralRegisterSet can be used.
     52 *
     53 * Baseline deals primarily with boxed values, so we define three
     54 * architecture-independent ValueOperands (R0, R1, and R2). When individual
     55 * registers are needed, R<N>.scratchReg() can be used. If the sum of live
     56 * Values and GPRs is greater than three, then AllocatableGeneralRegisterSet
     57 * may be required.
     58 *
     59 * In baseline IC code, one additional register is dedicated to ICStubReg, so at
     60 * most five registers (or 3 registers + 1 Value, ...) are available. Temps can
     61 * be allocated using AutoScratchRegister. It's common for IC stubs to return a
     62 * Value; to free up the register pair used for that output on 32-bit platforms,
     63 * AutoScratchRegisterMaybeOutput/AutoScratchRegisterMaybeOutputType can be used
     64 * for values that are dead before writing to the output.
     65 *
     66 * If more registers are necessary, there are a variety of workarounds. In some
     67 * cases, the simplest answer is simply to disable an optimization on x86. We
     68 * still support it, but it's not a performance priority. For example, we don't
     69 * attach some specialized stubs for Map.get/has/set on x86. In other cases, it
     70 * may be possible to manually spill a register to the stack to temporarily free
     71 * it up. One useful pattern is to pass InvalidReg in cases where a register is
     72 * not available, and decide whether to spill depending on whether a real
     73 * register is free. See, for example, CacheIRCompiler::emitDataViewBoundsCheck.
     74 *
     75 *
     76 * ### CallTempReg, ABINonArgReg, ABINonArgReturnReg, et al
     77 *
     78 * There are other more-or-less architecture-independent register definitions
     79 * that can be useful. These include:
     80 *
     81 * - CallTempReg<0-5>: Six registers that are not part of the call machinery
     82 *   itself (not the stack pointer, frame pointer, or the link register). They
     83 *   are useful when setting up a call that does not use the system ABI. In Ion,
     84 *   JS uses these to allocate temporary registers for LIR ops that will
     85 *   generate a call. No more CallTempRegs can be added for use in architecture-
     86 *   independent code, because x86 doesn't have enough registers.
     87 *
     88 * - ABINonArgReg<0-3>: Four registers that are not part of the call machinery,
     89 *   and are also not used for passing arguments according to the system/Wasm
     90 *   ABI. These are primarily used for Wasm. ABINonArgReg4 could be added if
     91 *   needed. After that, we run out of registers on x86, because Wasm also pins
     92 *   the InstanceReg. See the "Wasm ABIs" SMDOC for more information.
     93 *
     94 * - ABINonArgReturnReg<0-1> / ABINonVolatileReg: Three registers that are not
     95 *   part of the call machinery, and not used by the system ABI for passing
     96 *   arguments or return values. ABINonVolatileReg is also required to have its
     97 *   value preserved over a call. This set is (again) constrained by x86: esp
     98 *   and ebp are claimed by the call machinery, eax/edx are return registers,
     99 *   and esi is the instance register.
    100 *   ABINonArgReturnVolatileReg is a register that is not used for calls but is
    101 *   *not* preserved over a call; it may or may not be the same as
    102 *   ABINonArgReturn<0-1>.
    103 */
    104 
    105 namespace js {
    106 namespace jit {
    107 
    108 struct AnyRegister {
    109  using Code = uint8_t;
    110 
    111  static const uint8_t Total = Registers::Total + FloatRegisters::Total;
    112  static const uint8_t FirstFloatReg = Registers::Total;
    113  static const uint8_t Invalid = UINT8_MAX;
    114 
    115  static_assert(size_t(Registers::Total) + FloatRegisters::Total <= UINT8_MAX,
    116                "Number of registers must fit in uint8_t");
    117 
    118 private:
    119  Code code_;
    120 
    121 public:
    122  AnyRegister() : code_(Invalid) {}
    123 
    124  explicit AnyRegister(Register gpr) { code_ = gpr.code(); }
    125  explicit AnyRegister(FloatRegister fpu) {
    126    code_ = fpu.code() + Registers::Total;
    127  }
    128  static AnyRegister FromCode(uint8_t i) {
    129    MOZ_ASSERT(i < Total);
    130    AnyRegister r;
    131    r.code_ = i;
    132    return r;
    133  }
    134  bool isFloat() const {
    135    MOZ_ASSERT(isValid());
    136    return code_ >= Registers::Total;
    137  }
    138  Register gpr() const {
    139    MOZ_ASSERT(!isFloat());
    140    return Register::FromCode(code_);
    141  }
    142  FloatRegister fpu() const {
    143    MOZ_ASSERT(isFloat());
    144    return FloatRegister::FromCode(code_ - Registers::Total);
    145  }
    146  bool operator==(AnyRegister other) const {
    147    // We don't need the operands to be valid to test for equality.
    148    return code_ == other.code_;
    149  }
    150  bool operator!=(AnyRegister other) const {
    151    // We don't need the operands to be valid to test for equality.
    152    return code_ != other.code_;
    153  }
    154  const char* name() const { return isFloat() ? fpu().name() : gpr().name(); }
    155  Code code() const {
    156    MOZ_ASSERT(isValid());
    157    return code_;
    158  }
    159  bool volatile_() const {
    160    return isFloat() ? fpu().volatile_() : gpr().volatile_();
    161  }
    162  AnyRegister aliased(uint8_t aliasIdx) const {
    163    AnyRegister ret;
    164    if (isFloat()) {
    165      ret = AnyRegister(fpu().aliased(aliasIdx));
    166    } else {
    167      ret = AnyRegister(gpr().aliased(aliasIdx));
    168    }
    169    MOZ_ASSERT_IF(aliasIdx == 0, ret == *this);
    170    return ret;
    171  }
    172  uint32_t numAliased() const {
    173    if (isFloat()) {
    174      return fpu().numAliased();
    175    }
    176    return gpr().numAliased();
    177  }
    178  bool aliases(const AnyRegister& other) const {
    179    if (isFloat() && other.isFloat()) {
    180      return fpu().aliases(other.fpu());
    181    }
    182    if (!isFloat() && !other.isFloat()) {
    183      return gpr().aliases(other.gpr());
    184    }
    185    return false;
    186  }
    187  // do the two registers hold the same type of data (e.g. both float32, both
    188  // gpr)
    189  bool isCompatibleReg(const AnyRegister other) const {
    190    if (isFloat() && other.isFloat()) {
    191      return fpu().equiv(other.fpu());
    192    }
    193    if (!isFloat() && !other.isFloat()) {
    194      return true;
    195    }
    196    return false;
    197  }
    198  bool isValid() const { return code_ != Invalid; }
    199 };
    200 
    201 // Registers to hold a boxed value. Uses one register on 64 bit
    202 // platforms, two registers on 32 bit platforms.
    203 class ValueOperand {
    204 #if defined(JS_NUNBOX32)
    205  Register type_;
    206  Register payload_;
    207 
    208 public:
    209  constexpr ValueOperand(Register type, Register payload)
    210      : type_(type), payload_(payload) {}
    211 
    212  constexpr Register typeReg() const { return type_; }
    213  constexpr Register payloadReg() const { return payload_; }
    214  constexpr Register64 toRegister64() const {
    215    return Register64(typeReg(), payloadReg());
    216  }
    217  constexpr bool aliases(Register reg) const {
    218    return type_ == reg || payload_ == reg;
    219  }
    220  constexpr Register payloadOrValueReg() const { return payloadReg(); }
    221  bool hasVolatileReg() const {
    222    return type_.volatile_() || payload_.volatile_();
    223  }
    224  constexpr bool operator==(const ValueOperand& o) const {
    225    return type_ == o.type_ && payload_ == o.payload_;
    226  }
    227  constexpr bool operator!=(const ValueOperand& o) const {
    228    return !(*this == o);
    229  }
    230 
    231 #elif defined(JS_PUNBOX64)
    232  Register value_;
    233 
    234 public:
    235  explicit constexpr ValueOperand(Register value) : value_(value) {}
    236 
    237  constexpr Register valueReg() const { return value_; }
    238  constexpr Register64 toRegister64() const { return Register64(valueReg()); }
    239  constexpr bool aliases(Register reg) const { return value_ == reg; }
    240  constexpr Register payloadOrValueReg() const { return valueReg(); }
    241  bool hasVolatileReg() const { return value_.volatile_(); }
    242  constexpr bool operator==(const ValueOperand& o) const {
    243    return value_ == o.value_;
    244  }
    245  constexpr bool operator!=(const ValueOperand& o) const {
    246    return !(*this == o);
    247  }
    248 #endif
    249 
    250  constexpr Register scratchReg() const { return payloadOrValueReg(); }
    251 
    252  ValueOperand() = default;
    253 };
    254 
    255 // Registers to hold either either a typed or untyped value.
    256 class TypedOrValueRegister {
    257  // Type of value being stored.
    258  MIRType type_;
    259 
    260  union U {
    261    AnyRegister::Code typed;
    262 #if defined(JS_PUNBOX64)
    263    Register::Code value;
    264 #elif defined(JS_NUNBOX32)
    265    struct {
    266      Register::Code valueType;
    267      Register::Code valuePayload;
    268    } s;
    269 #else
    270 #  error "Bad architecture"
    271 #endif
    272  } data;
    273 
    274 public:
    275  TypedOrValueRegister() = default;
    276 
    277  TypedOrValueRegister(MIRType type, AnyRegister reg) : type_(type) {
    278    data.typed = reg.code();
    279  }
    280 
    281  MOZ_IMPLICIT TypedOrValueRegister(ValueOperand value)
    282      : type_(MIRType::Value) {
    283 #if defined(JS_PUNBOX64)
    284    data.value = value.valueReg().code();
    285 #elif defined(JS_NUNBOX32)
    286    data.s.valueType = value.typeReg().code();
    287    data.s.valuePayload = value.payloadReg().code();
    288 #else
    289 #  error "Bad architecture"
    290 #endif
    291  }
    292 
    293  MIRType type() const { return type_; }
    294 
    295  bool hasTyped() const {
    296    return type() != MIRType::None && type() != MIRType::Value;
    297  }
    298 
    299  bool hasValue() const { return type() == MIRType::Value; }
    300 
    301  AnyRegister typedReg() const {
    302    MOZ_ASSERT(hasTyped());
    303    return AnyRegister::FromCode(data.typed);
    304  }
    305 
    306  ValueOperand valueReg() const {
    307    MOZ_ASSERT(hasValue());
    308 #if defined(JS_PUNBOX64)
    309    return ValueOperand(Register::FromCode(data.value));
    310 #elif defined(JS_NUNBOX32)
    311    return ValueOperand(Register::FromCode(data.s.valueType),
    312                        Register::FromCode(data.s.valuePayload));
    313 #else
    314 #  error "Bad architecture"
    315 #endif
    316  }
    317 
    318  AnyRegister scratchReg() {
    319    if (hasValue()) {
    320      return AnyRegister(valueReg().scratchReg());
    321    }
    322    return typedReg();
    323  }
    324 };
    325 
    326 // A constant value, or registers to hold a typed/untyped value.
    327 class ConstantOrRegister {
    328  // Whether a constant value is being stored.
    329  bool constant_;
    330 
    331  // Space to hold either a Value or a TypedOrValueRegister.
    332  union U {
    333    JS::Value constant;
    334    TypedOrValueRegister reg;
    335 
    336    // |constant| has a non-trivial constructor and therefore MUST be
    337    // placement-new'd into existence.
    338    MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
    339    U() {}
    340    MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
    341  } data;
    342 
    343 public:
    344  ConstantOrRegister() = delete;
    345 
    346  MOZ_IMPLICIT ConstantOrRegister(const JS::Value& value) : constant_(true) {
    347    MOZ_ASSERT(constant());
    348    new (&data.constant) JS::Value(value);
    349  }
    350 
    351  MOZ_IMPLICIT ConstantOrRegister(TypedOrValueRegister reg) : constant_(false) {
    352    MOZ_ASSERT(!constant());
    353    new (&data.reg) TypedOrValueRegister(reg);
    354  }
    355 
    356  bool constant() const { return constant_; }
    357 
    358  JS::Value value() const {
    359    MOZ_ASSERT(constant());
    360    return data.constant;
    361  }
    362 
    363  const TypedOrValueRegister& reg() const {
    364    MOZ_ASSERT(!constant());
    365    return data.reg;
    366  }
    367 };
    368 
    369 template <typename T>
    370 class TypedRegisterSet {
    371 public:
    372  using RegType = T;
    373  using SetType = typename T::SetType;
    374 
    375 private:
    376  SetType bits_;
    377 
    378 public:
    379  explicit constexpr TypedRegisterSet(SetType bits) : bits_(bits) {}
    380 
    381  constexpr TypedRegisterSet() : bits_(0) {}
    382  constexpr TypedRegisterSet(const TypedRegisterSet<T>& set)
    383      : bits_(set.bits_) {}
    384 
    385  static inline TypedRegisterSet All() {
    386    return TypedRegisterSet(T::Codes::AllocatableMask);
    387  }
    388  static inline TypedRegisterSet Intersect(const TypedRegisterSet& lhs,
    389                                           const TypedRegisterSet& rhs) {
    390    return TypedRegisterSet(lhs.bits_ & rhs.bits_);
    391  }
    392  static inline TypedRegisterSet Union(const TypedRegisterSet& lhs,
    393                                       const TypedRegisterSet& rhs) {
    394    return TypedRegisterSet(lhs.bits_ | rhs.bits_);
    395  }
    396  static inline TypedRegisterSet Not(const TypedRegisterSet& in) {
    397    return TypedRegisterSet(~in.bits_ & T::Codes::AllocatableMask);
    398  }
    399  static inline TypedRegisterSet Subtract(const TypedRegisterSet& lhs,
    400                                          const TypedRegisterSet& rhs) {
    401    return TypedRegisterSet(lhs.bits_ & ~rhs.bits_);
    402  }
    403  static inline TypedRegisterSet VolatileNot(const TypedRegisterSet& in) {
    404    const SetType allocatableVolatile =
    405        T::Codes::AllocatableMask & T::Codes::VolatileMask;
    406    return TypedRegisterSet(~in.bits_ & allocatableVolatile);
    407  }
    408  static inline TypedRegisterSet Volatile() {
    409    return TypedRegisterSet(T::Codes::AllocatableMask & T::Codes::VolatileMask);
    410  }
    411  static inline TypedRegisterSet NonVolatile() {
    412    return TypedRegisterSet(T::Codes::AllocatableMask &
    413                            T::Codes::NonVolatileMask);
    414  }
    415 
    416  bool empty() const { return !bits_; }
    417  void clear() { bits_ = 0; }
    418 
    419  bool hasRegisterIndex(T reg) const {
    420    return !!(bits_ & (SetType(1) << reg.code()));
    421  }
    422  bool hasAllocatable(T reg) const {
    423    return !(~bits_ & reg.alignedOrDominatedAliasedSet());
    424  }
    425 
    426  void addRegisterIndex(T reg) { bits_ |= (SetType(1) << reg.code()); }
    427  void addAllocatable(T reg) { bits_ |= reg.alignedOrDominatedAliasedSet(); }
    428 
    429  void takeRegisterIndex(T reg) { bits_ &= ~(SetType(1) << reg.code()); }
    430  void takeAllocatable(T reg) { bits_ &= ~reg.alignedOrDominatedAliasedSet(); }
    431 
    432  static constexpr RegTypeName DefaultType = RegType::DefaultType;
    433 
    434  template <RegTypeName Name>
    435  SetType allLive() const {
    436    return T::template LiveAsIndexableSet<Name>(bits_);
    437  }
    438  template <RegTypeName Name>
    439  SetType allAllocatable() const {
    440    return T::template AllocatableAsIndexableSet<Name>(bits_);
    441  }
    442 
    443  static RegType FirstRegister(SetType set) {
    444    return RegType::FromCode(RegType::FirstBit(set));
    445  }
    446  static RegType LastRegister(SetType set) {
    447    return RegType::FromCode(RegType::LastBit(set));
    448  }
    449 
    450  SetType bits() const { return bits_; }
    451  uint32_t size() const { return T::SetSize(bits_); }
    452  bool operator==(const TypedRegisterSet<T>& other) const {
    453    return other.bits_ == bits_;
    454  }
    455  TypedRegisterSet<T> reduceSetForPush() const {
    456    return T::ReduceSetForPush(*this);
    457  }
    458  uint32_t getPushSizeInBytes() const { return T::GetPushSizeInBytes(*this); }
    459 
    460  size_t offsetOfPushedRegister(RegType reg) const {
    461    MOZ_ASSERT(hasRegisterIndex(reg));
    462    return T::OffsetOfPushedRegister(bits(), reg);
    463  }
    464 };
    465 
    466 using GeneralRegisterSet = TypedRegisterSet<Register>;
    467 using FloatRegisterSet = TypedRegisterSet<FloatRegister>;
    468 
    469 class AnyRegisterIterator;
    470 
    471 class RegisterSet {
    472  GeneralRegisterSet gpr_;
    473  FloatRegisterSet fpu_;
    474 
    475  friend class AnyRegisterIterator;
    476 
    477 public:
    478  RegisterSet() = default;
    479  constexpr RegisterSet(const GeneralRegisterSet& gpr,
    480                        const FloatRegisterSet& fpu)
    481      : gpr_(gpr), fpu_(fpu) {}
    482  static inline RegisterSet All() {
    483    return RegisterSet(GeneralRegisterSet::All(), FloatRegisterSet::All());
    484  }
    485  static inline RegisterSet Intersect(const RegisterSet& lhs,
    486                                      const RegisterSet& rhs) {
    487    return RegisterSet(GeneralRegisterSet::Intersect(lhs.gpr_, rhs.gpr_),
    488                       FloatRegisterSet::Intersect(lhs.fpu_, rhs.fpu_));
    489  }
    490  static inline RegisterSet Union(const RegisterSet& lhs,
    491                                  const RegisterSet& rhs) {
    492    return RegisterSet(GeneralRegisterSet::Union(lhs.gpr_, rhs.gpr_),
    493                       FloatRegisterSet::Union(lhs.fpu_, rhs.fpu_));
    494  }
    495  static inline RegisterSet Not(const RegisterSet& in) {
    496    return RegisterSet(GeneralRegisterSet::Not(in.gpr_),
    497                       FloatRegisterSet::Not(in.fpu_));
    498  }
    499  static inline RegisterSet Subtract(const RegisterSet& lhs,
    500                                     const RegisterSet& rhs) {
    501    return RegisterSet(GeneralRegisterSet::Subtract(lhs.gpr_, rhs.gpr_),
    502                       FloatRegisterSet::Subtract(lhs.fpu_, rhs.fpu_));
    503  }
    504  static inline RegisterSet VolatileNot(const RegisterSet& in) {
    505    return RegisterSet(GeneralRegisterSet::VolatileNot(in.gpr_),
    506                       FloatRegisterSet::VolatileNot(in.fpu_));
    507  }
    508  static inline RegisterSet Volatile() {
    509    return RegisterSet(GeneralRegisterSet::Volatile(),
    510                       FloatRegisterSet::Volatile());
    511  }
    512 
    513  bool empty() const { return fpu_.empty() && gpr_.empty(); }
    514  void clear() {
    515    fpu_.clear();
    516    gpr_.clear();
    517  }
    518  bool emptyGeneral() const { return gpr_.empty(); }
    519  bool emptyFloat() const { return fpu_.empty(); }
    520 
    521  static constexpr RegTypeName DefaultType = RegTypeName::GPR;
    522 
    523  constexpr GeneralRegisterSet gprs() const { return gpr_; }
    524  GeneralRegisterSet& gprs() { return gpr_; }
    525  constexpr FloatRegisterSet fpus() const { return fpu_; }
    526  FloatRegisterSet& fpus() { return fpu_; }
    527  bool operator==(const RegisterSet& other) const {
    528    return other.gpr_ == gpr_ && other.fpu_ == fpu_;
    529  }
    530 };
    531 
    532 // [SMDOC] JIT Register-Set overview
    533 //
    534 // There are 2 use cases for register sets:
    535 //
    536 //   1. To serve as a pool of allocatable register. This is useful for working
    537 //      on the code produced by some stub where free registers are available, or
    538 //      when we can release some registers.
    539 //
    540 //   2. To serve as a list of typed registers. This is useful for working with
    541 //      live registers and to manipulate them with the proper instructions. This
    542 //      is used by the register allocator to fill the Safepoints.
    543 //
    544 // These 2 uses cases can be used on top of 3 different backend representation
    545 // of register sets, which are either GeneralRegisterSet, FloatRegisterSet, or
    546 // RegisterSet (for both). These classes are used to store the bit sets to
    547 // represent each register.
    548 //
    549 // Each use case defines an Accessor class, such as AllocatableSetAccessor or
    550 // LiveSetAccessor, which is parameterized with the type of the register
    551 // set. These accessors are in charge of manipulating the register set in a
    552 // consistent way.
    553 //
    554 // The RegSetCommonInterface class is used to wrap the accessors with convenient
    555 // shortcuts which are based on the accessors.
    556 //
    557 // Then, to avoid to many levels of complexity while using these interfaces,
    558 // shortcut templates are created to make it easy to distinguish between a
    559 // register set used for allocating registers, or a register set used for making
    560 // a collection of allocated (live) registers.
    561 //
    562 // This separation exists to prevent mixing LiveSet and AllocatableSet
    563 // manipulations of the same register set, and ensure safety while avoiding
    564 // false positive.
    565 
    566 template <typename RegisterSet>
    567 class AllocatableSet;
    568 
    569 template <typename RegisterSet>
    570 class LiveSet;
    571 
    572 // [SMDOC] JIT Register-Set (Allocatable)
    573 //
    574 // Base accessors classes have the minimal set of raw methods to manipulate the
    575 // register set given as parameter in a consistent manner.  These methods are:
    576 //
    577 //    - all<Type>: Returns a bit-set of all the register of a specific type
    578 //      which are present.
    579 //
    580 //    - has: Returns if all the bits needed to take a register are present.
    581 //
    582 //    - takeUnchecked: Subtracts the bits used to represent the register in the
    583 //      register set.
    584 //
    585 //    - addUnchecked: Adds the bits used to represent the register in the
    586 //      register set.
    587 
    588 // The AllocatableSet accessors are used to make a pool of unused
    589 // registers. Taking or adding registers should consider the aliasing rules of
    590 // the architecture.  For example, on ARM, the following piece of code should
    591 // work fine, knowing that the double register |d0| is composed of float
    592 // registers |s0| and |s1|:
    593 //
    594 //     AllocatableFloatRegisterSet regs;
    595 //     regs.add(s0);
    596 //     regs.add(s1);
    597 //     // d0 is now available.
    598 //     regs.take(d0);
    599 //
    600 // These accessors are useful for allocating registers within the functions used
    601 // to generate stubs, trampolines, and inline caches (BaselineIC, IonCache).
    602 template <typename Set>
    603 class AllocatableSetAccessors {
    604 public:
    605  using RegSet = Set;
    606  using RegType = typename RegSet::RegType;
    607  using SetType = typename RegSet::SetType;
    608 
    609 protected:
    610  RegSet set_;
    611 
    612  template <RegTypeName Name>
    613  SetType all() const {
    614    return set_.template allAllocatable<Name>();
    615  }
    616 
    617 public:
    618  AllocatableSetAccessors() : set_() {}
    619  explicit constexpr AllocatableSetAccessors(SetType set) : set_(set) {}
    620  explicit constexpr AllocatableSetAccessors(RegSet set) : set_(set) {}
    621 
    622  bool has(RegType reg) const { return set_.hasAllocatable(reg); }
    623 
    624  template <RegTypeName Name>
    625  bool hasAny(RegType reg) const {
    626    return all<Name>() != 0;
    627  }
    628 
    629  void addUnchecked(RegType reg) { set_.addAllocatable(reg); }
    630 
    631  void takeUnchecked(RegType reg) { set_.takeAllocatable(reg); }
    632 };
    633 
    634 // Specialization of the AllocatableSet accessors for the RegisterSet aggregate.
    635 template <>
    636 class AllocatableSetAccessors<RegisterSet> {
    637 public:
    638  using RegSet = RegisterSet;
    639  using RegType = AnyRegister;
    640  using SetType = char;
    641 
    642 protected:
    643  RegisterSet set_;
    644 
    645  template <RegTypeName Name>
    646  GeneralRegisterSet::SetType allGpr() const {
    647    return set_.gprs().allAllocatable<Name>();
    648  }
    649  template <RegTypeName Name>
    650  FloatRegisterSet::SetType allFpu() const {
    651    return set_.fpus().allAllocatable<Name>();
    652  }
    653 
    654 public:
    655  AllocatableSetAccessors() = default;
    656  explicit constexpr AllocatableSetAccessors(SetType) = delete;
    657  explicit constexpr AllocatableSetAccessors(RegisterSet set) : set_(set) {}
    658 
    659  bool has(Register reg) const { return set_.gprs().hasAllocatable(reg); }
    660  bool has(FloatRegister reg) const { return set_.fpus().hasAllocatable(reg); }
    661 
    662  void addUnchecked(Register reg) { set_.gprs().addAllocatable(reg); }
    663  void addUnchecked(FloatRegister reg) { set_.fpus().addAllocatable(reg); }
    664 
    665  void takeUnchecked(Register reg) { set_.gprs().takeAllocatable(reg); }
    666  void takeUnchecked(FloatRegister reg) { set_.fpus().takeAllocatable(reg); }
    667 };
    668 
    669 // [SMDOC] JIT Register-Set (Live)
    670 //
    671 // The LiveSet accessors are used to collect a list of allocated
    672 // registers. Taking or adding a register should *not* consider the aliases, as
    673 // we care about interpreting the registers with the correct type.  For example,
    674 // on x64, where one float registers can be interpreted as an Simd128, a Double,
    675 // or a Float, adding xmm0 as an Simd128, does not make the register available
    676 // as a Double.
    677 //
    678 //     LiveFloatRegisterSet regs;
    679 //     regs.add(xmm0.asSimd128());
    680 //     regs.take(xmm0); // Assert!
    681 //
    682 // These accessors are useful for recording the result of a register allocator,
    683 // such as what the Backtracking allocator do on the Safepoints.
    684 template <typename Set>
    685 class LiveSetAccessors {
    686 public:
    687  using RegSet = Set;
    688  using RegType = typename RegSet::RegType;
    689  using SetType = typename RegSet::SetType;
    690 
    691 protected:
    692  RegSet set_;
    693 
    694  template <RegTypeName Name>
    695  SetType all() const {
    696    return set_.template allLive<Name>();
    697  }
    698 
    699 public:
    700  LiveSetAccessors() : set_() {}
    701  explicit constexpr LiveSetAccessors(SetType set) : set_(set) {}
    702  explicit constexpr LiveSetAccessors(RegSet set) : set_(set) {}
    703 
    704  bool has(RegType reg) const { return set_.hasRegisterIndex(reg); }
    705 
    706  void addUnchecked(RegType reg) { set_.addRegisterIndex(reg); }
    707 
    708  void takeUnchecked(RegType reg) { set_.takeRegisterIndex(reg); }
    709 };
    710 
    711 // Specialization of the LiveSet accessors for the RegisterSet aggregate.
    712 template <>
    713 class LiveSetAccessors<RegisterSet> {
    714 public:
    715  using RegSet = RegisterSet;
    716  using RegType = AnyRegister;
    717  using SetType = char;
    718 
    719 protected:
    720  RegisterSet set_;
    721 
    722  template <RegTypeName Name>
    723  GeneralRegisterSet::SetType allGpr() const {
    724    return set_.gprs().allLive<Name>();
    725  }
    726  template <RegTypeName Name>
    727  FloatRegisterSet::SetType allFpu() const {
    728    return set_.fpus().allLive<Name>();
    729  }
    730 
    731 public:
    732  LiveSetAccessors() = default;
    733  explicit constexpr LiveSetAccessors(SetType) = delete;
    734  explicit constexpr LiveSetAccessors(RegisterSet set) : set_(set) {}
    735 
    736  bool has(Register reg) const { return set_.gprs().hasRegisterIndex(reg); }
    737  bool has(FloatRegister reg) const {
    738    return set_.fpus().hasRegisterIndex(reg);
    739  }
    740 
    741  void addUnchecked(Register reg) { set_.gprs().addRegisterIndex(reg); }
    742  void addUnchecked(FloatRegister reg) { set_.fpus().addRegisterIndex(reg); }
    743 
    744  void takeUnchecked(Register reg) { set_.gprs().takeRegisterIndex(reg); }
    745  void takeUnchecked(FloatRegister reg) { set_.fpus().takeRegisterIndex(reg); }
    746 };
    747 
    748 #define DEFINE_ACCESSOR_CONSTRUCTORS_(REGSET)             \
    749  using typename Parent::RegSet;                          \
    750  using typename Parent::RegType;                         \
    751  using typename Parent::SetType;                         \
    752                                                          \
    753  constexpr REGSET() : Parent() {}                        \
    754  explicit constexpr REGSET(SetType set) : Parent(set) {} \
    755  explicit constexpr REGSET(RegSet set) : Parent(set) {}
    756 
    757 // This class adds checked accessors on top of the unchecked variants defined by
    758 // AllocatableSet and LiveSet accessors. Also it defines interface which are
    759 // specialized to the register set implementation, such as |getAny| and
    760 // |takeAny| variants.
    761 template <class Accessors, typename Set>
    762 class SpecializedRegSet : public Accessors {
    763  using Parent = Accessors;
    764 
    765 public:
    766  DEFINE_ACCESSOR_CONSTRUCTORS_(SpecializedRegSet)
    767 
    768  SetType bits() const { return this->Parent::set_.bits(); }
    769 
    770  using Parent::has;
    771 
    772  using Parent::addUnchecked;
    773  void add(RegType reg) {
    774    MOZ_ASSERT(!this->has(reg));
    775    addUnchecked(reg);
    776  }
    777 
    778  using Parent::takeUnchecked;
    779  void take(RegType reg) {
    780    MOZ_ASSERT(this->has(reg));
    781    takeUnchecked(reg);
    782  }
    783 
    784  template <RegTypeName Name>
    785  bool hasAny() const {
    786    return Parent::template all<Name>() != 0;
    787  }
    788 
    789  template <RegTypeName Name = RegSet::DefaultType>
    790  RegType getFirst() const {
    791    SetType set = Parent::template all<Name>();
    792    MOZ_ASSERT(set);
    793    return RegSet::FirstRegister(set);
    794  }
    795  template <RegTypeName Name = RegSet::DefaultType>
    796  RegType getLast() const {
    797    SetType set = Parent::template all<Name>();
    798    MOZ_ASSERT(set);
    799    return RegSet::LastRegister(set);
    800  }
    801  template <RegTypeName Name = RegSet::DefaultType>
    802  RegType getAny() const {
    803    // The choice of first or last here is mostly arbitrary, as they are
    804    // about the same speed on popular architectures. We choose first, as
    805    // it has the advantage of using the "lower" registers more often. These
    806    // registers are sometimes more efficient (e.g. optimized encodings for
    807    // EAX on x86).
    808    return getFirst<Name>();
    809  }
    810 
    811  template <RegTypeName Name = RegSet::DefaultType>
    812  RegType getAnyExcluding(RegType preclude) {
    813    if (!this->has(preclude)) {
    814      return getAny<Name>();
    815    }
    816 
    817    take(preclude);
    818    RegType result = getAny<Name>();
    819    add(preclude);
    820    return result;
    821  }
    822 
    823  template <RegTypeName Name = RegSet::DefaultType>
    824  RegType takeAny() {
    825    RegType reg = getAny<Name>();
    826    take(reg);
    827    return reg;
    828  }
    829  template <RegTypeName Name = RegSet::DefaultType>
    830  RegType takeFirst() {
    831    RegType reg = getFirst<Name>();
    832    take(reg);
    833    return reg;
    834  }
    835  template <RegTypeName Name = RegSet::DefaultType>
    836  RegType takeLast() {
    837    RegType reg = getLast<Name>();
    838    take(reg);
    839    return reg;
    840  }
    841 
    842  ValueOperand takeAnyValue() {
    843 #if defined(JS_NUNBOX32)
    844    return ValueOperand(takeAny<RegTypeName::GPR>(),
    845                        takeAny<RegTypeName::GPR>());
    846 #elif defined(JS_PUNBOX64)
    847    return ValueOperand(takeAny<RegTypeName::GPR>());
    848 #else
    849 #  error "Bad architecture"
    850 #endif
    851  }
    852 
    853  bool aliases(ValueOperand v) const {
    854 #ifdef JS_NUNBOX32
    855    return this->has(v.typeReg()) || this->has(v.payloadReg());
    856 #else
    857    return this->has(v.valueReg());
    858 #endif
    859  }
    860 
    861  template <RegTypeName Name = RegSet::DefaultType>
    862  RegType takeAnyExcluding(RegType preclude) {
    863    RegType reg = getAnyExcluding<Name>(preclude);
    864    take(reg);
    865    return reg;
    866  }
    867 };
    868 
    869 // Specialization of the accessors for the RegisterSet aggregate.
    870 template <class Accessors>
    871 class SpecializedRegSet<Accessors, RegisterSet> : public Accessors {
    872  using Parent = Accessors;
    873 
    874 public:
    875  DEFINE_ACCESSOR_CONSTRUCTORS_(SpecializedRegSet)
    876 
    877  GeneralRegisterSet gprs() const { return this->Parent::set_.gprs(); }
    878  GeneralRegisterSet& gprs() { return this->Parent::set_.gprs(); }
    879  FloatRegisterSet fpus() const { return this->Parent::set_.fpus(); }
    880  FloatRegisterSet& fpus() { return this->Parent::set_.fpus(); }
    881 
    882  bool emptyGeneral() const { return this->Parent::set_.emptyGeneral(); }
    883  bool emptyFloat() const { return this->Parent::set_.emptyFloat(); }
    884 
    885  using Parent::has;
    886  bool has(AnyRegister reg) const {
    887    return reg.isFloat() ? this->has(reg.fpu()) : this->has(reg.gpr());
    888  }
    889 
    890  template <RegTypeName Name>
    891  bool hasAny() const {
    892    if (Name == RegTypeName::GPR) {
    893      return Parent::template allGpr<RegTypeName::GPR>() != 0;
    894    }
    895    return Parent::template allFpu<Name>() != 0;
    896  }
    897 
    898  using Parent::addUnchecked;
    899  void addUnchecked(AnyRegister reg) {
    900    if (reg.isFloat()) {
    901      addUnchecked(reg.fpu());
    902    } else {
    903      addUnchecked(reg.gpr());
    904    }
    905  }
    906 
    907  void add(Register reg) {
    908    MOZ_ASSERT(!this->has(reg));
    909    addUnchecked(reg);
    910  }
    911  void add(FloatRegister reg) {
    912    MOZ_ASSERT(!this->has(reg));
    913    addUnchecked(reg);
    914  }
    915  void add(AnyRegister reg) {
    916    if (reg.isFloat()) {
    917      add(reg.fpu());
    918    } else {
    919      add(reg.gpr());
    920    }
    921  }
    922 
    923  using Parent::takeUnchecked;
    924  void takeUnchecked(AnyRegister reg) {
    925    if (reg.isFloat()) {
    926      takeUnchecked(reg.fpu());
    927    } else {
    928      takeUnchecked(reg.gpr());
    929    }
    930  }
    931 
    932  void take(Register reg) {
    933 #ifdef DEBUG
    934    bool hasReg = this->has(reg);
    935    MOZ_ASSERT(hasReg);
    936 #endif
    937    takeUnchecked(reg);
    938  }
    939  void take(FloatRegister reg) {
    940    MOZ_ASSERT(this->has(reg));
    941    takeUnchecked(reg);
    942  }
    943  void take(AnyRegister reg) {
    944    if (reg.isFloat()) {
    945      take(reg.fpu());
    946    } else {
    947      take(reg.gpr());
    948    }
    949  }
    950 
    951  Register getAnyGeneral() const {
    952    GeneralRegisterSet::SetType set =
    953        Parent::template allGpr<RegTypeName::GPR>();
    954    MOZ_ASSERT(set);
    955    return GeneralRegisterSet::FirstRegister(set);
    956  }
    957  template <RegTypeName Name = RegTypeName::Float64>
    958  FloatRegister getAnyFloat() const {
    959    FloatRegisterSet::SetType set = Parent::template allFpu<Name>();
    960    MOZ_ASSERT(set);
    961    return FloatRegisterSet::FirstRegister(set);
    962  }
    963 
    964  Register takeAnyGeneral() {
    965    Register reg = getAnyGeneral();
    966    take(reg);
    967    return reg;
    968  }
    969  template <RegTypeName Name = RegTypeName::Float64>
    970  FloatRegister takeAnyFloat() {
    971    FloatRegister reg = getAnyFloat<Name>();
    972    take(reg);
    973    return reg;
    974  }
    975  ValueOperand takeAnyValue() {
    976 #if defined(JS_NUNBOX32)
    977    return ValueOperand(takeAnyGeneral(), takeAnyGeneral());
    978 #elif defined(JS_PUNBOX64)
    979    return ValueOperand(takeAnyGeneral());
    980 #else
    981 #  error "Bad architecture"
    982 #endif
    983  }
    984 };
    985 
    986 // Interface which is common to all register set implementations. It overloads
    987 // |add|, |take| and |takeUnchecked| methods for types such as |ValueOperand|,
    988 // |TypedOrValueRegister|, and |Register64|.
    989 template <class Accessors, typename Set>
    990 class CommonRegSet : public SpecializedRegSet<Accessors, Set> {
    991  using Parent = SpecializedRegSet<Accessors, Set>;
    992 
    993 public:
    994  DEFINE_ACCESSOR_CONSTRUCTORS_(CommonRegSet)
    995 
    996  RegSet set() const { return this->Parent::set_; }
    997  RegSet& set() { return this->Parent::set_; }
    998 
    999  bool empty() const { return this->Parent::set_.empty(); }
   1000  void clear() { this->Parent::set_.clear(); }
   1001 
   1002  using Parent::add;
   1003  void add(ValueOperand value) {
   1004 #if defined(JS_NUNBOX32)
   1005    add(value.payloadReg());
   1006    add(value.typeReg());
   1007 #elif defined(JS_PUNBOX64)
   1008    add(value.valueReg());
   1009 #else
   1010 #  error "Bad architecture"
   1011 #endif
   1012  }
   1013  void add(Register64 reg) {
   1014 #if JS_BITS_PER_WORD == 32
   1015    add(reg.high);
   1016    add(reg.low);
   1017 #else
   1018    add(reg.reg);
   1019 #endif
   1020  }
   1021 
   1022  using Parent::addUnchecked;
   1023  void addUnchecked(ValueOperand value) {
   1024 #if defined(JS_NUNBOX32)
   1025    addUnchecked(value.payloadReg());
   1026    addUnchecked(value.typeReg());
   1027 #elif defined(JS_PUNBOX64)
   1028    addUnchecked(value.valueReg());
   1029 #else
   1030 #  error "Bad architecture"
   1031 #endif
   1032  }
   1033  void addUnchecked(Register64 reg) {
   1034 #if JS_BITS_PER_WORD == 32
   1035    addUnchecked(reg.high);
   1036    addUnchecked(reg.low);
   1037 #else
   1038    addUnchecked(reg.reg);
   1039 #endif
   1040  }
   1041 
   1042  void add(TypedOrValueRegister reg) {
   1043    if (reg.hasValue()) {
   1044      add(reg.valueReg());
   1045    } else if (reg.hasTyped()) {
   1046      add(reg.typedReg());
   1047    }
   1048  }
   1049 
   1050  using Parent::take;
   1051  void take(ValueOperand value) {
   1052 #if defined(JS_NUNBOX32)
   1053    take(value.payloadReg());
   1054    take(value.typeReg());
   1055 #elif defined(JS_PUNBOX64)
   1056    take(value.valueReg());
   1057 #else
   1058 #  error "Bad architecture"
   1059 #endif
   1060  }
   1061  void take(TypedOrValueRegister reg) {
   1062    if (reg.hasValue()) {
   1063      take(reg.valueReg());
   1064    } else if (reg.hasTyped()) {
   1065      take(reg.typedReg());
   1066    }
   1067  }
   1068  void take(Register64 reg) {
   1069 #if JS_BITS_PER_WORD == 32
   1070    take(reg.high);
   1071    take(reg.low);
   1072 #else
   1073    take(reg.reg);
   1074 #endif
   1075  }
   1076 
   1077  using Parent::takeUnchecked;
   1078  void takeUnchecked(ValueOperand value) {
   1079 #if defined(JS_NUNBOX32)
   1080    takeUnchecked(value.payloadReg());
   1081    takeUnchecked(value.typeReg());
   1082 #elif defined(JS_PUNBOX64)
   1083    takeUnchecked(value.valueReg());
   1084 #else
   1085 #  error "Bad architecture"
   1086 #endif
   1087  }
   1088  void takeUnchecked(TypedOrValueRegister reg) {
   1089    if (reg.hasValue()) {
   1090      takeUnchecked(reg.valueReg());
   1091    } else if (reg.hasTyped()) {
   1092      takeUnchecked(reg.typedReg());
   1093    }
   1094  }
   1095  void takeUnchecked(Register64 reg) {
   1096 #if JS_BITS_PER_WORD == 32
   1097    takeUnchecked(reg.high);
   1098    takeUnchecked(reg.low);
   1099 #else
   1100    takeUnchecked(reg.reg);
   1101 #endif
   1102  }
   1103 };
   1104 
   1105 // These classes do not provide any additional members, they only use their
   1106 // constructors to forward to the common interface for all register sets.  The
   1107 // only benefit of these classes is to provide user friendly names.
   1108 template <typename Set>
   1109 class LiveSet : public CommonRegSet<LiveSetAccessors<Set>, Set> {
   1110  using Parent = CommonRegSet<LiveSetAccessors<Set>, Set>;
   1111 
   1112 public:
   1113  DEFINE_ACCESSOR_CONSTRUCTORS_(LiveSet)
   1114 };
   1115 
   1116 template <typename Set>
   1117 class AllocatableSet : public CommonRegSet<AllocatableSetAccessors<Set>, Set> {
   1118  using Parent = CommonRegSet<AllocatableSetAccessors<Set>, Set>;
   1119 
   1120 public:
   1121  DEFINE_ACCESSOR_CONSTRUCTORS_(AllocatableSet)
   1122 
   1123  LiveSet<Set> asLiveSet() const { return LiveSet<Set>(this->set()); }
   1124 };
   1125 
   1126 #define DEFINE_ACCESSOR_CONSTRUCTORS_FOR_REGISTERSET_(REGSET)          \
   1127  using typename Parent::RegSet;                                       \
   1128  using typename Parent::RegType;                                      \
   1129  using typename Parent::SetType;                                      \
   1130                                                                       \
   1131  constexpr REGSET() : Parent() {}                                     \
   1132  explicit constexpr REGSET(SetType) = delete;                         \
   1133  explicit constexpr REGSET(RegSet set) : Parent(set) {}               \
   1134  constexpr REGSET(GeneralRegisterSet gpr, FloatRegisterSet fpu)       \
   1135      : Parent(RegisterSet(gpr, fpu)) {}                               \
   1136  REGSET(REGSET<GeneralRegisterSet> gpr, REGSET<FloatRegisterSet> fpu) \
   1137      : Parent(RegisterSet(gpr.set(), fpu.set())) {}
   1138 
   1139 template <>
   1140 class LiveSet<RegisterSet>
   1141    : public CommonRegSet<LiveSetAccessors<RegisterSet>, RegisterSet> {
   1142  // Note: We have to provide a qualified name for LiveSetAccessors, as it is
   1143  // interpreted as being the specialized class name inherited from the parent
   1144  // class specialization.
   1145  using Parent = CommonRegSet<jit::LiveSetAccessors<RegisterSet>, RegisterSet>;
   1146 
   1147 public:
   1148  DEFINE_ACCESSOR_CONSTRUCTORS_FOR_REGISTERSET_(LiveSet)
   1149 };
   1150 
   1151 template <>
   1152 class AllocatableSet<RegisterSet>
   1153    : public CommonRegSet<AllocatableSetAccessors<RegisterSet>, RegisterSet> {
   1154  // Note: We have to provide a qualified name for AllocatableSetAccessors, as
   1155  // it is interpreted as being the specialized class name inherited from the
   1156  // parent class specialization.
   1157  using Parent =
   1158      CommonRegSet<jit::AllocatableSetAccessors<RegisterSet>, RegisterSet>;
   1159 
   1160 public:
   1161  DEFINE_ACCESSOR_CONSTRUCTORS_FOR_REGISTERSET_(AllocatableSet)
   1162 
   1163  LiveSet<RegisterSet> asLiveSet() const {
   1164    return LiveSet<RegisterSet>(this->set());
   1165  }
   1166 };
   1167 
   1168 #undef DEFINE_ACCESSOR_CONSTRUCTORS_FOR_REGISTERSET_
   1169 #undef DEFINE_ACCESSOR_CONSTRUCTORS_
   1170 
   1171 using AllocatableGeneralRegisterSet = AllocatableSet<GeneralRegisterSet>;
   1172 using AllocatableFloatRegisterSet = AllocatableSet<FloatRegisterSet>;
   1173 using AllocatableRegisterSet = AllocatableSet<RegisterSet>;
   1174 
   1175 using LiveGeneralRegisterSet = LiveSet<GeneralRegisterSet>;
   1176 using LiveFloatRegisterSet = LiveSet<FloatRegisterSet>;
   1177 using LiveRegisterSet = LiveSet<RegisterSet>;
   1178 
   1179 // iterates in whatever order happens to be convenient.
   1180 // Use TypedRegisterBackwardIterator or TypedRegisterForwardIterator if a
   1181 // specific order is required.
   1182 template <typename T>
   1183 class TypedRegisterIterator {
   1184  LiveSet<TypedRegisterSet<T>> regset_;
   1185 
   1186 public:
   1187  explicit TypedRegisterIterator(TypedRegisterSet<T> regset)
   1188      : regset_(regset) {}
   1189  explicit TypedRegisterIterator(LiveSet<TypedRegisterSet<T>> regset)
   1190      : regset_(regset) {}
   1191  TypedRegisterIterator(const TypedRegisterIterator& other)
   1192      : regset_(other.regset_) {}
   1193 
   1194  bool more() const { return !regset_.empty(); }
   1195  TypedRegisterIterator<T>& operator++() {
   1196    regset_.template takeAny<RegTypeName::Any>();
   1197    return *this;
   1198  }
   1199  T operator*() const { return regset_.template getAny<RegTypeName::Any>(); }
   1200 };
   1201 
   1202 // iterates backwards, that is, rn to r0
   1203 template <typename T>
   1204 class TypedRegisterBackwardIterator {
   1205  LiveSet<TypedRegisterSet<T>> regset_;
   1206 
   1207 public:
   1208  explicit TypedRegisterBackwardIterator(TypedRegisterSet<T> regset)
   1209      : regset_(regset) {}
   1210  explicit TypedRegisterBackwardIterator(LiveSet<TypedRegisterSet<T>> regset)
   1211      : regset_(regset) {}
   1212  TypedRegisterBackwardIterator(const TypedRegisterBackwardIterator& other)
   1213      : regset_(other.regset_) {}
   1214 
   1215  bool more() const { return !regset_.empty(); }
   1216  TypedRegisterBackwardIterator<T>& operator++() {
   1217    regset_.template takeLast<RegTypeName::Any>();
   1218    return *this;
   1219  }
   1220  T operator*() const { return regset_.template getLast<RegTypeName::Any>(); }
   1221 };
   1222 
   1223 // iterates forwards, that is r0 to rn
   1224 template <typename T>
   1225 class TypedRegisterForwardIterator {
   1226  LiveSet<TypedRegisterSet<T>> regset_;
   1227 
   1228 public:
   1229  explicit TypedRegisterForwardIterator(TypedRegisterSet<T> regset)
   1230      : regset_(regset) {}
   1231  explicit TypedRegisterForwardIterator(LiveSet<TypedRegisterSet<T>> regset)
   1232      : regset_(regset) {}
   1233  TypedRegisterForwardIterator(const TypedRegisterForwardIterator& other)
   1234      : regset_(other.regset_) {}
   1235 
   1236  bool more() const { return !regset_.empty(); }
   1237  TypedRegisterForwardIterator<T>& operator++() {
   1238    regset_.template takeFirst<RegTypeName::Any>();
   1239    return *this;
   1240  }
   1241  T operator*() const { return regset_.template getFirst<RegTypeName::Any>(); }
   1242 };
   1243 
   1244 using GeneralRegisterIterator = TypedRegisterIterator<Register>;
   1245 using FloatRegisterIterator = TypedRegisterIterator<FloatRegister>;
   1246 using GeneralRegisterBackwardIterator = TypedRegisterBackwardIterator<Register>;
   1247 using FloatRegisterBackwardIterator =
   1248    TypedRegisterBackwardIterator<FloatRegister>;
   1249 using GeneralRegisterForwardIterator = TypedRegisterForwardIterator<Register>;
   1250 using FloatRegisterForwardIterator =
   1251    TypedRegisterForwardIterator<FloatRegister>;
   1252 
   1253 class AnyRegisterIterator {
   1254  GeneralRegisterIterator geniter_;
   1255  FloatRegisterIterator floatiter_;
   1256 
   1257 public:
   1258  AnyRegisterIterator()
   1259      : geniter_(GeneralRegisterSet::All()),
   1260        floatiter_(FloatRegisterSet::All()) {}
   1261  AnyRegisterIterator(GeneralRegisterSet genset, FloatRegisterSet floatset)
   1262      : geniter_(genset), floatiter_(floatset) {}
   1263  explicit AnyRegisterIterator(const RegisterSet& set)
   1264      : geniter_(set.gpr_), floatiter_(set.fpu_) {}
   1265  explicit AnyRegisterIterator(const LiveSet<RegisterSet>& set)
   1266      : geniter_(set.gprs()), floatiter_(set.fpus()) {}
   1267  AnyRegisterIterator(const AnyRegisterIterator& other) = default;
   1268  bool more() const { return geniter_.more() || floatiter_.more(); }
   1269  AnyRegisterIterator& operator++() {
   1270    if (geniter_.more()) {
   1271      ++geniter_;
   1272    } else {
   1273      ++floatiter_;
   1274    }
   1275    return *this;
   1276  }
   1277  AnyRegister operator*() const {
   1278    if (geniter_.more()) {
   1279      return AnyRegister(*geniter_);
   1280    }
   1281    return AnyRegister(*floatiter_);
   1282  }
   1283 };
   1284 
   1285 class ABIArg {
   1286 public:
   1287  enum Kind {
   1288    GPR,
   1289 #ifdef JS_CODEGEN_REGISTER_PAIR
   1290    GPR_PAIR,
   1291 #endif
   1292    FPU,
   1293    Stack,
   1294    Uninitialized = -1
   1295  };
   1296 
   1297 private:
   1298  Kind kind_;
   1299  union {
   1300    Register::Code gpr_;
   1301    FloatRegister::Code fpu_;
   1302    uint32_t offset_;
   1303  } u;
   1304 
   1305 public:
   1306  ABIArg() : kind_(Uninitialized) { u.offset_ = -1; }
   1307  explicit ABIArg(Register gpr) : kind_(GPR) { u.gpr_ = gpr.code(); }
   1308  explicit ABIArg(Register gprLow, Register gprHigh) {
   1309 #if defined(JS_CODEGEN_REGISTER_PAIR)
   1310    kind_ = GPR_PAIR;
   1311 #else
   1312    MOZ_CRASH("Unsupported type of ABI argument.");
   1313 #endif
   1314    u.gpr_ = gprLow.code();
   1315    MOZ_ASSERT(u.gpr_ % 2 == 0);
   1316    MOZ_ASSERT(u.gpr_ + 1 == gprHigh.code());
   1317  }
   1318  explicit ABIArg(FloatRegister fpu) : kind_(FPU) { u.fpu_ = fpu.code(); }
   1319  explicit ABIArg(uint32_t offset) : kind_(Stack) { u.offset_ = offset; }
   1320 
   1321  Kind kind() const {
   1322    MOZ_ASSERT(kind_ != Uninitialized);
   1323    return kind_;
   1324  }
   1325 #ifdef JS_CODEGEN_REGISTER_PAIR
   1326  bool isGeneralRegPair() const { return kind() == GPR_PAIR; }
   1327 #else
   1328  bool isGeneralRegPair() const { return false; }
   1329 #endif
   1330 
   1331  Register gpr() const {
   1332    MOZ_ASSERT(kind() == GPR);
   1333    return Register::FromCode(u.gpr_);
   1334  }
   1335  Register64 gpr64() const {
   1336 #ifdef JS_PUNBOX64
   1337    return Register64(gpr());
   1338 #else
   1339    return Register64(oddGpr(), evenGpr());
   1340 #endif
   1341  }
   1342  Register evenGpr() const {
   1343    MOZ_ASSERT(isGeneralRegPair());
   1344    return Register::FromCode(u.gpr_);
   1345  }
   1346  Register oddGpr() const {
   1347    MOZ_ASSERT(isGeneralRegPair());
   1348    return Register::FromCode(u.gpr_ + 1);
   1349  }
   1350  FloatRegister fpu() const {
   1351    MOZ_ASSERT(kind() == FPU);
   1352    return FloatRegister::FromCode(u.fpu_);
   1353  }
   1354  uint32_t offsetFromArgBase() const {
   1355    MOZ_ASSERT(kind() == Stack);
   1356    return u.offset_;
   1357  }
   1358 
   1359  bool argInRegister() const { return kind() != Stack; }
   1360  AnyRegister reg() const {
   1361    return kind() == GPR ? AnyRegister(gpr()) : AnyRegister(fpu());
   1362  }
   1363 
   1364  bool operator==(const ABIArg& rhs) const {
   1365    if (kind_ != rhs.kind_) {
   1366      return false;
   1367    }
   1368 
   1369    switch (kind_) {
   1370      case GPR:
   1371        return u.gpr_ == rhs.u.gpr_;
   1372 #if defined(JS_CODEGEN_REGISTER_PAIR)
   1373      case GPR_PAIR:
   1374        return u.gpr_ == rhs.u.gpr_;
   1375 #endif
   1376      case FPU:
   1377        return u.fpu_ == rhs.u.fpu_;
   1378      case Stack:
   1379        return u.offset_ == rhs.u.offset_;
   1380      case Uninitialized:
   1381        return true;
   1382    }
   1383    MOZ_CRASH("Invalid value for ABIArg kind");
   1384  }
   1385 
   1386  bool operator!=(const ABIArg& rhs) const { return !(*this == rhs); }
   1387 };
   1388 
   1389 // Get the set of registers which should be saved by a block of code which
   1390 // clobbers all registers besides |unused|, but does not clobber floating point
   1391 // registers.
   1392 inline LiveGeneralRegisterSet SavedNonVolatileRegisters(
   1393    const AllocatableGeneralRegisterSet& unused) {
   1394  LiveGeneralRegisterSet result;
   1395 
   1396  for (GeneralRegisterIterator iter(GeneralRegisterSet::NonVolatile());
   1397       iter.more(); ++iter) {
   1398    Register reg = *iter;
   1399    if (!unused.has(reg)) {
   1400      result.add(reg);
   1401    }
   1402  }
   1403 
   1404  // Some platforms require the link register to be saved, if calls can be made.
   1405 #if defined(JS_CODEGEN_ARM)
   1406  result.add(Register::FromCode(Registers::lr));
   1407 #elif defined(JS_CODEGEN_ARM64)
   1408  result.add(Register::FromCode(Registers::lr));
   1409 #elif defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONG64) || \
   1410    defined(JS_CODEGEN_RISCV64)
   1411  result.add(Register::FromCode(Registers::ra));
   1412 #endif
   1413 
   1414  return result;
   1415 }
   1416 
   1417 }  // namespace jit
   1418 }  // namespace js
   1419 
   1420 #endif /* jit_RegisterSets_h */