1/*
2 * Copyright (C) 2013-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#if !ENABLE(C_LOOP)
29
30#include "GPRInfo.h"
31#include "MacroAssembler.h"
32#include "Reg.h"
33#include "TempRegisterSet.h"
34#include <wtf/Bitmap.h>
35
36namespace JSC {
37
38typedef Bitmap<MacroAssembler::numGPRs + MacroAssembler::numFPRs + 1> RegisterBitmap;
39class RegisterAtOffsetList;
40
41class RegisterSet {
42public:
43 constexpr RegisterSet() { }
44
45 template<typename... Regs>
46 constexpr explicit RegisterSet(Regs... regs)
47 {
48 setMany(regs...);
49 }
50
51 JS_EXPORT_PRIVATE static RegisterSet stackRegisters();
52 JS_EXPORT_PRIVATE static RegisterSet reservedHardwareRegisters();
53 static RegisterSet runtimeTagRegisters();
54 static RegisterSet specialRegisters(); // The union of stack, reserved hardware, and runtime registers.
55 JS_EXPORT_PRIVATE static RegisterSet calleeSaveRegisters();
56 static RegisterSet vmCalleeSaveRegisters(); // Callee save registers that might be saved and used by any tier.
57 static RegisterAtOffsetList* vmCalleeSaveRegisterOffsets();
58 static RegisterSet llintBaselineCalleeSaveRegisters(); // Registers saved and used by the LLInt.
59 static RegisterSet dfgCalleeSaveRegisters(); // Registers saved and used by the DFG JIT.
60 static RegisterSet ftlCalleeSaveRegisters(); // Registers that might be saved and used by the FTL JIT.
61#if ENABLE(WEBASSEMBLY)
62 static RegisterSet webAssemblyCalleeSaveRegisters(); // Registers saved and used by the WebAssembly JIT.
63#endif
64 static RegisterSet volatileRegistersForJSCall();
65 static RegisterSet stubUnavailableRegisters(); // The union of callee saves and special registers.
66 JS_EXPORT_PRIVATE static RegisterSet macroScratchRegisters();
67 JS_EXPORT_PRIVATE static RegisterSet allGPRs();
68 JS_EXPORT_PRIVATE static RegisterSet allFPRs();
69 static RegisterSet allRegisters();
70 JS_EXPORT_PRIVATE static RegisterSet argumentGPRS();
71
72 static RegisterSet registersToNotSaveForJSCall();
73 static RegisterSet registersToNotSaveForCCall();
74
75 void set(Reg reg, bool value = true)
76 {
77 ASSERT(!!reg);
78 m_bits.set(reg.index(), value);
79 }
80
81 void set(JSValueRegs regs, bool value = true)
82 {
83 if (regs.tagGPR() != InvalidGPRReg)
84 set(regs.tagGPR(), value);
85 set(regs.payloadGPR(), value);
86 }
87
88 void set(const RegisterSet& other, bool value = true) { value ? merge(other) : exclude(other); }
89
90 void clear(Reg reg)
91 {
92 ASSERT(!!reg);
93 set(reg, false);
94 }
95
96 bool get(Reg reg) const
97 {
98 ASSERT(!!reg);
99 return m_bits.get(reg.index());
100 }
101
102 template<typename Iterable>
103 void setAll(const Iterable& iterable)
104 {
105 for (Reg reg : iterable)
106 set(reg);
107 }
108
109 // Also allow add/remove/contains terminology, which means the same thing as set/clear/get.
110 bool add(Reg reg)
111 {
112 ASSERT(!!reg);
113 return !m_bits.testAndSet(reg.index());
114 }
115 bool remove(Reg reg)
116 {
117 ASSERT(!!reg);
118 return m_bits.testAndClear(reg.index());
119 }
120 bool contains(Reg reg) const { return get(reg); }
121
122 void merge(const RegisterSet& other) { m_bits.merge(other.m_bits); }
123 void filter(const RegisterSet& other) { m_bits.filter(other.m_bits); }
124 void exclude(const RegisterSet& other) { m_bits.exclude(other.m_bits); }
125
126 bool subsumes(const RegisterSet& other) const { return m_bits.subsumes(other.m_bits); }
127
128 size_t numberOfSetGPRs() const;
129 size_t numberOfSetFPRs() const;
130 size_t numberOfSetRegisters() const { return m_bits.count(); }
131
132 bool isEmpty() const { return m_bits.isEmpty(); }
133
134 JS_EXPORT_PRIVATE void dump(PrintStream&) const;
135
136 enum EmptyValueTag { EmptyValue };
137 enum DeletedValueTag { DeletedValue };
138
139 RegisterSet(EmptyValueTag)
140 {
141 m_bits.set(hashSpecialBitIndex);
142 }
143
144 RegisterSet(DeletedValueTag)
145 {
146 m_bits.set(hashSpecialBitIndex);
147 m_bits.set(deletedBitIndex);
148 }
149
150 bool isEmptyValue() const
151 {
152 return m_bits.get(hashSpecialBitIndex) && !m_bits.get(deletedBitIndex);
153 }
154
155 bool isDeletedValue() const
156 {
157 return m_bits.get(hashSpecialBitIndex) && m_bits.get(deletedBitIndex);
158 }
159
160 bool operator==(const RegisterSet& other) const { return m_bits == other.m_bits; }
161 bool operator!=(const RegisterSet& other) const { return m_bits != other.m_bits; }
162
163 unsigned hash() const { return m_bits.hash(); }
164
165 template<typename Func>
166 void forEach(const Func& func) const
167 {
168 m_bits.forEachSetBit(
169 [&] (size_t index) {
170 func(Reg::fromIndex(index));
171 });
172 }
173
174 class iterator {
175 public:
176 iterator()
177 {
178 }
179
180 iterator(const RegisterBitmap::iterator& iter)
181 : m_iter(iter)
182 {
183 }
184
185 Reg operator*() const { return Reg::fromIndex(*m_iter); }
186
187 iterator& operator++()
188 {
189 ++m_iter;
190 return *this;
191 }
192
193 bool operator==(const iterator& other)
194 {
195 return m_iter == other.m_iter;
196 }
197
198 bool operator!=(const iterator& other)
199 {
200 return !(*this == other);
201 }
202
203 private:
204 RegisterBitmap::iterator m_iter;
205 };
206
207 iterator begin() const { return iterator(m_bits.begin()); }
208 iterator end() const { return iterator(m_bits.end()); }
209
210private:
211 void setAny(Reg reg) { set(reg); }
212 void setAny(JSValueRegs regs) { set(regs); }
213 void setAny(const RegisterSet& set) { merge(set); }
214 void setMany() { }
215 template<typename RegType, typename... Regs>
216 void setMany(RegType reg, Regs... regs)
217 {
218 setAny(reg);
219 setMany(regs...);
220 }
221
222 // These offsets mirror the logic in Reg.h.
223 static constexpr unsigned gprOffset = 0;
224 static constexpr unsigned fprOffset = gprOffset + MacroAssembler::numGPRs;
225 static constexpr unsigned hashSpecialBitIndex = fprOffset + MacroAssembler::numFPRs;
226 static constexpr unsigned deletedBitIndex = 0;
227
228 RegisterBitmap m_bits;
229};
230
231struct RegisterSetHash {
232 static unsigned hash(const RegisterSet& set) { return set.hash(); }
233 static bool equal(const RegisterSet& a, const RegisterSet& b) { return a == b; }
234 static constexpr bool safeToCompareToEmptyOrDeleted = false;
235};
236
237} // namespace JSC
238
239namespace WTF {
240
241template<typename T> struct DefaultHash;
242template<> struct DefaultHash<JSC::RegisterSet> {
243 typedef JSC::RegisterSetHash Hash;
244};
245
246template<typename T> struct HashTraits;
247template<> struct HashTraits<JSC::RegisterSet> : public CustomHashTraits<JSC::RegisterSet> { };
248
249} // namespace WTF
250
251#endif // !ENABLE(C_LOOP)
252