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 HandleSet_h
27#define HandleSet_h
28
29#include "Handle.h"
30#include "HandleBlock.h"
31#include <wtf/DoublyLinkedList.h>
32#include <wtf/HashCountedSet.h>
33#include <wtf/SentinelLinkedList.h>
34#include <wtf/SinglyLinkedList.h>
35
36namespace JSC {
37
38class HandleBlock;
39class HandleSet;
40class HeapRootVisitor;
41class VM;
42class JSValue;
43class SlotVisitor;
44
45class HandleNode {
46public:
47    HandleNode(WTF::SentinelTag);
48    HandleNode();
49
50    HandleSlot slot();
51    HandleSet* handleSet();
52
53    void setPrev(HandleNode*);
54    HandleNode* prev();
55
56    void setNext(HandleNode*);
57    HandleNode* next();
58
59private:
60    JSValue m_value;
61    HandleNode* m_prev;
62    HandleNode* m_next;
63};
64
65class HandleSet {
66    friend class HandleBlock;
67public:
68    static HandleSet* heapFor(HandleSlot);
69
70    HandleSet(VM*);
71    ~HandleSet();
72
73    VM* vm();
74
75    HandleSlot allocate();
76    void deallocate(HandleSlot);
77
78    void visitStrongHandles(HeapRootVisitor&);
79
80    JS_EXPORT_PRIVATE void writeBarrier(HandleSlot, const JSValue&);
81
82    unsigned protectedGlobalObjectCount();
83
84    template<typename Functor> void forEachStrongHandle(Functor&, const HashCountedSet<JSCell*>& skipSet);
85
86private:
87    typedef HandleNode Node;
88    static HandleSlot toHandle(Node*);
89    static Node* toNode(HandleSlot);
90
91    JS_EXPORT_PRIVATE void grow();
92
93#if ENABLE(GC_VALIDATION) || !ASSERT_DISABLED
94    bool isLiveNode(Node*);
95#endif
96
97    VM* m_vm;
98    DoublyLinkedList<HandleBlock> m_blockList;
99
100    SentinelLinkedList<Node> m_strongList;
101    SentinelLinkedList<Node> m_immediateList;
102    SinglyLinkedList<Node> m_freeList;
103};
104
105inline HandleSet* HandleSet::heapFor(HandleSlot handle)
106{
107    return toNode(handle)->handleSet();
108}
109
110inline VM* HandleSet::vm()
111{
112    return m_vm;
113}
114
115inline HandleSlot HandleSet::toHandle(HandleSet::Node* node)
116{
117    return reinterpret_cast<HandleSlot>(node);
118}
119
120inline HandleSet::Node* HandleSet::toNode(HandleSlot handle)
121{
122    return reinterpret_cast<HandleSet::Node*>(handle);
123}
124
125inline HandleSlot HandleSet::allocate()
126{
127    if (m_freeList.isEmpty())
128        grow();
129
130    HandleSet::Node* node = m_freeList.pop();
131    new (NotNull, node) HandleSet::Node();
132    m_immediateList.push(node);
133    return toHandle(node);
134}
135
136inline void HandleSet::deallocate(HandleSlot handle)
137{
138    HandleSet::Node* node = toNode(handle);
139    SentinelLinkedList<HandleSet::Node>::remove(node);
140    m_freeList.push(node);
141}
142
143inline HandleNode::HandleNode()
144    : m_prev(0)
145    , m_next(0)
146{
147}
148
149inline HandleNode::HandleNode(WTF::SentinelTag)
150    : m_prev(0)
151    , m_next(0)
152{
153}
154
155inline HandleSlot HandleNode::slot()
156{
157    return &m_value;
158}
159
160inline HandleSet* HandleNode::handleSet()
161{
162    return HandleBlock::blockFor(this)->handleSet();
163}
164
165inline void HandleNode::setPrev(HandleNode* prev)
166{
167    m_prev = prev;
168}
169
170inline HandleNode* HandleNode::prev()
171{
172    return m_prev;
173}
174
175inline void HandleNode::setNext(HandleNode* next)
176{
177    m_next = next;
178}
179
180inline HandleNode* HandleNode::next()
181{
182    return m_next;
183}
184
185template<typename Functor> void HandleSet::forEachStrongHandle(Functor& functor, const HashCountedSet<JSCell*>& skipSet)
186{
187    HandleSet::Node* end = m_strongList.end();
188    for (HandleSet::Node* node = m_strongList.begin(); node != end; node = node->next()) {
189        JSValue value = *node->slot();
190        if (!value || !value.isCell())
191            continue;
192        if (skipSet.contains(value.asCell()))
193            continue;
194        functor(value.asCell());
195    }
196}
197
198}
199
200#endif
201