| 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 | 
|---|