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