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