2
* Copyright (C) 2011, 2012 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.
26
#ifndef DFGAbstractValue_h
27
#define DFGAbstractValue_h
29
#include <wtf/Platform.h>
33
#include "ArrayProfile.h"
34
#include "DFGStructureAbstractValue.h"
36
#include "SpeculatedType.h"
37
#include "StructureSet.h"
39
namespace JSC { namespace DFG {
41
struct AbstractValue {
52
m_currentKnownStructure.clear();
53
m_futurePossibleStructure.clear();
60
bool result = m_type == SpecNone && !m_arrayModes && m_currentKnownStructure.isClear() && m_futurePossibleStructure.isClear();
69
m_arrayModes = ALL_ARRAY_MODES;
70
m_currentKnownStructure.makeTop();
71
m_futurePossibleStructure.makeTop();
76
void clobberStructures()
78
if (m_type & SpecCell) {
79
m_currentKnownStructure.makeTop();
82
ASSERT(m_currentKnownStructure.isClear());
83
ASSERT(!m_arrayModes);
95
return m_type == SpecTop && m_currentKnownStructure.isTop() && m_futurePossibleStructure.isTop();
98
bool valueIsTop() const
100
return !m_value && m_type;
103
JSValue value() const
108
static AbstractValue top()
110
AbstractValue result;
115
void setMostSpecific(JSValue value)
117
if (!!value && value.isCell()) {
118
Structure* structure = value.asCell()->structure();
119
m_currentKnownStructure = structure;
120
setFuturePossibleStructure(structure);
121
m_arrayModes = asArrayModes(structure->indexingType());
123
m_currentKnownStructure.clear();
124
m_futurePossibleStructure.clear();
128
m_type = speculationFromValue(value);
134
void set(JSValue value)
136
if (!!value && value.isCell()) {
137
m_currentKnownStructure.makeTop();
138
Structure* structure = value.asCell()->structure();
139
setFuturePossibleStructure(structure);
140
m_arrayModes = asArrayModes(structure->indexingType());
143
m_currentKnownStructure.clear();
144
m_futurePossibleStructure.clear();
148
m_type = speculationFromValue(value);
154
void set(Structure* structure)
156
m_currentKnownStructure = structure;
157
setFuturePossibleStructure(structure);
158
m_arrayModes = asArrayModes(structure->indexingType());
159
m_type = speculationFromStructure(structure);
165
void set(SpeculatedType type)
167
if (type & SpecCell) {
168
m_currentKnownStructure.makeTop();
169
m_futurePossibleStructure.makeTop();
170
m_arrayModes = ALL_ARRAY_MODES;
172
m_currentKnownStructure.clear();
173
m_futurePossibleStructure.clear();
181
bool operator==(const AbstractValue& other) const
183
return m_type == other.m_type
184
&& m_arrayModes == other.m_arrayModes
185
&& m_currentKnownStructure == other.m_currentKnownStructure
186
&& m_futurePossibleStructure == other.m_futurePossibleStructure
187
&& m_value == other.m_value;
189
bool operator!=(const AbstractValue& other) const
191
return !(*this == other);
194
bool merge(const AbstractValue& other)
197
AbstractValue oldMe = *this;
202
result = !other.isClear();
204
result |= mergeSpeculation(m_type, other.m_type);
205
result |= mergeArrayModes(m_arrayModes, other.m_arrayModes);
206
result |= m_currentKnownStructure.addAll(other.m_currentKnownStructure);
207
result |= m_futurePossibleStructure.addAll(other.m_futurePossibleStructure);
208
if (m_value != other.m_value) {
214
ASSERT(result == (*this != oldMe));
218
void merge(SpeculatedType type)
220
mergeSpeculation(m_type, type);
222
if (type & SpecCell) {
223
m_currentKnownStructure.makeTop();
224
m_futurePossibleStructure.makeTop();
225
m_arrayModes = ALL_ARRAY_MODES;
232
void filter(const StructureSet& other)
234
m_type &= other.speculationFromStructures();
235
m_arrayModes &= other.arrayModesFromStructures();
236
m_currentKnownStructure.filter(other);
237
if (m_currentKnownStructure.isClear())
238
m_futurePossibleStructure.clear();
239
else if (m_currentKnownStructure.hasSingleton())
240
filterFuturePossibleStructure(m_currentKnownStructure.singleton());
242
// It's possible that prior to the above two statements we had (Foo, TOP), where
243
// Foo is a SpeculatedType that is disjoint with the passed StructureSet. In that
244
// case, we will now have (None, [someStructure]). In general, we need to make
245
// sure that new information gleaned from the SpeculatedType needs to be fed back
246
// into the information gleaned from the StructureSet.
247
m_currentKnownStructure.filter(m_type);
248
m_futurePossibleStructure.filter(m_type);
250
filterArrayModesByType();
256
void filterArrayModes(ArrayModes arrayModes)
261
m_arrayModes &= arrayModes;
263
// I could do more fancy filtering here. But it probably won't make any difference.
268
void filter(SpeculatedType type)
274
// It's possible that prior to this filter() call we had, say, (Final, TOP), and
275
// the passed type is Array. At this point we'll have (None, TOP). The best way
276
// to ensure that the structure filtering does the right thing is to filter on
277
// the new type (None) rather than the one passed (Array).
278
m_currentKnownStructure.filter(m_type);
279
m_futurePossibleStructure.filter(m_type);
281
filterArrayModesByType();
287
bool filterByValue(JSValue value)
289
if (!validate(value))
292
if (!!value && value.isCell())
293
filter(StructureSet(value.asCell()->structure()));
295
filter(speculationFromValue(value));
302
bool validateType(JSValue value) const
307
if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type)
310
if (value.isEmpty()) {
311
ASSERT(m_type & SpecEmpty);
318
bool validate(JSValue value) const
323
if (!!m_value && m_value != value)
326
if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type)
329
if (value.isEmpty()) {
330
ASSERT(m_type & SpecEmpty);
334
if (!!value && value.isCell()) {
335
ASSERT(m_type & SpecCell);
336
Structure* structure = value.asCell()->structure();
337
return m_currentKnownStructure.contains(structure)
338
&& m_futurePossibleStructure.contains(structure)
339
&& (m_arrayModes & asArrayModes(structure->indexingType()));
345
Structure* bestProvenStructure() const
347
if (m_currentKnownStructure.hasSingleton())
348
return m_currentKnownStructure.singleton();
349
if (m_futurePossibleStructure.hasSingleton())
350
return m_futurePossibleStructure.singleton();
354
void checkConsistency() const
356
if (!(m_type & SpecCell)) {
357
ASSERT(m_currentKnownStructure.isClear());
358
ASSERT(m_futurePossibleStructure.isClear());
359
ASSERT(!m_arrayModes);
366
ASSERT(mergeSpeculations(m_type, speculationFromValue(m_value)) == m_type);
368
// Note that it's possible for a prediction like (Final, []). This really means that
369
// the value is bottom and that any code that uses the value is unreachable. But
370
// we don't want to get pedantic about this as it would only increase the computational
371
// complexity of the code.
374
void dump(PrintStream& out) const
377
"(", SpeculationDump(m_type), ", ", arrayModesToString(m_arrayModes), ", ",
378
m_currentKnownStructure, ", ", m_futurePossibleStructure);
380
out.print(", ", m_value.description());
384
// A great way to think about the difference between m_currentKnownStructure and
385
// m_futurePossibleStructure is to consider these four examples:
389
// In this case x's m_currentKnownStructure and m_futurePossibleStructure will
390
// both be TOP, since we don't know anything about x for sure, yet.
395
// Where x will later have a new property added to it, 'g'. Because of the
396
// known but not-yet-executed property addition, x's currently structure will
397
// not be watchpointable; hence we have no way of statically bounding the set
398
// of possible structures that x may have if a clobbering event happens. So,
399
// x's m_currentKnownStructure will be whatever structure we check to get
400
// property 'f', and m_futurePossibleStructure will be TOP.
405
// Where x has a terminal structure that is still watchpointable. In this case,
406
// x's m_currentKnownStructure and m_futurePossibleStructure will both be
407
// whatever structure we checked for when getting 'f'.
413
// Where x has a terminal structure that is still watchpointable. In this
414
// case, m_currentKnownStructure will be TOP because bar() may potentially
415
// change x's structure and we have no way of proving otherwise, but
416
// x's m_futurePossibleStructure will be whatever structure we had checked
417
// when getting property 'f'.
419
// This is a proven constraint on the structures that this value can have right
420
// now. The structure of the current value must belong to this set. The set may
421
// be TOP, indicating that it is the set of all possible structures, in which
422
// case the current value can have any structure. The set may be BOTTOM (empty)
423
// in which case this value cannot be a cell. This is all subject to change
424
// anytime a new value is assigned to this one, anytime there is a control flow
425
// merge, or most crucially, anytime a side-effect or structure check happens.
426
// In case of a side-effect, we typically must assume that any value may have
427
// had its structure changed, hence contravening our proof. We make the proof
428
// valid again by switching this to TOP (i.e. claiming that we have proved that
429
// this value may have any structure). Of note is that the proof represented by
430
// this field is not subject to structure transition watchpoints - even if one
431
// fires, we can be sure that this proof is still valid.
432
StructureAbstractValue m_currentKnownStructure;
434
// This is a proven constraint on the structures that this value can have now
435
// or any time in the future subject to the structure transition watchpoints of
436
// all members of this set not having fired. This set is impervious to side-
437
// effects; even if one happens the side-effect can only cause the value to
438
// change to at worst another structure that is also a member of this set. But,
439
// the theorem being proved by this field is predicated upon there not being
440
// any new structure transitions introduced into any members of this set. In
441
// cases where there is no way for us to guard this happening, the set must be
442
// TOP. But in cases where we can guard new structure transitions (all members
443
// of the set have still-valid structure transition watchpoints) then this set
444
// will be finite. Anytime that we make use of the finite nature of this set,
445
// we must first issue a structure transition watchpoint, which will effectively
446
// result in m_currentKnownStructure being filtered according to
447
// m_futurePossibleStructure.
448
StructureAbstractValue m_futurePossibleStructure;
450
// This is a proven constraint on the possible types that this value can have
451
// now or any time in the future, unless it is reassigned. This field is
452
// impervious to side-effects unless the side-effect can reassign the value
453
// (for example if we're talking about a captured variable). The relationship
454
// between this field, and the structure fields above, is as follows. The
455
// fields above constraint the structures that a cell may have, but they say
456
// nothing about whether or not the value is known to be a cell. More formally,
457
// the m_currentKnownStructure is itself an abstract value that consists of the
458
// union of the set of all non-cell values and the set of cell values that have
459
// the given structure. This abstract value is then the intersection of the
460
// m_currentKnownStructure and the set of values whose type is m_type. So, for
461
// example if m_type is SpecFinal|SpecInt32 and m_currentKnownStructure is
462
// [0x12345] then this abstract value corresponds to the set of all integers
463
// unified with the set of all objects with structure 0x12345.
464
SpeculatedType m_type;
466
// This is a proven constraint on the possible indexing types that this value
467
// can have right now. It also implicitly constraints the set of structures
468
// that the value may have right now, since a structure has an immutable
469
// indexing type. This is subject to change upon reassignment, or any side
470
// effect that makes non-obvious changes to the heap.
471
ArrayModes m_arrayModes;
473
// This is a proven constraint on the possible values that this value can
474
// have now or any time in the future, unless it is reassigned. Note that this
475
// implies nothing about the structure. Oddly, JSValue() (i.e. the empty value)
476
// means either BOTTOM or TOP depending on the state of m_type: if m_type is
477
// BOTTOM then JSValue() means BOTTOM; if m_type is not BOTTOM then JSValue()
482
void clobberArrayModes()
484
// FIXME: We could make this try to predict the set of array modes that this object
485
// could have in the future. For now, just do the simple thing.
486
m_arrayModes = ALL_ARRAY_MODES;
489
void setFuturePossibleStructure(Structure* structure)
491
if (structure->transitionWatchpointSetIsStillValid())
492
m_futurePossibleStructure = structure;
494
m_futurePossibleStructure.makeTop();
497
void filterFuturePossibleStructure(Structure* structure)
499
if (structure->transitionWatchpointSetIsStillValid())
500
m_futurePossibleStructure.filter(StructureAbstractValue(structure));
503
// We could go further, and ensure that if the futurePossibleStructure contravenes
504
// the value, then we could clear both of those things. But that's unlikely to help
505
// in any realistic scenario, so we don't do it. Simpler is better.
506
void filterValueByType()
509
// The type is still non-empty. This implies that regardless of what filtering
510
// was done, we either didn't have a value to begin with, or that value is still
512
ASSERT(!m_value || validateType(m_value));
516
// The type has been rendered empty. That means that the value must now be invalid,
518
ASSERT(!m_value || !validateType(m_value));
522
void filterArrayModesByType()
524
if (!(m_type & SpecCell))
526
else if (!(m_type & ~SpecArray))
527
m_arrayModes &= ALL_ARRAY_ARRAY_MODES;
528
else if (!(m_type & SpecArray))
529
m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES;
533
} } // namespace JSC::DFG
535
#endif // ENABLE(DFG_JIT)
537
#endif // DFGAbstractValue_h