| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // The reason we write our own hash map instead of using unordered_map in STL, | 5 // The reason we write our own hash map instead of using unordered_map in STL, |
| 6 // is that STL containers use a mutex pool on debug build, which will lead to | 6 // is that STL containers use a mutex pool on debug build, which will lead to |
| 7 // deadlock when we are using async signal handler. | 7 // deadlock when we are using async signal handler. |
| 8 | 8 |
| 9 #ifndef V8_BASE_HASHMAP_H_ | 9 #ifndef V8_BASE_HASHMAP_H_ |
| 10 #define V8_BASE_HASHMAP_H_ | 10 #define V8_BASE_HASHMAP_H_ |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 | 77 |
| 78 // Iteration | 78 // Iteration |
| 79 // | 79 // |
| 80 // for (Entry* p = map.Start(); p != nullptr; p = map.Next(p)) { | 80 // for (Entry* p = map.Start(); p != nullptr; p = map.Next(p)) { |
| 81 // ... | 81 // ... |
| 82 // } | 82 // } |
| 83 // | 83 // |
| 84 // If entries are inserted during iteration, the effect of | 84 // If entries are inserted during iteration, the effect of |
| 85 // calling Next() is undefined. | 85 // calling Next() is undefined. |
| 86 Entry* Start() const; | 86 Entry* Start() const; |
| 87 Entry* Next(Entry* p) const; | 87 Entry* Next(Entry* entry) const; |
| 88 | 88 |
| 89 // Some match functions defined for convenience. | 89 // Some match functions defined for convenience. |
| 90 // TODO(leszeks): This isn't really matching pointers, so the name doesn't | 90 // TODO(leszeks): This isn't really matching pointers, so the name doesn't |
| 91 // really make sense, but we should remove this entirely and template the map | 91 // really make sense, but we should remove this entirely and template the map |
| 92 // on the matching function. | 92 // on the matching function. |
| 93 static bool PointersMatch(typename MatchFunHelper<Key>::KeyRef key1, | 93 static bool PointersMatch(typename MatchFunHelper<Key>::KeyRef key1, |
| 94 typename MatchFunHelper<Key>::KeyRef key2) { | 94 typename MatchFunHelper<Key>::KeyRef key2) { |
| 95 return key1 == key2; | 95 return key1 == key2; |
| 96 } | 96 } |
| 97 | 97 |
| 98 private: | 98 private: |
| 99 MatchFun match_; | 99 MatchFun match_; |
| 100 Entry* map_; | 100 Entry* map_; |
| 101 uint32_t capacity_; | 101 uint32_t capacity_; |
| 102 uint32_t occupancy_; | 102 uint32_t occupancy_; |
| 103 AllocationPolicy allocator_; | 103 AllocationPolicy allocator_; |
| 104 | 104 |
| 105 Entry* map_end() const { return map_ + capacity_; } | 105 Entry* map_end() const { return map_ + capacity_; } |
| 106 Entry* Probe(const Key& key, uint32_t hash) const; | 106 Entry* Probe(const Key& key, uint32_t hash) const; |
| 107 Entry* FillEmptyEntry(Entry* entry, const Key& key, const Value& value, |
| 108 uint32_t hash); |
| 107 void Initialize(uint32_t capacity); | 109 void Initialize(uint32_t capacity); |
| 108 void Resize(); | 110 void Resize(); |
| 109 }; | 111 }; |
| 110 | 112 |
| 111 template <typename Key> | 113 template <typename Key> |
| 112 struct MatchFunHelper { | 114 struct MatchFunHelper { |
| 113 typedef const Key& KeyRef; | 115 typedef const Key& KeyRef; |
| 114 typedef bool (*Fun)(KeyRef key1, KeyRef key2); | 116 typedef bool (*Fun)(KeyRef key1, KeyRef key2); |
| 115 }; | 117 }; |
| 116 | 118 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 132 | 134 |
| 133 template <typename Key, typename Value, class AllocationPolicy> | 135 template <typename Key, typename Value, class AllocationPolicy> |
| 134 TemplateHashMapImpl<Key, Value, AllocationPolicy>::~TemplateHashMapImpl() { | 136 TemplateHashMapImpl<Key, Value, AllocationPolicy>::~TemplateHashMapImpl() { |
| 135 allocator_.Delete(map_); | 137 allocator_.Delete(map_); |
| 136 } | 138 } |
| 137 | 139 |
| 138 template <typename Key, typename Value, class AllocationPolicy> | 140 template <typename Key, typename Value, class AllocationPolicy> |
| 139 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* | 141 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 140 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Lookup(const Key& key, | 142 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Lookup(const Key& key, |
| 141 uint32_t hash) const { | 143 uint32_t hash) const { |
| 142 Entry* p = Probe(key, hash); | 144 Entry* entry = Probe(key, hash); |
| 143 return p->exists() ? p : nullptr; | 145 return entry->exists() ? entry : nullptr; |
| 144 } | 146 } |
| 145 | 147 |
| 146 template <typename Key, typename Value, class AllocationPolicy> | 148 template <typename Key, typename Value, class AllocationPolicy> |
| 147 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* | 149 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 148 TemplateHashMapImpl<Key, Value, AllocationPolicy>::LookupOrInsert( | 150 TemplateHashMapImpl<Key, Value, AllocationPolicy>::LookupOrInsert( |
| 149 const Key& key, uint32_t hash) { | 151 const Key& key, uint32_t hash) { |
| 150 // Find a matching entry. | 152 // Find a matching entry. |
| 151 Entry* p = Probe(key, hash); | 153 Entry* entry = Probe(key, hash); |
| 152 if (p->exists()) { | 154 if (entry->exists()) { |
| 153 return p; | 155 return entry; |
| 154 } | 156 } |
| 155 | 157 |
| 156 return InsertNew(key, hash); | 158 return FillEmptyEntry(entry, key, Value(), hash); |
| 157 } | 159 } |
| 158 | 160 |
| 159 template <typename Key, typename Value, class AllocationPolicy> | 161 template <typename Key, typename Value, class AllocationPolicy> |
| 160 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* | 162 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 161 TemplateHashMapImpl<Key, Value, AllocationPolicy>::InsertNew(const Key& key, | 163 TemplateHashMapImpl<Key, Value, AllocationPolicy>::InsertNew(const Key& key, |
| 162 uint32_t hash) { | 164 uint32_t hash) { |
| 163 // Find a matching entry. | 165 Entry* entry = Probe(key, hash); |
| 164 Entry* p = Probe(key, hash); | 166 return FillEmptyEntry(entry, key, Value(), hash); |
| 165 DCHECK(!p->exists()); | |
| 166 | |
| 167 // No entry found; construct one in-place in the empty slot using placement | |
| 168 // new. | |
| 169 new (p) Entry(key, Value(), hash); | |
| 170 occupancy_++; | |
| 171 | |
| 172 // Grow the map if we reached >= 80% occupancy. | |
| 173 if (occupancy_ + occupancy_ / 4 >= capacity_) { | |
| 174 Resize(); | |
| 175 p = Probe(key, hash); | |
| 176 } | |
| 177 | |
| 178 return p; | |
| 179 } | 167 } |
| 180 | 168 |
| 181 template <typename Key, typename Value, class AllocationPolicy> | 169 template <typename Key, typename Value, class AllocationPolicy> |
| 182 Value TemplateHashMapImpl<Key, Value, AllocationPolicy>::Remove(const Key& key, | 170 Value TemplateHashMapImpl<Key, Value, AllocationPolicy>::Remove(const Key& key, |
| 183 uint32_t hash) { | 171 uint32_t hash) { |
| 184 // Lookup the entry for the key to remove. | 172 // Lookup the entry for the key to remove. |
| 185 Entry* p = Probe(key, hash); | 173 Entry* p = Probe(key, hash); |
| 186 if (!p->exists()) { | 174 if (!p->exists()) { |
| 187 // Key not found nothing to remove. | 175 // Key not found nothing to remove. |
| 188 return nullptr; | 176 return nullptr; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 // Clear the entry which is allowed to en emptied. | 224 // Clear the entry which is allowed to en emptied. |
| 237 p->clear(); | 225 p->clear(); |
| 238 occupancy_--; | 226 occupancy_--; |
| 239 return value; | 227 return value; |
| 240 } | 228 } |
| 241 | 229 |
| 242 template <typename Key, typename Value, class AllocationPolicy> | 230 template <typename Key, typename Value, class AllocationPolicy> |
| 243 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Clear() { | 231 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Clear() { |
| 244 // Mark all entries as empty. | 232 // Mark all entries as empty. |
| 245 const Entry* end = map_end(); | 233 const Entry* end = map_end(); |
| 246 for (Entry* p = map_; p < end; p++) { | 234 for (Entry* entry = map_; entry < end; entry++) { |
| 247 p->clear(); | 235 entry->clear(); |
| 248 } | 236 } |
| 249 occupancy_ = 0; | 237 occupancy_ = 0; |
| 250 } | 238 } |
| 251 | 239 |
| 252 template <typename Key, typename Value, class AllocationPolicy> | 240 template <typename Key, typename Value, class AllocationPolicy> |
| 253 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* | 241 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 254 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Start() const { | 242 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Start() const { |
| 255 return Next(map_ - 1); | 243 return Next(map_ - 1); |
| 256 } | 244 } |
| 257 | 245 |
| 258 template <typename Key, typename Value, class AllocationPolicy> | 246 template <typename Key, typename Value, class AllocationPolicy> |
| 259 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* | 247 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 260 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Next(Entry* p) const { | 248 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Next(Entry* entry) const { |
| 261 const Entry* end = map_end(); | 249 const Entry* end = map_end(); |
| 262 DCHECK(map_ - 1 <= p && p < end); | 250 DCHECK(map_ - 1 <= entry && entry < end); |
| 263 for (p++; p < end; p++) { | 251 for (entry++; entry < end; entry++) { |
| 264 if (p->exists()) { | 252 if (entry->exists()) { |
| 265 return p; | 253 return entry; |
| 266 } | 254 } |
| 267 } | 255 } |
| 268 return nullptr; | 256 return nullptr; |
| 269 } | 257 } |
| 270 | 258 |
| 271 template <typename Key, typename Value, class AllocationPolicy> | 259 template <typename Key, typename Value, class AllocationPolicy> |
| 272 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* | 260 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 273 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Probe(const Key& key, | 261 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Probe(const Key& key, |
| 274 uint32_t hash) const { | 262 uint32_t hash) const { |
| 275 DCHECK(base::bits::IsPowerOfTwo32(capacity_)); | 263 DCHECK(base::bits::IsPowerOfTwo32(capacity_)); |
| 276 Entry* p = map_ + (hash & (capacity_ - 1)); | 264 Entry* entry = map_ + (hash & (capacity_ - 1)); |
| 277 const Entry* end = map_end(); | 265 const Entry* end = map_end(); |
| 278 DCHECK(map_ <= p && p < end); | 266 DCHECK(map_ <= entry && entry < end); |
| 279 | 267 |
| 280 DCHECK(occupancy_ < capacity_); // Guarantees loop termination. | 268 DCHECK(occupancy_ < capacity_); // Guarantees loop termination. |
| 281 while (p->exists() && (hash != p->hash || !match_(key, p->key))) { | 269 while (entry->exists() && (hash != entry->hash || !match_(key, entry->key))) { |
| 282 p++; | 270 entry++; |
| 283 if (p >= end) { | 271 if (entry >= end) { |
| 284 p = map_; | 272 entry = map_; |
| 285 } | 273 } |
| 286 } | 274 } |
| 287 | 275 |
| 288 return p; | 276 return entry; |
| 289 } | 277 } |
| 290 | 278 |
| 291 template <typename Key, typename Value, class AllocationPolicy> | 279 template <typename Key, typename Value, class AllocationPolicy> |
| 280 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 281 TemplateHashMapImpl<Key, Value, AllocationPolicy>::FillEmptyEntry( |
| 282 Entry* entry, const Key& key, const Value& value, uint32_t hash) { |
| 283 DCHECK(!entry->exists()); |
| 284 |
| 285 new (entry) Entry(key, value, hash); |
| 286 occupancy_++; |
| 287 |
| 288 // Grow the map if we reached >= 80% occupancy. |
| 289 if (occupancy_ + occupancy_ / 4 >= capacity_) { |
| 290 Resize(); |
| 291 entry = Probe(key, hash); |
| 292 } |
| 293 |
| 294 return entry; |
| 295 } |
| 296 |
| 297 template <typename Key, typename Value, class AllocationPolicy> |
| 292 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Initialize( | 298 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Initialize( |
| 293 uint32_t capacity) { | 299 uint32_t capacity) { |
| 294 DCHECK(base::bits::IsPowerOfTwo32(capacity)); | 300 DCHECK(base::bits::IsPowerOfTwo32(capacity)); |
| 295 map_ = reinterpret_cast<Entry*>(allocator_.New(capacity * sizeof(Entry))); | 301 map_ = reinterpret_cast<Entry*>(allocator_.New(capacity * sizeof(Entry))); |
| 296 if (map_ == nullptr) { | 302 if (map_ == nullptr) { |
| 297 FATAL("Out of memory: HashMap::Initialize"); | 303 FATAL("Out of memory: HashMap::Initialize"); |
| 298 return; | 304 return; |
| 299 } | 305 } |
| 300 capacity_ = capacity; | 306 capacity_ = capacity; |
| 301 Clear(); | 307 Clear(); |
| 302 } | 308 } |
| 303 | 309 |
| 304 template <typename Key, typename Value, class AllocationPolicy> | 310 template <typename Key, typename Value, class AllocationPolicy> |
| 305 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Resize() { | 311 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Resize() { |
| 306 Entry* map = map_; | 312 Entry* map = map_; |
| 307 uint32_t n = occupancy_; | 313 uint32_t n = occupancy_; |
| 308 | 314 |
| 309 // Allocate larger map. | 315 // Allocate larger map. |
| 310 Initialize(capacity_ * 2); | 316 Initialize(capacity_ * 2); |
| 311 | 317 |
| 312 // Rehash all current entries. | 318 // Rehash all current entries. |
| 313 for (Entry* p = map; n > 0; p++) { | 319 for (Entry* entry = map; n > 0; entry++) { |
| 314 if (p->exists()) { | 320 if (entry->exists()) { |
| 315 Entry* entry = LookupOrInsert(p->key, p->hash); | 321 Entry* new_entry = Probe(entry->key, entry->hash); |
| 316 entry->value = p->value; | 322 new_entry = |
| 323 FillEmptyEntry(new_entry, entry->key, entry->value, entry->hash); |
| 317 n--; | 324 n--; |
| 318 } | 325 } |
| 319 } | 326 } |
| 320 | 327 |
| 321 // Delete old map. | 328 // Delete old map. |
| 322 allocator_.Delete(map); | 329 allocator_.Delete(map); |
| 323 } | 330 } |
| 324 | 331 |
| 325 // A hash map for pointer keys and values with an STL-like interface. | 332 // A hash map for pointer keys and values with an STL-like interface. |
| 326 template <class Key, class Value, class AllocationPolicy> | 333 template <class Key, class Value, class AllocationPolicy> |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 return Iterator(this, this->LookupOrInsert(key, key->Hash())); | 379 return Iterator(this, this->LookupOrInsert(key, key->Hash())); |
| 373 } | 380 } |
| 374 return Iterator(this, this->Lookup(key, key->Hash())); | 381 return Iterator(this, this->Lookup(key, key->Hash())); |
| 375 } | 382 } |
| 376 }; | 383 }; |
| 377 | 384 |
| 378 } // namespace base | 385 } // namespace base |
| 379 } // namespace v8 | 386 } // namespace v8 |
| 380 | 387 |
| 381 #endif // V8_BASE_HASHMAP_H_ | 388 #endif // V8_BASE_HASHMAP_H_ |
| OLD | NEW |