2 * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #ifndef DFGAbstractHeap_h
27 #define DFGAbstractHeap_h
31 #include "VirtualRegister.h"
32 #include <wtf/HashMap.h>
33 #include <wtf/PrintStream.h>
35 namespace JSC
{ namespace DFG
{
37 // Implements a four-level type hierarchy:
38 // - World is the supertype of all of the things.
39 // - Stack with a TOP payload is a direct subtype of World
40 // - Stack with a non-TOP payload is a direct subtype of Stack with a TOP payload.
41 // - Heap is a direct subtype of World.
42 // - Any other kind with TOP payload is the direct subtype of Heap.
43 // - Any other kind with non-TOP payload is the direct subtype of the same kind with a TOP payload.
45 #define FOR_EACH_ABSTRACT_HEAP_KIND(macro) \
46 macro(InvalidAbstractHeap) \
50 macro(Butterfly_publicLength) \
51 macro(Butterfly_vectorLength) \
52 macro(GetterSetter_getter) \
53 macro(GetterSetter_setter) \
54 macro(JSCell_structureID) \
55 macro(JSCell_indexingType) \
56 macro(JSCell_typeInfoFlags) \
57 macro(JSCell_typeInfoType) \
58 macro(JSObject_butterfly) \
59 macro(JSPropertyNameEnumerator_cachedPropertyNames) \
60 macro(NamedProperties) \
61 macro(IndexedInt32Properties) \
62 macro(IndexedDoubleProperties) \
63 macro(IndexedContiguousProperties) \
64 macro(IndexedArrayStorageProperties) \
65 macro(ArrayStorageProperties) \
66 macro(DirectArgumentsProperties) \
67 macro(ScopeProperties) \
68 macro(TypedArrayProperties) \
69 macro(HeapObjectCount) /* Used to reflect the fact that some allocations reveal object identity */\
71 macro(InternalState) \
73 /* 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. */\
74 macro(Watchpoint_fire) \
75 /* Use these for reads only, just to indicate that if the world got clobbered, then this operation will not work. */\
77 /* 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. */\
80 enum AbstractHeapKind
{
81 #define ABSTRACT_HEAP_DECLARATION(name) name,
82 FOR_EACH_ABSTRACT_HEAP_KIND(ABSTRACT_HEAP_DECLARATION
)
83 #undef ABSTRACT_HEAP_DECLARATION
96 Payload(bool isTop
, int64_t value
)
100 ASSERT(!(isTop
&& value
));
103 Payload(int64_t value
)
109 Payload(const void* pointer
)
111 , m_value(bitwise_cast
<intptr_t>(pointer
))
115 Payload(VirtualRegister operand
)
117 , m_value(operand
.offset())
121 static Payload
top() { return Payload(true, 0); }
123 bool isTop() const { return m_isTop
; }
124 int64_t value() const
129 int64_t valueImpl() const
134 int32_t value32() const
136 return static_cast<int32_t>(value());
139 bool operator==(const Payload
& other
) const
141 return m_isTop
== other
.m_isTop
142 && m_value
== other
.m_value
;
145 bool operator!=(const Payload
& other
) const
147 return !(*this == other
);
150 bool operator<(const Payload
& other
) const
153 return !other
.isTop();
156 return value() < other
.value();
159 bool isDisjoint(const Payload
& other
) const
165 return m_value
!= other
.m_value
;
168 bool overlaps(const Payload
& other
) const
170 return !isDisjoint(other
);
173 void dump(PrintStream
&) const;
182 m_value
= encode(InvalidAbstractHeap
, Payload());
185 AbstractHeap(AbstractHeapKind kind
)
187 ASSERT(kind
!= InvalidAbstractHeap
);
188 m_value
= encode(kind
, Payload::top());
191 AbstractHeap(AbstractHeapKind kind
, Payload payload
)
193 ASSERT(kind
!= InvalidAbstractHeap
&& kind
!= World
&& kind
!= Heap
&& kind
!= SideState
);
194 m_value
= encode(kind
, payload
);
197 AbstractHeap(WTF::HashTableDeletedValueType
)
199 m_value
= encode(InvalidAbstractHeap
, Payload::top());
202 bool operator!() const { return kind() == InvalidAbstractHeap
&& !payloadImpl().isTop(); }
204 AbstractHeapKind
kind() const { return static_cast<AbstractHeapKind
>(m_value
& ((1 << topShift
) - 1)); }
205 Payload
payload() const
207 ASSERT(kind() != World
&& kind() != InvalidAbstractHeap
);
208 return payloadImpl();
211 AbstractHeap
supertype() const
213 ASSERT(kind() != InvalidAbstractHeap
);
216 return AbstractHeap();
221 if (payload().isTop()) {
226 return AbstractHeap(kind());
230 bool isStrictSubtypeOf(const AbstractHeap
& other
) const
232 AbstractHeap current
= *this;
233 while (current
.kind() != World
) {
234 current
= current
.supertype();
235 if (current
== other
)
241 bool isSubtypeOf(const AbstractHeap
& other
) const
243 return *this == other
|| isStrictSubtypeOf(other
);
246 bool overlaps(const AbstractHeap
& other
) const
248 return *this == other
|| isStrictSubtypeOf(other
) || other
.isStrictSubtypeOf(*this);
251 bool isDisjoint(const AbstractHeap
& other
) const
253 return !overlaps(other
);
256 unsigned hash() const
258 return WTF::IntHash
<int64_t>::hash(m_value
);
261 bool operator==(const AbstractHeap
& other
) const
263 return m_value
== other
.m_value
;
266 bool operator!=(const AbstractHeap
& other
) const
268 return !(*this == other
);
271 bool operator<(const AbstractHeap
& other
) const
273 if (kind() != other
.kind())
274 return kind() < other
.kind();
275 return payload() < other
.payload();
278 bool isHashTableDeletedValue() const
280 return kind() == InvalidAbstractHeap
&& payloadImpl().isTop();
283 void dump(PrintStream
& out
) const;
286 static const unsigned valueShift
= 15;
287 static const unsigned topShift
= 14;
289 Payload
payloadImpl() const
291 return Payload((m_value
>> topShift
) & 1, m_value
>> valueShift
);
294 static int64_t encode(AbstractHeapKind kind
, Payload payload
)
296 int64_t kindAsInt
= static_cast<int64_t>(kind
);
297 ASSERT(kindAsInt
< (1 << topShift
));
298 return kindAsInt
| (payload
.isTop() << topShift
) | (payload
.valueImpl() << valueShift
);
301 // The layout of the value is:
302 // Low 14 bits: the Kind
303 // 15th bit: whether or not the payload is TOP.
304 // The upper bits: the payload.value().
308 struct AbstractHeapHash
{
309 static unsigned hash(const AbstractHeap
& key
) { return key
.hash(); }
310 static bool equal(const AbstractHeap
& a
, const AbstractHeap
& b
) { return a
== b
; }
311 static const bool safeToCompareToEmptyOrDeleted
= true;
314 } } // namespace JSC::DFG
318 void printInternal(PrintStream
&, JSC::DFG::AbstractHeapKind
);
320 template<typename T
> struct DefaultHash
;
321 template<> struct DefaultHash
<JSC::DFG::AbstractHeap
> {
322 typedef JSC::DFG::AbstractHeapHash Hash
;
325 template<typename T
> struct HashTraits
;
326 template<> struct HashTraits
<JSC::DFG::AbstractHeap
> : SimpleClassHashTraits
<JSC::DFG::AbstractHeap
> { };
330 #endif // ENABLE(DFG_JIT)
332 #endif // DFGAbstractHeap_h