mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-13 22:24:07 +00:00
Fix http://llvm.org/PR5160, to let CallbackVHs modify other ValueHandles on the
same Value without breaking things. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@83861 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@ -111,10 +111,15 @@ private:
|
|||||||
HandleBaseKind getKind() const { return PrevPair.getInt(); }
|
HandleBaseKind getKind() const { return PrevPair.getInt(); }
|
||||||
void setPrevPtr(ValueHandleBase **Ptr) { PrevPair.setPointer(Ptr); }
|
void setPrevPtr(ValueHandleBase **Ptr) { PrevPair.setPointer(Ptr); }
|
||||||
|
|
||||||
/// AddToExistingUseList - Add this ValueHandle to the use list for VP,
|
/// AddToExistingUseList - Add this ValueHandle to the use list for VP, where
|
||||||
/// where List is known to point into the existing use list.
|
/// List is the address of either the head of the list or a Next node within
|
||||||
|
/// the existing use list.
|
||||||
void AddToExistingUseList(ValueHandleBase **List);
|
void AddToExistingUseList(ValueHandleBase **List);
|
||||||
|
|
||||||
|
/// AddToExistingUseListAfter - Add this ValueHandle to the use list after
|
||||||
|
/// Node.
|
||||||
|
void AddToExistingUseListAfter(ValueHandleBase *Node);
|
||||||
|
|
||||||
/// AddToUseList - Add this ValueHandle to the use list for VP.
|
/// AddToUseList - Add this ValueHandle to the use list for VP.
|
||||||
void AddToUseList();
|
void AddToUseList();
|
||||||
/// RemoveFromUseList - Remove this ValueHandle from its current use list.
|
/// RemoveFromUseList - Remove this ValueHandle from its current use list.
|
||||||
|
@ -411,6 +411,16 @@ void ValueHandleBase::AddToExistingUseList(ValueHandleBase **List) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ValueHandleBase::AddToExistingUseListAfter(ValueHandleBase *List) {
|
||||||
|
assert(List && "Must insert after existing node");
|
||||||
|
|
||||||
|
Next = List->Next;
|
||||||
|
setPrevPtr(&List->Next);
|
||||||
|
List->Next = this;
|
||||||
|
if (Next)
|
||||||
|
Next->setPrevPtr(&Next);
|
||||||
|
}
|
||||||
|
|
||||||
/// AddToUseList - Add this ValueHandle to the use list for VP.
|
/// AddToUseList - Add this ValueHandle to the use list for VP.
|
||||||
void ValueHandleBase::AddToUseList() {
|
void ValueHandleBase::AddToUseList() {
|
||||||
assert(VP && "Null pointer doesn't have a use list!");
|
assert(VP && "Null pointer doesn't have a use list!");
|
||||||
@ -490,37 +500,46 @@ void ValueHandleBase::ValueIsDeleted(Value *V) {
|
|||||||
ValueHandleBase *Entry = pImpl->ValueHandles[V];
|
ValueHandleBase *Entry = pImpl->ValueHandles[V];
|
||||||
assert(Entry && "Value bit set but no entries exist");
|
assert(Entry && "Value bit set but no entries exist");
|
||||||
|
|
||||||
while (Entry) {
|
// We use a local ValueHandleBase as an iterator so that
|
||||||
// Advance pointer to avoid invalidation.
|
// ValueHandles can add and remove themselves from the list without
|
||||||
ValueHandleBase *ThisNode = Entry;
|
// breaking our iteration. This is not really an AssertingVH; we
|
||||||
Entry = Entry->Next;
|
// just have to give ValueHandleBase some kind.
|
||||||
|
for (ValueHandleBase Iterator(Assert, *Entry); Entry; Entry = Iterator.Next) {
|
||||||
|
Iterator.RemoveFromUseList();
|
||||||
|
Iterator.AddToExistingUseListAfter(Entry);
|
||||||
|
assert(Entry->Next == &Iterator && "Loop invariant broken.");
|
||||||
|
|
||||||
switch (ThisNode->getKind()) {
|
switch (Entry->getKind()) {
|
||||||
case Assert:
|
case Assert:
|
||||||
#ifndef NDEBUG // Only in -g mode...
|
break;
|
||||||
errs() << "While deleting: " << *V->getType() << " %" << V->getNameStr()
|
|
||||||
<< "\n";
|
|
||||||
#endif
|
|
||||||
llvm_unreachable("An asserting value handle still pointed to this"
|
|
||||||
" value!");
|
|
||||||
case Tracking:
|
case Tracking:
|
||||||
// Mark that this value has been deleted by setting it to an invalid Value
|
// Mark that this value has been deleted by setting it to an invalid Value
|
||||||
// pointer.
|
// pointer.
|
||||||
ThisNode->operator=(DenseMapInfo<Value *>::getTombstoneKey());
|
Entry->operator=(DenseMapInfo<Value *>::getTombstoneKey());
|
||||||
break;
|
break;
|
||||||
case Weak:
|
case Weak:
|
||||||
// Weak just goes to null, which will unlink it from the list.
|
// Weak just goes to null, which will unlink it from the list.
|
||||||
ThisNode->operator=(0);
|
Entry->operator=(0);
|
||||||
break;
|
break;
|
||||||
case Callback:
|
case Callback:
|
||||||
// Forward to the subclass's implementation.
|
// Forward to the subclass's implementation.
|
||||||
static_cast<CallbackVH*>(ThisNode)->deleted();
|
static_cast<CallbackVH*>(Entry)->deleted();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// All callbacks and weak references should be dropped by now.
|
// All callbacks, weak references, and assertingVHs should be dropped by now.
|
||||||
assert(!V->HasValueHandle && "All references to V were not removed?");
|
if (V->HasValueHandle) {
|
||||||
|
#ifndef NDEBUG // Only in +Asserts mode...
|
||||||
|
errs() << "While deleting: " << *V->getType() << " %" << V->getNameStr()
|
||||||
|
<< "\n";
|
||||||
|
if (pImpl->ValueHandles[V]->getKind() == Assert)
|
||||||
|
llvm_unreachable("An asserting value handle still pointed to this"
|
||||||
|
" value!");
|
||||||
|
|
||||||
|
#endif
|
||||||
|
llvm_unreachable("All references to V were not removed?");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -535,12 +554,16 @@ void ValueHandleBase::ValueIsRAUWd(Value *Old, Value *New) {
|
|||||||
|
|
||||||
assert(Entry && "Value bit set but no entries exist");
|
assert(Entry && "Value bit set but no entries exist");
|
||||||
|
|
||||||
while (Entry) {
|
// We use a local ValueHandleBase as an iterator so that
|
||||||
// Advance pointer to avoid invalidation.
|
// ValueHandles can add and remove themselves from the list without
|
||||||
ValueHandleBase *ThisNode = Entry;
|
// breaking our iteration. This is not really an AssertingVH; we
|
||||||
Entry = Entry->Next;
|
// just have to give ValueHandleBase some kind.
|
||||||
|
for (ValueHandleBase Iterator(Assert, *Entry); Entry; Entry = Iterator.Next) {
|
||||||
|
Iterator.RemoveFromUseList();
|
||||||
|
Iterator.AddToExistingUseListAfter(Entry);
|
||||||
|
assert(Entry->Next == &Iterator && "Loop invariant broken.");
|
||||||
|
|
||||||
switch (ThisNode->getKind()) {
|
switch (Entry->getKind()) {
|
||||||
case Assert:
|
case Assert:
|
||||||
// Asserting handle does not follow RAUW implicitly.
|
// Asserting handle does not follow RAUW implicitly.
|
||||||
break;
|
break;
|
||||||
@ -553,11 +576,11 @@ void ValueHandleBase::ValueIsRAUWd(Value *Old, Value *New) {
|
|||||||
// FALLTHROUGH
|
// FALLTHROUGH
|
||||||
case Weak:
|
case Weak:
|
||||||
// Weak goes to the new value, which will unlink it from Old's list.
|
// Weak goes to the new value, which will unlink it from Old's list.
|
||||||
ThisNode->operator=(New);
|
Entry->operator=(New);
|
||||||
break;
|
break;
|
||||||
case Callback:
|
case Callback:
|
||||||
// Forward to the subclass's implementation.
|
// Forward to the subclass's implementation.
|
||||||
static_cast<CallbackVH*>(ThisNode)->allUsesReplacedWith(New);
|
static_cast<CallbackVH*>(Entry)->allUsesReplacedWith(New);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "llvm/Constants.h"
|
#include "llvm/Constants.h"
|
||||||
#include "llvm/Instructions.h"
|
#include "llvm/Instructions.h"
|
||||||
|
#include "llvm/ADT/OwningPtr.h"
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
@ -327,4 +328,84 @@ TEST_F(ValueHandle, CallbackVH_DeletionCanRAUW) {
|
|||||||
BitcastUser->getOperand(0));
|
BitcastUser->getOperand(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ValueHandle, DestroyingOtherVHOnSameValueDoesntBreakIteration) {
|
||||||
|
// When a CallbackVH modifies other ValueHandles in its callbacks,
|
||||||
|
// that shouldn't interfere with non-modified ValueHandles receiving
|
||||||
|
// their appropriate callbacks.
|
||||||
|
//
|
||||||
|
// We create the active CallbackVH in the middle of a palindromic
|
||||||
|
// arrangement of other VHs so that the bad behavior would be
|
||||||
|
// triggered in whichever order callbacks run.
|
||||||
|
|
||||||
|
class DestroyingVH : public CallbackVH {
|
||||||
|
public:
|
||||||
|
OwningPtr<WeakVH> ToClear[2];
|
||||||
|
DestroyingVH(Value *V) {
|
||||||
|
ToClear[0].reset(new WeakVH(V));
|
||||||
|
setValPtr(V);
|
||||||
|
ToClear[1].reset(new WeakVH(V));
|
||||||
|
}
|
||||||
|
virtual void deleted() {
|
||||||
|
ToClear[0].reset();
|
||||||
|
ToClear[1].reset();
|
||||||
|
CallbackVH::deleted();
|
||||||
|
}
|
||||||
|
virtual void allUsesReplacedWith(Value *) {
|
||||||
|
ToClear[0].reset();
|
||||||
|
ToClear[1].reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
WeakVH ShouldBeVisited1(BitcastV.get());
|
||||||
|
DestroyingVH C(BitcastV.get());
|
||||||
|
WeakVH ShouldBeVisited2(BitcastV.get());
|
||||||
|
|
||||||
|
BitcastV->replaceAllUsesWith(ConstantV);
|
||||||
|
EXPECT_EQ(ConstantV, static_cast<Value*>(ShouldBeVisited1));
|
||||||
|
EXPECT_EQ(ConstantV, static_cast<Value*>(ShouldBeVisited2));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
WeakVH ShouldBeVisited1(BitcastV.get());
|
||||||
|
DestroyingVH C(BitcastV.get());
|
||||||
|
WeakVH ShouldBeVisited2(BitcastV.get());
|
||||||
|
|
||||||
|
BitcastV.reset();
|
||||||
|
EXPECT_EQ(NULL, static_cast<Value*>(ShouldBeVisited1));
|
||||||
|
EXPECT_EQ(NULL, static_cast<Value*>(ShouldBeVisited2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValueHandle, AssertingVHCheckedLast) {
|
||||||
|
// If a CallbackVH exists to clear out a group of AssertingVHs on
|
||||||
|
// Value deletion, the CallbackVH should get a chance to do so
|
||||||
|
// before the AssertingVHs assert.
|
||||||
|
|
||||||
|
class ClearingVH : public CallbackVH {
|
||||||
|
public:
|
||||||
|
AssertingVH<Value> *ToClear[2];
|
||||||
|
ClearingVH(Value *V,
|
||||||
|
AssertingVH<Value> &A0, AssertingVH<Value> &A1)
|
||||||
|
: CallbackVH(V) {
|
||||||
|
ToClear[0] = &A0;
|
||||||
|
ToClear[1] = &A1;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void deleted() {
|
||||||
|
*ToClear[0] = 0;
|
||||||
|
*ToClear[1] = 0;
|
||||||
|
CallbackVH::deleted();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AssertingVH<Value> A1, A2;
|
||||||
|
A1 = BitcastV.get();
|
||||||
|
ClearingVH C(BitcastV.get(), A1, A2);
|
||||||
|
A2 = BitcastV.get();
|
||||||
|
// C.deleted() should run first, clearing the two AssertingVHs,
|
||||||
|
// which should prevent them from asserting.
|
||||||
|
BitcastV.reset();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user