mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-30 16:17:05 +00:00 
			
		
		
		
	Fix a really subtle bug where the entire hash table could fill with
tombstones, causing subsequent insertions to infinitely loop. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@33972 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
		| @@ -28,6 +28,7 @@ struct DenseMapKeyInfo { | |||||||
|   //static bool isPod() |   //static bool isPod() | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | // Provide DenseMapKeyInfo for all pointers. | ||||||
| template<typename T> | template<typename T> | ||||||
| struct DenseMapKeyInfo<T*> { | struct DenseMapKeyInfo<T*> { | ||||||
|   static inline T* getEmptyKey() { return (T*)-1; } |   static inline T* getEmptyKey() { return (T*)-1; } | ||||||
| @@ -51,6 +52,7 @@ class DenseMap { | |||||||
|   BucketT *Buckets; |   BucketT *Buckets; | ||||||
|    |    | ||||||
|   unsigned NumEntries; |   unsigned NumEntries; | ||||||
|  |   unsigned NumTombstones; | ||||||
|   DenseMap(const DenseMap &); // not implemented. |   DenseMap(const DenseMap &); // not implemented. | ||||||
| public: | public: | ||||||
|   explicit DenseMap(unsigned NumInitBuckets = 64) { |   explicit DenseMap(unsigned NumInitBuckets = 64) { | ||||||
| @@ -96,6 +98,7 @@ public: | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     assert(NumEntries == 0 && "Node count imbalance!"); |     assert(NumEntries == 0 && "Node count imbalance!"); | ||||||
|  |     NumTombstones = 0; | ||||||
|   } |   } | ||||||
|    |    | ||||||
|   /// count - Return true if the specified key is in the map. |   /// count - Return true if the specified key is in the map. | ||||||
| @@ -129,6 +132,7 @@ public: | |||||||
|     TheBucket->second.~ValueT(); |     TheBucket->second.~ValueT(); | ||||||
|     TheBucket->first = getTombstoneKey(); |     TheBucket->first = getTombstoneKey(); | ||||||
|     --NumEntries; |     --NumEntries; | ||||||
|  |     ++NumTombstones; | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|   bool erase(iterator I) { |   bool erase(iterator I) { | ||||||
| @@ -136,6 +140,7 @@ public: | |||||||
|     TheBucket->second.~ValueT(); |     TheBucket->second.~ValueT(); | ||||||
|     TheBucket->first = getTombstoneKey(); |     TheBucket->first = getTombstoneKey(); | ||||||
|     --NumEntries; |     --NumEntries; | ||||||
|  |     ++NumTombstones; | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|    |    | ||||||
| @@ -150,12 +155,26 @@ public: | |||||||
| private: | private: | ||||||
|   BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value, |   BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value, | ||||||
|                             BucketT *TheBucket) { |                             BucketT *TheBucket) { | ||||||
|     // If the load of the hash table is more than 3/4, grow it. |     // If the load of the hash table is more than 3/4, or if fewer than 1/8 of | ||||||
|     if (NumEntries*4 >= NumBuckets*3) { |     // the buckets are empty (meaning that many are filled with tombstones), | ||||||
|  |     // grow the table. | ||||||
|  |     // | ||||||
|  |     // The later case is tricky.  For example, if we had one empty bucket with | ||||||
|  |     // tons of tombstones, failing lookups (e.g. for insertion) would have to | ||||||
|  |     // probe almost the entire table until it found the empty bucket.  If the | ||||||
|  |     // table completely filled with tombstones, no lookup would ever succeed, | ||||||
|  |     // causing infinite loops in lookup. | ||||||
|  |     if (NumEntries*4 >= NumBuckets*3 || | ||||||
|  |         NumBuckets-(NumEntries+NumTombstones) < NumBuckets/8) {         | ||||||
|       this->grow(); |       this->grow(); | ||||||
|       LookupBucketFor(Key, TheBucket); |       LookupBucketFor(Key, TheBucket); | ||||||
|     } |     } | ||||||
|     ++NumEntries; |     ++NumEntries; | ||||||
|  |      | ||||||
|  |     // If we are writing over a tombstone, remember this. | ||||||
|  |     if (TheBucket->first != getEmptyKey()) | ||||||
|  |       --NumTombstones; | ||||||
|  |      | ||||||
|     TheBucket->first = Key; |     TheBucket->first = Key; | ||||||
|     new (&TheBucket->second) ValueT(Value); |     new (&TheBucket->second) ValueT(Value); | ||||||
|     return TheBucket; |     return TheBucket; | ||||||
| @@ -218,6 +237,7 @@ private: | |||||||
|  |  | ||||||
|   void init(unsigned InitBuckets) { |   void init(unsigned InitBuckets) { | ||||||
|     NumEntries = 0; |     NumEntries = 0; | ||||||
|  |     NumTombstones = 0; | ||||||
|     NumBuckets = InitBuckets; |     NumBuckets = InitBuckets; | ||||||
|     assert(InitBuckets && (InitBuckets & InitBuckets-1) == 0 && |     assert(InitBuckets && (InitBuckets & InitBuckets-1) == 0 && | ||||||
|            "# initial buckets must be a power of two!"); |            "# initial buckets must be a power of two!"); | ||||||
| @@ -234,6 +254,7 @@ private: | |||||||
|      |      | ||||||
|     // Double the number of buckets. |     // Double the number of buckets. | ||||||
|     NumBuckets <<= 1; |     NumBuckets <<= 1; | ||||||
|  |     NumTombstones = 0; | ||||||
|     Buckets = (BucketT*)new char[sizeof(BucketT)*NumBuckets]; |     Buckets = (BucketT*)new char[sizeof(BucketT)*NumBuckets]; | ||||||
|  |  | ||||||
|     // Initialize all the keys to EmptyKey. |     // Initialize all the keys to EmptyKey. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user