source: webkit/trunk/JavaScriptCore/wtf/RefPtrHashMap.h@ 65104

Last change on this file since 65104 was 53957, checked in by [email protected], 15 years ago

Reviewed by Darin Adler.

https://bugs.webkit.org/show_bug.cgi?id=34150
WebKit needs a mechanism to catch stale HashMap entries

It is very difficult to catch stale pointers that are HashMap keys - since a pointer's hash
is just its value, it is very unlikely that any observable problem is reproducible.

This extends hash table consistency checks to check that pointers are referencing allocated
memory blocks, and makes it possible to invoke the checks explicitly (it is not feasible
to enable CHECK_HASHTABLE_CONSISTENCY by default, because that affects performance too much).

  • wtf/HashMap.h: (WTF::::checkConsistency): Call through to HashTable implementation. We can add similar calls to HashSet and HashCountedSet, but I haven't seen hard to debug problems with those yet.
  • wtf/HashSet.h: (WTF::::remove): The version of checkTableConsistency that's guarded by CHECK_HASHTABLE_CONSISTENCY is now called internalCheckTableConsistency().
  • wtf/HashTable.h: (WTF::HashTable::internalCheckTableConsistency): (WTF::HashTable::internalCheckTableConsistencyExceptSize): (WTF::HashTable::checkTableConsistencyExceptSize): Expose checkTableConsistency() even if CHECK_HASHTABLE_CONSISTENCY is off. (WTF::::add): Updated for checkTableConsistency renaming. (WTF::::addPassingHashCode): Ditto. (WTF::::removeAndInvalidate): Ditto. (WTF::::remove): Ditto. (WTF::::rehash): Ditto. (WTF::::checkTableConsistency): The assertion for !shouldExpand() was not correct - this function returns true for tables with m_table == 0. (WTF::::checkTableConsistencyExceptSize): Call checkValueConsistency for key. Potentially, we could do the same for values.
  • wtf/HashTraits.h: (WTF::GenericHashTraits::checkValueConsistency): An empty function that can be overridden to add checks. Currently, the only override is for pointer hashes.
  • wtf/RefPtrHashMap.h: (WTF::::remove): Updated for checkTableConsistency renaming.
  • Property svn:eol-style set to native
File size: 13.1 KB
Line 
1/*
2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 */
20
21namespace WTF {
22
23 // This specialization is a direct copy of HashMap, with overloaded functions
24 // to allow for lookup by pointer instead of RefPtr, avoiding ref-count churn.
25
26 // FIXME: Find a better way that doesn't require an entire copy of the HashMap template.
27
28 template<typename RawKeyType, typename ValueType, typename ValueTraits, typename HashFunctions>
29 struct RefPtrHashMapRawKeyTranslator {
30 typedef typename ValueType::first_type KeyType;
31 typedef typename ValueType::second_type MappedType;
32 typedef typename ValueTraits::FirstTraits KeyTraits;
33 typedef typename ValueTraits::SecondTraits MappedTraits;
34
35 static unsigned hash(RawKeyType key) { return HashFunctions::hash(key); }
36 static bool equal(const KeyType& a, RawKeyType b) { return HashFunctions::equal(a, b); }
37 static void translate(ValueType& location, RawKeyType key, const MappedType& mapped)
38 {
39 location.first = key;
40 location.second = mapped;
41 }
42 };
43
44 template<typename T, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
45 class HashMap<RefPtr<T>, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> : public FastAllocBase {
46 private:
47 typedef KeyTraitsArg KeyTraits;
48 typedef MappedTraitsArg MappedTraits;
49 typedef PairHashTraits<KeyTraits, MappedTraits> ValueTraits;
50
51 public:
52 typedef typename KeyTraits::TraitType KeyType;
53 typedef T* RawKeyType;
54 typedef typename MappedTraits::TraitType MappedType;
55 typedef typename ValueTraits::TraitType ValueType;
56
57 private:
58 typedef HashArg HashFunctions;
59
60 typedef HashTable<KeyType, ValueType, PairFirstExtractor<ValueType>,
61 HashFunctions, ValueTraits, KeyTraits> HashTableType;
62
63 typedef RefPtrHashMapRawKeyTranslator<RawKeyType, ValueType, ValueTraits, HashFunctions>
64 RawKeyTranslator;
65
66 public:
67 typedef HashTableIteratorAdapter<HashTableType, ValueType> iterator;
68 typedef HashTableConstIteratorAdapter<HashTableType, ValueType> const_iterator;
69
70 void swap(HashMap&);
71
72 int size() const;
73 int capacity() const;
74 bool isEmpty() const;
75
76 // iterators iterate over pairs of keys and values
77 iterator begin();
78 iterator end();
79 const_iterator begin() const;
80 const_iterator end() const;
81
82 iterator find(const KeyType&);
83 iterator find(RawKeyType);
84 const_iterator find(const KeyType&) const;
85 const_iterator find(RawKeyType) const;
86 bool contains(const KeyType&) const;
87 bool contains(RawKeyType) const;
88 MappedType get(const KeyType&) const;
89 MappedType get(RawKeyType) const;
90 MappedType inlineGet(RawKeyType) const;
91
92 // replaces value but not key if key is already present
93 // return value is a pair of the iterator to the key location,
94 // and a boolean that's true if a new value was actually added
95 pair<iterator, bool> set(const KeyType&, const MappedType&);
96 pair<iterator, bool> set(RawKeyType, const MappedType&);
97
98 // does nothing if key is already present
99 // return value is a pair of the iterator to the key location,
100 // and a boolean that's true if a new value was actually added
101 pair<iterator, bool> add(const KeyType&, const MappedType&);
102 pair<iterator, bool> add(RawKeyType, const MappedType&);
103
104 void remove(const KeyType&);
105 void remove(RawKeyType);
106 void remove(iterator);
107 void clear();
108
109 MappedType take(const KeyType&); // efficient combination of get with remove
110 MappedType take(RawKeyType); // efficient combination of get with remove
111
112 private:
113 pair<iterator, bool> inlineAdd(const KeyType&, const MappedType&);
114 pair<iterator, bool> inlineAdd(RawKeyType, const MappedType&);
115
116 HashTableType m_impl;
117 };
118
119 template<typename T, typename U, typename V, typename W, typename X>
120 inline void HashMap<RefPtr<T>, U, V, W, X>::swap(HashMap& other)
121 {
122 m_impl.swap(other.m_impl);
123 }
124
125 template<typename T, typename U, typename V, typename W, typename X>
126 inline int HashMap<RefPtr<T>, U, V, W, X>::size() const
127 {
128 return m_impl.size();
129 }
130
131 template<typename T, typename U, typename V, typename W, typename X>
132 inline int HashMap<RefPtr<T>, U, V, W, X>::capacity() const
133 {
134 return m_impl.capacity();
135 }
136
137 template<typename T, typename U, typename V, typename W, typename X>
138 inline bool HashMap<RefPtr<T>, U, V, W, X>::isEmpty() const
139 {
140 return m_impl.isEmpty();
141 }
142
143 template<typename T, typename U, typename V, typename W, typename X>
144 inline typename HashMap<RefPtr<T>, U, V, W, X>::iterator HashMap<RefPtr<T>, U, V, W, X>::begin()
145 {
146 return m_impl.begin();
147 }
148
149 template<typename T, typename U, typename V, typename W, typename X>
150 inline typename HashMap<RefPtr<T>, U, V, W, X>::iterator HashMap<RefPtr<T>, U, V, W, X>::end()
151 {
152 return m_impl.end();
153 }
154
155 template<typename T, typename U, typename V, typename W, typename X>
156 inline typename HashMap<RefPtr<T>, U, V, W, X>::const_iterator HashMap<RefPtr<T>, U, V, W, X>::begin() const
157 {
158 return m_impl.begin();
159 }
160
161 template<typename T, typename U, typename V, typename W, typename X>
162 inline typename HashMap<RefPtr<T>, U, V, W, X>::const_iterator HashMap<RefPtr<T>, U, V, W, X>::end() const
163 {
164 return m_impl.end();
165 }
166
167 template<typename T, typename U, typename V, typename W, typename X>
168 inline typename HashMap<RefPtr<T>, U, V, W, X>::iterator HashMap<RefPtr<T>, U, V, W, X>::find(const KeyType& key)
169 {
170 return m_impl.find(key);
171 }
172
173 template<typename T, typename U, typename V, typename W, typename X>
174 inline typename HashMap<RefPtr<T>, U, V, W, X>::iterator HashMap<RefPtr<T>, U, V, W, X>::find(RawKeyType key)
175 {
176 return m_impl.template find<RawKeyType, RawKeyTranslator>(key);
177 }
178
179 template<typename T, typename U, typename V, typename W, typename X>
180 inline typename HashMap<RefPtr<T>, U, V, W, X>::const_iterator HashMap<RefPtr<T>, U, V, W, X>::find(const KeyType& key) const
181 {
182 return m_impl.find(key);
183 }
184
185 template<typename T, typename U, typename V, typename W, typename X>
186 inline typename HashMap<RefPtr<T>, U, V, W, X>::const_iterator HashMap<RefPtr<T>, U, V, W, X>::find(RawKeyType key) const
187 {
188 return m_impl.template find<RawKeyType, RawKeyTranslator>(key);
189 }
190
191 template<typename T, typename U, typename V, typename W, typename X>
192 inline bool HashMap<RefPtr<T>, U, V, W, X>::contains(const KeyType& key) const
193 {
194 return m_impl.contains(key);
195 }
196
197 template<typename T, typename U, typename V, typename W, typename X>
198 inline bool HashMap<RefPtr<T>, U, V, W, X>::contains(RawKeyType key) const
199 {
200 return m_impl.template contains<RawKeyType, RawKeyTranslator>(key);
201 }
202
203 template<typename T, typename U, typename V, typename W, typename X>
204 inline pair<typename HashMap<RefPtr<T>, U, V, W, X>::iterator, bool>
205 HashMap<RefPtr<T>, U, V, W, X>::inlineAdd(const KeyType& key, const MappedType& mapped)
206 {
207 typedef HashMapTranslator<ValueType, ValueTraits, HashFunctions> TranslatorType;
208 return m_impl.template add<KeyType, MappedType, TranslatorType>(key, mapped);
209 }
210
211 template<typename T, typename U, typename V, typename W, typename X>
212 inline pair<typename HashMap<RefPtr<T>, U, V, W, X>::iterator, bool>
213 HashMap<RefPtr<T>, U, V, W, X>::inlineAdd(RawKeyType key, const MappedType& mapped)
214 {
215 return m_impl.template add<RawKeyType, MappedType, RawKeyTranslator>(key, mapped);
216 }
217
218 template<typename T, typename U, typename V, typename W, typename X>
219 pair<typename HashMap<RefPtr<T>, U, V, W, X>::iterator, bool>
220 HashMap<RefPtr<T>, U, V, W, X>::set(const KeyType& key, const MappedType& mapped)
221 {
222 pair<iterator, bool> result = inlineAdd(key, mapped);
223 if (!result.second) {
224 // add call above didn't change anything, so set the mapped value
225 result.first->second = mapped;
226 }
227 return result;
228 }
229
230 template<typename T, typename U, typename V, typename W, typename X>
231 pair<typename HashMap<RefPtr<T>, U, V, W, X>::iterator, bool>
232 HashMap<RefPtr<T>, U, V, W, X>::set(RawKeyType key, const MappedType& mapped)
233 {
234 pair<iterator, bool> result = inlineAdd(key, mapped);
235 if (!result.second) {
236 // add call above didn't change anything, so set the mapped value
237 result.first->second = mapped;
238 }
239 return result;
240 }
241
242 template<typename T, typename U, typename V, typename W, typename X>
243 pair<typename HashMap<RefPtr<T>, U, V, W, X>::iterator, bool>
244 HashMap<RefPtr<T>, U, V, W, X>::add(const KeyType& key, const MappedType& mapped)
245 {
246 return inlineAdd(key, mapped);
247 }
248
249 template<typename T, typename U, typename V, typename W, typename X>
250 pair<typename HashMap<RefPtr<T>, U, V, W, X>::iterator, bool>
251 HashMap<RefPtr<T>, U, V, W, X>::add(RawKeyType key, const MappedType& mapped)
252 {
253 return inlineAdd(key, mapped);
254 }
255
256 template<typename T, typename U, typename V, typename W, typename MappedTraits>
257 typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedType
258 HashMap<RefPtr<T>, U, V, W, MappedTraits>::get(const KeyType& key) const
259 {
260 ValueType* entry = const_cast<HashTableType&>(m_impl).lookup(key);
261 if (!entry)
262 return MappedTraits::emptyValue();
263 return entry->second;
264 }
265
266 template<typename T, typename U, typename V, typename W, typename MappedTraits>
267 typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedType
268 inline HashMap<RefPtr<T>, U, V, W, MappedTraits>::inlineGet(RawKeyType key) const
269 {
270 ValueType* entry = const_cast<HashTableType&>(m_impl).template lookup<RawKeyType, RawKeyTranslator>(key);
271 if (!entry)
272 return MappedTraits::emptyValue();
273 return entry->second;
274 }
275
276 template<typename T, typename U, typename V, typename W, typename MappedTraits>
277 typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedType
278 HashMap<RefPtr<T>, U, V, W, MappedTraits>::get(RawKeyType key) const
279 {
280 return inlineGet(key);
281 }
282
283 template<typename T, typename U, typename V, typename W, typename X>
284 inline void HashMap<RefPtr<T>, U, V, W, X>::remove(iterator it)
285 {
286 if (it.m_impl == m_impl.end())
287 return;
288 m_impl.internalCheckTableConsistency();
289 m_impl.removeWithoutEntryConsistencyCheck(it.m_impl);
290 }
291
292 template<typename T, typename U, typename V, typename W, typename X>
293 inline void HashMap<RefPtr<T>, U, V, W, X>::remove(const KeyType& key)
294 {
295 remove(find(key));
296 }
297
298 template<typename T, typename U, typename V, typename W, typename X>
299 inline void HashMap<RefPtr<T>, U, V, W, X>::remove(RawKeyType key)
300 {
301 remove(find(key));
302 }
303
304 template<typename T, typename U, typename V, typename W, typename X>
305 inline void HashMap<RefPtr<T>, U, V, W, X>::clear()
306 {
307 m_impl.clear();
308 }
309
310 template<typename T, typename U, typename V, typename W, typename MappedTraits>
311 typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedType
312 HashMap<RefPtr<T>, U, V, W, MappedTraits>::take(const KeyType& key)
313 {
314 // This can probably be made more efficient to avoid ref/deref churn.
315 iterator it = find(key);
316 if (it == end())
317 return MappedTraits::emptyValue();
318 typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedType result = it->second;
319 remove(it);
320 return result;
321 }
322
323 template<typename T, typename U, typename V, typename W, typename MappedTraits>
324 typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedType
325 HashMap<RefPtr<T>, U, V, W, MappedTraits>::take(RawKeyType key)
326 {
327 // This can probably be made more efficient to avoid ref/deref churn.
328 iterator it = find(key);
329 if (it == end())
330 return MappedTraits::emptyValue();
331 typename HashMap<RefPtr<T>, U, V, W, MappedTraits>::MappedType result = it->second;
332 remove(it);
333 return result;
334 }
335
336} // namespace WTF
Note: See TracBrowser for help on using the repository browser.