1/*
2 * Copyright (C) 2013, 2015-2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
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.
24 */
25
26#pragma once
27
28#if ENABLE(FTL_JIT)
29
30#include "B3HeapRange.h"
31#include "FTLAbbreviatedTypes.h"
32#include "JSCJSValue.h"
33#include <array>
34#include <wtf/FastMalloc.h>
35#include <wtf/HashMap.h>
36#include <wtf/Noncopyable.h>
37#include <wtf/Vector.h>
38#include <wtf/text/CString.h>
39
40namespace JSC { namespace FTL {
41
42class AbstractHeapRepository;
43class Output;
44class TypedPointer;
45
46class AbstractHeap {
47 WTF_MAKE_NONCOPYABLE(AbstractHeap); WTF_MAKE_FAST_ALLOCATED;
48public:
49 AbstractHeap()
50 {
51 }
52
53 AbstractHeap(AbstractHeap* parent, const char* heapName, ptrdiff_t offset = 0);
54
55 bool isInitialized() const { return !!m_heapName; }
56
57 void initialize(AbstractHeap* parent, const char* heapName, ptrdiff_t offset = 0)
58 {
59 changeParent(parent);
60 m_heapName = heapName;
61 m_offset = offset;
62 }
63
64 void changeParent(AbstractHeap* parent);
65
66 AbstractHeap* parent() const
67 {
68 ASSERT(isInitialized());
69 return m_parent;
70 }
71
72 const Vector<AbstractHeap*>& children() const;
73
74 const char* heapName() const
75 {
76 ASSERT(isInitialized());
77 return m_heapName;
78 }
79
80 B3::HeapRange range() const
81 {
82 // This will not have a valid value until after all lowering is done. Do associate an
83 // AbstractHeap with a B3::Value*, use AbstractHeapRepository::decorateXXX().
84 if (!m_range)
85 badRangeError();
86
87 return m_range;
88 }
89
90 // WARNING: Not all abstract heaps have a meaningful offset.
91 ptrdiff_t offset() const
92 {
93 ASSERT(isInitialized());
94 return m_offset;
95 }
96
97 void compute(unsigned begin = 0);
98
99 // Print information about just this heap.
100 void shallowDump(PrintStream&) const;
101
102 // Print information about this heap and its ancestors. This is the default.
103 void dump(PrintStream&) const;
104
105 // Print information about this heap and its descendents. This is a multi-line dump.
106 void deepDump(PrintStream&, unsigned indent = 0) const;
107
108private:
109 friend class AbstractHeapRepository;
110
111 NO_RETURN_DUE_TO_CRASH void badRangeError() const;
112
113 AbstractHeap* m_parent { nullptr };
114 Vector<AbstractHeap*> m_children;
115 intptr_t m_offset { 0 };
116 B3::HeapRange m_range;
117 const char* m_heapName { nullptr };
118};
119
120class IndexedAbstractHeap {
121public:
122 IndexedAbstractHeap(AbstractHeap* parent, const char* heapName, ptrdiff_t offset, size_t elementSize);
123 ~IndexedAbstractHeap();
124
125 const AbstractHeap& atAnyIndex() const { return m_heapForAnyIndex; }
126
127 const AbstractHeap& at(ptrdiff_t index)
128 {
129 if (static_cast<size_t>(index) < m_smallIndices.size())
130 return returnInitialized(m_smallIndices[index], index);
131 return atSlow(index);
132 }
133
134 const AbstractHeap& operator[](ptrdiff_t index) { return at(index); }
135
136 TypedPointer baseIndex(Output& out, LValue base, LValue index, JSValue indexAsConstant = JSValue(), ptrdiff_t offset = 0, LValue mask = nullptr);
137
138 void dump(PrintStream&) const;
139
140private:
141 const AbstractHeap& returnInitialized(AbstractHeap& field, ptrdiff_t index)
142 {
143 if (UNLIKELY(!field.isInitialized()))
144 initialize(field, index);
145 return field;
146 }
147
148 const AbstractHeap& atSlow(ptrdiff_t index);
149 void initialize(AbstractHeap& field, ptrdiff_t index);
150
151 AbstractHeap m_heapForAnyIndex;
152 size_t m_heapNameLength;
153 ptrdiff_t m_offset;
154 size_t m_elementSize;
155 std::array<AbstractHeap, 16> m_smallIndices;
156
157 struct WithoutZeroOrOneHashTraits : WTF::GenericHashTraits<ptrdiff_t> {
158 static void constructDeletedValue(ptrdiff_t& slot) { slot = 1; }
159 static bool isDeletedValue(ptrdiff_t value) { return value == 1; }
160 };
161 typedef HashMap<ptrdiff_t, std::unique_ptr<AbstractHeap>, WTF::IntHash<ptrdiff_t>, WithoutZeroOrOneHashTraits> MapType;
162
163 std::unique_ptr<MapType> m_largeIndices;
164 Vector<CString, 16> m_largeIndexNames;
165};
166
167// A numbered abstract heap is like an indexed abstract heap, except that you
168// can't rely on there being a relationship between the number you use to
169// retrieve the sub-heap, and the offset that this heap has. (In particular,
170// the sub-heaps don't have indices.)
171
172class NumberedAbstractHeap {
173public:
174 NumberedAbstractHeap(AbstractHeap* parent, const char* heapName);
175 ~NumberedAbstractHeap();
176
177 const AbstractHeap& atAnyNumber() const { return m_indexedHeap.atAnyIndex(); }
178
179 const AbstractHeap& at(unsigned number) { return m_indexedHeap.at(number); }
180 const AbstractHeap& operator[](unsigned number) { return at(number); }
181
182 void dump(PrintStream&) const;
183
184private:
185
186 // We use the fact that the indexed heap already has a superset of the
187 // functionality we need.
188 IndexedAbstractHeap m_indexedHeap;
189};
190
191class AbsoluteAbstractHeap {
192public:
193 AbsoluteAbstractHeap(AbstractHeap* parent, const char* heapName);
194 ~AbsoluteAbstractHeap();
195
196 const AbstractHeap& atAnyAddress() const { return m_indexedHeap.atAnyIndex(); }
197
198 const AbstractHeap& at(const void* address)
199 {
200 return m_indexedHeap.at(bitwise_cast<ptrdiff_t>(address));
201 }
202
203 const AbstractHeap& operator[](const void* address) { return at(address); }
204
205 void dump(PrintStream&) const;
206
207private:
208 // The trick here is that the indexed heap is "indexed" by a pointer-width
209 // integer. Pointers are themselves pointer-width integers. So we can reuse
210 // all of the functionality.
211 IndexedAbstractHeap m_indexedHeap;
212};
213
214} } // namespace JSC::FTL
215
216#endif // ENABLE(FTL_JIT)
217