1/*
2 * Copyright (C) 2011, 2012, 2013 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#ifndef DFGStructureAbstractValue_h
27#define DFGStructureAbstractValue_h
28
29#if ENABLE(DFG_JIT)
30
31#include "JSCell.h"
32#include "SpeculatedType.h"
33#include "DumpContext.h"
34#include "StructureSet.h"
35
36namespace JSC { namespace DFG {
37
38class StructureAbstractValue {
39public:
40    StructureAbstractValue()
41        : m_structure(0)
42    {
43    }
44
45    StructureAbstractValue(Structure* structure)
46        : m_structure(structure)
47    {
48    }
49
50    StructureAbstractValue(const StructureSet& set)
51    {
52        switch (set.size()) {
53        case 0:
54            m_structure = 0;
55            break;
56
57        case 1:
58            m_structure = set[0];
59            break;
60
61        default:
62            m_structure = topValue();
63            break;
64        }
65    }
66
67    void clear()
68    {
69        m_structure = 0;
70    }
71
72    void makeTop()
73    {
74        m_structure = topValue();
75    }
76
77    static StructureAbstractValue top()
78    {
79        StructureAbstractValue value;
80        value.makeTop();
81        return value;
82    }
83
84    void add(Structure* structure)
85    {
86        ASSERT(!contains(structure) && !isTop());
87        if (m_structure)
88            makeTop();
89        else
90            m_structure = structure;
91    }
92
93    bool addAll(const StructureSet& other)
94    {
95        if (isTop() || !other.size())
96            return false;
97        if (other.size() > 1) {
98            makeTop();
99            return true;
100        }
101        if (!m_structure) {
102            m_structure = other[0];
103            return true;
104        }
105        if (m_structure == other[0])
106            return false;
107        makeTop();
108        return true;
109    }
110
111    bool addAll(const StructureAbstractValue& other)
112    {
113        if (!other.m_structure)
114            return false;
115        if (isTop())
116            return false;
117        if (other.isTop()) {
118            makeTop();
119            return true;
120        }
121        if (m_structure) {
122            if (m_structure == other.m_structure)
123                return false;
124            makeTop();
125            return true;
126        }
127        m_structure = other.m_structure;
128        return true;
129    }
130
131    bool contains(Structure* structure) const
132    {
133        if (isTop())
134            return true;
135        if (m_structure == structure)
136            return true;
137        return false;
138    }
139
140    bool isSubsetOf(const StructureSet& other) const
141    {
142        if (isTop())
143            return false;
144        if (!m_structure)
145            return true;
146        return other.contains(m_structure);
147    }
148
149    bool doesNotContainAnyOtherThan(Structure* structure) const
150    {
151        if (isTop())
152            return false;
153        if (!m_structure)
154            return true;
155        return m_structure == structure;
156    }
157
158    bool isSupersetOf(const StructureSet& other) const
159    {
160        if (isTop())
161            return true;
162        if (!other.size())
163            return true;
164        if (other.size() > 1)
165            return false;
166        return m_structure == other[0];
167    }
168
169    bool isSubsetOf(const StructureAbstractValue& other) const
170    {
171        if (other.isTop())
172            return true;
173        if (isTop())
174            return false;
175        if (m_structure) {
176            if (other.m_structure)
177                return m_structure == other.m_structure;
178            return false;
179        }
180        return true;
181    }
182
183    bool isSupersetOf(const StructureAbstractValue& other) const
184    {
185        return other.isSubsetOf(*this);
186    }
187
188    void filter(const StructureSet& other)
189    {
190        if (!m_structure)
191            return;
192
193        if (isTop()) {
194            switch (other.size()) {
195            case 0:
196                m_structure = 0;
197                return;
198
199            case 1:
200                m_structure = other[0];
201                return;
202
203            default:
204                return;
205            }
206        }
207
208        if (other.contains(m_structure))
209            return;
210
211        m_structure = 0;
212    }
213
214    void filter(const StructureAbstractValue& other)
215    {
216        if (isTop()) {
217            m_structure = other.m_structure;
218            return;
219        }
220        if (m_structure == other.m_structure)
221            return;
222        if (other.isTop())
223            return;
224        m_structure = 0;
225    }
226
227    void filter(SpeculatedType other)
228    {
229        if (!(other & SpecCell)) {
230            clear();
231            return;
232        }
233
234        if (isClearOrTop())
235            return;
236
237        if (!(speculationFromStructure(m_structure) & other))
238            m_structure = 0;
239    }
240
241    bool isClear() const
242    {
243        return !m_structure;
244    }
245
246    bool isTop() const { return m_structure == topValue(); }
247
248    bool isClearOrTop() const { return m_structure <= topValue(); }
249    bool isNeitherClearNorTop() const { return !isClearOrTop(); }
250
251    size_t size() const
252    {
253        ASSERT(!isTop());
254        return !!m_structure;
255    }
256
257    Structure* at(size_t i) const
258    {
259        ASSERT(!isTop());
260        ASSERT(m_structure);
261        ASSERT_UNUSED(i, !i);
262        return m_structure;
263    }
264
265    Structure* operator[](size_t i) const
266    {
267        return at(i);
268    }
269
270    Structure* last() const
271    {
272        return at(0);
273    }
274
275    SpeculatedType speculationFromStructures() const
276    {
277        if (isTop())
278            return SpecCell;
279        if (isClear())
280            return SpecNone;
281        return speculationFromStructure(m_structure);
282    }
283
284    bool isValidOffset(PropertyOffset offset)
285    {
286        if (isTop())
287            return false;
288        if (isClear())
289            return true;
290        return m_structure->isValidOffset(offset);
291    }
292
293    bool hasSingleton() const
294    {
295        return isNeitherClearNorTop();
296    }
297
298    Structure* singleton() const
299    {
300        ASSERT(isNeitherClearNorTop());
301        return m_structure;
302    }
303
304    bool operator==(const StructureAbstractValue& other) const
305    {
306        return m_structure == other.m_structure;
307    }
308
309    void dumpInContext(PrintStream& out, DumpContext* context) const
310    {
311        if (isTop()) {
312            out.print("TOP");
313            return;
314        }
315
316        out.print("[");
317        if (m_structure)
318            out.print(inContext(*m_structure, context));
319        out.print("]");
320    }
321
322    void dump(PrintStream& out) const
323    {
324        dumpInContext(out, 0);
325    }
326
327private:
328    static Structure* topValue() { return reinterpret_cast<Structure*>(1); }
329
330    // NB. This must have a trivial destructor.
331
332    // This can only remember one structure at a time.
333    Structure* m_structure;
334};
335
336} } // namespace JSC::DFG
337
338#endif // ENABLE(DFG_JIT)
339
340#endif // DFGStructureAbstractValue_h
341
342
343