]> git.saurik.com Git - apple/javascriptcore.git/blame - dfg/DFGAbstractValue.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGAbstractValue.cpp
CommitLineData
81345200 1/*
ed1e77d3 2 * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
81345200
A
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"
ed1e77d3 33#include "TrackedReferences.h"
81345200
A
34
35namespace JSC { namespace DFG {
36
ed1e77d3 37void AbstractValue::observeTransitions(const TransitionVector& vector)
81345200 38{
ed1e77d3
A
39 if (m_type & SpecCell) {
40 m_structure.observeTransitions(vector);
41 ArrayModes newModes = 0;
42 for (unsigned i = vector.size(); i--;) {
43 if (m_arrayModes & asArrayModes(vector[i].previous->indexingType()))
44 newModes |= asArrayModes(vector[i].next->indexingType());
45 }
46 m_arrayModes |= newModes;
81345200 47 }
81345200
A
48 checkConsistency();
49}
50
ed1e77d3 51void AbstractValue::set(Graph& graph, const FrozenValue& value, StructureClobberState clobberState)
81345200 52{
ed1e77d3
A
53 if (!!value && value.value().isCell()) {
54 Structure* structure = value.structure();
55 if (graph.registerStructure(structure) == StructureRegisteredAndWatched) {
56 m_structure = structure;
57 if (clobberState == StructuresAreClobbered) {
58 m_arrayModes = ALL_ARRAY_MODES;
59 m_structure.clobber();
60 } else
61 m_arrayModes = asArrayModes(structure->indexingType());
62 } else {
63 m_structure.makeTop();
64 m_arrayModes = ALL_ARRAY_MODES;
65 }
81345200 66 } else {
ed1e77d3 67 m_structure.clear();
81345200
A
68 m_arrayModes = 0;
69 }
70
ed1e77d3
A
71 m_type = speculationFromValue(value.value());
72 m_value = value.value();
81345200
A
73
74 checkConsistency();
ed1e77d3 75 assertIsRegistered(graph);
81345200
A
76}
77
78void AbstractValue::set(Graph& graph, Structure* structure)
79{
ed1e77d3 80 m_structure = structure;
81345200
A
81 m_arrayModes = asArrayModes(structure->indexingType());
82 m_type = speculationFromStructure(structure);
83 m_value = JSValue();
84
85 checkConsistency();
ed1e77d3
A
86 assertIsRegistered(graph);
87}
88
89void AbstractValue::set(Graph& graph, const StructureSet& set)
90{
91 m_structure = set;
92 m_arrayModes = set.arrayModesFromStructures();
93 m_type = set.speculationFromStructures();
94 m_value = JSValue();
95
96 checkConsistency();
97 assertIsRegistered(graph);
81345200
A
98}
99
ed1e77d3
A
100void AbstractValue::setType(Graph& graph, SpeculatedType type)
101{
102 SpeculatedType cellType = type & SpecCell;
103 if (cellType) {
104 if (!(cellType & ~SpecString))
105 m_structure = graph.m_vm.stringStructure.get();
106 else if (isSymbolSpeculation(cellType))
107 m_structure = graph.m_vm.symbolStructure.get();
108 else
109 m_structure.makeTop();
110 m_arrayModes = ALL_ARRAY_MODES;
111 } else {
112 m_structure.clear();
113 m_arrayModes = 0;
114 }
115 m_type = type;
116 m_value = JSValue();
117 checkConsistency();
118}
119
120void AbstractValue::fixTypeForRepresentation(Graph& graph, NodeFlags representation, Node* node)
81345200
A
121{
122 if (representation == NodeResultDouble) {
123 if (m_value) {
124 ASSERT(m_value.isNumber());
125 if (m_value.isInt32())
126 m_value = jsDoubleNumber(m_value.asNumber());
127 }
128 if (m_type & SpecMachineInt) {
129 m_type &= ~SpecMachineInt;
130 m_type |= SpecInt52AsDouble;
131 }
ed1e77d3
A
132 if (m_type & ~SpecFullDouble)
133 DFG_CRASH(graph, node, toCString("Abstract value ", *this, " for double node has type outside SpecFullDouble.\n").data());
81345200
A
134 } else if (representation == NodeResultInt52) {
135 if (m_type & SpecInt52AsDouble) {
136 m_type &= ~SpecInt52AsDouble;
137 m_type |= SpecInt52;
138 }
ed1e77d3
A
139 if (m_type & ~SpecMachineInt)
140 DFG_CRASH(graph, node, toCString("Abstract value ", *this, " for int52 node has type outside SpecMachineInt.\n").data());
81345200
A
141 } else {
142 if (m_type & SpecInt52) {
143 m_type &= ~SpecInt52;
144 m_type |= SpecInt52AsDouble;
145 }
ed1e77d3
A
146 if (m_type & ~SpecBytecodeTop)
147 DFG_CRASH(graph, node, toCString("Abstract value ", *this, " for value node has type outside SpecBytecodeTop.\n").data());
81345200
A
148 }
149
150 checkConsistency();
151}
152
ed1e77d3 153void AbstractValue::fixTypeForRepresentation(Graph& graph, Node* node)
81345200 154{
ed1e77d3
A
155 fixTypeForRepresentation(graph, node->result(), node);
156}
157
158bool AbstractValue::mergeOSREntryValue(Graph& graph, JSValue value)
159{
160 AbstractValue oldMe = *this;
161
162 if (isClear()) {
163 FrozenValue* frozenValue = graph.freeze(value);
164 if (frozenValue->pointsToHeap()) {
165 m_structure = frozenValue->structure();
166 m_arrayModes = asArrayModes(frozenValue->structure()->indexingType());
167 } else {
168 m_structure.clear();
169 m_arrayModes = 0;
170 }
171
172 m_type = speculationFromValue(value);
173 m_value = value;
174 } else {
175 mergeSpeculation(m_type, speculationFromValue(value));
176 if (!!value && value.isCell()) {
177 Structure* structure = value.asCell()->structure();
178 graph.registerStructure(structure);
179 mergeArrayModes(m_arrayModes, asArrayModes(structure->indexingType()));
180 m_structure.merge(StructureSet(structure));
181 }
182 if (m_value != value)
183 m_value = JSValue();
184 }
185
186 checkConsistency();
187 assertIsRegistered(graph);
188
189 return oldMe != *this;
81345200
A
190}
191
192FiltrationResult AbstractValue::filter(Graph& graph, const StructureSet& other)
193{
194 if (isClear())
195 return FiltrationOK;
196
197 // FIXME: This could be optimized for the common case of m_type not
198 // having structures, array modes, or a specific value.
199 // https://bugs.webkit.org/show_bug.cgi?id=109663
200
201 m_type &= other.speculationFromStructures();
202 m_arrayModes &= other.arrayModesFromStructures();
ed1e77d3 203 m_structure.filter(other);
81345200
A
204
205 // It's possible that prior to the above two statements we had (Foo, TOP), where
206 // Foo is a SpeculatedType that is disjoint with the passed StructureSet. In that
207 // case, we will now have (None, [someStructure]). In general, we need to make
208 // sure that new information gleaned from the SpeculatedType needs to be fed back
209 // into the information gleaned from the StructureSet.
ed1e77d3 210 m_structure.filter(m_type);
81345200 211
81345200
A
212 filterArrayModesByType();
213 filterValueByType();
ed1e77d3
A
214 return normalizeClarity(graph);
215}
216
217FiltrationResult AbstractValue::changeStructure(Graph& graph, const StructureSet& other)
218{
219 m_type &= other.speculationFromStructures();
220 m_arrayModes = other.arrayModesFromStructures();
221 m_structure = other;
222
223 filterValueByType();
224
225 return normalizeClarity(graph);
81345200
A
226}
227
228FiltrationResult AbstractValue::filterArrayModes(ArrayModes arrayModes)
229{
230 ASSERT(arrayModes);
231
232 if (isClear())
233 return FiltrationOK;
234
235 m_type &= SpecCell;
236 m_arrayModes &= arrayModes;
237 return normalizeClarity();
238}
239
240FiltrationResult AbstractValue::filter(SpeculatedType type)
241{
242 if ((m_type & type) == m_type)
243 return FiltrationOK;
244
ed1e77d3
A
245 // Fast path for the case that we don't even have a cell.
246 if (!(m_type & SpecCell)) {
247 m_type &= type;
248 FiltrationResult result;
249 if (m_type == SpecNone) {
250 clear();
251 result = Contradiction;
252 } else
253 result = FiltrationOK;
254 checkConsistency();
255 return result;
256 }
257
81345200
A
258 m_type &= type;
259
260 // It's possible that prior to this filter() call we had, say, (Final, TOP), and
261 // the passed type is Array. At this point we'll have (None, TOP). The best way
262 // to ensure that the structure filtering does the right thing is to filter on
263 // the new type (None) rather than the one passed (Array).
ed1e77d3 264 m_structure.filter(type);
81345200
A
265 filterArrayModesByType();
266 filterValueByType();
267 return normalizeClarity();
268}
269
ed1e77d3 270FiltrationResult AbstractValue::filterByValue(const FrozenValue& value)
81345200 271{
ed1e77d3 272 FiltrationResult result = filter(speculationFromValue(value.value()));
81345200 273 if (m_type)
ed1e77d3 274 m_value = value.value();
81345200
A
275 return result;
276}
277
ed1e77d3
A
278bool AbstractValue::contains(Structure* structure) const
279{
280 return couldBeType(speculationFromStructure(structure))
281 && (m_arrayModes & arrayModeFromStructure(structure))
282 && m_structure.contains(structure);
283}
284
285FiltrationResult AbstractValue::filter(const AbstractValue& other)
81345200 286{
ed1e77d3
A
287 m_type &= other.m_type;
288 m_structure.filter(other.m_structure);
289 m_arrayModes &= other.m_arrayModes;
290
291 m_structure.filter(m_type);
292 filterArrayModesByType();
293 filterValueByType();
294
295 if (normalizeClarity() == Contradiction)
296 return Contradiction;
297
298 if (m_value == other.m_value)
299 return FiltrationOK;
300
301 // Neither of us are BOTTOM, so an empty value means TOP.
302 if (!m_value) {
303 // We previously didn't prove a value but now we have done so.
304 m_value = other.m_value;
305 return FiltrationOK;
306 }
307
308 if (!other.m_value) {
309 // We had proved a value but the other guy hadn't, so keep our proof.
310 return FiltrationOK;
311 }
312
313 // We both proved there to be a specific value but they are different.
314 clear();
315 return Contradiction;
81345200
A
316}
317
318void AbstractValue::filterValueByType()
319{
320 // We could go further, and ensure that if the futurePossibleStructure contravenes
321 // the value, then we could clear both of those things. But that's unlikely to help
322 // in any realistic scenario, so we don't do it. Simpler is better.
323
324 if (!!m_type) {
325 // The type is still non-empty. It may be that the new type renders
326 // the value empty because it contravenes the constant value we had.
327 if (m_value && !validateType(m_value))
328 clear();
329 return;
330 }
331
332 // The type has been rendered empty. That means that the value must now be invalid,
333 // as well.
334 ASSERT(!m_value || !validateType(m_value));
335 m_value = JSValue();
336}
337
338void AbstractValue::filterArrayModesByType()
339{
340 if (!(m_type & SpecCell))
341 m_arrayModes = 0;
342 else if (!(m_type & ~SpecArray))
343 m_arrayModes &= ALL_ARRAY_ARRAY_MODES;
344
345 // NOTE: If m_type doesn't have SpecArray set, that doesn't mean that the
346 // array modes have to be a subset of ALL_NON_ARRAY_ARRAY_MODES, since
347 // in the speculated type type-system, RegExpMatchesArry and ArrayPrototype
348 // are Otherobj (since they are not *exactly* JSArray) but in the ArrayModes
349 // type system they are arrays (since they expose the magical length
350 // property and are otherwise allocated using array allocation). Hence the
351 // following would be wrong:
352 //
353 // if (!(m_type & SpecArray))
354 // m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES;
355}
356
357bool AbstractValue::shouldBeClear() const
358{
359 if (m_type == SpecNone)
360 return true;
361
362 if (!(m_type & ~SpecCell)
ed1e77d3 363 && (!m_arrayModes || m_structure.isClear()))
81345200
A
364 return true;
365
366 return false;
367}
368
369FiltrationResult AbstractValue::normalizeClarity()
370{
371 // It's useful to be able to quickly check if an abstract value is clear.
372 // This normalizes everything to make that easy.
373
374 FiltrationResult result;
375
376 if (shouldBeClear()) {
377 clear();
378 result = Contradiction;
379 } else
380 result = FiltrationOK;
381
382 checkConsistency();
383
384 return result;
385}
386
ed1e77d3
A
387FiltrationResult AbstractValue::normalizeClarity(Graph& graph)
388{
389 FiltrationResult result = normalizeClarity();
390 assertIsRegistered(graph);
391 return result;
392}
393
81345200
A
394#if !ASSERT_DISABLED
395void AbstractValue::checkConsistency() const
396{
397 if (!(m_type & SpecCell)) {
ed1e77d3 398 ASSERT(m_structure.isClear());
81345200
A
399 ASSERT(!m_arrayModes);
400 }
401
402 if (isClear())
403 ASSERT(!m_value);
404
405 if (!!m_value) {
406 SpeculatedType type = m_type;
407 // This relaxes the assertion below a bit, since we don't know the representation of the
408 // node.
409 if (type & SpecInt52)
410 type |= SpecInt52AsDouble;
411 ASSERT(mergeSpeculations(type, speculationFromValue(m_value)) == type);
412 }
413
414 // Note that it's possible for a prediction like (Final, []). This really means that
415 // the value is bottom and that any code that uses the value is unreachable. But
416 // we don't want to get pedantic about this as it would only increase the computational
417 // complexity of the code.
418}
ed1e77d3
A
419
420void AbstractValue::assertIsRegistered(Graph& graph) const
421{
422 m_structure.assertIsRegistered(graph);
423}
81345200
A
424#endif
425
426void AbstractValue::dump(PrintStream& out) const
427{
428 dumpInContext(out, 0);
429}
430
431void AbstractValue::dumpInContext(PrintStream& out, DumpContext* context) const
432{
433 out.print("(", SpeculationDump(m_type));
434 if (m_type & SpecCell) {
435 out.print(
436 ", ", ArrayModesDump(m_arrayModes), ", ",
ed1e77d3 437 inContext(m_structure, context));
81345200
A
438 }
439 if (!!m_value)
440 out.print(", ", inContext(m_value, context));
441 out.print(")");
442}
443
ed1e77d3
A
444void AbstractValue::validateReferences(const TrackedReferences& trackedReferences)
445{
446 trackedReferences.check(m_value);
447 m_structure.validateReferences(trackedReferences);
448}
449
81345200
A
450} } // namespace JSC::DFG
451
452#endif // ENABLE(DFG_JIT)
453