1 | /* |
2 | * Copyright (C) 2014, 2015 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 | #include "config.h" |
27 | #include "DFGVariableAccessData.h" |
28 | |
29 | #if ENABLE(DFG_JIT) |
30 | |
31 | namespace JSC { namespace DFG { |
32 | |
33 | VariableAccessData::VariableAccessData() |
34 | : m_local(static_cast<VirtualRegister>(std::numeric_limits<int>::min())) |
35 | , m_prediction(SpecNone) |
36 | , m_argumentAwarePrediction(SpecNone) |
37 | , m_flags(0) |
38 | , m_shouldNeverUnbox(false) |
39 | , m_structureCheckHoistingFailed(false) |
40 | , m_checkArrayHoistingFailed(false) |
41 | , m_isProfitableToUnbox(false) |
42 | , m_isLoadedFrom(false) |
43 | , m_doubleFormatState(EmptyDoubleFormatState) |
44 | { |
45 | clearVotes(); |
46 | } |
47 | |
48 | VariableAccessData::VariableAccessData(VirtualRegister local) |
49 | : m_local(local) |
50 | , m_prediction(SpecNone) |
51 | , m_argumentAwarePrediction(SpecNone) |
52 | , m_flags(0) |
53 | , m_shouldNeverUnbox(false) |
54 | , m_structureCheckHoistingFailed(false) |
55 | , m_checkArrayHoistingFailed(false) |
56 | , m_isProfitableToUnbox(false) |
57 | , m_isLoadedFrom(false) |
58 | , m_doubleFormatState(EmptyDoubleFormatState) |
59 | { |
60 | clearVotes(); |
61 | } |
62 | |
63 | bool VariableAccessData::mergeShouldNeverUnbox(bool shouldNeverUnbox) |
64 | { |
65 | bool newShouldNeverUnbox = m_shouldNeverUnbox | shouldNeverUnbox; |
66 | if (newShouldNeverUnbox == m_shouldNeverUnbox) |
67 | return false; |
68 | m_shouldNeverUnbox = newShouldNeverUnbox; |
69 | return true; |
70 | } |
71 | |
72 | bool VariableAccessData::predict(SpeculatedType prediction) |
73 | { |
74 | VariableAccessData* self = find(); |
75 | bool result = mergeSpeculation(self->m_prediction, prediction); |
76 | if (result) |
77 | mergeSpeculation(m_argumentAwarePrediction, m_prediction); |
78 | return result; |
79 | } |
80 | |
81 | bool VariableAccessData::mergeArgumentAwarePrediction(SpeculatedType prediction) |
82 | { |
83 | return mergeSpeculation(find()->m_argumentAwarePrediction, prediction); |
84 | } |
85 | |
86 | bool VariableAccessData::shouldUseDoubleFormatAccordingToVote() |
87 | { |
88 | // We don't support this facility for arguments, yet. |
89 | // FIXME: make this work for arguments. |
90 | if (local().isArgument()) |
91 | return false; |
92 | |
93 | // If the variable is not a number prediction, then this doesn't |
94 | // make any sense. |
95 | if (!isFullNumberSpeculation(prediction())) { |
96 | // FIXME: we may end up forcing a local in inlined argument position to be a double even |
97 | // if it is sometimes not even numeric, since this never signals the fact that it doesn't |
98 | // want doubles. https://bugs.webkit.org/show_bug.cgi?id=109511 |
99 | return false; |
100 | } |
101 | |
102 | // If the variable is predicted to hold only doubles, then it's a |
103 | // no-brainer: it should be formatted as a double. |
104 | if (isDoubleSpeculation(prediction())) |
105 | return true; |
106 | |
107 | // If the variable is known to be used as an integer, then be safe - |
108 | // don't force it to be a double. |
109 | if (flags() & NodeBytecodeUsesAsInt) |
110 | return false; |
111 | |
112 | // If the variable has been voted to become a double, then make it a |
113 | // double. |
114 | if (voteRatio() >= Options::doubleVoteRatioForDoubleFormat()) |
115 | return true; |
116 | |
117 | return false; |
118 | } |
119 | |
120 | bool VariableAccessData::tallyVotesForShouldUseDoubleFormat() |
121 | { |
122 | ASSERT(isRoot()); |
123 | |
124 | if (local().isArgument() || shouldNeverUnbox() |
125 | || (flags() & NodeBytecodeUsesAsArrayIndex)) |
126 | return DFG::mergeDoubleFormatState(m_doubleFormatState, NotUsingDoubleFormat); |
127 | |
128 | if (m_doubleFormatState == CantUseDoubleFormat) |
129 | return false; |
130 | |
131 | bool newValueOfShouldUseDoubleFormat = shouldUseDoubleFormatAccordingToVote(); |
132 | if (!newValueOfShouldUseDoubleFormat) { |
133 | // We monotonically convert to double. Hence, if the fixpoint leads us to conclude that we should |
134 | // switch back to int, we instead ignore this and stick with double. |
135 | return false; |
136 | } |
137 | |
138 | if (m_doubleFormatState == UsingDoubleFormat) |
139 | return false; |
140 | |
141 | return DFG::mergeDoubleFormatState(m_doubleFormatState, UsingDoubleFormat); |
142 | } |
143 | |
144 | bool VariableAccessData::mergeDoubleFormatState(DoubleFormatState doubleFormatState) |
145 | { |
146 | return DFG::mergeDoubleFormatState(find()->m_doubleFormatState, doubleFormatState); |
147 | } |
148 | |
149 | bool VariableAccessData::makePredictionForDoubleFormat() |
150 | { |
151 | ASSERT(isRoot()); |
152 | |
153 | if (m_doubleFormatState != UsingDoubleFormat) |
154 | return false; |
155 | |
156 | SpeculatedType type = m_prediction; |
157 | if (type & ~SpecBytecodeNumber) |
158 | type |= SpecDoublePureNaN; |
159 | if (type & (SpecInt32Only | SpecInt52Any)) |
160 | type |= SpecAnyIntAsDouble; |
161 | return checkAndSet(m_prediction, type); |
162 | } |
163 | |
164 | bool VariableAccessData::couldRepresentInt52() |
165 | { |
166 | if (shouldNeverUnbox()) |
167 | return false; |
168 | |
169 | return couldRepresentInt52Impl(); |
170 | } |
171 | |
172 | bool VariableAccessData::couldRepresentInt52Impl() |
173 | { |
174 | // The hardware has to support it. |
175 | if (!enableInt52()) |
176 | return false; |
177 | |
178 | // We punt for machine arguments. |
179 | if (m_local.isArgument()) |
180 | return false; |
181 | |
182 | // The argument-aware prediction -- which merges all of an (inlined or machine) |
183 | // argument's variable access datas' predictions -- must possibly be Int52Any. |
184 | return isInt32OrInt52Speculation(argumentAwarePrediction()); |
185 | } |
186 | |
187 | FlushFormat VariableAccessData::flushFormat() |
188 | { |
189 | ASSERT(find() == this); |
190 | |
191 | if (!shouldUnboxIfPossible()) |
192 | return FlushedJSValue; |
193 | |
194 | if (shouldUseDoubleFormat()) |
195 | return FlushedDouble; |
196 | |
197 | SpeculatedType prediction = argumentAwarePrediction(); |
198 | |
199 | // This guard is here to protect the call to couldRepresentInt52(), which will return |
200 | // true for !prediction. |
201 | if (!prediction) |
202 | return FlushedJSValue; |
203 | |
204 | if (isInt32Speculation(prediction)) |
205 | return FlushedInt32; |
206 | |
207 | if (couldRepresentInt52Impl()) |
208 | return FlushedInt52; |
209 | |
210 | if (isCellSpeculation(prediction)) |
211 | return FlushedCell; |
212 | |
213 | if (isBooleanSpeculation(prediction)) |
214 | return FlushedBoolean; |
215 | |
216 | return FlushedJSValue; |
217 | } |
218 | |
219 | } } // namespace JSC::DFG |
220 | |
221 | #endif // ENABLE(DFG_JIT) |
222 | |
223 | |