feb02472ff4c825d86b5944d07105ae07f81523e
[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 "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