Home | History | Annotate | Download | only in v8
      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:
     42     ChunkedTable() : m_chunks(0), m_current(0), m_last(0) { }
     43 
     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 
     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 
     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 
     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 {
    106         explicit Chunk(Chunk* previous) : m_previous(previous) { }
    107         Chunk* const m_previous;
    108         T m_entries[CHUNK_SIZE];
    109     };
    110 
    111     static void clearEntries(T* first, T* last)
    112     {
    113         for (T* entry = first; entry < last; entry++)
    114             Traits::clear(entry);
    115     }
    116 
    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:
    131     IntrusiveDOMWrapperMap(v8::WeakReferenceCallback callback)
    132         : AbstractWeakReferenceMap<Node, v8::Object>(callback) { }
    133 
    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 
    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 
    149     virtual bool contains(Node* obj)
    150     {
    151         return obj->wrapper();
    152     }
    153 
    154     virtual void visit(DOMDataStore* store, Visitor* visitor)
    155     {
    156         m_table.visit(store, visitor);
    157     }
    158 
    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 
    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 
    185         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 
    193         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 
    202         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