summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h')
-rw-r--r--Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h400
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
-
-