2  * Copyright (C) 2011, 2012, 2013 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(); 
  68         m_type 
|= SpecTop
; // The state may have included SpecEmpty, in which case we want this to become SpecEmptyOrTop. 
  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
) 
 200         AbstractValue oldMe 
= *this; 
 205             result 
= !other
.isClear(); 
 207             result 
|= mergeSpeculation(m_type
, other
.m_type
); 
 208             result 
|= mergeArrayModes(m_arrayModes
, other
.m_arrayModes
); 
 209             result 
|= m_currentKnownStructure
.addAll(other
.m_currentKnownStructure
); 
 210             result 
|= m_futurePossibleStructure
.addAll(other
.m_futurePossibleStructure
); 
 211             if (m_value 
!= other
.m_value
) { 
 217         ASSERT(result 
== (*this != oldMe
)); 
 221     void merge(SpeculatedType type
) 
 223         mergeSpeculation(m_type
, type
); 
 225         if (type 
& SpecCell
) { 
 226             m_currentKnownStructure
.makeTop(); 
 227             m_futurePossibleStructure
.makeTop(); 
 228             m_arrayModes 
= ALL_ARRAY_MODES
; 
 235     void filter(const StructureSet
& other
) 
 237         // FIXME: This could be optimized for the common case of m_type not 
 238         // having structures, array modes, or a specific value. 
 239         // https://bugs.webkit.org/show_bug.cgi?id=109663 
 240         m_type 
&= other
.speculationFromStructures(); 
 241         m_arrayModes 
&= other
.arrayModesFromStructures(); 
 242         m_currentKnownStructure
.filter(other
); 
 243         if (m_currentKnownStructure
.isClear()) 
 244             m_futurePossibleStructure
.clear(); 
 245         else if (m_currentKnownStructure
.hasSingleton()) 
 246             filterFuturePossibleStructure(m_currentKnownStructure
.singleton()); 
 248         // It's possible that prior to the above two statements we had (Foo, TOP), where 
 249         // Foo is a SpeculatedType that is disjoint with the passed StructureSet. In that 
 250         // case, we will now have (None, [someStructure]). In general, we need to make 
 251         // sure that new information gleaned from the SpeculatedType needs to be fed back 
 252         // into the information gleaned from the StructureSet. 
 253         m_currentKnownStructure
.filter(m_type
); 
 254         m_futurePossibleStructure
.filter(m_type
); 
 256         filterArrayModesByType(); 
 262     void filterArrayModes(ArrayModes arrayModes
) 
 267         m_arrayModes 
&= arrayModes
; 
 269         // I could do more fancy filtering here. But it probably won't make any difference. 
 274     void filter(SpeculatedType type
) 
 280         // It's possible that prior to this filter() call we had, say, (Final, TOP), and 
 281         // the passed type is Array. At this point we'll have (None, TOP). The best way 
 282         // to ensure that the structure filtering does the right thing is to filter on 
 283         // the new type (None) rather than the one passed (Array). 
 284         m_currentKnownStructure
.filter(m_type
); 
 285         m_futurePossibleStructure
.filter(m_type
); 
 287         filterArrayModesByType(); 
 293     void filterByValue(JSValue value
) 
 295         filter(speculationFromValue(value
)); 
 300     bool validateType(JSValue value
) const 
 305         if (mergeSpeculations(m_type
, speculationFromValue(value
)) != m_type
) 
 308         if (value
.isEmpty()) { 
 309             ASSERT(m_type 
& SpecEmpty
); 
 316     bool validate(JSValue value
) const 
 321         if (!!m_value 
&& m_value 
!= value
) 
 324         if (mergeSpeculations(m_type
, speculationFromValue(value
)) != m_type
) 
 327         if (value
.isEmpty()) { 
 328             ASSERT(m_type 
& SpecEmpty
); 
 332         if (!!value 
&& value
.isCell()) { 
 333             ASSERT(m_type 
& SpecCell
); 
 334             Structure
* structure 
= value
.asCell()->structure(); 
 335             return m_currentKnownStructure
.contains(structure
) 
 336                 && m_futurePossibleStructure
.contains(structure
) 
 337                 && (m_arrayModes 
& asArrayModes(structure
->indexingType())); 
 343     Structure
* bestProvenStructure() const 
 345         if (m_currentKnownStructure
.hasSingleton()) 
 346             return m_currentKnownStructure
.singleton(); 
 347         if (m_futurePossibleStructure
.hasSingleton()) 
 348             return m_futurePossibleStructure
.singleton(); 
 352     void checkConsistency() const 
 354         if (!(m_type 
& SpecCell
)) { 
 355             ASSERT(m_currentKnownStructure
.isClear()); 
 356             ASSERT(m_futurePossibleStructure
.isClear()); 
 357             ASSERT(!m_arrayModes
); 
 364             ASSERT(mergeSpeculations(m_type
, speculationFromValue(m_value
)) == m_type
); 
 366         // Note that it's possible for a prediction like (Final, []). This really means that 
 367         // the value is bottom and that any code that uses the value is unreachable. But 
 368         // we don't want to get pedantic about this as it would only increase the computational 
 369         // complexity of the code. 
 372     void dump(PrintStream
& out
) const 
 375             "(", SpeculationDump(m_type
), ", ", ArrayModesDump(m_arrayModes
), ", ", 
 376             m_currentKnownStructure
, ", ", m_futurePossibleStructure
); 
 378             out
.print(", ", m_value
); 
 382     // A great way to think about the difference between m_currentKnownStructure and 
 383     // m_futurePossibleStructure is to consider these four examples: 
 387     //    In this case x's m_currentKnownStructure and m_futurePossibleStructure will 
 388     //    both be TOP, since we don't know anything about x for sure, yet. 
 393     //    Where x will later have a new property added to it, 'g'. Because of the 
 394     //    known but not-yet-executed property addition, x's currently structure will 
 395     //    not be watchpointable; hence we have no way of statically bounding the set 
 396     //    of possible structures that x may have if a clobbering event happens. So, 
 397     //    x's m_currentKnownStructure will be whatever structure we check to get 
 398     //    property 'f', and m_futurePossibleStructure will be TOP. 
 403     //    Where x has a terminal structure that is still watchpointable. In this case, 
 404     //    x's m_currentKnownStructure and m_futurePossibleStructure will both be 
 405     //    whatever structure we checked for when getting 'f'. 
 411     //    Where x has a terminal structure that is still watchpointable. In this 
 412     //    case, m_currentKnownStructure will be TOP because bar() may potentially 
 413     //    change x's structure and we have no way of proving otherwise, but 
 414     //    x's m_futurePossibleStructure will be whatever structure we had checked 
 415     //    when getting property 'f'. 
 417     // NB. All fields in this struct must have trivial destructors. 
 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
; 
 529         // NOTE: If m_type doesn't have SpecArray set, that doesn't mean that the 
 530         // array modes have to be a subset of ALL_NON_ARRAY_ARRAY_MODES, since 
 531         // in the speculated type type-system, RegExpMatchesArry and ArrayPrototype 
 532         // are Otherobj (since they are not *exactly* JSArray) but in the ArrayModes 
 533         // type system they are arrays (since they expose the magical length 
 534         // property and are otherwise allocated using array allocation). Hence the 
 535         // following would be wrong: 
 537         // if (!(m_type & SpecArray)) 
 538         //    m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES; 
 542 } } // namespace JSC::DFG 
 544 #endif // ENABLE(DFG_JIT) 
 546 #endif // DFGAbstractValue_h