Skip to content

Commit b1b0be2

Browse files
[ADT] Make DenseMapBase::moveFrom safer (NFC) (#168180)
Without this patch, DenseMapBase::moveFrom() moves buckets and leaves the moved-from object in a zombie state. This patch teaches moveFrom() to call kill() so that the move-from object is in a known good state. This brings moveFrom()'s behavior in line with standard C++ move semantics. kill() is implemented so that it takes the fast path in the destructor -- both destroyAll() and deallocateBuckets().
1 parent eb9d56c commit b1b0be2

File tree

1 file changed

+23
-6
lines changed

1 file changed

+23
-6
lines changed

llvm/include/llvm/ADT/DenseMap.h

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -441,8 +441,12 @@ class DenseMapBase : public DebugEpochBase {
441441
moveFromImpl(OldBuckets);
442442
}
443443

444-
// Move key/value from Other to *this. Other will be in a zombie state.
445-
void moveFrom(DerivedT &Other) { moveFromImpl(Other.buckets()); }
444+
// Move key/value from Other to *this.
445+
// Other is left in a valid but empty state.
446+
void moveFrom(DerivedT &Other) {
447+
moveFromImpl(Other.buckets());
448+
Other.derived().kill();
449+
}
446450

447451
void copyFrom(const DerivedT &other) {
448452
this->destroyAll();
@@ -830,6 +834,13 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
830834
}
831835
}
832836

837+
// Put the zombie instance in a known good state after a move.
838+
void kill() {
839+
deallocateBuckets();
840+
Buckets = nullptr;
841+
NumBuckets = 0;
842+
}
843+
833844
void grow(unsigned AtLeast) {
834845
unsigned OldNumBuckets = NumBuckets;
835846
BucketT *OldBuckets = Buckets;
@@ -1107,6 +1118,13 @@ class SmallDenseMap
11071118
this->BaseT::initEmpty();
11081119
}
11091120

1121+
// Put the zombie instance in a known good state after a move.
1122+
void kill() {
1123+
deallocateBuckets();
1124+
Small = false;
1125+
new (getLargeRep()) LargeRep{nullptr, 0};
1126+
}
1127+
11101128
void grow(unsigned AtLeast) {
11111129
if (AtLeast > InlineBuckets)
11121130
AtLeast = std::max<unsigned>(64, NextPowerOf2(AtLeast - 1));
@@ -1117,14 +1135,13 @@ class SmallDenseMap
11171135
if (Tmp.Small) {
11181136
// Use moveFrom in those rare cases where we stay in the small mode. This
11191137
// can happen when we have many tombstones.
1138+
Small = true;
11201139
this->BaseT::initEmpty();
11211140
this->moveFrom(Tmp);
1122-
Tmp.Small = false;
1123-
Tmp.getLargeRep()->NumBuckets = 0;
11241141
} else {
1125-
deallocateBuckets();
11261142
Small = false;
1127-
NumTombstones = 0;
1143+
NumEntries = Tmp.NumEntries;
1144+
NumTombstones = Tmp.NumTombstones;
11281145
*getLargeRep() = std::move(*Tmp.getLargeRep());
11291146
Tmp.getLargeRep()->NumBuckets = 0;
11301147
}

0 commit comments

Comments
 (0)