| /* | 
 |  * Copyright (C) 2011-2015 Apple Inc. All rights reserved. | 
 |  * | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions | 
 |  * are met: | 
 |  * 1. Redistributions of source code must retain the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer. | 
 |  * 2. Redistributions in binary form must reproduce the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer in the | 
 |  *    documentation and/or other materials provided with the distribution. | 
 |  * | 
 |  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
 |  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
 |  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR | 
 |  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
 |  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
 |  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
 |  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
 |  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  | 
 |  */ | 
 |  | 
 | #ifndef DFGStructureAbstractValue_h | 
 | #define DFGStructureAbstractValue_h | 
 |  | 
 | #if ENABLE(DFG_JIT) | 
 |  | 
 | #include "DFGTransition.h" | 
 | #include "JSCell.h" | 
 | #include "SpeculatedType.h" | 
 | #include "DumpContext.h" | 
 | #include "StructureSet.h" | 
 |  | 
 | namespace JSC { | 
 |  | 
 | class TrackedReferences; | 
 |  | 
 | namespace DFG { | 
 |  | 
 | class StructureAbstractValue { | 
 | public: | 
 |     StructureAbstractValue() { } | 
 |     StructureAbstractValue(Structure* structure) | 
 |         : m_set(StructureSet(structure)) | 
 |     { | 
 |         setClobbered(false); | 
 |     } | 
 |     StructureAbstractValue(const StructureSet& other) | 
 |         : m_set(other) | 
 |     { | 
 |         setClobbered(false); | 
 |     } | 
 |     ALWAYS_INLINE StructureAbstractValue(const StructureAbstractValue& other) | 
 |         : m_set(other.m_set) | 
 |     { | 
 |         setClobbered(other.isClobbered()); | 
 |     } | 
 |      | 
 |     ALWAYS_INLINE StructureAbstractValue& operator=(Structure* structure) | 
 |     { | 
 |         m_set = StructureSet(structure); | 
 |         setClobbered(false); | 
 |         return *this; | 
 |     } | 
 |     ALWAYS_INLINE StructureAbstractValue& operator=(const StructureSet& other) | 
 |     { | 
 |         m_set = other; | 
 |         setClobbered(false); | 
 |         return *this; | 
 |     } | 
 |     ALWAYS_INLINE StructureAbstractValue& operator=(const StructureAbstractValue& other) | 
 |     { | 
 |         m_set = other.m_set; | 
 |         setClobbered(other.isClobbered()); | 
 |         return *this; | 
 |     } | 
 |      | 
 |     void clear() | 
 |     { | 
 |         m_set.clear(); | 
 |         setClobbered(false); | 
 |     } | 
 |      | 
 |     void makeTop() | 
 |     { | 
 |         m_set.deleteListIfNecessary(); | 
 |         m_set.m_pointer = topValue; | 
 |     } | 
 |      | 
 | #if ASSERT_DISABLED | 
 |     void assertIsRegistered(Graph&) const { } | 
 | #else | 
 |     void assertIsRegistered(Graph&) const; | 
 | #endif | 
 |      | 
 |     void clobber(); | 
 |     void observeInvalidationPoint() { setClobbered(false); } | 
 |      | 
 |     void observeTransition(Structure* from, Structure* to); | 
 |     void observeTransitions(const TransitionVector&); | 
 |      | 
 |     static StructureAbstractValue top() | 
 |     { | 
 |         StructureAbstractValue result; | 
 |         result.m_set.m_pointer = topValue; | 
 |         return result; | 
 |     } | 
 |      | 
 |     bool isClear() const { return m_set.isEmpty(); } | 
 |     bool isTop() const { return m_set.m_pointer == topValue; } | 
 |     bool isNeitherClearNorTop() const { return !isClear() && !isTop(); } | 
 |      | 
 |     // A clobbered abstract value means that the set currently contains the m_set set of | 
 |     // structures plus TOP, except that the "plus TOP" will go away at the next invalidation | 
 |     // point. Note that it's tempting to think of this as "the set of structures in m_set plus | 
 |     // the set of structures transition-reachable from m_set" - but this isn't really correct, | 
 |     // since if we add an unwatchable structure after clobbering, the two definitions are not | 
 |     // equivalent. If we do this, the new unwatchable structure will be added to m_set. | 
 |     // Invalidation points do not try to "clip" the set of transition-reachable structures from | 
 |     // m_set by looking at reachability as this would mean that the new set is TOP. Instead they | 
 |     // literally assume that the set is just m_set rather than m_set plus TOP. | 
 |     bool isClobbered() const { return m_set.getReservedFlag(); } | 
 |      | 
 |     bool add(Structure* structure); | 
 |      | 
 |     bool merge(const StructureSet& other); | 
 |      | 
 |     ALWAYS_INLINE bool merge(const StructureAbstractValue& other) | 
 |     { | 
 |         if (other.isClear()) | 
 |             return false; | 
 |          | 
 |         if (isTop()) | 
 |             return false; | 
 |          | 
 |         if (other.isTop()) { | 
 |             makeTop(); | 
 |             return true; | 
 |         } | 
 |          | 
 |         return mergeSlow(other); | 
 |     } | 
 |      | 
 |     void filter(const StructureSet& other); | 
 |     void filter(const StructureAbstractValue& other); | 
 |      | 
 |     ALWAYS_INLINE void filter(SpeculatedType type) | 
 |     { | 
 |         if (!(type & SpecCell)) { | 
 |             clear(); | 
 |             return; | 
 |         } | 
 |         if (isNeitherClearNorTop()) | 
 |             filterSlow(type); | 
 |     } | 
 |      | 
 |     ALWAYS_INLINE bool operator==(const StructureAbstractValue& other) const | 
 |     { | 
 |         if ((m_set.isThin() && other.m_set.isThin()) || isTop() || other.isTop()) | 
 |             return m_set.m_pointer == other.m_set.m_pointer; | 
 |          | 
 |         return equalsSlow(other); | 
 |     } | 
 |      | 
 |     const StructureSet& set() const | 
 |     { | 
 |         ASSERT(!isTop()); | 
 |         return m_set; | 
 |     } | 
 |      | 
 |     size_t size() const | 
 |     { | 
 |         ASSERT(!isTop()); | 
 |         return m_set.size(); | 
 |     } | 
 |      | 
 |     Structure* at(size_t i) const | 
 |     { | 
 |         ASSERT(!isTop()); | 
 |         return m_set.at(i); | 
 |     } | 
 |      | 
 |     Structure* operator[](size_t i) const { return at(i); } | 
 |      | 
 |     // In most cases, what you really want to do is verify whether the set is top or clobbered, and | 
 |     // if not, enumerate the set of structures. Use this only in cases where the singleton case is | 
 |     // meaningfully special, like for transitions. | 
 |     Structure* onlyStructure() const | 
 |     { | 
 |         if (isTop() || isClobbered()) | 
 |             return nullptr; | 
 |         return m_set.onlyStructure(); | 
 |     } | 
 |      | 
 |     void dumpInContext(PrintStream&, DumpContext*) const; | 
 |     void dump(PrintStream&) const; | 
 |      | 
 |     // The methods below are all conservative and err on the side of making 'this' appear bigger | 
 |     // than it is. For example, contains() may return true if the set is clobbered or TOP. | 
 |     // isSubsetOf() may return false in case of ambiguities. Therefore you should only perform | 
 |     // optimizations as a consequence of the "this is smaller" return value - so false for | 
 |     // contains(), true for isSubsetOf(), false for isSupersetOf(), and false for overlaps(). | 
 |  | 
 |     bool contains(Structure* structure) const; | 
 |      | 
 |     bool isSubsetOf(const StructureSet& other) const; | 
 |     bool isSubsetOf(const StructureAbstractValue& other) const; | 
 |      | 
 |     bool isSupersetOf(const StructureSet& other) const; | 
 |     bool isSupersetOf(const StructureAbstractValue& other) const | 
 |     { | 
 |         return other.isSubsetOf(*this); | 
 |     } | 
 |      | 
 |     bool overlaps(const StructureSet& other) const; | 
 |     bool overlaps(const StructureAbstractValue& other) const; | 
 |      | 
 |     void validateReferences(const TrackedReferences&) const; | 
 |      | 
 | private: | 
 |     static const uintptr_t clobberedFlag = StructureSet::reservedFlag; | 
 |     static const uintptr_t topValue = StructureSet::reservedValue; | 
 |     static const unsigned polymorphismLimit = 10; | 
 |     static const unsigned clobberedSupremacyThreshold = 2; | 
 |      | 
 |     void filterSlow(SpeculatedType type); | 
 |     bool mergeSlow(const StructureAbstractValue& other); | 
 |      | 
 |     bool equalsSlow(const StructureAbstractValue& other) const; | 
 |      | 
 |     void makeTopWhenThin() | 
 |     { | 
 |         ASSERT(m_set.isThin()); | 
 |         m_set.m_pointer = topValue; | 
 |     } | 
 |      | 
 |     bool mergeNotTop(const StructureSet& other); | 
 |      | 
 |     void setClobbered(bool clobbered) | 
 |     { | 
 |         ASSERT(!isTop() || !clobbered); | 
 |         m_set.setReservedFlag(clobbered); | 
 |     } | 
 |      | 
 |     StructureSet m_set; | 
 | }; | 
 |  | 
 | } } // namespace JSC::DFG | 
 |  | 
 | #endif // ENABLE(DFG_JIT) | 
 |  | 
 | #endif // DFGStructureAbstractValue_h | 
 |  | 
 |  |