]>
Commit | Line | Data |
---|---|---|
6fe7ccc8 | 1 | /* |
81345200 | 2 | * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. |
6fe7ccc8 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 | #ifndef DFGAbstractValue_h | |
27 | #define DFGAbstractValue_h | |
28 | ||
6fe7ccc8 A |
29 | #if ENABLE(DFG_JIT) |
30 | ||
93a37866 | 31 | #include "ArrayProfile.h" |
81345200 A |
32 | #include "DFGFiltrationResult.h" |
33 | #include "DFGNodeFlags.h" | |
93a37866 | 34 | #include "DFGStructureAbstractValue.h" |
6fe7ccc8 | 35 | #include "JSCell.h" |
93a37866 | 36 | #include "SpeculatedType.h" |
81345200 | 37 | #include "DumpContext.h" |
6fe7ccc8 A |
38 | #include "StructureSet.h" |
39 | ||
40 | namespace JSC { namespace DFG { | |
41 | ||
81345200 A |
42 | class Graph; |
43 | struct Node; | |
44 | ||
93a37866 A |
45 | struct AbstractValue { |
46 | AbstractValue() | |
47 | : m_type(SpecNone) | |
48 | , m_arrayModes(0) | |
6fe7ccc8 | 49 | { |
6fe7ccc8 A |
50 | } |
51 | ||
52 | void clear() | |
53 | { | |
93a37866 A |
54 | m_type = SpecNone; |
55 | m_arrayModes = 0; | |
56 | m_currentKnownStructure.clear(); | |
57 | m_futurePossibleStructure.clear(); | |
58 | m_value = JSValue(); | |
59 | checkConsistency(); | |
6fe7ccc8 A |
60 | } |
61 | ||
81345200 A |
62 | bool isClear() const { return m_type == SpecNone; } |
63 | bool operator!() const { return isClear(); } | |
64 | ||
65 | void makeHeapTop() | |
6fe7ccc8 | 66 | { |
81345200 | 67 | makeTop(SpecHeapTop); |
6fe7ccc8 A |
68 | } |
69 | ||
81345200 | 70 | void makeBytecodeTop() |
6fe7ccc8 | 71 | { |
81345200 | 72 | makeTop(SpecBytecodeTop); |
6fe7ccc8 A |
73 | } |
74 | ||
93a37866 | 75 | void clobberStructures() |
6fe7ccc8 | 76 | { |
93a37866 A |
77 | if (m_type & SpecCell) { |
78 | m_currentKnownStructure.makeTop(); | |
79 | clobberArrayModes(); | |
80 | } else { | |
81 | ASSERT(m_currentKnownStructure.isClear()); | |
82 | ASSERT(!m_arrayModes); | |
6fe7ccc8 | 83 | } |
93a37866 | 84 | checkConsistency(); |
6fe7ccc8 | 85 | } |
6fe7ccc8 | 86 | |
93a37866 | 87 | void clobberValue() |
6fe7ccc8 | 88 | { |
93a37866 | 89 | m_value = JSValue(); |
6fe7ccc8 A |
90 | } |
91 | ||
81345200 | 92 | bool isHeapTop() const |
6fe7ccc8 | 93 | { |
81345200 | 94 | return (m_type | SpecHeapTop) == m_type && m_currentKnownStructure.isTop() && m_futurePossibleStructure.isTop(); |
6fe7ccc8 A |
95 | } |
96 | ||
93a37866 | 97 | bool valueIsTop() const |
6fe7ccc8 | 98 | { |
93a37866 | 99 | return !m_value && m_type; |
6fe7ccc8 A |
100 | } |
101 | ||
93a37866 | 102 | JSValue value() const |
6fe7ccc8 | 103 | { |
93a37866 | 104 | return m_value; |
6fe7ccc8 A |
105 | } |
106 | ||
81345200 | 107 | static AbstractValue heapTop() |
6fe7ccc8 | 108 | { |
93a37866 | 109 | AbstractValue result; |
81345200 | 110 | result.makeHeapTop(); |
93a37866 | 111 | return result; |
6fe7ccc8 A |
112 | } |
113 | ||
81345200 A |
114 | void setMostSpecific(Graph&, JSValue); |
115 | void set(Graph&, JSValue); | |
116 | void set(Graph&, Structure*); | |
6fe7ccc8 | 117 | |
81345200 | 118 | void setType(SpeculatedType type) |
6fe7ccc8 | 119 | { |
93a37866 A |
120 | if (type & SpecCell) { |
121 | m_currentKnownStructure.makeTop(); | |
122 | m_futurePossibleStructure.makeTop(); | |
123 | m_arrayModes = ALL_ARRAY_MODES; | |
124 | } else { | |
125 | m_currentKnownStructure.clear(); | |
126 | m_futurePossibleStructure.clear(); | |
127 | m_arrayModes = 0; | |
128 | } | |
6fe7ccc8 | 129 | m_type = type; |
93a37866 | 130 | m_value = JSValue(); |
6fe7ccc8 A |
131 | checkConsistency(); |
132 | } | |
133 | ||
81345200 A |
134 | void fixTypeForRepresentation(NodeFlags representation); |
135 | void fixTypeForRepresentation(Node*); | |
136 | ||
6fe7ccc8 A |
137 | bool operator==(const AbstractValue& other) const |
138 | { | |
93a37866 A |
139 | return m_type == other.m_type |
140 | && m_arrayModes == other.m_arrayModes | |
141 | && m_currentKnownStructure == other.m_currentKnownStructure | |
142 | && m_futurePossibleStructure == other.m_futurePossibleStructure | |
143 | && m_value == other.m_value; | |
144 | } | |
145 | bool operator!=(const AbstractValue& other) const | |
146 | { | |
147 | return !(*this == other); | |
6fe7ccc8 A |
148 | } |
149 | ||
150 | bool merge(const AbstractValue& other) | |
151 | { | |
93a37866 A |
152 | if (other.isClear()) |
153 | return false; | |
154 | ||
155 | #if !ASSERT_DISABLED | |
156 | AbstractValue oldMe = *this; | |
157 | #endif | |
158 | bool result = false; | |
159 | if (isClear()) { | |
160 | *this = other; | |
161 | result = !other.isClear(); | |
162 | } else { | |
163 | result |= mergeSpeculation(m_type, other.m_type); | |
164 | result |= mergeArrayModes(m_arrayModes, other.m_arrayModes); | |
165 | result |= m_currentKnownStructure.addAll(other.m_currentKnownStructure); | |
166 | result |= m_futurePossibleStructure.addAll(other.m_futurePossibleStructure); | |
167 | if (m_value != other.m_value) { | |
168 | result |= !!m_value; | |
169 | m_value = JSValue(); | |
170 | } | |
171 | } | |
6fe7ccc8 | 172 | checkConsistency(); |
93a37866 | 173 | ASSERT(result == (*this != oldMe)); |
6fe7ccc8 A |
174 | return result; |
175 | } | |
176 | ||
93a37866 | 177 | void merge(SpeculatedType type) |
6fe7ccc8 | 178 | { |
93a37866 | 179 | mergeSpeculation(m_type, type); |
6fe7ccc8 | 180 | |
93a37866 A |
181 | if (type & SpecCell) { |
182 | m_currentKnownStructure.makeTop(); | |
183 | m_futurePossibleStructure.makeTop(); | |
184 | m_arrayModes = ALL_ARRAY_MODES; | |
185 | } | |
186 | m_value = JSValue(); | |
6fe7ccc8 A |
187 | |
188 | checkConsistency(); | |
189 | } | |
190 | ||
81345200 | 191 | bool couldBeType(SpeculatedType desiredType) |
6fe7ccc8 | 192 | { |
81345200 | 193 | return !!(m_type & desiredType); |
93a37866 A |
194 | } |
195 | ||
81345200 | 196 | bool isType(SpeculatedType desiredType) |
93a37866 | 197 | { |
81345200 | 198 | return !(m_type & ~desiredType); |
6fe7ccc8 A |
199 | } |
200 | ||
81345200 | 201 | FiltrationResult filter(Graph&, const StructureSet&); |
6fe7ccc8 | 202 | |
81345200 | 203 | FiltrationResult filterArrayModes(ArrayModes); |
93a37866 | 204 | |
81345200 A |
205 | FiltrationResult filter(SpeculatedType); |
206 | ||
207 | FiltrationResult filterByValue(JSValue); | |
93a37866 A |
208 | |
209 | bool validate(JSValue value) const | |
210 | { | |
81345200 | 211 | if (isHeapTop()) |
6fe7ccc8 A |
212 | return true; |
213 | ||
93a37866 A |
214 | if (!!m_value && m_value != value) |
215 | return false; | |
216 | ||
217 | if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type) | |
218 | return false; | |
219 | ||
220 | if (value.isEmpty()) { | |
221 | ASSERT(m_type & SpecEmpty); | |
222 | return true; | |
223 | } | |
224 | ||
225 | if (!!value && value.isCell()) { | |
226 | ASSERT(m_type & SpecCell); | |
227 | Structure* structure = value.asCell()->structure(); | |
228 | return m_currentKnownStructure.contains(structure) | |
229 | && m_futurePossibleStructure.contains(structure) | |
230 | && (m_arrayModes & asArrayModes(structure->indexingType())); | |
6fe7ccc8 A |
231 | } |
232 | ||
233 | return true; | |
234 | } | |
235 | ||
93a37866 A |
236 | Structure* bestProvenStructure() const |
237 | { | |
238 | if (m_currentKnownStructure.hasSingleton()) | |
239 | return m_currentKnownStructure.singleton(); | |
240 | if (m_futurePossibleStructure.hasSingleton()) | |
241 | return m_futurePossibleStructure.singleton(); | |
242 | return 0; | |
243 | } | |
244 | ||
81345200 | 245 | bool hasClobberableState() const |
6fe7ccc8 | 246 | { |
81345200 A |
247 | return m_currentKnownStructure.isNeitherClearNorTop() |
248 | || !arrayModesAreClearOrTop(m_arrayModes); | |
6fe7ccc8 A |
249 | } |
250 | ||
81345200 A |
251 | #if ASSERT_DISABLED |
252 | void checkConsistency() const { } | |
253 | #else | |
254 | void checkConsistency() const; | |
255 | #endif | |
256 | ||
257 | void dumpInContext(PrintStream&, DumpContext*) const; | |
258 | void dump(PrintStream&) const; | |
93a37866 A |
259 | |
260 | // A great way to think about the difference between m_currentKnownStructure and | |
261 | // m_futurePossibleStructure is to consider these four examples: | |
262 | // | |
263 | // 1) x = foo(); | |
264 | // | |
265 | // In this case x's m_currentKnownStructure and m_futurePossibleStructure will | |
266 | // both be TOP, since we don't know anything about x for sure, yet. | |
267 | // | |
268 | // 2) x = foo(); | |
269 | // y = x.f; | |
270 | // | |
271 | // Where x will later have a new property added to it, 'g'. Because of the | |
81345200 | 272 | // known but not-yet-executed property addition, x's current structure will |
93a37866 A |
273 | // not be watchpointable; hence we have no way of statically bounding the set |
274 | // of possible structures that x may have if a clobbering event happens. So, | |
275 | // x's m_currentKnownStructure will be whatever structure we check to get | |
276 | // property 'f', and m_futurePossibleStructure will be TOP. | |
277 | // | |
278 | // 3) x = foo(); | |
279 | // y = x.f; | |
280 | // | |
281 | // Where x has a terminal structure that is still watchpointable. In this case, | |
282 | // x's m_currentKnownStructure and m_futurePossibleStructure will both be | |
283 | // whatever structure we checked for when getting 'f'. | |
284 | // | |
285 | // 4) x = foo(); | |
286 | // y = x.f; | |
287 | // bar(); | |
288 | // | |
289 | // Where x has a terminal structure that is still watchpointable. In this | |
290 | // case, m_currentKnownStructure will be TOP because bar() may potentially | |
291 | // change x's structure and we have no way of proving otherwise, but | |
292 | // x's m_futurePossibleStructure will be whatever structure we had checked | |
293 | // when getting property 'f'. | |
294 | ||
295 | // NB. All fields in this struct must have trivial destructors. | |
296 | ||
297 | // This is a proven constraint on the structures that this value can have right | |
298 | // now. The structure of the current value must belong to this set. The set may | |
299 | // be TOP, indicating that it is the set of all possible structures, in which | |
300 | // case the current value can have any structure. The set may be BOTTOM (empty) | |
301 | // in which case this value cannot be a cell. This is all subject to change | |
302 | // anytime a new value is assigned to this one, anytime there is a control flow | |
303 | // merge, or most crucially, anytime a side-effect or structure check happens. | |
304 | // In case of a side-effect, we typically must assume that any value may have | |
305 | // had its structure changed, hence contravening our proof. We make the proof | |
306 | // valid again by switching this to TOP (i.e. claiming that we have proved that | |
307 | // this value may have any structure). Of note is that the proof represented by | |
308 | // this field is not subject to structure transition watchpoints - even if one | |
309 | // fires, we can be sure that this proof is still valid. | |
310 | StructureAbstractValue m_currentKnownStructure; | |
311 | ||
312 | // This is a proven constraint on the structures that this value can have now | |
313 | // or any time in the future subject to the structure transition watchpoints of | |
314 | // all members of this set not having fired. This set is impervious to side- | |
315 | // effects; even if one happens the side-effect can only cause the value to | |
316 | // change to at worst another structure that is also a member of this set. But, | |
317 | // the theorem being proved by this field is predicated upon there not being | |
318 | // any new structure transitions introduced into any members of this set. In | |
319 | // cases where there is no way for us to guard this happening, the set must be | |
320 | // TOP. But in cases where we can guard new structure transitions (all members | |
321 | // of the set have still-valid structure transition watchpoints) then this set | |
322 | // will be finite. Anytime that we make use of the finite nature of this set, | |
323 | // we must first issue a structure transition watchpoint, which will effectively | |
324 | // result in m_currentKnownStructure being filtered according to | |
325 | // m_futurePossibleStructure. | |
326 | StructureAbstractValue m_futurePossibleStructure; | |
327 | ||
328 | // This is a proven constraint on the possible types that this value can have | |
329 | // now or any time in the future, unless it is reassigned. This field is | |
330 | // impervious to side-effects unless the side-effect can reassign the value | |
331 | // (for example if we're talking about a captured variable). The relationship | |
332 | // between this field, and the structure fields above, is as follows. The | |
333 | // fields above constraint the structures that a cell may have, but they say | |
334 | // nothing about whether or not the value is known to be a cell. More formally, | |
335 | // the m_currentKnownStructure is itself an abstract value that consists of the | |
336 | // union of the set of all non-cell values and the set of cell values that have | |
337 | // the given structure. This abstract value is then the intersection of the | |
338 | // m_currentKnownStructure and the set of values whose type is m_type. So, for | |
339 | // example if m_type is SpecFinal|SpecInt32 and m_currentKnownStructure is | |
340 | // [0x12345] then this abstract value corresponds to the set of all integers | |
341 | // unified with the set of all objects with structure 0x12345. | |
342 | SpeculatedType m_type; | |
343 | ||
344 | // This is a proven constraint on the possible indexing types that this value | |
345 | // can have right now. It also implicitly constraints the set of structures | |
346 | // that the value may have right now, since a structure has an immutable | |
347 | // indexing type. This is subject to change upon reassignment, or any side | |
348 | // effect that makes non-obvious changes to the heap. | |
349 | ArrayModes m_arrayModes; | |
350 | ||
351 | // This is a proven constraint on the possible values that this value can | |
352 | // have now or any time in the future, unless it is reassigned. Note that this | |
353 | // implies nothing about the structure. Oddly, JSValue() (i.e. the empty value) | |
354 | // means either BOTTOM or TOP depending on the state of m_type: if m_type is | |
355 | // BOTTOM then JSValue() means BOTTOM; if m_type is not BOTTOM then JSValue() | |
356 | // means TOP. | |
357 | JSValue m_value; | |
358 | ||
359 | private: | |
360 | void clobberArrayModes() | |
6fe7ccc8 | 361 | { |
93a37866 A |
362 | // FIXME: We could make this try to predict the set of array modes that this object |
363 | // could have in the future. For now, just do the simple thing. | |
364 | m_arrayModes = ALL_ARRAY_MODES; | |
365 | } | |
366 | ||
81345200 | 367 | bool validateType(JSValue value) const |
93a37866 | 368 | { |
81345200 A |
369 | if (isHeapTop()) |
370 | return true; | |
371 | ||
372 | // Constant folding always represents Int52's in a double (i.e. Int52AsDouble). | |
373 | // So speculationFromValue(value) for an Int52 value will return Int52AsDouble, | |
374 | // and that's fine - the type validates just fine. | |
375 | SpeculatedType type = m_type; | |
376 | if (type & SpecInt52) | |
377 | type |= SpecInt52AsDouble; | |
378 | ||
379 | if (mergeSpeculations(type, speculationFromValue(value)) != type) | |
380 | return false; | |
381 | ||
382 | if (value.isEmpty()) { | |
383 | ASSERT(m_type & SpecEmpty); | |
384 | return true; | |
385 | } | |
386 | ||
387 | return true; | |
93a37866 A |
388 | } |
389 | ||
81345200 | 390 | void makeTop(SpeculatedType top) |
93a37866 | 391 | { |
81345200 A |
392 | m_type |= top; |
393 | m_arrayModes = ALL_ARRAY_MODES; | |
394 | m_currentKnownStructure.makeTop(); | |
395 | m_futurePossibleStructure.makeTop(); | |
93a37866 | 396 | m_value = JSValue(); |
81345200 | 397 | checkConsistency(); |
93a37866 A |
398 | } |
399 | ||
81345200 | 400 | void setFuturePossibleStructure(Graph&, Structure*); |
93a37866 | 401 | |
81345200 A |
402 | void filterValueByType(); |
403 | void filterArrayModesByType(); | |
404 | ||
405 | bool shouldBeClear() const; | |
406 | FiltrationResult normalizeClarity(); | |
6fe7ccc8 A |
407 | }; |
408 | ||
409 | } } // namespace JSC::DFG | |
410 | ||
411 | #endif // ENABLE(DFG_JIT) | |
412 | ||
413 | #endif // DFGAbstractValue_h | |
414 | ||
415 |