2 * Copyright (C) 2013-2015 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.
27 #include "DFGAbstractValue.h"
32 #include "JSCInlines.h"
33 #include "TrackedReferences.h"
35 namespace JSC
{ namespace DFG
{
37 void AbstractValue::observeTransitions(const TransitionVector
& vector
)
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());
46 m_arrayModes
|= newModes
;
51 void AbstractValue::set(Graph
& graph
, const FrozenValue
& value
, StructureClobberState clobberState
)
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();
61 m_arrayModes
= asArrayModes(structure
->indexingType());
63 m_structure
.makeTop();
64 m_arrayModes
= ALL_ARRAY_MODES
;
71 m_type
= speculationFromValue(value
.value());
72 m_value
= value
.value();
75 assertIsRegistered(graph
);
78 void AbstractValue::set(Graph
& graph
, Structure
* structure
)
80 m_structure
= structure
;
81 m_arrayModes
= asArrayModes(structure
->indexingType());
82 m_type
= speculationFromStructure(structure
);
86 assertIsRegistered(graph
);
89 void AbstractValue::set(Graph
& graph
, const StructureSet
& set
)
92 m_arrayModes
= set
.arrayModesFromStructures();
93 m_type
= set
.speculationFromStructures();
97 assertIsRegistered(graph
);
100 void AbstractValue::setType(Graph
& graph
, SpeculatedType type
)
102 SpeculatedType cellType
= type
& SpecCell
;
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();
109 m_structure
.makeTop();
110 m_arrayModes
= ALL_ARRAY_MODES
;
120 void AbstractValue::fixTypeForRepresentation(Graph
& graph
, NodeFlags representation
, Node
* node
)
122 if (representation
== NodeResultDouble
) {
124 ASSERT(m_value
.isNumber());
125 if (m_value
.isInt32())
126 m_value
= jsDoubleNumber(m_value
.asNumber());
128 if (m_type
& SpecMachineInt
) {
129 m_type
&= ~SpecMachineInt
;
130 m_type
|= SpecInt52AsDouble
;
132 if (m_type
& ~SpecFullDouble
)
133 DFG_CRASH(graph
, node
, toCString("Abstract value ", *this, " for double node has type outside SpecFullDouble.\n").data());
134 } else if (representation
== NodeResultInt52
) {
135 if (m_type
& SpecInt52AsDouble
) {
136 m_type
&= ~SpecInt52AsDouble
;
139 if (m_type
& ~SpecMachineInt
)
140 DFG_CRASH(graph
, node
, toCString("Abstract value ", *this, " for int52 node has type outside SpecMachineInt.\n").data());
142 if (m_type
& SpecInt52
) {
143 m_type
&= ~SpecInt52
;
144 m_type
|= SpecInt52AsDouble
;
146 if (m_type
& ~SpecBytecodeTop
)
147 DFG_CRASH(graph
, node
, toCString("Abstract value ", *this, " for value node has type outside SpecBytecodeTop.\n").data());
153 void AbstractValue::fixTypeForRepresentation(Graph
& graph
, Node
* node
)
155 fixTypeForRepresentation(graph
, node
->result(), node
);
158 bool AbstractValue::mergeOSREntryValue(Graph
& graph
, JSValue value
)
160 AbstractValue oldMe
= *this;
163 FrozenValue
* frozenValue
= graph
.freeze(value
);
164 if (frozenValue
->pointsToHeap()) {
165 m_structure
= frozenValue
->structure();
166 m_arrayModes
= asArrayModes(frozenValue
->structure()->indexingType());
172 m_type
= speculationFromValue(value
);
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
));
182 if (m_value
!= value
)
187 assertIsRegistered(graph
);
189 return oldMe
!= *this;
192 FiltrationResult
AbstractValue::filter(Graph
& graph
, const StructureSet
& other
)
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
201 m_type
&= other
.speculationFromStructures();
202 m_arrayModes
&= other
.arrayModesFromStructures();
203 m_structure
.filter(other
);
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.
210 m_structure
.filter(m_type
);
212 filterArrayModesByType();
214 return normalizeClarity(graph
);
217 FiltrationResult
AbstractValue::changeStructure(Graph
& graph
, const StructureSet
& other
)
219 m_type
&= other
.speculationFromStructures();
220 m_arrayModes
= other
.arrayModesFromStructures();
225 return normalizeClarity(graph
);
228 FiltrationResult
AbstractValue::filterArrayModes(ArrayModes arrayModes
)
236 m_arrayModes
&= arrayModes
;
237 return normalizeClarity();
240 FiltrationResult
AbstractValue::filter(SpeculatedType type
)
242 if ((m_type
& type
) == m_type
)
245 // Fast path for the case that we don't even have a cell.
246 if (!(m_type
& SpecCell
)) {
248 FiltrationResult result
;
249 if (m_type
== SpecNone
) {
251 result
= Contradiction
;
253 result
= FiltrationOK
;
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).
264 m_structure
.filter(type
);
265 filterArrayModesByType();
267 return normalizeClarity();
270 FiltrationResult
AbstractValue::filterByValue(const FrozenValue
& value
)
272 FiltrationResult result
= filter(speculationFromValue(value
.value()));
274 m_value
= value
.value();
278 bool AbstractValue::contains(Structure
* structure
) const
280 return couldBeType(speculationFromStructure(structure
))
281 && (m_arrayModes
& arrayModeFromStructure(structure
))
282 && m_structure
.contains(structure
);
285 FiltrationResult
AbstractValue::filter(const AbstractValue
& other
)
287 m_type
&= other
.m_type
;
288 m_structure
.filter(other
.m_structure
);
289 m_arrayModes
&= other
.m_arrayModes
;
291 m_structure
.filter(m_type
);
292 filterArrayModesByType();
295 if (normalizeClarity() == Contradiction
)
296 return Contradiction
;
298 if (m_value
== other
.m_value
)
301 // Neither of us are BOTTOM, so an empty value means TOP.
303 // We previously didn't prove a value but now we have done so.
304 m_value
= other
.m_value
;
308 if (!other
.m_value
) {
309 // We had proved a value but the other guy hadn't, so keep our proof.
313 // We both proved there to be a specific value but they are different.
315 return Contradiction
;
318 void AbstractValue::filterValueByType()
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.
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
))
332 // The type has been rendered empty. That means that the value must now be invalid,
334 ASSERT(!m_value
|| !validateType(m_value
));
338 void AbstractValue::filterArrayModesByType()
340 if (!(m_type
& SpecCell
))
342 else if (!(m_type
& ~SpecArray
))
343 m_arrayModes
&= ALL_ARRAY_ARRAY_MODES
;
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:
353 // if (!(m_type & SpecArray))
354 // m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES;
357 bool AbstractValue::shouldBeClear() const
359 if (m_type
== SpecNone
)
362 if (!(m_type
& ~SpecCell
)
363 && (!m_arrayModes
|| m_structure
.isClear()))
369 FiltrationResult
AbstractValue::normalizeClarity()
371 // It's useful to be able to quickly check if an abstract value is clear.
372 // This normalizes everything to make that easy.
374 FiltrationResult result
;
376 if (shouldBeClear()) {
378 result
= Contradiction
;
380 result
= FiltrationOK
;
387 FiltrationResult
AbstractValue::normalizeClarity(Graph
& graph
)
389 FiltrationResult result
= normalizeClarity();
390 assertIsRegistered(graph
);
395 void AbstractValue::checkConsistency() const
397 if (!(m_type
& SpecCell
)) {
398 ASSERT(m_structure
.isClear());
399 ASSERT(!m_arrayModes
);
406 SpeculatedType type
= m_type
;
407 // This relaxes the assertion below a bit, since we don't know the representation of the
409 if (type
& SpecInt52
)
410 type
|= SpecInt52AsDouble
;
411 ASSERT(mergeSpeculations(type
, speculationFromValue(m_value
)) == type
);
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.
420 void AbstractValue::assertIsRegistered(Graph
& graph
) const
422 m_structure
.assertIsRegistered(graph
);
426 void AbstractValue::dump(PrintStream
& out
) const
428 dumpInContext(out
, 0);
431 void AbstractValue::dumpInContext(PrintStream
& out
, DumpContext
* context
) const
433 out
.print("(", SpeculationDump(m_type
));
434 if (m_type
& SpecCell
) {
436 ", ", ArrayModesDump(m_arrayModes
), ", ",
437 inContext(m_structure
, context
));
440 out
.print(", ", inContext(m_value
, context
));
444 void AbstractValue::validateReferences(const TrackedReferences
& trackedReferences
)
446 trackedReferences
.check(m_value
);
447 m_structure
.validateReferences(trackedReferences
);
450 } } // namespace JSC::DFG
452 #endif // ENABLE(DFG_JIT)