Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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_MIPS32)
20 : # include "jit/mips32/Architecture-mips32.h"
21 : #elif defined(JS_CODEGEN_MIPS64)
22 : # include "jit/mips64/Architecture-mips64.h"
23 : #elif defined(JS_CODEGEN_NONE)
24 : # include "jit/none/Architecture-none.h"
25 : #else
26 : # error "Unknown architecture!"
27 : #endif
28 :
29 : namespace js {
30 : namespace jit {
31 :
32 : struct Register {
33 : typedef Registers Codes;
34 : typedef Codes::Encoding Encoding;
35 : typedef Codes::Code Code;
36 : typedef Codes::SetType SetType;
37 :
38 : Encoding reg_;
39 542895 : explicit constexpr Register(Encoding e)
40 542895 : : reg_(e)
41 542895 : { }
42 25262 : Register() = default;
43 :
44 542903 : static Register FromCode(Code i) {
45 542903 : MOZ_ASSERT(i < Registers::Total);
46 542903 : Register r { Encoding(i) };
47 542892 : return r;
48 : }
49 : static Register FromName(const char* name) {
50 : Code code = Registers::FromName(name);
51 : Register r { Encoding(code) };
52 : return r;
53 : }
54 0 : static Register Invalid() {
55 0 : Register r { Encoding(Codes::Invalid) };
56 0 : return r;
57 : }
58 637783 : constexpr Code code() const {
59 637783 : return Code(reg_);
60 : }
61 1093891 : Encoding encoding() const {
62 1093891 : MOZ_ASSERT(Code(reg_) < Registers::Total);
63 1093891 : return reg_;
64 : }
65 5463 : const char* name() const {
66 5463 : return Registers::GetName(code());
67 : }
68 77005 : bool operator ==(Register other) const {
69 77005 : return reg_ == other.reg_;
70 : }
71 38394 : bool operator !=(Register other) const {
72 38394 : return reg_ != other.reg_;
73 : }
74 0 : bool volatile_() const {
75 0 : return !!((SetType(1) << code()) & Registers::VolatileMask);
76 : }
77 0 : bool aliases(const Register& other) const {
78 0 : return reg_ == other.reg_;
79 : }
80 41753 : uint32_t numAliased() const {
81 41753 : return 1;
82 : }
83 :
84 : // N.B. FloatRegister is an explicit outparam here because msvc-2010
85 : // miscompiled it on win64 when the value was simply returned. This
86 : // now has an explicit outparam for compatability.
87 22848 : void aliased(uint32_t aliasIdx, Register* ret) const {
88 22848 : MOZ_ASSERT(aliasIdx == 0);
89 22848 : *ret = *this;
90 22848 : }
91 :
92 161312 : SetType alignedOrDominatedAliasedSet() const {
93 161312 : return SetType(1) << code();
94 : }
95 :
96 : static constexpr RegTypeName DefaultType = RegTypeName::GPR;
97 :
98 : template <RegTypeName = DefaultType>
99 : static SetType LiveAsIndexableSet(SetType s) {
100 : return SetType(0);
101 : }
102 :
103 : template <RegTypeName Name = DefaultType>
104 : static SetType AllocatableAsIndexableSet(SetType s) {
105 : static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable");
106 : return SetType(0);
107 : }
108 :
109 22827 : static uint32_t SetSize(SetType x) {
110 22827 : return Codes::SetSize(x);
111 : }
112 200302 : static uint32_t FirstBit(SetType x) {
113 200302 : return Codes::FirstBit(x);
114 : }
115 182879 : static uint32_t LastBit(SetType x) {
116 182879 : return Codes::LastBit(x);
117 : }
118 : };
119 :
120 : template <> inline Register::SetType
121 112 : Register::LiveAsIndexableSet<RegTypeName::GPR>(SetType set)
122 : {
123 112 : return set;
124 : }
125 :
126 : template <> inline Register::SetType
127 364079 : Register::LiveAsIndexableSet<RegTypeName::Any>(SetType set)
128 : {
129 364079 : return set;
130 : }
131 :
132 : template <> inline Register::SetType
133 18961 : Register::AllocatableAsIndexableSet<RegTypeName::GPR>(SetType set)
134 : {
135 18961 : return set;
136 : }
137 :
138 : #if defined(JS_NUNBOX32)
139 : static const uint32_t INT64LOW_OFFSET = 0 * sizeof(int32_t);
140 : static const uint32_t INT64HIGH_OFFSET = 1 * sizeof(int32_t);
141 : #endif
142 :
143 : struct Register64
144 : {
145 : #ifdef JS_PUNBOX64
146 : Register reg;
147 : #else
148 : Register high;
149 : Register low;
150 : #endif
151 :
152 : #ifdef JS_PUNBOX64
153 0 : explicit constexpr Register64(Register r)
154 0 : : reg(r)
155 0 : {}
156 0 : bool operator ==(Register64 other) const {
157 0 : return reg == other.reg;
158 : }
159 0 : bool operator !=(Register64 other) const {
160 0 : return reg != other.reg;
161 : }
162 0 : static Register64 Invalid() {
163 0 : return Register64(Register::Invalid());
164 : }
165 : #else
166 : constexpr Register64(Register h, Register l)
167 : : high(h), low(l)
168 : {}
169 : bool operator ==(Register64 other) const {
170 : return high == other.high && low == other.low;
171 : }
172 : bool operator !=(Register64 other) const {
173 : return high != other.high || low != other.low;
174 : }
175 : static Register64 Invalid() {
176 : return Register64(Register::Invalid(), Register::Invalid());
177 : }
178 : #endif
179 : };
180 :
181 7673 : class RegisterDump
182 : {
183 : public:
184 : typedef mozilla::Array<Registers::RegisterContent, Registers::Total> GPRArray;
185 : typedef mozilla::Array<FloatRegisters::RegisterContent, FloatRegisters::TotalPhys> FPUArray;
186 :
187 : protected: // Silence Clang warning.
188 : GPRArray regs_;
189 : FPUArray fpregs_;
190 :
191 : public:
192 0 : static size_t offsetOfRegister(Register reg) {
193 0 : return offsetof(RegisterDump, regs_) + reg.code() * sizeof(uintptr_t);
194 : }
195 0 : static size_t offsetOfRegister(FloatRegister reg) {
196 0 : return offsetof(RegisterDump, fpregs_) + reg.getRegisterDumpOffsetInBytes();
197 : }
198 : };
199 :
200 : // Information needed to recover machine register state. This records the
201 : // location of spilled register and not the content of the spilled
202 : // registers. Thus we can safely assume that this structure is unchanged, even
203 : // if the GC pointers mapped by this structure are relocated.
204 : class MachineState
205 : {
206 : mozilla::Array<Registers::RegisterContent*, Registers::Total> regs_;
207 : mozilla::Array<FloatRegisters::RegisterContent*, FloatRegisters::Total> fpregs_;
208 :
209 : public:
210 4026 : MachineState() {
211 : #ifndef JS_CODEGEN_NONE
212 68442 : for (uintptr_t i = 0; i < Registers::Total; i++)
213 64416 : regs_[i] = reinterpret_cast<Registers::RegisterContent*>(i + 0x100);
214 197274 : for (uintptr_t i = 0; i < FloatRegisters::Total; i++)
215 193248 : fpregs_[i] = reinterpret_cast<FloatRegisters::RegisterContent*>(i + 0x200);
216 : #endif
217 4026 : }
218 :
219 : static MachineState FromBailout(RegisterDump::GPRArray& regs, RegisterDump::FPUArray& fpregs);
220 :
221 0 : void setRegisterLocation(Register reg, uintptr_t* up) {
222 0 : regs_[reg.code()] = (Registers::RegisterContent*) up;
223 0 : }
224 : void setRegisterLocation(FloatRegister reg, float* fp) {
225 : MOZ_ASSERT(reg.isSingle());
226 : fpregs_[reg.code()] = (FloatRegisters::RegisterContent*) fp;
227 : }
228 0 : void setRegisterLocation(FloatRegister reg, double* dp) {
229 0 : fpregs_[reg.code()] = (FloatRegisters::RegisterContent*) dp;
230 0 : }
231 0 : void setRegisterLocation(FloatRegister reg, FloatRegisters::RegisterContent* rp) {
232 0 : fpregs_[reg.code()] = rp;
233 0 : }
234 :
235 0 : bool has(Register reg) const {
236 0 : return regs_[reg.code()] != nullptr;
237 : }
238 0 : bool has(FloatRegister reg) const {
239 0 : return fpregs_[reg.code()] != nullptr;
240 : }
241 0 : uintptr_t read(Register reg) const {
242 0 : return regs_[reg.code()]->r;
243 : }
244 0 : double read(FloatRegister reg) const {
245 0 : return fpregs_[reg.code()]->d;
246 : }
247 0 : void write(Register reg, uintptr_t value) const {
248 0 : regs_[reg.code()]->r = value;
249 0 : }
250 0 : const FloatRegisters::RegisterContent* address(FloatRegister reg) const {
251 0 : return fpregs_[reg.code()];
252 : }
253 : };
254 :
255 : class MacroAssembler;
256 :
257 : // Declares a register as owned within the scope of the object.
258 : // In debug mode, owned register state is tracked within the MacroAssembler,
259 : // and an assert will fire if ownership is conflicting.
260 : // In contrast to ARM64's UseScratchRegisterScope, this class has no overhead
261 : // in non-debug builds.
262 : template <class RegisterType>
263 : struct AutoGenericRegisterScope : public RegisterType
264 : {
265 : // Prevent MacroAssembler templates from creating copies,
266 : // which causes the destructor to fire more than once.
267 : AutoGenericRegisterScope(const AutoGenericRegisterScope& other) = delete;
268 :
269 : #ifdef DEBUG
270 : MacroAssembler& masm_;
271 : explicit AutoGenericRegisterScope(MacroAssembler& masm, RegisterType reg);
272 : ~AutoGenericRegisterScope();
273 : #else
274 : constexpr explicit AutoGenericRegisterScope(MacroAssembler& masm, RegisterType reg)
275 : : RegisterType(reg)
276 : { }
277 : #endif
278 : };
279 :
280 : typedef AutoGenericRegisterScope<Register> AutoRegisterScope;
281 : typedef AutoGenericRegisterScope<FloatRegister> AutoFloatRegisterScope;
282 :
283 : } // namespace jit
284 : } // namespace js
285 :
286 : #endif /* jit_Registers_h */
|