diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h | 400 |
1 files changed, 170 insertions, 230 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h b/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h index 54d3bd29b..5c6adc7ed 100644 --- a/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h +++ b/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. + * 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 @@ -23,322 +23,262 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DFGStructureAbstractValue_h -#define DFGStructureAbstractValue_h - -#include <wtf/Platform.h> +#pragma once #if ENABLE(DFG_JIT) +#include "DFGRegisteredStructureSet.h" +#include "DFGTransition.h" +#include "DumpContext.h" #include "JSCell.h" #include "SpeculatedType.h" -#include "DumpContext.h" #include "StructureSet.h" -namespace JSC { namespace DFG { +namespace JSC { + +class TrackedReferences; + +namespace DFG { class StructureAbstractValue { public: - StructureAbstractValue() - : m_structure(0) + StructureAbstractValue() { } + StructureAbstractValue(RegisteredStructure structure) + : m_set(structure) { + setClobbered(false); } - - StructureAbstractValue(Structure* structure) - : m_structure(structure) + StructureAbstractValue(const RegisteredStructureSet& other) + : m_set(other) + { + setClobbered(false); + } + ALWAYS_INLINE StructureAbstractValue(const StructureAbstractValue& other) + : m_set(other.m_set) { + setClobbered(other.isClobbered()); } - StructureAbstractValue(const StructureSet& set) + ALWAYS_INLINE StructureAbstractValue& operator=(RegisteredStructure structure) { - switch (set.size()) { - case 0: - m_structure = 0; - break; - - case 1: - m_structure = set[0]; - break; - - default: - m_structure = topValue(); - break; - } + m_set = RegisteredStructureSet(structure); + setClobbered(false); + return *this; + } + ALWAYS_INLINE StructureAbstractValue& operator=(const RegisteredStructureSet& 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_structure = 0; + m_set.clear(); + setClobbered(false); } void makeTop() { - m_structure = topValue(); + 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(RegisteredStructure from, RegisteredStructure to); + void observeTransitions(const TransitionVector&); + static StructureAbstractValue top() { - StructureAbstractValue value; - value.makeTop(); - return value; + StructureAbstractValue result; + result.m_set.m_pointer = topValue; + return result; } - void add(Structure* structure) - { - ASSERT(!contains(structure) && !isTop()); - if (m_structure) - makeTop(); - else - m_structure = structure; - } + 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(); } + + // A finite structure abstract value is one where enumerating over it will yield all + // of the structures that the value may have right now. This is true so long as we're + // neither top nor clobbered. + bool isFinite() const { return !isTop() && !isClobbered(); } + + // An infinite structure abstract value may currently have any structure. + bool isInfinite() const { return !isFinite(); } - bool addAll(const StructureSet& other) - { - if (isTop() || !other.size()) - return false; - if (other.size() > 1) { - makeTop(); - return true; - } - if (!m_structure) { - m_structure = other[0]; - return true; - } - if (m_structure == other[0]) - return false; - makeTop(); - return true; - } + bool add(RegisteredStructure); + + bool merge(const RegisteredStructureSet& other); - bool addAll(const StructureAbstractValue& other) + ALWAYS_INLINE bool merge(const StructureAbstractValue& other) { - if (!other.m_structure) + if (other.isClear()) return false; + if (isTop()) return false; + if (other.isTop()) { makeTop(); return true; } - if (m_structure) { - if (m_structure == other.m_structure) - return false; - makeTop(); - return true; - } - m_structure = other.m_structure; - return true; - } - - bool contains(Structure* structure) const - { - if (isTop()) - return true; - if (m_structure == structure) - return true; - return false; - } - - bool isSubsetOf(const StructureSet& other) const - { - if (isTop()) - return false; - if (!m_structure) - return true; - return other.contains(m_structure); - } - - bool doesNotContainAnyOtherThan(Structure* structure) const - { - if (isTop()) - return false; - if (!m_structure) - return true; - return m_structure == structure; + + return mergeSlow(other); } - bool isSupersetOf(const StructureSet& other) const - { - if (isTop()) - return true; - if (!other.size()) - return true; - if (other.size() > 1) - return false; - return m_structure == other[0]; - } + void filter(const RegisteredStructureSet& other); + void filter(const StructureAbstractValue& other); - bool isSubsetOf(const StructureAbstractValue& other) const + ALWAYS_INLINE void filter(SpeculatedType type) { - if (other.isTop()) - return true; - if (isTop()) - return false; - if (m_structure) { - if (other.m_structure) - return m_structure == other.m_structure; - return false; + if (!(type & SpecCell)) { + clear(); + return; } - return true; + if (isNeitherClearNorTop()) + filterSlow(type); } - - bool isSupersetOf(const StructureAbstractValue& other) const + + ALWAYS_INLINE void filterClassInfo(const ClassInfo* classInfo) { - return other.isSubsetOf(*this); + if (isNeitherClearNorTop()) + filterClassInfoSlow(classInfo); } - void filter(const StructureSet& other) + ALWAYS_INLINE bool operator==(const StructureAbstractValue& other) const { - if (!m_structure) - return; - - if (isTop()) { - switch (other.size()) { - case 0: - m_structure = 0; - return; - - case 1: - m_structure = other[0]; - return; - - default: - return; - } - } - - if (other.contains(m_structure)) - return; + if ((m_set.isThin() && other.m_set.isThin()) || isTop() || other.isTop()) + return m_set.m_pointer == other.m_set.m_pointer; - m_structure = 0; + return equalsSlow(other); } - void filter(const StructureAbstractValue& other) + const RegisteredStructureSet& set() const { - if (isTop()) { - m_structure = other.m_structure; - return; - } - if (m_structure == other.m_structure) - return; - if (other.isTop()) - return; - m_structure = 0; + ASSERT(!isTop()); + return m_set; } - - void filter(SpeculatedType other) - { - if (!(other & SpecCell)) { - clear(); - return; - } - - if (isClearOrTop()) - return; - if (!(speculationFromStructure(m_structure) & other)) - m_structure = 0; - } - - bool isClear() const + StructureSet toStructureSet() const { - return !m_structure; + RELEASE_ASSERT(isFinite()); + return m_set.toStructureSet(); } - bool isTop() const { return m_structure == topValue(); } - - bool isClearOrTop() const { return m_structure <= topValue(); } - bool isNeitherClearNorTop() const { return !isClearOrTop(); } - size_t size() const { ASSERT(!isTop()); - return !!m_structure; + return m_set.size(); } - Structure* at(size_t i) const + RegisteredStructure at(size_t i) const { ASSERT(!isTop()); - ASSERT(m_structure); - ASSERT_UNUSED(i, !i); - return m_structure; + return m_set.at(i); } - Structure* operator[](size_t i) const + RegisteredStructure 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. + RegisteredStructure onlyStructure() const { - return at(i); + if (isInfinite()) + return RegisteredStructure(); + return m_set.onlyStructure(); } - - Structure* last() const + + template<typename Functor> + void forEach(const Functor& functor) const { - return at(0); + ASSERT(!isTop()); + m_set.forEach(functor); } - SpeculatedType speculationFromStructures() const - { - if (isTop()) - return SpecCell; - if (isClear()) - return SpecNone; - return speculationFromStructure(m_structure); - } + void dumpInContext(PrintStream&, DumpContext*) const; + void dump(PrintStream&) const; - bool isValidOffset(PropertyOffset offset) - { - if (isTop()) - return false; - if (isClear()) - return true; - return m_structure->isValidOffset(offset); - } + // 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(RegisteredStructure) const; + bool contains(Structure* structure) const; - bool hasSingleton() const - { - return isNeitherClearNorTop(); - } + bool isSubsetOf(const RegisteredStructureSet& other) const; + bool isSubsetOf(const StructureAbstractValue& other) const; - Structure* singleton() const + bool isSupersetOf(const RegisteredStructureSet& other) const; + bool isSupersetOf(const StructureAbstractValue& other) const { - ASSERT(isNeitherClearNorTop()); - return m_structure; + return other.isSubsetOf(*this); } - bool operator==(const StructureAbstractValue& other) const - { - return m_structure == other.m_structure; - } + bool overlaps(const RegisteredStructureSet& other) const; + bool overlaps(const StructureAbstractValue& other) const; + + bool isSubClassOf(const ClassInfo*) const; + + void validateReferences(const TrackedReferences&) const; - void dumpInContext(PrintStream& out, DumpContext* context) const +private: + static const uintptr_t clobberedFlag = RegisteredStructureSet::reservedFlag; + static const uintptr_t topValue = RegisteredStructureSet::reservedValue; + static const unsigned polymorphismLimit = 10; + static const unsigned clobberedSupremacyThreshold = 2; + + void filterSlow(SpeculatedType type); + void filterClassInfoSlow(const ClassInfo*); + bool mergeSlow(const StructureAbstractValue& other); + + bool equalsSlow(const StructureAbstractValue& other) const; + + void makeTopWhenThin() { - if (isTop()) { - out.print("TOP"); - return; - } - - out.print("["); - if (m_structure) - out.print(inContext(*m_structure, context)); - out.print("]"); + ASSERT(m_set.isThin()); + m_set.m_pointer = topValue; } - - void dump(PrintStream& out) const + + bool mergeNotTop(const RegisteredStructureSet& other); + + void setClobbered(bool clobbered) { - dumpInContext(out, 0); + ASSERT(!isTop() || !clobbered); + m_set.setReservedFlag(clobbered); } - -private: - static Structure* topValue() { return reinterpret_cast<Structure*>(1); } - // NB. This must have a trivial destructor. - - // This can only remember one structure at a time. - Structure* m_structure; + RegisteredStructureSet m_set; }; } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) - -#endif // DFGStructureAbstractValue_h - - |