HandleHeap.h revision 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00
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
34namespace JSC {
35
36class HandleHeap;
37class HeapRootMarker;
38class JSGlobalData;
39class JSValue;
40class MarkStack;
41class TypeCounter;
42
43class WeakHandleOwner {
44public:
45    virtual ~WeakHandleOwner();
46    virtual bool isReachableFromOpaqueRoots(Handle<Unknown>, void* context, MarkStack&);
47    virtual void finalize(Handle<Unknown>, void* context);
48};
49
50class HandleHeap {
51public:
52    static HandleHeap* heapFor(HandleSlot);
53
54    HandleHeap(JSGlobalData*);
55
56    JSGlobalData* globalData();
57
58    HandleSlot allocate();
59    void deallocate(HandleSlot);
60
61    void makeWeak(HandleSlot, WeakHandleOwner* = 0, void* context = 0);
62    HandleSlot copyWeak(HandleSlot);
63
64    void markStrongHandles(HeapRootMarker&);
65    void markWeakHandles(HeapRootMarker&);
66    void finalizeWeakHandles();
67
68    void writeBarrier(HandleSlot, const JSValue&);
69
70#if !ASSERT_DISABLED
71    bool hasWeakOwner(HandleSlot, WeakHandleOwner*);
72#endif
73
74    unsigned protectedGlobalObjectCount();
75    void protectedObjectTypeCounts(TypeCounter&);
76
77private:
78    class Node {
79    public:
80        Node(WTF::SentinelTag);
81        Node(HandleHeap*);
82
83        HandleSlot slot();
84        HandleHeap* handleHeap();
85
86        void makeWeak(WeakHandleOwner*, void* context);
87        bool isWeak();
88
89        WeakHandleOwner* weakOwner();
90        void* weakOwnerContext();
91
92        void setPrev(Node*);
93        Node* prev();
94
95        void setNext(Node*);
96        Node* next();
97
98    private:
99        WeakHandleOwner* emptyWeakOwner();
100
101        JSValue m_value;
102        HandleHeap* m_handleHeap;
103        WeakHandleOwner* m_weakOwner;
104        void* m_weakOwnerContext;
105        Node* m_prev;
106        Node* m_next;
107    };
108
109    static HandleSlot toHandle(Node*);
110    static Node* toNode(HandleSlot);
111
112    void grow();
113
114#if !ASSERT_DISABLED
115    bool isValidWeakNode(Node*);
116#endif
117
118    JSGlobalData* m_globalData;
119    BlockStack<Node> m_blockStack;
120
121    SentinelLinkedList<Node> m_strongList;
122    SentinelLinkedList<Node> m_weakList;
123    SentinelLinkedList<Node> m_immediateList;
124    SinglyLinkedList<Node> m_freeList;
125    Node* m_nextToFinalize;
126};
127
128inline HandleHeap* HandleHeap::heapFor(HandleSlot handle)
129{
130    return toNode(handle)->handleHeap();
131}
132
133inline JSGlobalData* HandleHeap::globalData()
134{
135    return m_globalData;
136}
137
138inline HandleSlot HandleHeap::toHandle(Node* node)
139{
140    return reinterpret_cast<HandleSlot>(node);
141}
142
143inline HandleHeap::Node* HandleHeap::toNode(HandleSlot handle)
144{
145    return reinterpret_cast<Node*>(handle);
146}
147
148inline HandleSlot HandleHeap::allocate()
149{
150    if (m_freeList.isEmpty())
151        grow();
152
153    Node* node = m_freeList.pop();
154    new (node) Node(this);
155    m_immediateList.push(node);
156    return toHandle(node);
157}
158
159inline void HandleHeap::deallocate(HandleSlot handle)
160{
161    Node* node = toNode(handle);
162    if (node == m_nextToFinalize) {
163        m_nextToFinalize = node->next();
164        ASSERT(m_nextToFinalize->next());
165    }
166
167    SentinelLinkedList<Node>::remove(node);
168    m_freeList.push(node);
169}
170
171inline HandleSlot HandleHeap::copyWeak(HandleSlot other)
172{
173    Node* node = toNode(allocate());
174    node->makeWeak(toNode(other)->weakOwner(), toNode(other)->weakOwnerContext());
175    writeBarrier(node->slot(), *other);
176    *node->slot() = *other;
177    return toHandle(node);
178}
179
180inline void HandleHeap::makeWeak(HandleSlot handle, WeakHandleOwner* weakOwner, void* context)
181{
182    Node* node = toNode(handle);
183    node->makeWeak(weakOwner, context);
184
185    SentinelLinkedList<Node>::remove(node);
186    if (!*handle || !handle->isCell()) {
187        m_immediateList.push(node);
188        return;
189    }
190
191    m_weakList.push(node);
192}
193
194#if !ASSERT_DISABLED
195inline bool HandleHeap::hasWeakOwner(HandleSlot handle, WeakHandleOwner* weakOwner)
196{
197    return toNode(handle)->weakOwner() == weakOwner;
198}
199#endif
200
201inline HandleHeap::Node::Node(HandleHeap* handleHeap)
202    : m_handleHeap(handleHeap)
203    , m_weakOwner(0)
204    , m_weakOwnerContext(0)
205{
206}
207
208inline HandleHeap::Node::Node(WTF::SentinelTag)
209    : m_handleHeap(0)
210    , m_weakOwner(0)
211    , m_weakOwnerContext(0)
212{
213}
214
215inline HandleSlot HandleHeap::Node::slot()
216{
217    return &m_value;
218}
219
220inline HandleHeap* HandleHeap::Node::handleHeap()
221{
222    return m_handleHeap;
223}
224
225inline void HandleHeap::Node::makeWeak(WeakHandleOwner* weakOwner, void* context)
226{
227    m_weakOwner = weakOwner ? weakOwner : emptyWeakOwner();
228    m_weakOwnerContext = context;
229}
230
231inline bool HandleHeap::Node::isWeak()
232{
233    return m_weakOwner; // True for emptyWeakOwner().
234}
235
236inline WeakHandleOwner* HandleHeap::Node::weakOwner()
237{
238    return m_weakOwner == emptyWeakOwner() ? 0 : m_weakOwner; // 0 for emptyWeakOwner().
239}
240
241inline void* HandleHeap::Node::weakOwnerContext()
242{
243    ASSERT(weakOwner());
244    return m_weakOwnerContext;
245}
246
247inline void HandleHeap::Node::setPrev(Node* prev)
248{
249    m_prev = prev;
250}
251
252inline HandleHeap::Node* HandleHeap::Node::prev()
253{
254    return m_prev;
255}
256
257inline void HandleHeap::Node::setNext(Node* next)
258{
259    m_next = next;
260}
261
262inline HandleHeap::Node* HandleHeap::Node::next()
263{
264    return m_next;
265}
266
267// Sentinel to indicate that a node is weak, but its owner has no meaningful
268// callbacks. This allows us to optimize by skipping such nodes.
269inline WeakHandleOwner* HandleHeap::Node::emptyWeakOwner()
270{
271    return reinterpret_cast<WeakHandleOwner*>(-1);
272}
273
274}
275
276#endif
277