summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGAbstractHeap.h')
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractHeap.h335
1 files changed, 335 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractHeap.h b/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
new file mode 100644
index 000000000..4dec8fa03
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2013-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 DFGAbstractHeap_h
+#define DFGAbstractHeap_h
+
+#if ENABLE(DFG_JIT)
+
+#include "VirtualRegister.h"
+#include <wtf/HashMap.h>
+#include <wtf/PrintStream.h>
+
+namespace JSC { namespace DFG {
+
+// Implements a four-level type hierarchy:
+// - World is the supertype of all of the things.
+// - Stack with a TOP payload is a direct subtype of World
+// - Stack with a non-TOP payload is a direct subtype of Stack with a TOP payload.
+// - Heap is a direct subtype of World.
+// - SideState is a direct subtype of World.
+// - Any other kind with TOP payload is the direct subtype of Heap.
+// - Any other kind with non-TOP payload is the direct subtype of the same kind with a TOP payload.
+
+#define FOR_EACH_ABSTRACT_HEAP_KIND(macro) \
+ macro(InvalidAbstractHeap) \
+ macro(World) \
+ macro(Stack) \
+ macro(Heap) \
+ macro(Butterfly_publicLength) \
+ macro(Butterfly_vectorLength) \
+ macro(GetterSetter_getter) \
+ macro(GetterSetter_setter) \
+ macro(JSCell_structureID) \
+ macro(JSCell_indexingType) \
+ macro(JSCell_typeInfoFlags) \
+ macro(JSCell_typeInfoType) \
+ macro(JSObject_butterfly) \
+ macro(JSPropertyNameEnumerator_cachedPropertyNames) \
+ macro(NamedProperties) \
+ macro(IndexedInt32Properties) \
+ macro(IndexedDoubleProperties) \
+ macro(IndexedContiguousProperties) \
+ macro(IndexedArrayStorageProperties) \
+ macro(ArrayStorageProperties) \
+ macro(DirectArgumentsProperties) \
+ macro(ScopeProperties) \
+ macro(TypedArrayProperties) \
+ macro(HeapObjectCount) /* Used to reflect the fact that some allocations reveal object identity */\
+ macro(RegExpState) \
+ macro(MathDotRandomState) \
+ macro(InternalState) \
+ macro(Absolute) \
+ /* Use this for writes only, to indicate that this may fire watchpoints. Usually this is never directly written but instead we test to see if a node clobbers this; it just so happens that you have to write world to clobber it. */\
+ macro(Watchpoint_fire) \
+ /* Use these for reads only, just to indicate that if the world got clobbered, then this operation will not work. */\
+ macro(MiscFields) \
+ /* Use this for writes only, just to indicate that hoisting the node is invalid. This works because we don't hoist anything that has any side effects at all. */\
+ macro(SideState)
+
+enum AbstractHeapKind {
+#define ABSTRACT_HEAP_DECLARATION(name) name,
+ FOR_EACH_ABSTRACT_HEAP_KIND(ABSTRACT_HEAP_DECLARATION)
+#undef ABSTRACT_HEAP_DECLARATION
+};
+
+class AbstractHeap {
+public:
+ class Payload {
+ public:
+ Payload()
+ : m_isTop(false)
+ , m_value(0)
+ {
+ }
+
+ Payload(bool isTop, int64_t value)
+ : m_isTop(isTop)
+ , m_value(value)
+ {
+ ASSERT(!(isTop && value));
+ }
+
+ Payload(int64_t value)
+ : m_isTop(false)
+ , m_value(value)
+ {
+ }
+
+ Payload(const void* pointer)
+ : m_isTop(false)
+ , m_value(bitwise_cast<intptr_t>(pointer))
+ {
+ }
+
+ Payload(VirtualRegister operand)
+ : m_isTop(false)
+ , m_value(operand.offset())
+ {
+ }
+
+ static Payload top() { return Payload(true, 0); }
+
+ bool isTop() const { return m_isTop; }
+ int64_t value() const
+ {
+ ASSERT(!isTop());
+ return valueImpl();
+ }
+ int64_t valueImpl() const
+ {
+ return m_value;
+ }
+
+ int32_t value32() const
+ {
+ return static_cast<int32_t>(value());
+ }
+
+ bool operator==(const Payload& other) const
+ {
+ return m_isTop == other.m_isTop
+ && m_value == other.m_value;
+ }
+
+ bool operator!=(const Payload& other) const
+ {
+ return !(*this == other);
+ }
+
+ bool operator<(const Payload& other) const
+ {
+ if (isTop())
+ return !other.isTop();
+ if (other.isTop())
+ return false;
+ return value() < other.value();
+ }
+
+ bool isDisjoint(const Payload& other) const
+ {
+ if (isTop())
+ return false;
+ if (other.isTop())
+ return false;
+ return m_value != other.m_value;
+ }
+
+ bool overlaps(const Payload& other) const
+ {
+ return !isDisjoint(other);
+ }
+
+ void dump(PrintStream&) const;
+
+ private:
+ bool m_isTop;
+ int64_t m_value;
+ };
+
+ AbstractHeap()
+ {
+ m_value = encode(InvalidAbstractHeap, Payload());
+ }
+
+ AbstractHeap(AbstractHeapKind kind)
+ {
+ ASSERT(kind != InvalidAbstractHeap);
+ m_value = encode(kind, Payload::top());
+ }
+
+ AbstractHeap(AbstractHeapKind kind, Payload payload)
+ {
+ ASSERT(kind != InvalidAbstractHeap && kind != World && kind != Heap && kind != SideState);
+ m_value = encode(kind, payload);
+ }
+
+ AbstractHeap(WTF::HashTableDeletedValueType)
+ {
+ m_value = encode(InvalidAbstractHeap, Payload::top());
+ }
+
+ bool operator!() const { return kind() == InvalidAbstractHeap && !payloadImpl().isTop(); }
+
+ AbstractHeapKind kind() const { return static_cast<AbstractHeapKind>(m_value & ((1 << topShift) - 1)); }
+ Payload payload() const
+ {
+ ASSERT(kind() != World && kind() != InvalidAbstractHeap);
+ return payloadImpl();
+ }
+
+ AbstractHeap supertype() const
+ {
+ ASSERT(kind() != InvalidAbstractHeap);
+ switch (kind()) {
+ case World:
+ return AbstractHeap();
+ case Heap:
+ case SideState:
+ return World;
+ default:
+ if (payload().isTop()) {
+ if (kind() == Stack)
+ return World;
+ return Heap;
+ }
+ return AbstractHeap(kind());
+ }
+ }
+
+ bool isStrictSubtypeOf(const AbstractHeap& other) const
+ {
+ AbstractHeap current = *this;
+ while (current.kind() != World) {
+ current = current.supertype();
+ if (current == other)
+ return true;
+ }
+ return false;
+ }
+
+ bool isSubtypeOf(const AbstractHeap& other) const
+ {
+ return *this == other || isStrictSubtypeOf(other);
+ }
+
+ bool overlaps(const AbstractHeap& other) const
+ {
+ return *this == other || isStrictSubtypeOf(other) || other.isStrictSubtypeOf(*this);
+ }
+
+ bool isDisjoint(const AbstractHeap& other) const
+ {
+ return !overlaps(other);
+ }
+
+ unsigned hash() const
+ {
+ return WTF::IntHash<int64_t>::hash(m_value);
+ }
+
+ bool operator==(const AbstractHeap& other) const
+ {
+ return m_value == other.m_value;
+ }
+
+ bool operator!=(const AbstractHeap& other) const
+ {
+ return !(*this == other);
+ }
+
+ bool operator<(const AbstractHeap& other) const
+ {
+ if (kind() != other.kind())
+ return kind() < other.kind();
+ return payload() < other.payload();
+ }
+
+ bool isHashTableDeletedValue() const
+ {
+ return kind() == InvalidAbstractHeap && payloadImpl().isTop();
+ }
+
+ void dump(PrintStream& out) const;
+
+private:
+ static const unsigned valueShift = 15;
+ static const unsigned topShift = 14;
+
+ Payload payloadImpl() const
+ {
+ return Payload((m_value >> topShift) & 1, m_value >> valueShift);
+ }
+
+ static int64_t encode(AbstractHeapKind kind, Payload payload)
+ {
+ int64_t kindAsInt = static_cast<int64_t>(kind);
+ ASSERT(kindAsInt < (1 << topShift));
+ return kindAsInt | (payload.isTop() << topShift) | (payload.valueImpl() << valueShift);
+ }
+
+ // The layout of the value is:
+ // Low 14 bits: the Kind
+ // 15th bit: whether or not the payload is TOP.
+ // The upper bits: the payload.value().
+ int64_t m_value;
+};
+
+struct AbstractHeapHash {
+ static unsigned hash(const AbstractHeap& key) { return key.hash(); }
+ static bool equal(const AbstractHeap& a, const AbstractHeap& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+} } // namespace JSC::DFG
+
+namespace WTF {
+
+void printInternal(PrintStream&, JSC::DFG::AbstractHeapKind);
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::DFG::AbstractHeap> {
+ typedef JSC::DFG::AbstractHeapHash Hash;
+};
+
+template<typename T> struct HashTraits;
+template<> struct HashTraits<JSC::DFG::AbstractHeap> : SimpleClassHashTraits<JSC::DFG::AbstractHeap> { };
+
+} // namespace WTF
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGAbstractHeap_h
+