diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/jit/Registers.h | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit/Registers.h')
-rw-r--r-- | js/src/jit/Registers.h | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/js/src/jit/Registers.h b/js/src/jit/Registers.h new file mode 100644 index 0000000000..f17f4d5d9c --- /dev/null +++ b/js/src/jit/Registers.h @@ -0,0 +1,311 @@ +/* -*- 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_Registers_h +#define jit_Registers_h + +#include "mozilla/Array.h" + +#include "jit/IonTypes.h" +#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) +# include "jit/x86-shared/Architecture-x86-shared.h" +#elif defined(JS_CODEGEN_ARM) +# include "jit/arm/Architecture-arm.h" +#elif defined(JS_CODEGEN_ARM64) +# include "jit/arm64/Architecture-arm64.h" +#elif defined(JS_CODEGEN_MIPS32) +# include "jit/mips32/Architecture-mips32.h" +#elif defined(JS_CODEGEN_MIPS64) +# include "jit/mips64/Architecture-mips64.h" +#elif defined(JS_CODEGEN_NONE) +# include "jit/none/Architecture-none.h" +#else +# error "Unknown architecture!" +#endif + +namespace js { +namespace jit { + +struct Register { + using Codes = Registers; + using Encoding = Codes::Encoding; + using Code = Codes::Code; + using SetType = Codes::SetType; + + Encoding reg_; + explicit constexpr Register(Encoding e) : reg_(e) {} + Register() = default; + + static Register FromCode(Code i) { + MOZ_ASSERT(i < Registers::Total); + Register r{Encoding(i)}; + return r; + } + static Register FromName(const char* name) { + Code code = Registers::FromName(name); + Register r{Encoding(code)}; + return r; + } + constexpr static Register Invalid() { + Register r{Encoding(Codes::Invalid)}; + return r; + } + constexpr Code code() const { return Code(reg_); } + Encoding encoding() const { + MOZ_ASSERT(Code(reg_) < Registers::Total); + return reg_; + } + const char* name() const { return Registers::GetName(code()); } + constexpr bool operator==(Register other) const { return reg_ == other.reg_; } + constexpr bool operator!=(Register other) const { return reg_ != other.reg_; } + bool volatile_() const { + return !!((SetType(1) << code()) & Registers::VolatileMask); + } + bool aliases(const Register& other) const { return reg_ == other.reg_; } + uint32_t numAliased() const { return 1; } + + Register aliased(uint32_t aliasIdx) const { + MOZ_ASSERT(aliasIdx == 0); + return *this; + } + + SetType alignedOrDominatedAliasedSet() const { return SetType(1) << code(); } + + static constexpr RegTypeName DefaultType = RegTypeName::GPR; + + template <RegTypeName = DefaultType> + static SetType LiveAsIndexableSet(SetType s) { + return SetType(0); + } + + template <RegTypeName Name = DefaultType> + static SetType AllocatableAsIndexableSet(SetType s) { + static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable"); + return SetType(0); + } + + static uint32_t SetSize(SetType x) { return Codes::SetSize(x); } + static uint32_t FirstBit(SetType x) { return Codes::FirstBit(x); } + static uint32_t LastBit(SetType x) { return Codes::LastBit(x); } +}; + +// Architectures where the stack pointer is not a plain register with a standard +// register encoding must define JS_HAS_HIDDEN_SP and HiddenSPEncoding. + +#ifdef JS_HAS_HIDDEN_SP +struct RegisterOrSP { + // The register code -- but possibly one that cannot be represented as a bit + // position in a 32-bit vector. + uint32_t code; + + explicit RegisterOrSP(uint32_t code) : code(code) {} + explicit RegisterOrSP(Register r) : code(r.code()) {} +}; + +static inline bool IsHiddenSP(RegisterOrSP r) { + return r.code == HiddenSPEncoding; +} + +static inline Register AsRegister(RegisterOrSP r) { + MOZ_ASSERT(!IsHiddenSP(r)); + return Register::FromCode(r.code); +} + +static inline Register AsRegister(Register r) { return r; } + +inline bool operator==(Register r, RegisterOrSP e) { + return r.code() == e.code; +} + +inline bool operator!=(Register r, RegisterOrSP e) { return !(r == e); } + +inline bool operator==(RegisterOrSP e, Register r) { return r == e; } + +inline bool operator!=(RegisterOrSP e, Register r) { return r != e; } + +inline bool operator==(RegisterOrSP lhs, RegisterOrSP rhs) { + return lhs.code == rhs.code; +} + +inline bool operator!=(RegisterOrSP lhs, RegisterOrSP rhs) { + return !(lhs == rhs); +} +#else +// On platforms where there's nothing special about SP, make RegisterOrSP be +// just Register, and return false for IsHiddenSP(r) for any r so that we use +// "normal" code for handling the SP. This reduces ifdeffery throughout the +// jit. +using RegisterOrSP = Register; + +static inline bool IsHiddenSP(RegisterOrSP r) { return false; } + +static inline Register AsRegister(RegisterOrSP r) { return r; } +#endif + +template <> +inline Register::SetType Register::LiveAsIndexableSet<RegTypeName::GPR>( + SetType set) { + return set; +} + +template <> +inline Register::SetType Register::LiveAsIndexableSet<RegTypeName::Any>( + SetType set) { + return set; +} + +template <> +inline Register::SetType Register::AllocatableAsIndexableSet<RegTypeName::GPR>( + SetType set) { + return set; +} + +#if JS_BITS_PER_WORD == 32 +// Note, some platform code depends on INT64LOW_OFFSET being zero. +static const uint32_t INT64LOW_OFFSET = 0 * sizeof(int32_t); +static const uint32_t INT64HIGH_OFFSET = 1 * sizeof(int32_t); +#endif + +struct Register64 { +#ifdef JS_PUNBOX64 + Register reg; +#else + Register high; + Register low; +#endif + +#ifdef JS_PUNBOX64 + explicit constexpr Register64(Register r) : reg(r) {} + constexpr bool operator==(Register64 other) const { return reg == other.reg; } + constexpr bool operator!=(Register64 other) const { return reg != other.reg; } + Register scratchReg() { return reg; } + static Register64 Invalid() { return Register64(Register::Invalid()); } +#else + constexpr Register64(Register h, Register l) : high(h), low(l) {} + constexpr bool operator==(Register64 other) const { + return high == other.high && low == other.low; + } + constexpr bool operator!=(Register64 other) const { + return high != other.high || low != other.low; + } + Register scratchReg() { return high; } + static Register64 Invalid() { + return Register64(Register::Invalid(), Register::Invalid()); + } +#endif +}; + +class RegisterDump { + public: + typedef mozilla::Array<Registers::RegisterContent, Registers::Total> GPRArray; + typedef mozilla::Array<FloatRegisters::RegisterContent, + FloatRegisters::TotalPhys> + FPUArray; + + protected: // Silence Clang warning. + GPRArray regs_; + FPUArray fpregs_; + + public: + static size_t offsetOfRegister(Register reg) { + return offsetof(RegisterDump, regs_) + reg.code() * sizeof(uintptr_t); + } + static size_t offsetOfRegister(FloatRegister reg) { + return offsetof(RegisterDump, fpregs_) + reg.getRegisterDumpOffsetInBytes(); + } +}; + +// Information needed to recover machine register state. This records the +// location of spilled register and not the content of the spilled +// registers. Thus we can safely assume that this structure is unchanged, even +// if the GC pointers mapped by this structure are relocated. +class MachineState { + mozilla::Array<Registers::RegisterContent*, Registers::Total> regs_; + mozilla::Array<FloatRegisters::RegisterContent*, FloatRegisters::Total> + fpregs_; + + public: + MachineState() { +#ifndef JS_CODEGEN_NONE + for (uintptr_t i = 0; i < Registers::Total; i++) { + regs_[i] = reinterpret_cast<Registers::RegisterContent*>(i + 0x100); + } + for (uintptr_t i = 0; i < FloatRegisters::Total; i++) { + fpregs_[i] = + reinterpret_cast<FloatRegisters::RegisterContent*>(i + 0x200); + } +#endif + } + + static MachineState FromBailout(RegisterDump::GPRArray& regs, + RegisterDump::FPUArray& fpregs); + + void setRegisterLocation(Register reg, uintptr_t* up) { + regs_[reg.code()] = (Registers::RegisterContent*)up; + } + void setRegisterLocation(FloatRegister reg, float* fp) { + MOZ_ASSERT(reg.isSingle()); + fpregs_[reg.code()] = (FloatRegisters::RegisterContent*)fp; + } + void setRegisterLocation(FloatRegister reg, double* dp) { + fpregs_[reg.code()] = (FloatRegisters::RegisterContent*)dp; + } + void setRegisterLocation(FloatRegister reg, + FloatRegisters::RegisterContent* rp) { + fpregs_[reg.code()] = rp; + } + + bool has(Register reg) const { return regs_[reg.code()] != nullptr; } + bool has(FloatRegister reg) const { return fpregs_[reg.code()] != nullptr; } + uintptr_t read(Register reg) const { return regs_[reg.code()]->r; } + double read(FloatRegister reg) const { return fpregs_[reg.code()]->d; } + void write(Register reg, uintptr_t value) const { + regs_[reg.code()]->r = value; + } + const Registers::RegisterContent* address(Register reg) const { + return regs_[reg.code()]; + } + const FloatRegisters::RegisterContent* address(FloatRegister reg) const { + return fpregs_[reg.code()]; + } +}; + +class MacroAssembler; + +// Declares a register as owned within the scope of the object. +// In debug mode, owned register state is tracked within the MacroAssembler, +// and an assert will fire if ownership is conflicting. +// In contrast to ARM64's UseScratchRegisterScope, this class has no overhead +// in non-debug builds. +template <class RegisterType> +struct AutoGenericRegisterScope : public RegisterType { + // Prevent MacroAssembler templates from creating copies, + // which causes the destructor to fire more than once. + AutoGenericRegisterScope(const AutoGenericRegisterScope& other) = delete; + +#ifdef DEBUG + MacroAssembler& masm_; + bool released_; + explicit AutoGenericRegisterScope(MacroAssembler& masm, RegisterType reg); + ~AutoGenericRegisterScope(); + void release(); + void reacquire(); +#else + constexpr explicit AutoGenericRegisterScope(MacroAssembler& masm, + RegisterType reg) + : RegisterType(reg) {} + void release() {} + void reacquire() {} +#endif +}; + +using AutoRegisterScope = AutoGenericRegisterScope<Register>; +using AutoFloatRegisterScope = AutoGenericRegisterScope<FloatRegister>; + +} // namespace jit +} // namespace js + +#endif /* jit_Registers_h */ |