d39ca877c2105fec60511852c9f6f9aaba39b0fc
[WebKit-https.git] / Source / JavaScriptCore / 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