]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGVariableAccessData.h
JavaScriptCore-1218.33.tar.gz
[apple/javascriptcore.git] / dfg / DFGVariableAccessData.h
1 /*
2 * Copyright (C) 2011, 2012, 2013 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 #ifndef DFGVariableAccessData_h
27 #define DFGVariableAccessData_h
28
29 #include "DFGDoubleFormatState.h"
30 #include "DFGNodeFlags.h"
31 #include "Operands.h"
32 #include "SpeculatedType.h"
33 #include "VirtualRegister.h"
34 #include <wtf/Platform.h>
35 #include <wtf/UnionFind.h>
36 #include <wtf/Vector.h>
37
38 namespace JSC { namespace DFG {
39
40 enum DoubleBallot { VoteValue, VoteDouble };
41
42 class VariableAccessData : public UnionFind<VariableAccessData> {
43 public:
44 VariableAccessData()
45 : m_local(static_cast<VirtualRegister>(std::numeric_limits<int>::min()))
46 , m_prediction(SpecNone)
47 , m_argumentAwarePrediction(SpecNone)
48 , m_flags(0)
49 , m_isCaptured(false)
50 , m_shouldNeverUnbox(false)
51 , m_isArgumentsAlias(false)
52 , m_structureCheckHoistingFailed(false)
53 , m_isProfitableToUnbox(false)
54 , m_isLoadedFrom(false)
55 , m_doubleFormatState(EmptyDoubleFormatState)
56 {
57 clearVotes();
58 }
59
60 VariableAccessData(VirtualRegister local, bool isCaptured)
61 : m_local(local)
62 , m_prediction(SpecNone)
63 , m_argumentAwarePrediction(SpecNone)
64 , m_flags(0)
65 , m_isCaptured(isCaptured)
66 , m_shouldNeverUnbox(isCaptured)
67 , m_isArgumentsAlias(false)
68 , m_structureCheckHoistingFailed(false)
69 , m_isProfitableToUnbox(false)
70 , m_doubleFormatState(EmptyDoubleFormatState)
71 {
72 clearVotes();
73 }
74
75 VirtualRegister local()
76 {
77 ASSERT(m_local == find()->m_local);
78 return m_local;
79 }
80
81 int operand()
82 {
83 return static_cast<int>(local());
84 }
85
86 bool mergeIsCaptured(bool isCaptured)
87 {
88 return checkAndSet(m_shouldNeverUnbox, m_shouldNeverUnbox | isCaptured)
89 | checkAndSet(m_isCaptured, m_isCaptured | isCaptured);
90 }
91
92 bool isCaptured()
93 {
94 return m_isCaptured;
95 }
96
97 bool mergeIsProfitableToUnbox(bool isProfitableToUnbox)
98 {
99 return checkAndSet(m_isProfitableToUnbox, m_isProfitableToUnbox | isProfitableToUnbox);
100 }
101
102 bool isProfitableToUnbox()
103 {
104 return m_isProfitableToUnbox;
105 }
106
107 bool mergeShouldNeverUnbox(bool shouldNeverUnbox)
108 {
109 bool newShouldNeverUnbox = m_shouldNeverUnbox | shouldNeverUnbox;
110 if (newShouldNeverUnbox == m_shouldNeverUnbox)
111 return false;
112 m_shouldNeverUnbox = newShouldNeverUnbox;
113 return true;
114 }
115
116 // Returns true if it would be unsound to store the value in an unboxed fashion.
117 // If this returns false, it simply means that it is sound to unbox; it doesn't
118 // mean that we have actually done so.
119 bool shouldNeverUnbox()
120 {
121 ASSERT(!(m_isCaptured && !m_shouldNeverUnbox));
122 return m_shouldNeverUnbox;
123 }
124
125 // Returns true if we should be unboxing the value provided that the predictions
126 // and double format vote say so. This may return false even if shouldNeverUnbox()
127 // returns false, since this incorporates heuristics of profitability.
128 bool shouldUnboxIfPossible()
129 {
130 return !shouldNeverUnbox() && isProfitableToUnbox();
131 }
132
133 bool mergeStructureCheckHoistingFailed(bool failed)
134 {
135 return checkAndSet(m_structureCheckHoistingFailed, m_structureCheckHoistingFailed | failed);
136 }
137
138 bool structureCheckHoistingFailed()
139 {
140 return m_structureCheckHoistingFailed;
141 }
142
143 bool mergeIsArgumentsAlias(bool isArgumentsAlias)
144 {
145 return checkAndSet(m_isArgumentsAlias, m_isArgumentsAlias | isArgumentsAlias);
146 }
147
148 bool isArgumentsAlias()
149 {
150 return m_isArgumentsAlias;
151 }
152
153 bool mergeIsLoadedFrom(bool isLoadedFrom)
154 {
155 return checkAndSet(m_isLoadedFrom, m_isLoadedFrom | isLoadedFrom);
156 }
157
158 void setIsLoadedFrom(bool isLoadedFrom)
159 {
160 m_isLoadedFrom = isLoadedFrom;
161 }
162
163 bool isLoadedFrom()
164 {
165 return m_isLoadedFrom;
166 }
167
168 bool predict(SpeculatedType prediction)
169 {
170 VariableAccessData* self = find();
171 bool result = mergeSpeculation(self->m_prediction, prediction);
172 if (result)
173 mergeSpeculation(m_argumentAwarePrediction, m_prediction);
174 return result;
175 }
176
177 SpeculatedType nonUnifiedPrediction()
178 {
179 return m_prediction;
180 }
181
182 SpeculatedType prediction()
183 {
184 return find()->m_prediction;
185 }
186
187 SpeculatedType argumentAwarePrediction()
188 {
189 return find()->m_argumentAwarePrediction;
190 }
191
192 bool mergeArgumentAwarePrediction(SpeculatedType prediction)
193 {
194 return mergeSpeculation(find()->m_argumentAwarePrediction, prediction);
195 }
196
197 void clearVotes()
198 {
199 ASSERT(find() == this);
200 m_votes[0] = 0;
201 m_votes[1] = 0;
202 }
203
204 void vote(unsigned ballot)
205 {
206 ASSERT(ballot < 2);
207 m_votes[ballot]++;
208 }
209
210 double voteRatio()
211 {
212 ASSERT(find() == this);
213 return static_cast<double>(m_votes[1]) / m_votes[0];
214 }
215
216 bool shouldUseDoubleFormatAccordingToVote()
217 {
218 // We don't support this facility for arguments, yet.
219 // FIXME: make this work for arguments.
220 if (operandIsArgument(operand()))
221 return false;
222
223 // If the variable is not a number prediction, then this doesn't
224 // make any sense.
225 if (!isNumberSpeculation(prediction())) {
226 // FIXME: we may end up forcing a local in inlined argument position to be a double even
227 // if it is sometimes not even numeric, since this never signals the fact that it doesn't
228 // want doubles. https://bugs.webkit.org/show_bug.cgi?id=109511
229 return false;
230 }
231
232 // If the variable is predicted to hold only doubles, then it's a
233 // no-brainer: it should be formatted as a double.
234 if (isDoubleSpeculation(prediction()))
235 return true;
236
237 // If the variable is known to be used as an integer, then be safe -
238 // don't force it to be a double.
239 if (flags() & NodeUsedAsInt)
240 return false;
241
242 // If the variable has been voted to become a double, then make it a
243 // double.
244 if (voteRatio() >= Options::doubleVoteRatioForDoubleFormat())
245 return true;
246
247 return false;
248 }
249
250 DoubleFormatState doubleFormatState()
251 {
252 return find()->m_doubleFormatState;
253 }
254
255 bool shouldUseDoubleFormat()
256 {
257 ASSERT(isRoot());
258 bool doubleState = m_doubleFormatState == UsingDoubleFormat;
259 ASSERT(!(doubleState && shouldNeverUnbox()));
260 ASSERT(!(doubleState && isCaptured()));
261 return doubleState && isProfitableToUnbox();
262 }
263
264 bool tallyVotesForShouldUseDoubleFormat()
265 {
266 ASSERT(isRoot());
267
268 if (operandIsArgument(local()) || shouldNeverUnbox())
269 return DFG::mergeDoubleFormatState(m_doubleFormatState, NotUsingDoubleFormat);
270
271 if (m_doubleFormatState == CantUseDoubleFormat)
272 return false;
273
274 bool newValueOfShouldUseDoubleFormat = shouldUseDoubleFormatAccordingToVote();
275 if (!newValueOfShouldUseDoubleFormat) {
276 // We monotonically convert to double. Hence, if the fixpoint leads us to conclude that we should
277 // switch back to int, we instead ignore this and stick with double.
278 return false;
279 }
280
281 if (m_doubleFormatState == UsingDoubleFormat)
282 return false;
283
284 return DFG::mergeDoubleFormatState(m_doubleFormatState, UsingDoubleFormat);
285 }
286
287 bool mergeDoubleFormatState(DoubleFormatState doubleFormatState)
288 {
289 return DFG::mergeDoubleFormatState(find()->m_doubleFormatState, doubleFormatState);
290 }
291
292 bool makePredictionForDoubleFormat()
293 {
294 ASSERT(isRoot());
295
296 if (m_doubleFormatState != UsingDoubleFormat)
297 return false;
298
299 return mergeSpeculation(m_prediction, SpecDouble);
300 }
301
302 NodeFlags flags() const { return m_flags; }
303
304 bool mergeFlags(NodeFlags newFlags)
305 {
306 return checkAndSet(m_flags, m_flags | newFlags);
307 }
308
309 private:
310 // This is slightly space-inefficient, since anything we're unified with
311 // will have the same operand and should have the same prediction. But
312 // putting them here simplifies the code, and we don't expect DFG space
313 // usage for variable access nodes do be significant.
314
315 VirtualRegister m_local;
316 SpeculatedType m_prediction;
317 SpeculatedType m_argumentAwarePrediction;
318 NodeFlags m_flags;
319
320 bool m_isCaptured;
321 bool m_shouldNeverUnbox;
322 bool m_isArgumentsAlias;
323 bool m_structureCheckHoistingFailed;
324 bool m_isProfitableToUnbox;
325 bool m_isLoadedFrom;
326
327 float m_votes[2]; // Used primarily for double voting but may be reused for other purposes.
328 DoubleFormatState m_doubleFormatState;
329 };
330
331 } } // namespace JSC::DFG
332
333 #endif // DFGVariableAccessData_h