• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #ifndef IntrusiveDOMWrapperMap_h
32 #define IntrusiveDOMWrapperMap_h
33 
34 #include "DOMDataStore.h"
35 #include "V8Node.h"
36 
37 namespace WebCore {
38 
39 template <class T, int CHUNK_SIZE, class Traits>
40 class ChunkedTable {
41   public:
ChunkedTable()42     ChunkedTable() : m_chunks(0), m_current(0), m_last(0) { }
43 
add(T element)44     T* add(T element)
45     {
46         if (m_current == m_last) {
47             m_chunks = new Chunk(m_chunks);
48             m_current = m_chunks->m_entries;
49             m_last = m_current + CHUNK_SIZE;
50         }
51         ASSERT((m_chunks->m_entries <= m_current) && (m_current < m_last));
52         T* p = m_current++;
53         *p = element;
54         return p;
55     }
56 
remove(T * element)57     void remove(T* element)
58     {
59         ASSERT(element);
60         ASSERT(m_current > m_chunks->m_entries);
61         m_current--;
62         if (element != m_current)
63             Traits::move(element, m_current);
64         if (m_current == m_chunks->m_entries) {
65             Chunk* toDelete = m_chunks;
66             m_chunks = toDelete->m_previous;
67             m_current = m_last = m_chunks ? m_chunks->m_entries + CHUNK_SIZE : 0;
68             delete toDelete;
69         }
70         ASSERT(!m_chunks || ((m_chunks->m_entries < m_current) && (m_current <= m_last)));
71     }
72 
clear()73     void clear()
74     {
75         if (!m_chunks)
76             return;
77 
78         clearEntries(m_chunks->m_entries, m_current);
79         Chunk* last = m_chunks;
80         while (true) {
81             Chunk* previous = last->m_previous;
82             if (!previous)
83                 break;
84             delete last;
85             clearEntries(previous->m_entries, previous->m_entries + CHUNK_SIZE);
86             last = previous;
87         }
88 
89         m_chunks = last;
90         m_current = m_chunks->m_entries;
91         m_last = m_current + CHUNK_SIZE;
92     }
93 
visit(DOMDataStore * store,typename Traits::Visitor * visitor)94     void visit(DOMDataStore* store, typename Traits::Visitor* visitor)
95     {
96         if (!m_chunks)
97             return;
98 
99         visitEntries(store, m_chunks->m_entries, m_current, visitor);
100         for (Chunk* chunk = m_chunks->m_previous; chunk; chunk = chunk->m_previous)
101             visitEntries(store, chunk->m_entries, chunk->m_entries + CHUNK_SIZE, visitor);
102     }
103 
104   private:
105     struct Chunk {
ChunkChunk106         explicit Chunk(Chunk* previous) : m_previous(previous) { }
107         Chunk* const m_previous;
108         T m_entries[CHUNK_SIZE];
109     };
110 
clearEntries(T * first,T * last)111     static void clearEntries(T* first, T* last)
112     {
113         for (T* entry = first; entry < last; entry++)
114             Traits::clear(entry);
115     }
116 
visitEntries(DOMDataStore * store,T * first,T * last,typename Traits::Visitor * visitor)117     static void visitEntries(DOMDataStore* store, T* first, T* last, typename Traits::Visitor* visitor)
118     {
119         for (T* entry = first; entry < last; entry++)
120             Traits::visit(store, entry, visitor);
121     }
122 
123     Chunk* m_chunks;
124     T* m_current;
125     T* m_last;
126 };
127 
128 
129 class IntrusiveDOMWrapperMap : public AbstractWeakReferenceMap<Node, v8::Object> {
130 public:
IntrusiveDOMWrapperMap(v8::WeakReferenceCallback callback)131     IntrusiveDOMWrapperMap(v8::WeakReferenceCallback callback)
132         : AbstractWeakReferenceMap<Node, v8::Object>(callback) { }
133 
get(Node * obj)134     virtual v8::Persistent<v8::Object> get(Node* obj)
135     {
136         v8::Persistent<v8::Object>* wrapper = obj->wrapper();
137         return wrapper ? *wrapper : v8::Persistent<v8::Object>();
138     }
139 
set(Node * obj,v8::Persistent<v8::Object> wrapper)140     virtual void set(Node* obj, v8::Persistent<v8::Object> wrapper)
141     {
142         ASSERT(obj);
143         ASSERT(!obj->wrapper());
144         v8::Persistent<v8::Object>* entry = m_table.add(wrapper);
145         obj->setWrapper(entry);
146         wrapper.MakeWeak(obj, weakReferenceCallback());
147     }
148 
contains(Node * obj)149     virtual bool contains(Node* obj)
150     {
151         return obj->wrapper();
152     }
153 
visit(DOMDataStore * store,Visitor * visitor)154     virtual void visit(DOMDataStore* store, Visitor* visitor)
155     {
156         m_table.visit(store, visitor);
157     }
158 
removeIfPresent(Node * obj,v8::Persistent<v8::Object> value)159     virtual bool removeIfPresent(Node* obj, v8::Persistent<v8::Object> value)
160     {
161         ASSERT(obj);
162         v8::Persistent<v8::Object>* entry = obj->wrapper();
163         if (!entry)
164             return false;
165         if (*entry != value)
166             return false;
167         obj->clearWrapper();
168         m_table.remove(entry);
169         value.Dispose();
170         return true;
171     }
172 
173 
clear()174     virtual void clear()
175     {
176         m_table.clear();
177     }
178 
179 private:
180     static int const numberOfEntries = (1 << 10) - 1;
181 
182     struct ChunkedTableTraits {
183         typedef IntrusiveDOMWrapperMap::Visitor Visitor;
184 
moveChunkedTableTraits185         static void move(v8::Persistent<v8::Object>* target, v8::Persistent<v8::Object>* source)
186         {
187             *target = *source;
188             Node* node = V8Node::toNative(*target);
189             ASSERT(node);
190             node->setWrapper(target);
191         }
192 
clearChunkedTableTraits193         static void clear(v8::Persistent<v8::Object>* entry)
194         {
195             Node* node = V8Node::toNative(*entry);
196             ASSERT(node->wrapper() == entry);
197 
198             node->clearWrapper();
199             entry->Dispose();
200         }
201 
visitChunkedTableTraits202         static void visit(DOMDataStore* store, v8::Persistent<v8::Object>* entry, Visitor* visitor)
203         {
204             Node* node = V8Node::toNative(*entry);
205             ASSERT(node->wrapper() == entry);
206 
207             visitor->visitDOMWrapper(store, node, *entry);
208         }
209     };
210 
211     typedef ChunkedTable<v8::Persistent<v8::Object>, numberOfEntries, ChunkedTableTraits> Table;
212     Table m_table;
213 };
214 
215 } // namespace WebCore
216 
217 #endif
218