Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2009 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 WeakGCMap_h
     27 #define WeakGCMap_h
     28 
     29 #include "Handle.h"
     30 #include "JSGlobalData.h"
     31 #include <wtf/HashMap.h>
     32 
     33 namespace JSC {
     34 
     35 // A HashMap for GC'd values that removes entries when the associated value
     36 // dies.
     37 template <typename KeyType, typename MappedType> struct DefaultWeakGCMapFinalizerCallback {
     38     static void* finalizerContextFor(KeyType key)
     39     {
     40         return reinterpret_cast<void*>(key);
     41     }
     42 
     43     static KeyType keyForFinalizer(void* context, typename HandleTypes<MappedType>::ExternalType)
     44     {
     45         return reinterpret_cast<KeyType>(context);
     46     }
     47 };
     48 
     49 template<typename KeyType, typename MappedType, typename FinalizerCallback = DefaultWeakGCMapFinalizerCallback<KeyType, MappedType>, typename HashArg = typename DefaultHash<KeyType>::Hash, typename KeyTraitsArg = HashTraits<KeyType> >
     50 class WeakGCMap : private WeakHandleOwner {
     51     WTF_MAKE_FAST_ALLOCATED;
     52     WTF_MAKE_NONCOPYABLE(WeakGCMap);
     53 
     54     typedef HashMap<KeyType, HandleSlot, HashArg, KeyTraitsArg> MapType;
     55     typedef typename HandleTypes<MappedType>::ExternalType ExternalType;
     56     typedef typename MapType::iterator map_iterator;
     57 
     58 public:
     59 
     60     struct iterator {
     61         friend class WeakGCMap;
     62         iterator(map_iterator iter)
     63             : m_iterator(iter)
     64         {
     65         }
     66 
     67         std::pair<KeyType, ExternalType> get() const { return std::make_pair(m_iterator->first, HandleTypes<MappedType>::getFromSlot(m_iterator->second)); }
     68         std::pair<KeyType, HandleSlot> getSlot() const { return *m_iterator; }
     69 
     70         iterator& operator++() { ++m_iterator; return *this; }
     71 
     72         // postfix ++ intentionally omitted
     73 
     74         // Comparison.
     75         bool operator==(const iterator& other) const { return m_iterator == other.m_iterator; }
     76         bool operator!=(const iterator& other) const { return m_iterator != other.m_iterator; }
     77 
     78     private:
     79         map_iterator m_iterator;
     80     };
     81 
     82     WeakGCMap()
     83     {
     84     }
     85 
     86     bool isEmpty() { return m_map.isEmpty(); }
     87     void clear()
     88     {
     89         map_iterator end = m_map.end();
     90         for (map_iterator ptr = m_map.begin(); ptr != end; ++ptr)
     91             HandleHeap::heapFor(ptr->second)->deallocate(ptr->second);
     92         m_map.clear();
     93     }
     94 
     95     bool contains(const KeyType& key) const
     96     {
     97         return m_map.contains(key);
     98     }
     99 
    100     iterator find(const KeyType& key)
    101     {
    102         return m_map.find(key);
    103     }
    104 
    105     void remove(iterator iter)
    106     {
    107         ASSERT(iter.m_iterator != m_map.end());
    108         HandleSlot slot = iter.m_iterator->second;
    109         ASSERT(slot);
    110         HandleHeap::heapFor(slot)->deallocate(slot);
    111         m_map.remove(iter.m_iterator);
    112     }
    113 
    114     ExternalType get(const KeyType& key) const
    115     {
    116         return HandleTypes<MappedType>::getFromSlot(m_map.get(key));
    117     }
    118 
    119     HandleSlot getSlot(const KeyType& key) const
    120     {
    121         return m_map.get(key);
    122     }
    123 
    124     pair<iterator, bool> add(JSGlobalData& globalData, const KeyType& key, ExternalType value)
    125     {
    126         pair<typename MapType::iterator, bool> iter = m_map.add(key, 0);
    127         if (iter.second) {
    128             HandleSlot slot = globalData.allocateGlobalHandle();
    129             iter.first->second = slot;
    130             HandleHeap::heapFor(slot)->makeWeak(slot, this, FinalizerCallback::finalizerContextFor(key));
    131             HandleHeap::heapFor(slot)->writeBarrier(slot, value);
    132             *slot = value;
    133         }
    134         return iter;
    135     }
    136 
    137     void set(iterator iter, ExternalType value)
    138     {
    139         HandleSlot slot = iter.m_iterator->second;
    140         ASSERT(slot);
    141         HandleHeap::heapFor(slot)->writeBarrier(slot, value);
    142         *slot = value;
    143     }
    144 
    145     void set(JSGlobalData& globalData, const KeyType& key, ExternalType value)
    146     {
    147         pair<typename MapType::iterator, bool> iter = m_map.add(key, 0);
    148         HandleSlot slot = iter.first->second;
    149         if (iter.second) {
    150             slot = globalData.allocateGlobalHandle();
    151             HandleHeap::heapFor(slot)->makeWeak(slot, this, key);
    152             iter.first->second = slot;
    153         }
    154         HandleHeap::heapFor(slot)->writeBarrier(slot, value);
    155         *slot = value;
    156     }
    157 
    158     ExternalType take(const KeyType& key)
    159     {
    160         HandleSlot slot = m_map.take(key);
    161         if (!slot)
    162             return HashTraits<ExternalType>::emptyValue();
    163         ExternalType result = HandleTypes<MappedType>::getFromSlot(slot);
    164         HandleHeap::heapFor(slot)->deallocate(slot);
    165         return result;
    166     }
    167 
    168     size_t size() { return m_map.size(); }
    169 
    170     iterator begin() { return iterator(m_map.begin()); }
    171     iterator end() { return iterator(m_map.end()); }
    172 
    173     ~WeakGCMap()
    174     {
    175         clear();
    176     }
    177 
    178 private:
    179     virtual void finalize(Handle<Unknown> handle, void* context)
    180     {
    181         HandleSlot slot = m_map.take(FinalizerCallback::keyForFinalizer(context, HandleTypes<MappedType>::getFromSlot(handle.slot())));
    182         ASSERT(slot);
    183         HandleHeap::heapFor(slot)->deallocate(slot);
    184     }
    185 
    186     MapType m_map;
    187 };
    188 
    189 } // namespace JSC
    190 
    191 #endif // WeakGCMap_h
    192