2 * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #ifndef DFGVariableAccessData_h
27 #define DFGVariableAccessData_h
29 #include "DFGDoubleFormatState.h"
30 #include "DFGNodeFlags.h"
32 #include "SpeculatedType.h"
33 #include "VirtualRegister.h"
34 #include <wtf/Platform.h>
35 #include <wtf/UnionFind.h>
36 #include <wtf/Vector.h>
38 namespace JSC
{ namespace DFG
{
40 enum DoubleBallot
{ VoteValue
, VoteDouble
};
42 class VariableAccessData
: public UnionFind
<VariableAccessData
> {
45 : m_local(static_cast<VirtualRegister
>(std::numeric_limits
<int>::min()))
46 , m_prediction(SpecNone
)
47 , m_argumentAwarePrediction(SpecNone
)
50 , m_shouldNeverUnbox(false)
51 , m_isArgumentsAlias(false)
52 , m_structureCheckHoistingFailed(false)
53 , m_isProfitableToUnbox(false)
54 , m_isLoadedFrom(false)
55 , m_doubleFormatState(EmptyDoubleFormatState
)
60 VariableAccessData(VirtualRegister local
, bool isCaptured
)
62 , m_prediction(SpecNone
)
63 , m_argumentAwarePrediction(SpecNone
)
65 , m_isCaptured(isCaptured
)
66 , m_shouldNeverUnbox(isCaptured
)
67 , m_isArgumentsAlias(false)
68 , m_structureCheckHoistingFailed(false)
69 , m_isProfitableToUnbox(false)
70 , m_doubleFormatState(EmptyDoubleFormatState
)
75 VirtualRegister
local()
77 ASSERT(m_local
== find()->m_local
);
83 return static_cast<int>(local());
86 bool mergeIsCaptured(bool isCaptured
)
88 return checkAndSet(m_shouldNeverUnbox
, m_shouldNeverUnbox
| isCaptured
)
89 | checkAndSet(m_isCaptured
, m_isCaptured
| isCaptured
);
97 bool mergeIsProfitableToUnbox(bool isProfitableToUnbox
)
99 return checkAndSet(m_isProfitableToUnbox
, m_isProfitableToUnbox
| isProfitableToUnbox
);
102 bool isProfitableToUnbox()
104 return m_isProfitableToUnbox
;
107 bool mergeShouldNeverUnbox(bool shouldNeverUnbox
)
109 bool newShouldNeverUnbox
= m_shouldNeverUnbox
| shouldNeverUnbox
;
110 if (newShouldNeverUnbox
== m_shouldNeverUnbox
)
112 m_shouldNeverUnbox
= newShouldNeverUnbox
;
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()
121 ASSERT(!(m_isCaptured
&& !m_shouldNeverUnbox
));
122 return m_shouldNeverUnbox
;
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()
130 return !shouldNeverUnbox() && isProfitableToUnbox();
133 bool mergeStructureCheckHoistingFailed(bool failed
)
135 return checkAndSet(m_structureCheckHoistingFailed
, m_structureCheckHoistingFailed
| failed
);
138 bool structureCheckHoistingFailed()
140 return m_structureCheckHoistingFailed
;
143 bool mergeIsArgumentsAlias(bool isArgumentsAlias
)
145 return checkAndSet(m_isArgumentsAlias
, m_isArgumentsAlias
| isArgumentsAlias
);
148 bool isArgumentsAlias()
150 return m_isArgumentsAlias
;
153 bool mergeIsLoadedFrom(bool isLoadedFrom
)
155 return checkAndSet(m_isLoadedFrom
, m_isLoadedFrom
| isLoadedFrom
);
158 void setIsLoadedFrom(bool isLoadedFrom
)
160 m_isLoadedFrom
= isLoadedFrom
;
165 return m_isLoadedFrom
;
168 bool predict(SpeculatedType prediction
)
170 VariableAccessData
* self
= find();
171 bool result
= mergeSpeculation(self
->m_prediction
, prediction
);
173 mergeSpeculation(m_argumentAwarePrediction
, m_prediction
);
177 SpeculatedType
nonUnifiedPrediction()
182 SpeculatedType
prediction()
184 return find()->m_prediction
;
187 SpeculatedType
argumentAwarePrediction()
189 return find()->m_argumentAwarePrediction
;
192 bool mergeArgumentAwarePrediction(SpeculatedType prediction
)
194 return mergeSpeculation(find()->m_argumentAwarePrediction
, prediction
);
199 ASSERT(find() == this);
204 void vote(unsigned ballot
)
212 ASSERT(find() == this);
213 return static_cast<double>(m_votes
[1]) / m_votes
[0];
216 bool shouldUseDoubleFormatAccordingToVote()
218 // We don't support this facility for arguments, yet.
219 // FIXME: make this work for arguments.
220 if (operandIsArgument(operand()))
223 // If the variable is not a number prediction, then this doesn't
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
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()))
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
)
242 // If the variable has been voted to become a double, then make it a
244 if (voteRatio() >= Options::doubleVoteRatioForDoubleFormat())
250 DoubleFormatState
doubleFormatState()
252 return find()->m_doubleFormatState
;
255 bool shouldUseDoubleFormat()
258 bool doubleState
= m_doubleFormatState
== UsingDoubleFormat
;
259 ASSERT(!(doubleState
&& shouldNeverUnbox()));
260 ASSERT(!(doubleState
&& isCaptured()));
261 return doubleState
&& isProfitableToUnbox();
264 bool tallyVotesForShouldUseDoubleFormat()
268 if (operandIsArgument(local()) || shouldNeverUnbox())
269 return DFG::mergeDoubleFormatState(m_doubleFormatState
, NotUsingDoubleFormat
);
271 if (m_doubleFormatState
== CantUseDoubleFormat
)
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.
281 if (m_doubleFormatState
== UsingDoubleFormat
)
284 return DFG::mergeDoubleFormatState(m_doubleFormatState
, UsingDoubleFormat
);
287 bool mergeDoubleFormatState(DoubleFormatState doubleFormatState
)
289 return DFG::mergeDoubleFormatState(find()->m_doubleFormatState
, doubleFormatState
);
292 bool makePredictionForDoubleFormat()
296 if (m_doubleFormatState
!= UsingDoubleFormat
)
299 return mergeSpeculation(m_prediction
, SpecDouble
);
302 NodeFlags
flags() const { return m_flags
; }
304 bool mergeFlags(NodeFlags newFlags
)
306 return checkAndSet(m_flags
, m_flags
| newFlags
);
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.
315 VirtualRegister m_local
;
316 SpeculatedType m_prediction
;
317 SpeculatedType m_argumentAwarePrediction
;
321 bool m_shouldNeverUnbox
;
322 bool m_isArgumentsAlias
;
323 bool m_structureCheckHoistingFailed
;
324 bool m_isProfitableToUnbox
;
327 float m_votes
[2]; // Used primarily for double voting but may be reused for other purposes.
328 DoubleFormatState m_doubleFormatState
;
331 } } // namespace JSC::DFG
333 #endif // DFGVariableAccessData_h