]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - dfg/DFGAbstractValue.h
JavaScriptCore-7600.1.4.9.tar.gz
[apple/javascriptcore.git] / dfg / DFGAbstractValue.h
index 25757b54ea98177d2ec3292e08ca132501336404..14363dfa3f763b599f3413e1c7ce34754bbb7751 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #ifndef DFGAbstractValue_h
 #define DFGAbstractValue_h
 
-#include <wtf/Platform.h>
-
 #if ENABLE(DFG_JIT)
 
 #include "ArrayProfile.h"
+#include "DFGFiltrationResult.h"
+#include "DFGNodeFlags.h"
 #include "DFGStructureAbstractValue.h"
 #include "JSCell.h"
 #include "SpeculatedType.h"
+#include "DumpContext.h"
 #include "StructureSet.h"
 
 namespace JSC { namespace DFG {
 
+class Graph;
+struct Node;
+
 struct AbstractValue {
     AbstractValue()
         : m_type(SpecNone)
@@ -55,22 +59,17 @@ struct AbstractValue {
         checkConsistency();
     }
     
-    bool isClear() const
+    bool isClear() const { return m_type == SpecNone; }
+    bool operator!() const { return isClear(); }
+    
+    void makeHeapTop()
     {
-        bool result = m_type == SpecNone && !m_arrayModes && m_currentKnownStructure.isClear() && m_futurePossibleStructure.isClear();
-        if (result)
-            ASSERT(!m_value);
-        return result;
+        makeTop(SpecHeapTop);
     }
     
-    void makeTop()
+    void makeBytecodeTop()
     {
-        m_type |= SpecTop; // The state may have included SpecEmpty, in which case we want this to become SpecEmptyOrTop.
-        m_arrayModes = ALL_ARRAY_MODES;
-        m_currentKnownStructure.makeTop();
-        m_futurePossibleStructure.makeTop();
-        m_value = JSValue();
-        checkConsistency();
+        makeTop(SpecBytecodeTop);
     }
     
     void clobberStructures()
@@ -90,9 +89,9 @@ struct AbstractValue {
         m_value = JSValue();
     }
     
-    bool isTop() const
+    bool isHeapTop() const
     {
-        return m_type == SpecTop && m_currentKnownStructure.isTop() && m_futurePossibleStructure.isTop();
+        return (m_type | SpecHeapTop) == m_type && m_currentKnownStructure.isTop() && m_futurePossibleStructure.isTop();
     }
     
     bool valueIsTop() const
@@ -105,64 +104,18 @@ struct AbstractValue {
         return m_value;
     }
     
-    static AbstractValue top()
+    static AbstractValue heapTop()
     {
         AbstractValue result;
-        result.makeTop();
+        result.makeHeapTop();
         return result;
     }
     
-    void setMostSpecific(JSValue value)
-    {
-        if (!!value && value.isCell()) {
-            Structure* structure = value.asCell()->structure();
-            m_currentKnownStructure = structure;
-            setFuturePossibleStructure(structure);
-            m_arrayModes = asArrayModes(structure->indexingType());
-        } else {
-            m_currentKnownStructure.clear();
-            m_futurePossibleStructure.clear();
-            m_arrayModes = 0;
-        }
-        
-        m_type = speculationFromValue(value);
-        m_value = value;
-        
-        checkConsistency();
-    }
-    
-    void set(JSValue value)
-    {
-        if (!!value && value.isCell()) {
-            m_currentKnownStructure.makeTop();
-            Structure* structure = value.asCell()->structure();
-            setFuturePossibleStructure(structure);
-            m_arrayModes = asArrayModes(structure->indexingType());
-            clobberArrayModes();
-        } else {
-            m_currentKnownStructure.clear();
-            m_futurePossibleStructure.clear();
-            m_arrayModes = 0;
-        }
-        
-        m_type = speculationFromValue(value);
-        m_value = value;
-        
-        checkConsistency();
-    }
-    
-    void set(Structure* structure)
-    {
-        m_currentKnownStructure = structure;
-        setFuturePossibleStructure(structure);
-        m_arrayModes = asArrayModes(structure->indexingType());
-        m_type = speculationFromStructure(structure);
-        m_value = JSValue();
-        
-        checkConsistency();
-    }
+    void setMostSpecific(Graph&, JSValue);
+    void set(Graph&, JSValue);
+    void set(Graph&, Structure*);
     
-    void set(SpeculatedType type)
+    void setType(SpeculatedType type)
     {
         if (type & SpecCell) {
             m_currentKnownStructure.makeTop();
@@ -178,6 +131,9 @@ struct AbstractValue {
         checkConsistency();
     }
     
+    void fixTypeForRepresentation(NodeFlags representation);
+    void fixTypeForRepresentation(Node*);
+    
     bool operator==(const AbstractValue& other) const
     {
         return m_type == other.m_type
@@ -232,90 +188,27 @@ struct AbstractValue {
         checkConsistency();
     }
     
-    void filter(const StructureSet& other)
+    bool couldBeType(SpeculatedType desiredType)
     {
-        // FIXME: This could be optimized for the common case of m_type not
-        // having structures, array modes, or a specific value.
-        // https://bugs.webkit.org/show_bug.cgi?id=109663
-        m_type &= other.speculationFromStructures();
-        m_arrayModes &= other.arrayModesFromStructures();
-        m_currentKnownStructure.filter(other);
-        if (m_currentKnownStructure.isClear())
-            m_futurePossibleStructure.clear();
-        else if (m_currentKnownStructure.hasSingleton())
-            filterFuturePossibleStructure(m_currentKnownStructure.singleton());
-        
-        // It's possible that prior to the above two statements we had (Foo, TOP), where
-        // Foo is a SpeculatedType that is disjoint with the passed StructureSet. In that
-        // case, we will now have (None, [someStructure]). In general, we need to make
-        // sure that new information gleaned from the SpeculatedType needs to be fed back
-        // into the information gleaned from the StructureSet.
-        m_currentKnownStructure.filter(m_type);
-        m_futurePossibleStructure.filter(m_type);
-        
-        filterArrayModesByType();
-        filterValueByType();
-        
-        checkConsistency();
+        return !!(m_type & desiredType);
     }
     
-    void filterArrayModes(ArrayModes arrayModes)
+    bool isType(SpeculatedType desiredType)
     {
-        ASSERT(arrayModes);
-        
-        m_type &= SpecCell;
-        m_arrayModes &= arrayModes;
-        
-        // I could do more fancy filtering here. But it probably won't make any difference.
-        
-        checkConsistency();
+        return !(m_type & ~desiredType);
     }
     
-    void filter(SpeculatedType type)
-    {
-        if (type == SpecTop)
-            return;
-        m_type &= type;
-        
-        // It's possible that prior to this filter() call we had, say, (Final, TOP), and
-        // the passed type is Array. At this point we'll have (None, TOP). The best way
-        // to ensure that the structure filtering does the right thing is to filter on
-        // the new type (None) rather than the one passed (Array).
-        m_currentKnownStructure.filter(m_type);
-        m_futurePossibleStructure.filter(m_type);
-        
-        filterArrayModesByType();
-        filterValueByType();
-        
-        checkConsistency();
-    }
+    FiltrationResult filter(Graph&, const StructureSet&);
     
-    void filterByValue(JSValue value)
-    {
-        filter(speculationFromValue(value));
-        if (m_type)
-            m_value = value;
-    }
+    FiltrationResult filterArrayModes(ArrayModes);
     
-    bool validateType(JSValue value) const
-    {
-        if (isTop())
-            return true;
-        
-        if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type)
-            return false;
-        
-        if (value.isEmpty()) {
-            ASSERT(m_type & SpecEmpty);
-            return true;
-        }
-        
-        return true;
-    }
+    FiltrationResult filter(SpeculatedType);
+    
+    FiltrationResult filterByValue(JSValue);
     
     bool validate(JSValue value) const
     {
-        if (isTop())
+        if (isHeapTop())
             return true;
         
         if (!!m_value && m_value != value)
@@ -349,35 +242,20 @@ struct AbstractValue {
         return 0;
     }
     
-    void checkConsistency() const
+    bool hasClobberableState() const
     {
-        if (!(m_type & SpecCell)) {
-            ASSERT(m_currentKnownStructure.isClear());
-            ASSERT(m_futurePossibleStructure.isClear());
-            ASSERT(!m_arrayModes);
-        }
-        
-        if (isClear())
-            ASSERT(!m_value);
-        
-        if (!!m_value)
-            ASSERT(mergeSpeculations(m_type, speculationFromValue(m_value)) == m_type);
-        
-        // Note that it's possible for a prediction like (Final, []). This really means that
-        // the value is bottom and that any code that uses the value is unreachable. But
-        // we don't want to get pedantic about this as it would only increase the computational
-        // complexity of the code.
+        return m_currentKnownStructure.isNeitherClearNorTop()
+            || !arrayModesAreClearOrTop(m_arrayModes);
     }
     
-    void dump(PrintStream& out) const
-    {
-        out.print(
-            "(", SpeculationDump(m_type), ", ", ArrayModesDump(m_arrayModes), ", ",
-            m_currentKnownStructure, ", ", m_futurePossibleStructure);
-        if (!!m_value)
-            out.print(", ", m_value);
-        out.print(")");
-    }
+#if ASSERT_DISABLED
+    void checkConsistency() const { }
+#else
+    void checkConsistency() const;
+#endif
+    
+    void dumpInContext(PrintStream&, DumpContext*) const;
+    void dump(PrintStream&) const;
     
     // A great way to think about the difference between m_currentKnownStructure and
     // m_futurePossibleStructure is to consider these four examples:
@@ -391,7 +269,7 @@ struct AbstractValue {
     //    y = x.f;
     //
     //    Where x will later have a new property added to it, 'g'. Because of the
-    //    known but not-yet-executed property addition, x's currently structure will
+    //    known but not-yet-executed property addition, x's current structure will
     //    not be watchpointable; hence we have no way of statically bounding the set
     //    of possible structures that x may have if a clobbering event happens. So,
     //    x's m_currentKnownStructure will be whatever structure we check to get
@@ -486,57 +364,46 @@ private:
         m_arrayModes = ALL_ARRAY_MODES;
     }
     
-    void setFuturePossibleStructure(Structure* structure)
+    bool validateType(JSValue value) const
     {
-        if (structure->transitionWatchpointSetIsStillValid())
-            m_futurePossibleStructure = structure;
-        else
-            m_futurePossibleStructure.makeTop();
+        if (isHeapTop())
+            return true;
+        
+        // Constant folding always represents Int52's in a double (i.e. Int52AsDouble).
+        // So speculationFromValue(value) for an Int52 value will return Int52AsDouble,
+        // and that's fine - the type validates just fine.
+        SpeculatedType type = m_type;
+        if (type & SpecInt52)
+            type |= SpecInt52AsDouble;
+        
+        if (mergeSpeculations(type, speculationFromValue(value)) != type)
+            return false;
+        
+        if (value.isEmpty()) {
+            ASSERT(m_type & SpecEmpty);
+            return true;
+        }
+        
+        return true;
     }
     
-    void filterFuturePossibleStructure(Structure* structure)
+    void makeTop(SpeculatedType top)
     {
-        if (structure->transitionWatchpointSetIsStillValid())
-            m_futurePossibleStructure.filter(StructureAbstractValue(structure));
-    }
-
-    // We could go further, and ensure that if the futurePossibleStructure contravenes
-    // the value, then we could clear both of those things. But that's unlikely to help
-    // in any realistic scenario, so we don't do it. Simpler is better.
-    void filterValueByType()
-    {
-        if (!!m_type) {
-            // The type is still non-empty. This implies that regardless of what filtering
-            // was done, we either didn't have a value to begin with, or that value is still
-            // valid.
-            ASSERT(!m_value || validateType(m_value));
-            return;
-        }
-        
-        // The type has been rendered empty. That means that the value must now be invalid,
-        // as well.
-        ASSERT(!m_value || !validateType(m_value));
+        m_type |= top;
+        m_arrayModes = ALL_ARRAY_MODES;
+        m_currentKnownStructure.makeTop();
+        m_futurePossibleStructure.makeTop();
         m_value = JSValue();
+        checkConsistency();
     }
     
-    void filterArrayModesByType()
-    {
-        if (!(m_type & SpecCell))
-            m_arrayModes = 0;
-        else if (!(m_type & ~SpecArray))
-            m_arrayModes &= ALL_ARRAY_ARRAY_MODES;
+    void setFuturePossibleStructure(Graph&, Structure*);
 
-        // NOTE: If m_type doesn't have SpecArray set, that doesn't mean that the
-        // array modes have to be a subset of ALL_NON_ARRAY_ARRAY_MODES, since
-        // in the speculated type type-system, RegExpMatchesArry and ArrayPrototype
-        // are Otherobj (since they are not *exactly* JSArray) but in the ArrayModes
-        // type system they are arrays (since they expose the magical length
-        // property and are otherwise allocated using array allocation). Hence the
-        // following would be wrong:
-        //
-        // if (!(m_type & SpecArray))
-        //    m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES;
-    }
+    void filterValueByType();
+    void filterArrayModesByType();
+    
+    bool shouldBeClear() const;
+    FiltrationResult normalizeClarity();
 };
 
 } } // namespace JSC::DFG