• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
finalizerContextForDefaultWeakGCMapFinalizerCallback38     static void* finalizerContextFor(KeyType key)
39     {
40         return reinterpret_cast<void*>(key);
41     }
42 
keyForFinalizerDefaultWeakGCMapFinalizerCallback43     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;
iteratoriterator62         iterator(map_iterator iter)
63             : m_iterator(iter)
64         {
65         }
66 
getiterator67         std::pair<KeyType, ExternalType> get() const { return std::make_pair(m_iterator->first, HandleTypes<MappedType>::getFromSlot(m_iterator->second)); }
getSlotiterator68         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 
WeakGCMap()82     WeakGCMap()
83     {
84     }
85 
isEmpty()86     bool isEmpty() { return m_map.isEmpty(); }
clear()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 
contains(const KeyType & key)95     bool contains(const KeyType& key) const
96     {
97         return m_map.contains(key);
98     }
99 
find(const KeyType & key)100     iterator find(const KeyType& key)
101     {
102         return m_map.find(key);
103     }
104 
remove(iterator iter)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 
get(const KeyType & key)114     ExternalType get(const KeyType& key) const
115     {
116         return HandleTypes<MappedType>::getFromSlot(m_map.get(key));
117     }
118 
getSlot(const KeyType & key)119     HandleSlot getSlot(const KeyType& key) const
120     {
121         return m_map.get(key);
122     }
123 
add(JSGlobalData & globalData,const KeyType & key,ExternalType value)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 
set(iterator iter,ExternalType value)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 
set(JSGlobalData & globalData,const KeyType & key,ExternalType value)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 
take(const KeyType & key)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 
size()168     size_t size() { return m_map.size(); }
169 
begin()170     iterator begin() { return iterator(m_map.begin()); }
end()171     iterator end() { return iterator(m_map.end()); }
172 
~WeakGCMap()173     ~WeakGCMap()
174     {
175         clear();
176     }
177 
178 private:
finalize(Handle<Unknown> handle,void * context)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