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
34namespace JSC { namespace DFG {
35
36void 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
55void 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
75void 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
86void 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
128void AbstractValue::fixTypeForRepresentation(Node* node)
129{
130    fixTypeForRepresentation(node->result());
131}
132
133FiltrationResult 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
161FiltrationResult 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
173FiltrationResult 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
191FiltrationResult AbstractValue::filterByValue(JSValue value)
192{
193    FiltrationResult result = filter(speculationFromValue(value));
194    if (m_type)
195        m_value = value;
196    return result;
197}
198
199void 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
208void 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
228void 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
247bool 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
260FiltrationResult 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
279void 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
306void AbstractValue::dump(PrintStream& out) const
307{
308    dumpInContext(out, 0);
309}
310
311void 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
329