]>
Commit | Line | Data |
---|---|---|
14957cd0 A |
1 | /* |
2 | * Copyright (C) 2011 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. AND ITS CONTRIBUTORS ``AS IS'' | |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
23 | * THE POSSIBILITY OF SUCH DAMAGE. | |
24 | */ | |
25 | ||
26 | #ifndef HandleHeap_h | |
27 | #define HandleHeap_h | |
28 | ||
29 | #include "BlockStack.h" | |
30 | #include "Handle.h" | |
31 | #include "SentinelLinkedList.h" | |
32 | #include "SinglyLinkedList.h" | |
33 | ||
34 | namespace JSC { | |
35 | ||
36 | class HandleHeap; | |
37 | class HeapRootVisitor; | |
38 | class JSGlobalData; | |
39 | class JSValue; | |
40 | class MarkStack; | |
41 | class TypeCounter; | |
42 | typedef MarkStack SlotVisitor; | |
43 | ||
44 | class WeakHandleOwner { | |
45 | public: | |
46 | virtual ~WeakHandleOwner(); | |
47 | virtual bool isReachableFromOpaqueRoots(Handle<Unknown>, void* context, SlotVisitor&); | |
48 | virtual void finalize(Handle<Unknown>, void* context); | |
49 | }; | |
50 | ||
51 | class HandleHeap { | |
52 | public: | |
53 | static HandleHeap* heapFor(HandleSlot); | |
54 | ||
55 | HandleHeap(JSGlobalData*); | |
56 | ||
57 | JSGlobalData* globalData(); | |
58 | ||
59 | HandleSlot allocate(); | |
60 | void deallocate(HandleSlot); | |
61 | ||
62 | void makeWeak(HandleSlot, WeakHandleOwner* = 0, void* context = 0); | |
63 | HandleSlot copyWeak(HandleSlot); | |
64 | ||
65 | void markStrongHandles(HeapRootVisitor&); | |
66 | void markWeakHandles(HeapRootVisitor&); | |
67 | void finalizeWeakHandles(); | |
68 | ||
69 | void writeBarrier(HandleSlot, const JSValue&); | |
70 | ||
71 | #if !ASSERT_DISABLED | |
72 | bool hasWeakOwner(HandleSlot, WeakHandleOwner*); | |
73 | bool hasFinalizer(HandleSlot); | |
74 | #endif | |
75 | ||
76 | unsigned protectedGlobalObjectCount(); | |
77 | void protectedObjectTypeCounts(TypeCounter&); | |
78 | ||
79 | private: | |
80 | class Node { | |
81 | public: | |
82 | Node(WTF::SentinelTag); | |
83 | Node(HandleHeap*); | |
84 | ||
85 | HandleSlot slot(); | |
86 | HandleHeap* handleHeap(); | |
87 | ||
88 | void makeWeak(WeakHandleOwner*, void* context); | |
89 | bool isWeak(); | |
90 | ||
91 | WeakHandleOwner* weakOwner(); | |
92 | void* weakOwnerContext(); | |
93 | ||
94 | void setPrev(Node*); | |
95 | Node* prev(); | |
96 | ||
97 | void setNext(Node*); | |
98 | Node* next(); | |
99 | ||
100 | private: | |
101 | WeakHandleOwner* emptyWeakOwner(); | |
102 | ||
103 | JSValue m_value; | |
104 | HandleHeap* m_handleHeap; | |
105 | WeakHandleOwner* m_weakOwner; | |
106 | void* m_weakOwnerContext; | |
107 | Node* m_prev; | |
108 | Node* m_next; | |
109 | }; | |
110 | ||
111 | static HandleSlot toHandle(Node*); | |
112 | static Node* toNode(HandleSlot); | |
113 | ||
114 | void grow(); | |
115 | ||
116 | #if !ASSERT_DISABLED | |
117 | bool isValidWeakNode(Node*); | |
118 | #endif | |
119 | ||
120 | JSGlobalData* m_globalData; | |
121 | BlockStack<Node> m_blockStack; | |
122 | ||
123 | SentinelLinkedList<Node> m_strongList; | |
124 | SentinelLinkedList<Node> m_weakList; | |
125 | SentinelLinkedList<Node> m_immediateList; | |
126 | SinglyLinkedList<Node> m_freeList; | |
127 | Node* m_nextToFinalize; | |
128 | }; | |
129 | ||
130 | inline HandleHeap* HandleHeap::heapFor(HandleSlot handle) | |
131 | { | |
132 | return toNode(handle)->handleHeap(); | |
133 | } | |
134 | ||
135 | inline JSGlobalData* HandleHeap::globalData() | |
136 | { | |
137 | return m_globalData; | |
138 | } | |
139 | ||
140 | inline HandleSlot HandleHeap::toHandle(Node* node) | |
141 | { | |
142 | return reinterpret_cast<HandleSlot>(node); | |
143 | } | |
144 | ||
145 | inline HandleHeap::Node* HandleHeap::toNode(HandleSlot handle) | |
146 | { | |
147 | return reinterpret_cast<Node*>(handle); | |
148 | } | |
149 | ||
150 | inline HandleSlot HandleHeap::allocate() | |
151 | { | |
152 | if (m_freeList.isEmpty()) | |
153 | grow(); | |
154 | ||
155 | Node* node = m_freeList.pop(); | |
156 | new (node) Node(this); | |
157 | m_immediateList.push(node); | |
158 | return toHandle(node); | |
159 | } | |
160 | ||
161 | inline void HandleHeap::deallocate(HandleSlot handle) | |
162 | { | |
163 | Node* node = toNode(handle); | |
164 | if (node == m_nextToFinalize) { | |
165 | m_nextToFinalize = node->next(); | |
166 | ASSERT(m_nextToFinalize->next()); | |
167 | } | |
168 | ||
169 | SentinelLinkedList<Node>::remove(node); | |
170 | m_freeList.push(node); | |
171 | } | |
172 | ||
173 | inline HandleSlot HandleHeap::copyWeak(HandleSlot other) | |
174 | { | |
175 | Node* node = toNode(allocate()); | |
176 | node->makeWeak(toNode(other)->weakOwner(), toNode(other)->weakOwnerContext()); | |
177 | writeBarrier(node->slot(), *other); | |
178 | *node->slot() = *other; | |
179 | return toHandle(node); | |
180 | } | |
181 | ||
182 | inline void HandleHeap::makeWeak(HandleSlot handle, WeakHandleOwner* weakOwner, void* context) | |
183 | { | |
184 | Node* node = toNode(handle); | |
185 | node->makeWeak(weakOwner, context); | |
186 | ||
187 | SentinelLinkedList<Node>::remove(node); | |
188 | if (!*handle || !handle->isCell()) { | |
189 | m_immediateList.push(node); | |
190 | return; | |
191 | } | |
192 | ||
193 | m_weakList.push(node); | |
194 | } | |
195 | ||
196 | #if !ASSERT_DISABLED | |
197 | inline bool HandleHeap::hasWeakOwner(HandleSlot handle, WeakHandleOwner* weakOwner) | |
198 | { | |
199 | return toNode(handle)->weakOwner() == weakOwner; | |
200 | } | |
201 | ||
202 | inline bool HandleHeap::hasFinalizer(HandleSlot handle) | |
203 | { | |
204 | return toNode(handle)->weakOwner(); | |
205 | } | |
206 | #endif | |
207 | ||
208 | inline HandleHeap::Node::Node(HandleHeap* handleHeap) | |
209 | : m_handleHeap(handleHeap) | |
210 | , m_weakOwner(0) | |
211 | , m_weakOwnerContext(0) | |
212 | { | |
213 | } | |
214 | ||
215 | inline HandleHeap::Node::Node(WTF::SentinelTag) | |
216 | : m_handleHeap(0) | |
217 | , m_weakOwner(0) | |
218 | , m_weakOwnerContext(0) | |
219 | { | |
220 | } | |
221 | ||
222 | inline HandleSlot HandleHeap::Node::slot() | |
223 | { | |
224 | return &m_value; | |
225 | } | |
226 | ||
227 | inline HandleHeap* HandleHeap::Node::handleHeap() | |
228 | { | |
229 | return m_handleHeap; | |
230 | } | |
231 | ||
232 | inline void HandleHeap::Node::makeWeak(WeakHandleOwner* weakOwner, void* context) | |
233 | { | |
234 | m_weakOwner = weakOwner ? weakOwner : emptyWeakOwner(); | |
235 | m_weakOwnerContext = context; | |
236 | } | |
237 | ||
238 | inline bool HandleHeap::Node::isWeak() | |
239 | { | |
240 | return m_weakOwner; // True for emptyWeakOwner(). | |
241 | } | |
242 | ||
243 | inline WeakHandleOwner* HandleHeap::Node::weakOwner() | |
244 | { | |
245 | return m_weakOwner == emptyWeakOwner() ? 0 : m_weakOwner; // 0 for emptyWeakOwner(). | |
246 | } | |
247 | ||
248 | inline void* HandleHeap::Node::weakOwnerContext() | |
249 | { | |
250 | ASSERT(weakOwner()); | |
251 | return m_weakOwnerContext; | |
252 | } | |
253 | ||
254 | inline void HandleHeap::Node::setPrev(Node* prev) | |
255 | { | |
256 | m_prev = prev; | |
257 | } | |
258 | ||
259 | inline HandleHeap::Node* HandleHeap::Node::prev() | |
260 | { | |
261 | return m_prev; | |
262 | } | |
263 | ||
264 | inline void HandleHeap::Node::setNext(Node* next) | |
265 | { | |
266 | m_next = next; | |
267 | } | |
268 | ||
269 | inline HandleHeap::Node* HandleHeap::Node::next() | |
270 | { | |
271 | return m_next; | |
272 | } | |
273 | ||
274 | // Sentinel to indicate that a node is weak, but its owner has no meaningful | |
275 | // callbacks. This allows us to optimize by skipping such nodes. | |
276 | inline WeakHandleOwner* HandleHeap::Node::emptyWeakOwner() | |
277 | { | |
278 | return reinterpret_cast<WeakHandleOwner*>(-1); | |
279 | } | |
280 | ||
281 | } | |
282 | ||
283 | #endif |