1 | /* |
2 | * Copyright (C) 2011-2018 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 | #include "CallFrame.h" |
29 | #include "VirtualRegister.h" |
30 | |
31 | #include <wtf/PrintStream.h> |
32 | #include <wtf/Vector.h> |
33 | |
34 | namespace JSC { |
35 | |
36 | template<typename T> struct OperandValueTraits; |
37 | |
38 | enum OperandKind { ArgumentOperand, LocalOperand }; |
39 | |
40 | enum OperandsLikeTag { OperandsLike }; |
41 | |
42 | template<typename T> |
43 | class Operands { |
44 | public: |
45 | Operands() |
46 | : m_numArguments(0) { } |
47 | |
48 | explicit Operands(size_t numArguments, size_t numLocals) |
49 | : m_numArguments(numArguments) |
50 | { |
51 | if (WTF::VectorTraits<T>::needsInitialization) { |
52 | m_values.resize(numArguments + numLocals); |
53 | } else { |
54 | m_values.fill(T(), numArguments + numLocals); |
55 | } |
56 | } |
57 | |
58 | explicit Operands(size_t numArguments, size_t numLocals, const T& initialValue) |
59 | : m_numArguments(numArguments) |
60 | { |
61 | m_values.fill(initialValue, numArguments + numLocals); |
62 | } |
63 | |
64 | template<typename U> |
65 | explicit Operands(OperandsLikeTag, const Operands<U>& other) |
66 | : m_numArguments(other.numberOfArguments()) |
67 | { |
68 | m_values.fill(T(), other.numberOfArguments() + other.numberOfLocals()); |
69 | } |
70 | |
71 | size_t numberOfArguments() const { return m_numArguments; } |
72 | size_t numberOfLocals() const { return m_values.size() - m_numArguments; } |
73 | |
74 | size_t argumentIndex(size_t idx) const |
75 | { |
76 | ASSERT(idx < m_numArguments); |
77 | return idx; |
78 | } |
79 | |
80 | size_t localIndex(size_t idx) const |
81 | { |
82 | return m_numArguments + idx; |
83 | } |
84 | |
85 | T& argument(size_t idx) |
86 | { |
87 | return m_values[argumentIndex(idx)]; |
88 | } |
89 | const T& argument(size_t idx) const |
90 | { |
91 | return m_values[argumentIndex(idx)]; |
92 | } |
93 | |
94 | T& local(size_t idx) { return m_values[localIndex(idx)]; } |
95 | const T& local(size_t idx) const { return m_values[localIndex(idx)]; } |
96 | |
97 | template<OperandKind operandKind> |
98 | size_t sizeFor() const |
99 | { |
100 | if (operandKind == ArgumentOperand) |
101 | return numberOfArguments(); |
102 | return numberOfLocals(); |
103 | } |
104 | template<OperandKind operandKind> |
105 | T& atFor(size_t idx) |
106 | { |
107 | if (operandKind == ArgumentOperand) |
108 | return argument(idx); |
109 | return local(idx); |
110 | } |
111 | template<OperandKind operandKind> |
112 | const T& atFor(size_t idx) const |
113 | { |
114 | if (operandKind == ArgumentOperand) |
115 | return argument(idx); |
116 | return local(idx); |
117 | } |
118 | |
119 | void ensureLocals(size_t size) |
120 | { |
121 | size_t oldSize = m_values.size(); |
122 | size_t newSize = m_numArguments + size; |
123 | if (newSize <= oldSize) |
124 | return; |
125 | |
126 | m_values.grow(newSize); |
127 | if (!WTF::VectorTraits<T>::needsInitialization) { |
128 | for (size_t i = oldSize; i < m_values.size(); ++i) |
129 | m_values[i] = T(); |
130 | } |
131 | } |
132 | |
133 | void ensureLocals(size_t size, const T& ensuredValue) |
134 | { |
135 | size_t oldSize = m_values.size(); |
136 | size_t newSize = m_numArguments + size; |
137 | if (newSize <= oldSize) |
138 | return; |
139 | |
140 | m_values.grow(newSize); |
141 | for (size_t i = oldSize; i < m_values.size(); ++i) |
142 | m_values[i] = ensuredValue; |
143 | } |
144 | |
145 | void setLocal(size_t idx, const T& value) |
146 | { |
147 | ensureLocals(idx + 1); |
148 | local(idx) = value; |
149 | } |
150 | |
151 | T getLocal(size_t idx) |
152 | { |
153 | return idx >= numberOfLocals() ? T() : local(idx); |
154 | } |
155 | |
156 | void setArgumentFirstTime(size_t idx, const T& value) |
157 | { |
158 | ASSERT(m_values[idx] == T()); |
159 | argument(idx) = value; |
160 | } |
161 | |
162 | void setLocalFirstTime(size_t idx, const T& value) |
163 | { |
164 | ASSERT(idx >= numberOfLocals() || local(idx) == T()); |
165 | setLocal(idx, value); |
166 | } |
167 | |
168 | size_t operandIndex(int operand) const |
169 | { |
170 | if (operandIsArgument(operand)) |
171 | return argumentIndex(VirtualRegister(operand).toArgument()); |
172 | return localIndex(VirtualRegister(operand).toLocal()); |
173 | } |
174 | |
175 | size_t operandIndex(VirtualRegister virtualRegister) const |
176 | { |
177 | return operandIndex(virtualRegister.offset()); |
178 | } |
179 | |
180 | T& operand(int operand) |
181 | { |
182 | if (operandIsArgument(operand)) |
183 | return argument(VirtualRegister(operand).toArgument()); |
184 | return local(VirtualRegister(operand).toLocal()); |
185 | } |
186 | |
187 | T& operand(VirtualRegister virtualRegister) |
188 | { |
189 | return operand(virtualRegister.offset()); |
190 | } |
191 | |
192 | const T& operand(int operand) const { return const_cast<const T&>(const_cast<Operands*>(this)->operand(operand)); } |
193 | const T& operand(VirtualRegister operand) const { return const_cast<const T&>(const_cast<Operands*>(this)->operand(operand)); } |
194 | |
195 | bool hasOperand(int operand) const |
196 | { |
197 | if (operandIsArgument(operand)) |
198 | return true; |
199 | return static_cast<size_t>(VirtualRegister(operand).toLocal()) < numberOfLocals(); |
200 | } |
201 | bool hasOperand(VirtualRegister reg) const |
202 | { |
203 | return hasOperand(reg.offset()); |
204 | } |
205 | |
206 | void setOperand(int operand, const T& value) |
207 | { |
208 | this->operand(operand) = value; |
209 | } |
210 | |
211 | void setOperand(VirtualRegister virtualRegister, const T& value) |
212 | { |
213 | setOperand(virtualRegister.offset(), value); |
214 | } |
215 | |
216 | size_t size() const { return m_values.size(); } |
217 | const T& at(size_t index) const { return m_values[index]; } |
218 | T& at(size_t index) { return m_values[index]; } |
219 | const T& operator[](size_t index) const { return at(index); } |
220 | T& operator[](size_t index) { return at(index); } |
221 | |
222 | bool isArgument(size_t index) const { return index < m_numArguments; } |
223 | bool isLocal(size_t index) const { return !isArgument(index); } |
224 | int operandForIndex(size_t index) const |
225 | { |
226 | if (index < numberOfArguments()) |
227 | return virtualRegisterForArgument(index).offset(); |
228 | return virtualRegisterForLocal(index - numberOfArguments()).offset(); |
229 | } |
230 | VirtualRegister virtualRegisterForIndex(size_t index) const |
231 | { |
232 | return VirtualRegister(operandForIndex(index)); |
233 | } |
234 | |
235 | void setOperandFirstTime(int operand, const T& value) |
236 | { |
237 | if (operandIsArgument(operand)) { |
238 | setArgumentFirstTime(VirtualRegister(operand).toArgument(), value); |
239 | return; |
240 | } |
241 | |
242 | setLocalFirstTime(VirtualRegister(operand).toLocal(), value); |
243 | } |
244 | |
245 | void fill(T value) |
246 | { |
247 | for (size_t i = 0; i < m_values.size(); ++i) |
248 | m_values[i] = value; |
249 | } |
250 | |
251 | void clear() |
252 | { |
253 | fill(T()); |
254 | } |
255 | |
256 | bool operator==(const Operands& other) const |
257 | { |
258 | ASSERT(numberOfArguments() == other.numberOfArguments()); |
259 | ASSERT(numberOfLocals() == other.numberOfLocals()); |
260 | |
261 | return m_values == other.m_values; |
262 | } |
263 | |
264 | void dumpInContext(PrintStream& out, DumpContext* context) const; |
265 | void dump(PrintStream& out) const; |
266 | |
267 | private: |
268 | // The first m_numArguments of m_values are arguments, the rest are locals. |
269 | Vector<T, 0, UnsafeVectorOverflow> m_values; |
270 | unsigned m_numArguments; |
271 | }; |
272 | |
273 | } // namespace JSC |
274 | |