• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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 DOMDataStore_h
32 #define DOMDataStore_h
33 
34 #include "DOMObjectsInclude.h"
35 #include "V8Node.h"
36 
37 #include <v8.h>
38 #include <wtf/HashMap.h>
39 #include <wtf/MainThread.h>
40 #include <wtf/Noncopyable.h>
41 #include <wtf/OwnPtr.h>
42 #include <wtf/StdLibExtras.h>
43 #include <wtf/Threading.h>
44 #include <wtf/ThreadSpecific.h>
45 #include <wtf/Vector.h>
46 
47 namespace WebCore {
48 
49     class DOMData;
50 
51     typedef WTF::Vector<DOMDataStore*> DOMDataList;
52 
53     template <class T, int CHUNK_SIZE, class Traits>
54     class ChunkedTable {
55       public:
ChunkedTable()56         ChunkedTable() : m_chunks(0), m_current(0), m_last(0) { }
57 
add(T element)58         T* add(T element)
59         {
60             if (m_current == m_last) {
61                 m_chunks = new Chunk(m_chunks);
62                 m_current = m_chunks->m_entries;
63                 m_last = m_current + CHUNK_SIZE;
64             }
65             ASSERT((m_chunks->m_entries <= m_current) && (m_current < m_last));
66             T* p = m_current++;
67             *p = element;
68             return p;
69         }
70 
remove(T * element)71         void remove(T* element)
72         {
73             ASSERT(element);
74             ASSERT(m_current > m_chunks->m_entries);
75             m_current--;
76             if (element != m_current)
77                 Traits::move(element, m_current);
78             if (m_current == m_chunks->m_entries) {
79                 Chunk* toDelete = m_chunks;
80                 m_chunks = toDelete->m_previous;
81                 m_current = m_last = m_chunks ? m_chunks->m_entries + CHUNK_SIZE : 0;
82                 delete toDelete;
83             }
84             ASSERT(!m_chunks || ((m_chunks->m_entries < m_current) && (m_current <= m_last)));
85         }
86 
clear()87         void clear()
88         {
89             if (!m_chunks)
90                 return;
91 
92             clearEntries(m_chunks->m_entries, m_current);
93             Chunk* last = m_chunks;
94             while (true) {
95                 Chunk* previous = last->m_previous;
96                 if (!previous)
97                     break;
98                 delete last;
99                 clearEntries(previous->m_entries, previous->m_entries + CHUNK_SIZE);
100                 last = previous;
101             }
102 
103             m_chunks = last;
104             m_current = m_chunks->m_entries;
105             m_last = m_current + CHUNK_SIZE;
106         }
107 
visit(typename Traits::Visitor * visitor)108         void visit(typename Traits::Visitor* visitor)
109         {
110             if (!m_chunks)
111                 return;
112 
113             visitEntries(m_chunks->m_entries, m_current, visitor);
114             for (Chunk* chunk = m_chunks->m_previous; chunk; chunk = chunk->m_previous)
115                 visitEntries(chunk->m_entries, chunk->m_entries + CHUNK_SIZE, visitor);
116         }
117 
118       private:
119         struct Chunk {
ChunkChunk120             explicit Chunk(Chunk* previous) : m_previous(previous) { }
121             Chunk* const m_previous;
122             T m_entries[CHUNK_SIZE];
123         };
124 
clearEntries(T * first,T * last)125         static void clearEntries(T* first, T* last)
126         {
127             for (T* entry = first; entry < last; entry++)
128                 Traits::clear(entry);
129         }
130 
visitEntries(T * first,T * last,typename Traits::Visitor * visitor)131         static void visitEntries(T* first, T* last, typename Traits::Visitor* visitor)
132         {
133             for (T* entry = first; entry < last; entry++)
134                 Traits::visit(entry, visitor);
135         }
136 
137         Chunk* m_chunks;
138         T* m_current;
139         T* m_last;
140     };
141 
142     // DOMDataStore
143     //
144     // DOMDataStore is the backing store that holds the maps between DOM objects
145     // and JavaScript objects.  In general, each thread can have multiple backing
146     // stores, one per isolated world.
147     //
148     // This class doesn't manage the lifetime of the store.  The data store
149     // lifetime is managed by subclasses.
150     //
151     class DOMDataStore : public Noncopyable {
152     public:
153         enum DOMWrapperMapType {
154             DOMNodeMap,
155             DOMObjectMap,
156             ActiveDOMObjectMap,
157 #if ENABLE(SVG)
158             DOMSVGElementInstanceMap,
159             DOMSVGObjectWithContextMap
160 #endif
161         };
162 
163         template <class KeyType>
164         class InternalDOMWrapperMap : public DOMWrapperMap<KeyType> {
165         public:
InternalDOMWrapperMap(DOMData * domData,v8::WeakReferenceCallback callback)166             InternalDOMWrapperMap(DOMData* domData, v8::WeakReferenceCallback callback)
167                 : DOMWrapperMap<KeyType>(callback), m_domData(domData) { }
168 
forget(KeyType * object)169             virtual void forget(KeyType* object)
170             {
171                 DOMWrapperMap<KeyType>::forget(object);
172                 forgetDelayedObject(m_domData, object);
173             }
174 
175         private:
176             DOMData* m_domData;
177         };
178 
179         class IntrusiveDOMWrapperMap : public AbstractWeakReferenceMap<Node, v8::Object> {
180         public:
IntrusiveDOMWrapperMap(v8::WeakReferenceCallback callback)181             IntrusiveDOMWrapperMap(v8::WeakReferenceCallback callback)
182                 : AbstractWeakReferenceMap<Node, v8::Object>(callback) { }
183 
get(Node * obj)184             virtual v8::Persistent<v8::Object> get(Node* obj)
185             {
186                 v8::Persistent<v8::Object>* wrapper = obj->wrapper();
187                 return wrapper ? *wrapper : v8::Persistent<v8::Object>();
188             }
189 
set(Node * obj,v8::Persistent<v8::Object> wrapper)190             virtual void set(Node* obj, v8::Persistent<v8::Object> wrapper)
191             {
192                 ASSERT(obj);
193                 ASSERT(!obj->wrapper());
194                 v8::Persistent<v8::Object>* entry = m_table.add(wrapper);
195                 obj->setWrapper(entry);
196                 wrapper.MakeWeak(obj, weakReferenceCallback());
197             }
198 
contains(Node * obj)199             virtual bool contains(Node* obj)
200             {
201                 return obj->wrapper();
202             }
203 
visit(Visitor * visitor)204             virtual void visit(Visitor* visitor)
205             {
206                 m_table.visit(visitor);
207             }
208 
209             virtual bool removeIfPresent(Node* key, v8::Persistent<v8::Data> value);
210 
clear()211             virtual void clear()
212             {
213                 m_table.clear();
214             }
215 
216         private:
217             static int const numberOfEntries = (1 << 10) - 1;
218 
219             struct ChunkedTableTraits {
220                 typedef IntrusiveDOMWrapperMap::Visitor Visitor;
221 
moveChunkedTableTraits222                 static void move(v8::Persistent<v8::Object>* target, v8::Persistent<v8::Object>* source)
223                 {
224                     *target = *source;
225                     Node* node = V8Node::toNative(*target);
226                     ASSERT(node);
227                     node->setWrapper(target);
228                 }
229 
clearChunkedTableTraits230                 static void clear(v8::Persistent<v8::Object>* entry)
231                 {
232                     Node* node = V8Node::toNative(*entry);
233                     ASSERT(node->wrapper() == entry);
234 
235                     node->clearWrapper();
236                     entry->Dispose();
237                 }
238 
visitChunkedTableTraits239                 static void visit(v8::Persistent<v8::Object>* entry, Visitor* visitor)
240                 {
241                     Node* node = V8Node::toNative(*entry);
242                     ASSERT(node->wrapper() == entry);
243 
244                     visitor->visitDOMWrapper(node, *entry);
245                 }
246             };
247 
248             typedef ChunkedTable<v8::Persistent<v8::Object>, numberOfEntries, ChunkedTableTraits> Table;
249             Table m_table;
250         };
251 
252         DOMDataStore(DOMData*);
253         virtual ~DOMDataStore();
254 
255         // A list of all DOMDataStore objects.  Traversed during GC to find a thread-specific map that
256         // contains the object - so we can schedule the object to be deleted on the thread which created it.
257         static DOMDataList& allStores();
258         // Mutex to protect against concurrent access of DOMDataList.
259         static WTF::Mutex& allStoresMutex();
260 
261         // Helper function to avoid circular includes.
262         static void forgetDelayedObject(DOMData*, void* object);
263 
domData()264         DOMData* domData() const { return m_domData; }
265 
266         void* getDOMWrapperMap(DOMWrapperMapType);
267 
domNodeMap()268         DOMNodeMapping& domNodeMap() { return *m_domNodeMap; }
domObjectMap()269         InternalDOMWrapperMap<void>& domObjectMap() { return *m_domObjectMap; }
activeDomObjectMap()270         InternalDOMWrapperMap<void>& activeDomObjectMap() { return *m_activeDomObjectMap; }
271 #if ENABLE(SVG)
domSvgElementInstanceMap()272         InternalDOMWrapperMap<SVGElementInstance>& domSvgElementInstanceMap() { return *m_domSvgElementInstanceMap; }
domSvgObjectWithContextMap()273         InternalDOMWrapperMap<void>& domSvgObjectWithContextMap() { return *m_domSvgObjectWithContextMap; }
274 #endif
275 
276         // Need by V8GCController.
277         static void weakActiveDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject);
278 
279     protected:
280         static void weakNodeCallback(v8::Persistent<v8::Value> v8Object, void* domObject);
281         static void weakDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject);
282 #if ENABLE(SVG)
283         static void weakSVGElementInstanceCallback(v8::Persistent<v8::Value> v8Object, void* domObject);
284         // SVG non-node elements may have a reference to a context node which should be notified when the element is change.
285         static void weakSVGObjectWithContextCallback(v8::Persistent<v8::Value> v8Object, void* domObject);
286 #endif
287 
288         DOMNodeMapping* m_domNodeMap;
289         InternalDOMWrapperMap<void>* m_domObjectMap;
290         InternalDOMWrapperMap<void>* m_activeDomObjectMap;
291 #if ENABLE(SVG)
292         InternalDOMWrapperMap<SVGElementInstance>* m_domSvgElementInstanceMap;
293         InternalDOMWrapperMap<void>* m_domSvgObjectWithContextMap;
294 #endif
295 
296     private:
297         // A back-pointer to the DOMData to which we belong.
298         DOMData* m_domData;
299     };
300 
301 } // namespace WebCore
302 
303 #endif // DOMDataStore_h
304