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