]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGAbstractValue.cpp
JavaScriptCore-7600.1.4.9.tar.gz
[apple/javascriptcore.git] / dfg / DFGAbstractValue.cpp
1 /*
2 * Copyright (C) 2013, 2014 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 "DFGAbstractValue.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "DFGGraph.h"
32 #include "JSCInlines.h"
33
34 namespace JSC { namespace DFG {
35
36 void AbstractValue::setMostSpecific(Graph& graph, JSValue value)
37 {
38 if (!!value && value.isCell()) {
39 Structure* structure = value.asCell()->structure();
40 m_currentKnownStructure = structure;
41 setFuturePossibleStructure(graph, structure);
42 m_arrayModes = asArrayModes(structure->indexingType());
43 } else {
44 m_currentKnownStructure.clear();
45 m_futurePossibleStructure.clear();
46 m_arrayModes = 0;
47 }
48
49 m_type = speculationFromValue(value);
50 m_value = value;
51
52 checkConsistency();
53 }
54
55 void AbstractValue::set(Graph& graph, JSValue value)
56 {
57 if (!!value && value.isCell()) {
58 m_currentKnownStructure.makeTop();
59 Structure* structure = value.asCell()->structure();
60 setFuturePossibleStructure(graph, structure);
61 m_arrayModes = asArrayModes(structure->indexingType());
62 clobberArrayModes();
63 } else {
64 m_currentKnownStructure.clear();
65 m_futurePossibleStructure.clear();
66 m_arrayModes = 0;
67 }
68
69 m_type = speculationFromValue(value);
70 m_value = value;
71
72 checkConsistency();
73 }
74
75 void AbstractValue::set(Graph& graph, Structure* structure)
76 {
77 m_currentKnownStructure = structure;
78 setFuturePossibleStructure(graph, structure);
79 m_arrayModes = asArrayModes(structure->indexingType());
80 m_type = speculationFromStructure(structure);
81 m_value = JSValue();
82
83 checkConsistency();
84 }
85
86 void AbstractValue::fixTypeForRepresentation(NodeFlags representation)
87 {
88 if (representation == NodeResultDouble) {
89 if (m_value) {
90 ASSERT(m_value.isNumber());
91 if (m_value.isInt32())
92 m_value = jsDoubleNumber(m_value.asNumber());
93 }
94 if (m_type & SpecMachineInt) {
95 m_type &= ~SpecMachineInt;
96 m_type |= SpecInt52AsDouble;
97 }
98 if (m_type & ~SpecFullDouble) {
99 startCrashing();
100 dataLog("Abstract value ", *this, " for double node has type outside SpecFullDouble.\n");
101 CRASH();
102 }
103 } else if (representation == NodeResultInt52) {
104 if (m_type & SpecInt52AsDouble) {
105 m_type &= ~SpecInt52AsDouble;
106 m_type |= SpecInt52;
107 }
108 if (m_type & ~SpecMachineInt) {
109 startCrashing();
110 dataLog("Abstract value ", *this, " for int52 node has type outside SpecMachineInt.\n");
111 CRASH();
112 }
113 } else {
114 if (m_type & SpecInt52) {
115 m_type &= ~SpecInt52;
116 m_type |= SpecInt52AsDouble;
117 }
118 if (m_type & ~SpecBytecodeTop) {
119 startCrashing();
120 dataLog("Abstract value ", *this, " for value node has type outside SpecBytecodeTop.\n");
121 CRASH();
122 }
123 }
124
125 checkConsistency();
126 }
127
128 void AbstractValue::fixTypeForRepresentation(Node* node)
129 {
130 fixTypeForRepresentation(node->result());
131 }
132
133 FiltrationResult AbstractValue::filter(Graph& graph, const StructureSet& other)
134 {
135 if (isClear())
136 return FiltrationOK;
137
138 // FIXME: This could be optimized for the common case of m_type not
139 // having structures, array modes, or a specific value.
140 // https://bugs.webkit.org/show_bug.cgi?id=109663
141
142 m_type &= other.speculationFromStructures();
143 m_arrayModes &= other.arrayModesFromStructures();
144 m_currentKnownStructure.filter(other);
145
146 // It's possible that prior to the above two statements we had (Foo, TOP), where
147 // Foo is a SpeculatedType that is disjoint with the passed StructureSet. In that
148 // case, we will now have (None, [someStructure]). In general, we need to make
149 // sure that new information gleaned from the SpeculatedType needs to be fed back
150 // into the information gleaned from the StructureSet.
151 m_currentKnownStructure.filter(m_type);
152
153 if (m_currentKnownStructure.hasSingleton())
154 setFuturePossibleStructure(graph, m_currentKnownStructure.singleton());
155
156 filterArrayModesByType();
157 filterValueByType();
158 return normalizeClarity();
159 }
160
161 FiltrationResult AbstractValue::filterArrayModes(ArrayModes arrayModes)
162 {
163 ASSERT(arrayModes);
164
165 if (isClear())
166 return FiltrationOK;
167
168 m_type &= SpecCell;
169 m_arrayModes &= arrayModes;
170 return normalizeClarity();
171 }
172
173 FiltrationResult AbstractValue::filter(SpeculatedType type)
174 {
175 if ((m_type & type) == m_type)
176 return FiltrationOK;
177
178 m_type &= type;
179
180 // It's possible that prior to this filter() call we had, say, (Final, TOP), and
181 // the passed type is Array. At this point we'll have (None, TOP). The best way
182 // to ensure that the structure filtering does the right thing is to filter on
183 // the new type (None) rather than the one passed (Array).
184 m_currentKnownStructure.filter(m_type);
185 m_futurePossibleStructure.filter(m_type);
186 filterArrayModesByType();
187 filterValueByType();
188 return normalizeClarity();
189 }
190
191 FiltrationResult AbstractValue::filterByValue(JSValue value)
192 {
193 FiltrationResult result = filter(speculationFromValue(value));
194 if (m_type)
195 m_value = value;
196 return result;
197 }
198
199 void AbstractValue::setFuturePossibleStructure(Graph& graph, Structure* structure)
200 {
201 ASSERT(structure);
202 if (graph.watchpoints().isStillValid(structure->transitionWatchpointSet()))
203 m_futurePossibleStructure = structure;
204 else
205 m_futurePossibleStructure.makeTop();
206 }
207
208 void AbstractValue::filterValueByType()
209 {
210 // We could go further, and ensure that if the futurePossibleStructure contravenes
211 // the value, then we could clear both of those things. But that's unlikely to help
212 // in any realistic scenario, so we don't do it. Simpler is better.
213
214 if (!!m_type) {
215 // The type is still non-empty. It may be that the new type renders
216 // the value empty because it contravenes the constant value we had.
217 if (m_value && !validateType(m_value))
218 clear();
219 return;
220 }
221
222 // The type has been rendered empty. That means that the value must now be invalid,
223 // as well.
224 ASSERT(!m_value || !validateType(m_value));
225 m_value = JSValue();
226 }
227
228 void AbstractValue::filterArrayModesByType()
229 {
230 if (!(m_type & SpecCell))
231 m_arrayModes = 0;
232 else if (!(m_type & ~SpecArray))
233 m_arrayModes &= ALL_ARRAY_ARRAY_MODES;
234
235 // NOTE: If m_type doesn't have SpecArray set, that doesn't mean that the
236 // array modes have to be a subset of ALL_NON_ARRAY_ARRAY_MODES, since
237 // in the speculated type type-system, RegExpMatchesArry and ArrayPrototype
238 // are Otherobj (since they are not *exactly* JSArray) but in the ArrayModes
239 // type system they are arrays (since they expose the magical length
240 // property and are otherwise allocated using array allocation). Hence the
241 // following would be wrong:
242 //
243 // if (!(m_type & SpecArray))
244 // m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES;
245 }
246
247 bool AbstractValue::shouldBeClear() const
248 {
249 if (m_type == SpecNone)
250 return true;
251
252 if (!(m_type & ~SpecCell)
253 && (!m_arrayModes
254 || m_currentKnownStructure.isClear()))
255 return true;
256
257 return false;
258 }
259
260 FiltrationResult AbstractValue::normalizeClarity()
261 {
262 // It's useful to be able to quickly check if an abstract value is clear.
263 // This normalizes everything to make that easy.
264
265 FiltrationResult result;
266
267 if (shouldBeClear()) {
268 clear();
269 result = Contradiction;
270 } else
271 result = FiltrationOK;
272
273 checkConsistency();
274
275 return result;
276 }
277
278 #if !ASSERT_DISABLED
279 void AbstractValue::checkConsistency() const
280 {
281 if (!(m_type & SpecCell)) {
282 ASSERT(m_currentKnownStructure.isClear());
283 ASSERT(m_futurePossibleStructure.isClear());
284 ASSERT(!m_arrayModes);
285 }
286
287 if (isClear())
288 ASSERT(!m_value);
289
290 if (!!m_value) {
291 SpeculatedType type = m_type;
292 // This relaxes the assertion below a bit, since we don't know the representation of the
293 // node.
294 if (type & SpecInt52)
295 type |= SpecInt52AsDouble;
296 ASSERT(mergeSpeculations(type, speculationFromValue(m_value)) == type);
297 }
298
299 // Note that it's possible for a prediction like (Final, []). This really means that
300 // the value is bottom and that any code that uses the value is unreachable. But
301 // we don't want to get pedantic about this as it would only increase the computational
302 // complexity of the code.
303 }
304 #endif
305
306 void AbstractValue::dump(PrintStream& out) const
307 {
308 dumpInContext(out, 0);
309 }
310
311 void AbstractValue::dumpInContext(PrintStream& out, DumpContext* context) const
312 {
313 out.print("(", SpeculationDump(m_type));
314 if (m_type & SpecCell) {
315 out.print(
316 ", ", ArrayModesDump(m_arrayModes), ", ",
317 inContext(m_currentKnownStructure, context), ", ",
318 inContext(m_futurePossibleStructure, context));
319 }
320 if (!!m_value)
321 out.print(", ", inContext(m_value, context));
322 out.print(")");
323 }
324
325 } } // namespace JSC::DFG
326
327 #endif // ENABLE(DFG_JIT)
328