tor-browser

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

Registers.h (9353B)


      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_Registers_h
      8 #define jit_Registers_h
      9 
     10 #include "mozilla/Array.h"
     11 
     12 #include "jit/IonTypes.h"
     13 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     14 #  include "jit/x86-shared/Architecture-x86-shared.h"
     15 #elif defined(JS_CODEGEN_ARM)
     16 #  include "jit/arm/Architecture-arm.h"
     17 #elif defined(JS_CODEGEN_ARM64)
     18 #  include "jit/arm64/Architecture-arm64.h"
     19 #elif defined(JS_CODEGEN_MIPS64)
     20 #  include "jit/mips64/Architecture-mips64.h"
     21 #elif defined(JS_CODEGEN_LOONG64)
     22 #  include "jit/loong64/Architecture-loong64.h"
     23 #elif defined(JS_CODEGEN_RISCV64)
     24 #  include "jit/riscv64/Architecture-riscv64.h"
     25 #elif defined(JS_CODEGEN_WASM32)
     26 #  include "jit/wasm32/Architecture-wasm32.h"
     27 #elif defined(JS_CODEGEN_NONE)
     28 #  include "jit/none/Architecture-none.h"
     29 #else
     30 #  error "Unknown architecture!"
     31 #endif
     32 
     33 namespace js {
     34 namespace jit {
     35 
     36 struct Register {
     37  using Codes = Registers;
     38  using Encoding = Codes::Encoding;
     39  using Code = Codes::Code;
     40  using SetType = Codes::SetType;
     41 
     42  Encoding reg_;
     43  explicit constexpr Register(Encoding e) : reg_(e) {}
     44  Register() : reg_(Encoding(Codes::Invalid)) {}
     45 
     46  static Register FromCode(Code i) {
     47    MOZ_ASSERT(i < Registers::Total);
     48    Register r{Encoding(i)};
     49    return r;
     50  }
     51  static Register FromName(const char* name) {
     52    Code code = Registers::FromName(name);
     53    Register r{Encoding(code)};
     54    return r;
     55  }
     56  constexpr static Register Invalid() {
     57    Register r{Encoding(Codes::Invalid)};
     58    return r;
     59  }
     60  constexpr Code code() const { return Code(reg_); }
     61  Encoding encoding() const {
     62    MOZ_ASSERT(Code(reg_) < Registers::Total);
     63    return reg_;
     64  }
     65  const char* name() const { return Registers::GetName(code()); }
     66  constexpr bool operator==(Register other) const { return reg_ == other.reg_; }
     67  constexpr bool operator!=(Register other) const { return reg_ != other.reg_; }
     68  bool volatile_() const {
     69    return !!((SetType(1) << code()) & Registers::VolatileMask);
     70  }
     71  bool aliases(const Register& other) const { return reg_ == other.reg_; }
     72  uint32_t numAliased() const { return 1; }
     73 
     74  Register aliased(uint32_t aliasIdx) const {
     75    MOZ_ASSERT(aliasIdx == 0);
     76    return *this;
     77  }
     78 
     79  SetType alignedOrDominatedAliasedSet() const { return SetType(1) << code(); }
     80 
     81  static constexpr RegTypeName DefaultType = RegTypeName::GPR;
     82 
     83  template <RegTypeName = DefaultType>
     84  static SetType LiveAsIndexableSet(SetType s) {
     85    return SetType(0);
     86  }
     87 
     88  template <RegTypeName Name = DefaultType>
     89  static SetType AllocatableAsIndexableSet(SetType s) {
     90    static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable");
     91    return SetType(0);
     92  }
     93 
     94  static uint32_t SetSize(SetType x) { return Codes::SetSize(x); }
     95  static uint32_t FirstBit(SetType x) { return Codes::FirstBit(x); }
     96  static uint32_t LastBit(SetType x) { return Codes::LastBit(x); }
     97 
     98  // Returns the offset of |reg| on the stack, assuming all registers in |set|
     99  // were pushed in order (e.g. by |PushRegsInMask|). This is computed by
    100  // clearing the lower bits (registers that were pushed later).
    101  static size_t OffsetOfPushedRegister(SetType set, Register reg) {
    102    return sizeof(Codes::RegisterContent) * Codes::SetSize(set >> reg.code());
    103  }
    104 };
    105 
    106 // Architectures where the stack pointer is not a plain register with a standard
    107 // register encoding must define JS_HAS_HIDDEN_SP and HiddenSPEncoding.
    108 
    109 #ifdef JS_HAS_HIDDEN_SP
    110 struct RegisterOrSP {
    111  // The register code -- but possibly one that cannot be represented as a bit
    112  // position in a 32-bit vector.
    113  uint32_t code;
    114 
    115  explicit RegisterOrSP(uint32_t code) : code(code) {}
    116  explicit RegisterOrSP(Register r) : code(r.code()) {}
    117 };
    118 
    119 static inline bool IsHiddenSP(RegisterOrSP r) {
    120  return r.code == HiddenSPEncoding;
    121 }
    122 
    123 static inline Register AsRegister(RegisterOrSP r) {
    124  MOZ_ASSERT(!IsHiddenSP(r));
    125  return Register::FromCode(r.code);
    126 }
    127 
    128 static inline Register AsRegister(Register r) { return r; }
    129 
    130 inline bool operator==(Register r, RegisterOrSP e) {
    131  return r.code() == e.code;
    132 }
    133 
    134 inline bool operator!=(Register r, RegisterOrSP e) { return !(r == e); }
    135 
    136 inline bool operator==(RegisterOrSP e, Register r) { return r == e; }
    137 
    138 inline bool operator!=(RegisterOrSP e, Register r) { return r != e; }
    139 
    140 inline bool operator==(RegisterOrSP lhs, RegisterOrSP rhs) {
    141  return lhs.code == rhs.code;
    142 }
    143 
    144 inline bool operator!=(RegisterOrSP lhs, RegisterOrSP rhs) {
    145  return !(lhs == rhs);
    146 }
    147 #else
    148 // On platforms where there's nothing special about SP, make RegisterOrSP be
    149 // just Register, and return false for IsHiddenSP(r) for any r so that we use
    150 // "normal" code for handling the SP.  This reduces ifdeffery throughout the
    151 // jit.
    152 using RegisterOrSP = Register;
    153 
    154 static inline bool IsHiddenSP(RegisterOrSP r) { return false; }
    155 
    156 static inline Register AsRegister(RegisterOrSP r) { return r; }
    157 #endif
    158 
    159 template <>
    160 inline Register::SetType Register::LiveAsIndexableSet<RegTypeName::GPR>(
    161    SetType set) {
    162  return set;
    163 }
    164 
    165 template <>
    166 inline Register::SetType Register::LiveAsIndexableSet<RegTypeName::Any>(
    167    SetType set) {
    168  return set;
    169 }
    170 
    171 template <>
    172 inline Register::SetType Register::AllocatableAsIndexableSet<RegTypeName::GPR>(
    173    SetType set) {
    174  return set;
    175 }
    176 
    177 #if JS_BITS_PER_WORD == 32
    178 // Note, some platform code depends on INT64LOW_OFFSET being zero.
    179 static const uint32_t INT64LOW_OFFSET = 0 * sizeof(int32_t);
    180 static const uint32_t INT64HIGH_OFFSET = 1 * sizeof(int32_t);
    181 #endif
    182 
    183 struct Register64 {
    184 #ifdef JS_PUNBOX64
    185  Register reg;
    186 #else
    187  Register high;
    188  Register low;
    189 #endif
    190 
    191 #ifdef JS_PUNBOX64
    192  explicit constexpr Register64(Register r) : reg(r) {}
    193  constexpr bool operator==(Register64 other) const { return reg == other.reg; }
    194  constexpr bool operator!=(Register64 other) const { return reg != other.reg; }
    195  Register scratchReg() { return reg; }
    196  static constexpr Register64 Invalid() {
    197    return Register64(Register::Invalid());
    198  }
    199 #else
    200  constexpr Register64(Register h, Register l) : high(h), low(l) {}
    201  constexpr bool operator==(Register64 other) const {
    202    return high == other.high && low == other.low;
    203  }
    204  constexpr bool operator!=(Register64 other) const {
    205    return high != other.high || low != other.low;
    206  }
    207  Register scratchReg() { return high; }
    208  Register secondScratchReg() { return low; }
    209  static constexpr Register64 Invalid() {
    210    return Register64(Register::Invalid(), Register::Invalid());
    211  }
    212 #endif
    213 };
    214 
    215 class RegisterDump {
    216 public:
    217  using GPRArray = mozilla::Array<Registers::RegisterContent, Registers::Total>;
    218  using FPUArray = mozilla::Array<FloatRegisters::RegisterContent,
    219                                  FloatRegisters::TotalPhys>;
    220 
    221 protected:  // Silence Clang warning.
    222  GPRArray regs_;
    223  FPUArray fpregs_;
    224 
    225 public:
    226  static size_t offsetOfRegister(Register reg) {
    227    return offsetof(RegisterDump, regs_) + reg.code() * sizeof(uintptr_t);
    228  }
    229  static size_t offsetOfRegister(FloatRegister reg) {
    230    return offsetof(RegisterDump, fpregs_) + reg.getRegisterDumpOffsetInBytes();
    231  }
    232 };
    233 
    234 // Class for mapping each register to an offset.
    235 class RegisterOffsets {
    236  mozilla::Array<uint32_t, Registers::Total> offsets_;
    237 
    238  // Sentinel value representing an uninitialized offset.
    239  static constexpr uint32_t InvalidOffset = UINT32_MAX;
    240 
    241 public:
    242  RegisterOffsets() {
    243    for (size_t i = 0; i < Registers::Total; i++) {
    244      offsets_[i] = InvalidOffset;
    245    }
    246  }
    247 
    248  RegisterOffsets(const RegisterOffsets&) = delete;
    249  void operator=(const RegisterOffsets&) = delete;
    250 
    251  bool hasOffset(Register reg) const {
    252    return offsets_[reg.code()] != InvalidOffset;
    253  }
    254  uint32_t getOffset(Register reg) const {
    255    MOZ_ASSERT(hasOffset(reg));
    256    return offsets_[reg.code()];
    257  }
    258  void setOffset(Register reg, size_t offset) {
    259    MOZ_ASSERT(offset < InvalidOffset);
    260    offsets_[reg.code()] = uint32_t(offset);
    261  }
    262 };
    263 
    264 class MacroAssembler;
    265 
    266 // Declares a register as owned within the scope of the object.
    267 // In debug mode, owned register state is tracked within the MacroAssembler,
    268 // and an assert will fire if ownership is conflicting.
    269 // In contrast to ARM64's UseScratchRegisterScope, this class has no overhead
    270 // in non-debug builds.
    271 template <class RegisterType>
    272 struct AutoGenericRegisterScope : public RegisterType {
    273  // Prevent MacroAssembler templates from creating copies,
    274  // which causes the destructor to fire more than once.
    275  AutoGenericRegisterScope(const AutoGenericRegisterScope& other) = delete;
    276 
    277 #ifdef DEBUG
    278  MacroAssembler& masm_;
    279  bool released_;
    280  explicit AutoGenericRegisterScope(MacroAssembler& masm, RegisterType reg);
    281  ~AutoGenericRegisterScope();
    282  void release();
    283  void reacquire();
    284 #else
    285  constexpr explicit AutoGenericRegisterScope(MacroAssembler& masm,
    286                                              RegisterType reg)
    287      : RegisterType(reg) {}
    288  void release() {}
    289  void reacquire() {}
    290 #endif
    291 };
    292 
    293 using AutoRegisterScope = AutoGenericRegisterScope<Register>;
    294 using AutoFloatRegisterScope = AutoGenericRegisterScope<FloatRegister>;
    295 
    296 }  // namespace jit
    297 }  // namespace js
    298 
    299 #endif /* jit_Registers_h */