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
34namespace JSC {
35
36template<typename T> struct OperandValueTraits;
37
38enum OperandKind { ArgumentOperand, LocalOperand };
39
40enum OperandsLikeTag { OperandsLike };
41
42template<typename T>
43class Operands {
44public:
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
267private:
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