From eb3d76da81e2148ed7c577594c873ba147f4f435 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Tue, 4 Mar 2014 11:17:44 +0000 Subject: [Modules] Move ValueHandle into the IR library where Value itself lives. Move the test for this class into the IR unittests as well. This uncovers that ValueMap too is in the IR library. Ironically, the unittest for ValueMap is useless in the Support library (honestly, so was the ValueHandle test) and so it already lives in the IR unittests. Mmmm, tasty layering. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@202821 91177308-0d34-0410-b5e6-96231b3b80d8 --- unittests/IR/CMakeLists.txt | 1 + unittests/IR/MetadataTest.cpp | 2 +- unittests/IR/ValueHandleTest.cpp | 408 ++++++++++++++++++++++++++++++++++ unittests/Support/CMakeLists.txt | 1 - unittests/Support/ValueHandleTest.cpp | 408 ---------------------------------- 5 files changed, 410 insertions(+), 410 deletions(-) create mode 100644 unittests/IR/ValueHandleTest.cpp delete mode 100644 unittests/Support/ValueHandleTest.cpp (limited to 'unittests') diff --git a/unittests/IR/CMakeLists.txt b/unittests/IR/CMakeLists.txt index 305079f2dd..fd8d842c80 100644 --- a/unittests/IR/CMakeLists.txt +++ b/unittests/IR/CMakeLists.txt @@ -19,6 +19,7 @@ set(IRSources PatternMatch.cpp TypeBuilderTest.cpp TypesTest.cpp + ValueHandleTest.cpp ValueMapTest.cpp ValueTest.cpp VerifierTest.cpp diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp index 352e83ee66..00a2783fbf 100644 --- a/unittests/IR/MetadataTest.cpp +++ b/unittests/IR/MetadataTest.cpp @@ -13,7 +13,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" -#include "llvm/Support/ValueHandle.h" +#include "llvm/IR/ValueHandle.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" using namespace llvm; diff --git a/unittests/IR/ValueHandleTest.cpp b/unittests/IR/ValueHandleTest.cpp new file mode 100644 index 0000000000..bbca701776 --- /dev/null +++ b/unittests/IR/ValueHandleTest.cpp @@ -0,0 +1,408 @@ +//===- ValueHandleTest.cpp - ValueHandle tests ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/ValueHandle.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "gtest/gtest.h" +#include + +using namespace llvm; + +namespace { + +class ValueHandle : public testing::Test { +protected: + Constant *ConstantV; + std::auto_ptr BitcastV; + + ValueHandle() : + ConstantV(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0)), + BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(getGlobalContext()))) { + } +}; + +class ConcreteCallbackVH : public CallbackVH { +public: + ConcreteCallbackVH(Value *V) : CallbackVH(V) {} +}; + +TEST_F(ValueHandle, WeakVH_BasicOperation) { + WeakVH WVH(BitcastV.get()); + EXPECT_EQ(BitcastV.get(), WVH); + WVH = ConstantV; + EXPECT_EQ(ConstantV, WVH); + + // Make sure I can call a method on the underlying Value. It + // doesn't matter which method. + EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), WVH->getType()); + EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (*WVH).getType()); +} + +TEST_F(ValueHandle, WeakVH_Comparisons) { + WeakVH BitcastWVH(BitcastV.get()); + WeakVH ConstantWVH(ConstantV); + + EXPECT_TRUE(BitcastWVH == BitcastWVH); + EXPECT_TRUE(BitcastV.get() == BitcastWVH); + EXPECT_TRUE(BitcastWVH == BitcastV.get()); + EXPECT_FALSE(BitcastWVH == ConstantWVH); + + EXPECT_TRUE(BitcastWVH != ConstantWVH); + EXPECT_TRUE(BitcastV.get() != ConstantWVH); + EXPECT_TRUE(BitcastWVH != ConstantV); + EXPECT_FALSE(BitcastWVH != BitcastWVH); + + // Cast to Value* so comparisons work. + Value *BV = BitcastV.get(); + Value *CV = ConstantV; + EXPECT_EQ(BV < CV, BitcastWVH < ConstantWVH); + EXPECT_EQ(BV <= CV, BitcastWVH <= ConstantWVH); + EXPECT_EQ(BV > CV, BitcastWVH > ConstantWVH); + EXPECT_EQ(BV >= CV, BitcastWVH >= ConstantWVH); + + EXPECT_EQ(BV < CV, BitcastV.get() < ConstantWVH); + EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantWVH); + EXPECT_EQ(BV > CV, BitcastV.get() > ConstantWVH); + EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantWVH); + + EXPECT_EQ(BV < CV, BitcastWVH < ConstantV); + EXPECT_EQ(BV <= CV, BitcastWVH <= ConstantV); + EXPECT_EQ(BV > CV, BitcastWVH > ConstantV); + EXPECT_EQ(BV >= CV, BitcastWVH >= ConstantV); +} + +TEST_F(ValueHandle, WeakVH_FollowsRAUW) { + WeakVH WVH(BitcastV.get()); + WeakVH WVH_Copy(WVH); + WeakVH WVH_Recreated(BitcastV.get()); + BitcastV->replaceAllUsesWith(ConstantV); + EXPECT_EQ(ConstantV, WVH); + EXPECT_EQ(ConstantV, WVH_Copy); + EXPECT_EQ(ConstantV, WVH_Recreated); +} + +TEST_F(ValueHandle, WeakVH_NullOnDeletion) { + WeakVH WVH(BitcastV.get()); + WeakVH WVH_Copy(WVH); + WeakVH WVH_Recreated(BitcastV.get()); + BitcastV.reset(); + Value *null_value = NULL; + EXPECT_EQ(null_value, WVH); + EXPECT_EQ(null_value, WVH_Copy); + EXPECT_EQ(null_value, WVH_Recreated); +} + + +TEST_F(ValueHandle, AssertingVH_BasicOperation) { + AssertingVH AVH(BitcastV.get()); + CastInst *implicit_to_exact_type = AVH; + (void)implicit_to_exact_type; // Avoid warning. + + AssertingVH GenericAVH(BitcastV.get()); + EXPECT_EQ(BitcastV.get(), GenericAVH); + GenericAVH = ConstantV; + EXPECT_EQ(ConstantV, GenericAVH); + + // Make sure I can call a method on the underlying CastInst. It + // doesn't matter which method. + EXPECT_FALSE(AVH->mayWriteToMemory()); + EXPECT_FALSE((*AVH).mayWriteToMemory()); +} + +TEST_F(ValueHandle, AssertingVH_Const) { + const CastInst *ConstBitcast = BitcastV.get(); + AssertingVH AVH(ConstBitcast); + const CastInst *implicit_to_exact_type = AVH; + (void)implicit_to_exact_type; // Avoid warning. +} + +TEST_F(ValueHandle, AssertingVH_Comparisons) { + AssertingVH BitcastAVH(BitcastV.get()); + AssertingVH ConstantAVH(ConstantV); + + EXPECT_TRUE(BitcastAVH == BitcastAVH); + EXPECT_TRUE(BitcastV.get() == BitcastAVH); + EXPECT_TRUE(BitcastAVH == BitcastV.get()); + EXPECT_FALSE(BitcastAVH == ConstantAVH); + + EXPECT_TRUE(BitcastAVH != ConstantAVH); + EXPECT_TRUE(BitcastV.get() != ConstantAVH); + EXPECT_TRUE(BitcastAVH != ConstantV); + EXPECT_FALSE(BitcastAVH != BitcastAVH); + + // Cast to Value* so comparisons work. + Value *BV = BitcastV.get(); + Value *CV = ConstantV; + EXPECT_EQ(BV < CV, BitcastAVH < ConstantAVH); + EXPECT_EQ(BV <= CV, BitcastAVH <= ConstantAVH); + EXPECT_EQ(BV > CV, BitcastAVH > ConstantAVH); + EXPECT_EQ(BV >= CV, BitcastAVH >= ConstantAVH); + + EXPECT_EQ(BV < CV, BitcastV.get() < ConstantAVH); + EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantAVH); + EXPECT_EQ(BV > CV, BitcastV.get() > ConstantAVH); + EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantAVH); + + EXPECT_EQ(BV < CV, BitcastAVH < ConstantV); + EXPECT_EQ(BV <= CV, BitcastAVH <= ConstantV); + EXPECT_EQ(BV > CV, BitcastAVH > ConstantV); + EXPECT_EQ(BV >= CV, BitcastAVH >= ConstantV); +} + +TEST_F(ValueHandle, AssertingVH_DoesNotFollowRAUW) { + AssertingVH AVH(BitcastV.get()); + BitcastV->replaceAllUsesWith(ConstantV); + EXPECT_EQ(BitcastV.get(), AVH); +} + +#ifdef NDEBUG + +TEST_F(ValueHandle, AssertingVH_ReducesToPointer) { + EXPECT_EQ(sizeof(CastInst *), sizeof(AssertingVH)); +} + +#else // !NDEBUG + +#ifdef GTEST_HAS_DEATH_TEST + +TEST_F(ValueHandle, AssertingVH_Asserts) { + AssertingVH AVH(BitcastV.get()); + EXPECT_DEATH({BitcastV.reset();}, + "An asserting value handle still pointed to this value!"); + AssertingVH Copy(AVH); + AVH = NULL; + EXPECT_DEATH({BitcastV.reset();}, + "An asserting value handle still pointed to this value!"); + Copy = NULL; + BitcastV.reset(); +} + +#endif // GTEST_HAS_DEATH_TEST + +#endif // NDEBUG + +TEST_F(ValueHandle, CallbackVH_BasicOperation) { + ConcreteCallbackVH CVH(BitcastV.get()); + EXPECT_EQ(BitcastV.get(), CVH); + CVH = ConstantV; + EXPECT_EQ(ConstantV, CVH); + + // Make sure I can call a method on the underlying Value. It + // doesn't matter which method. + EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), CVH->getType()); + EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (*CVH).getType()); +} + +TEST_F(ValueHandle, CallbackVH_Comparisons) { + ConcreteCallbackVH BitcastCVH(BitcastV.get()); + ConcreteCallbackVH ConstantCVH(ConstantV); + + EXPECT_TRUE(BitcastCVH == BitcastCVH); + EXPECT_TRUE(BitcastV.get() == BitcastCVH); + EXPECT_TRUE(BitcastCVH == BitcastV.get()); + EXPECT_FALSE(BitcastCVH == ConstantCVH); + + EXPECT_TRUE(BitcastCVH != ConstantCVH); + EXPECT_TRUE(BitcastV.get() != ConstantCVH); + EXPECT_TRUE(BitcastCVH != ConstantV); + EXPECT_FALSE(BitcastCVH != BitcastCVH); + + // Cast to Value* so comparisons work. + Value *BV = BitcastV.get(); + Value *CV = ConstantV; + EXPECT_EQ(BV < CV, BitcastCVH < ConstantCVH); + EXPECT_EQ(BV <= CV, BitcastCVH <= ConstantCVH); + EXPECT_EQ(BV > CV, BitcastCVH > ConstantCVH); + EXPECT_EQ(BV >= CV, BitcastCVH >= ConstantCVH); + + EXPECT_EQ(BV < CV, BitcastV.get() < ConstantCVH); + EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantCVH); + EXPECT_EQ(BV > CV, BitcastV.get() > ConstantCVH); + EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantCVH); + + EXPECT_EQ(BV < CV, BitcastCVH < ConstantV); + EXPECT_EQ(BV <= CV, BitcastCVH <= ConstantV); + EXPECT_EQ(BV > CV, BitcastCVH > ConstantV); + EXPECT_EQ(BV >= CV, BitcastCVH >= ConstantV); +} + +TEST_F(ValueHandle, CallbackVH_CallbackOnDeletion) { + class RecordingVH : public CallbackVH { + public: + int DeletedCalls; + int AURWCalls; + + RecordingVH() : DeletedCalls(0), AURWCalls(0) {} + RecordingVH(Value *V) : CallbackVH(V), DeletedCalls(0), AURWCalls(0) {} + + private: + virtual void deleted() { DeletedCalls++; CallbackVH::deleted(); } + virtual void allUsesReplacedWith(Value *) { AURWCalls++; } + }; + + RecordingVH RVH; + RVH = BitcastV.get(); + EXPECT_EQ(0, RVH.DeletedCalls); + EXPECT_EQ(0, RVH.AURWCalls); + BitcastV.reset(); + EXPECT_EQ(1, RVH.DeletedCalls); + EXPECT_EQ(0, RVH.AURWCalls); +} + +TEST_F(ValueHandle, CallbackVH_CallbackOnRAUW) { + class RecordingVH : public CallbackVH { + public: + int DeletedCalls; + Value *AURWArgument; + + RecordingVH() : DeletedCalls(0), AURWArgument(NULL) {} + RecordingVH(Value *V) + : CallbackVH(V), DeletedCalls(0), AURWArgument(NULL) {} + + private: + virtual void deleted() { DeletedCalls++; CallbackVH::deleted(); } + virtual void allUsesReplacedWith(Value *new_value) { + EXPECT_EQ(NULL, AURWArgument); + AURWArgument = new_value; + } + }; + + RecordingVH RVH; + RVH = BitcastV.get(); + EXPECT_EQ(0, RVH.DeletedCalls); + EXPECT_EQ(NULL, RVH.AURWArgument); + BitcastV->replaceAllUsesWith(ConstantV); + EXPECT_EQ(0, RVH.DeletedCalls); + EXPECT_EQ(ConstantV, RVH.AURWArgument); +} + +TEST_F(ValueHandle, CallbackVH_DeletionCanRAUW) { + class RecoveringVH : public CallbackVH { + public: + int DeletedCalls; + Value *AURWArgument; + LLVMContext *Context; + + RecoveringVH() : DeletedCalls(0), AURWArgument(NULL), + Context(&getGlobalContext()) {} + RecoveringVH(Value *V) + : CallbackVH(V), DeletedCalls(0), AURWArgument(NULL), + Context(&getGlobalContext()) {} + + private: + virtual void deleted() { + getValPtr()->replaceAllUsesWith(Constant::getNullValue(Type::getInt32Ty(getGlobalContext()))); + setValPtr(NULL); + } + virtual void allUsesReplacedWith(Value *new_value) { + ASSERT_TRUE(NULL != getValPtr()); + EXPECT_EQ(1U, getValPtr()->getNumUses()); + EXPECT_EQ(NULL, AURWArgument); + AURWArgument = new_value; + } + }; + + // Normally, if a value has uses, deleting it will crash. However, we can use + // a CallbackVH to remove the uses before the check for no uses. + RecoveringVH RVH; + RVH = BitcastV.get(); + std::auto_ptr BitcastUser( + BinaryOperator::CreateAdd(RVH, + Constant::getNullValue(Type::getInt32Ty(getGlobalContext())))); + EXPECT_EQ(BitcastV.get(), BitcastUser->getOperand(0)); + BitcastV.reset(); // Would crash without the ValueHandler. + EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(getGlobalContext())), RVH.AURWArgument); + EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(getGlobalContext())), + 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 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(ShouldBeVisited1)); + EXPECT_EQ(ConstantV, static_cast(ShouldBeVisited2)); + } + + { + WeakVH ShouldBeVisited1(BitcastV.get()); + DestroyingVH C(BitcastV.get()); + WeakVH ShouldBeVisited2(BitcastV.get()); + + BitcastV.reset(); + EXPECT_EQ(NULL, static_cast(ShouldBeVisited1)); + EXPECT_EQ(NULL, static_cast(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 *ToClear[2]; + ClearingVH(Value *V, + AssertingVH &A0, AssertingVH &A1) + : CallbackVH(V) { + ToClear[0] = &A0; + ToClear[1] = &A1; + } + + virtual void deleted() { + *ToClear[0] = 0; + *ToClear[1] = 0; + CallbackVH::deleted(); + } + }; + + AssertingVH 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(); +} + +} diff --git a/unittests/Support/CMakeLists.txt b/unittests/Support/CMakeLists.txt index bfbef982e2..46c5c334ff 100644 --- a/unittests/Support/CMakeLists.txt +++ b/unittests/Support/CMakeLists.txt @@ -35,7 +35,6 @@ add_llvm_unittest(SupportTests ThreadLocalTest.cpp TimeValueTest.cpp UnicodeTest.cpp - ValueHandleTest.cpp YAMLIOTest.cpp YAMLParserTest.cpp formatted_raw_ostream_test.cpp diff --git a/unittests/Support/ValueHandleTest.cpp b/unittests/Support/ValueHandleTest.cpp deleted file mode 100644 index 05aafa2d05..0000000000 --- a/unittests/Support/ValueHandleTest.cpp +++ /dev/null @@ -1,408 +0,0 @@ -//===- llvm/unittest/Support/ValueHandleTest.cpp - ValueHandle tests --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/ValueHandle.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/LLVMContext.h" -#include "gtest/gtest.h" -#include - -using namespace llvm; - -namespace { - -class ValueHandle : public testing::Test { -protected: - Constant *ConstantV; - std::auto_ptr BitcastV; - - ValueHandle() : - ConstantV(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0)), - BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(getGlobalContext()))) { - } -}; - -class ConcreteCallbackVH : public CallbackVH { -public: - ConcreteCallbackVH(Value *V) : CallbackVH(V) {} -}; - -TEST_F(ValueHandle, WeakVH_BasicOperation) { - WeakVH WVH(BitcastV.get()); - EXPECT_EQ(BitcastV.get(), WVH); - WVH = ConstantV; - EXPECT_EQ(ConstantV, WVH); - - // Make sure I can call a method on the underlying Value. It - // doesn't matter which method. - EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), WVH->getType()); - EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (*WVH).getType()); -} - -TEST_F(ValueHandle, WeakVH_Comparisons) { - WeakVH BitcastWVH(BitcastV.get()); - WeakVH ConstantWVH(ConstantV); - - EXPECT_TRUE(BitcastWVH == BitcastWVH); - EXPECT_TRUE(BitcastV.get() == BitcastWVH); - EXPECT_TRUE(BitcastWVH == BitcastV.get()); - EXPECT_FALSE(BitcastWVH == ConstantWVH); - - EXPECT_TRUE(BitcastWVH != ConstantWVH); - EXPECT_TRUE(BitcastV.get() != ConstantWVH); - EXPECT_TRUE(BitcastWVH != ConstantV); - EXPECT_FALSE(BitcastWVH != BitcastWVH); - - // Cast to Value* so comparisons work. - Value *BV = BitcastV.get(); - Value *CV = ConstantV; - EXPECT_EQ(BV < CV, BitcastWVH < ConstantWVH); - EXPECT_EQ(BV <= CV, BitcastWVH <= ConstantWVH); - EXPECT_EQ(BV > CV, BitcastWVH > ConstantWVH); - EXPECT_EQ(BV >= CV, BitcastWVH >= ConstantWVH); - - EXPECT_EQ(BV < CV, BitcastV.get() < ConstantWVH); - EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantWVH); - EXPECT_EQ(BV > CV, BitcastV.get() > ConstantWVH); - EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantWVH); - - EXPECT_EQ(BV < CV, BitcastWVH < ConstantV); - EXPECT_EQ(BV <= CV, BitcastWVH <= ConstantV); - EXPECT_EQ(BV > CV, BitcastWVH > ConstantV); - EXPECT_EQ(BV >= CV, BitcastWVH >= ConstantV); -} - -TEST_F(ValueHandle, WeakVH_FollowsRAUW) { - WeakVH WVH(BitcastV.get()); - WeakVH WVH_Copy(WVH); - WeakVH WVH_Recreated(BitcastV.get()); - BitcastV->replaceAllUsesWith(ConstantV); - EXPECT_EQ(ConstantV, WVH); - EXPECT_EQ(ConstantV, WVH_Copy); - EXPECT_EQ(ConstantV, WVH_Recreated); -} - -TEST_F(ValueHandle, WeakVH_NullOnDeletion) { - WeakVH WVH(BitcastV.get()); - WeakVH WVH_Copy(WVH); - WeakVH WVH_Recreated(BitcastV.get()); - BitcastV.reset(); - Value *null_value = NULL; - EXPECT_EQ(null_value, WVH); - EXPECT_EQ(null_value, WVH_Copy); - EXPECT_EQ(null_value, WVH_Recreated); -} - - -TEST_F(ValueHandle, AssertingVH_BasicOperation) { - AssertingVH AVH(BitcastV.get()); - CastInst *implicit_to_exact_type = AVH; - (void)implicit_to_exact_type; // Avoid warning. - - AssertingVH GenericAVH(BitcastV.get()); - EXPECT_EQ(BitcastV.get(), GenericAVH); - GenericAVH = ConstantV; - EXPECT_EQ(ConstantV, GenericAVH); - - // Make sure I can call a method on the underlying CastInst. It - // doesn't matter which method. - EXPECT_FALSE(AVH->mayWriteToMemory()); - EXPECT_FALSE((*AVH).mayWriteToMemory()); -} - -TEST_F(ValueHandle, AssertingVH_Const) { - const CastInst *ConstBitcast = BitcastV.get(); - AssertingVH AVH(ConstBitcast); - const CastInst *implicit_to_exact_type = AVH; - (void)implicit_to_exact_type; // Avoid warning. -} - -TEST_F(ValueHandle, AssertingVH_Comparisons) { - AssertingVH BitcastAVH(BitcastV.get()); - AssertingVH ConstantAVH(ConstantV); - - EXPECT_TRUE(BitcastAVH == BitcastAVH); - EXPECT_TRUE(BitcastV.get() == BitcastAVH); - EXPECT_TRUE(BitcastAVH == BitcastV.get()); - EXPECT_FALSE(BitcastAVH == ConstantAVH); - - EXPECT_TRUE(BitcastAVH != ConstantAVH); - EXPECT_TRUE(BitcastV.get() != ConstantAVH); - EXPECT_TRUE(BitcastAVH != ConstantV); - EXPECT_FALSE(BitcastAVH != BitcastAVH); - - // Cast to Value* so comparisons work. - Value *BV = BitcastV.get(); - Value *CV = ConstantV; - EXPECT_EQ(BV < CV, BitcastAVH < ConstantAVH); - EXPECT_EQ(BV <= CV, BitcastAVH <= ConstantAVH); - EXPECT_EQ(BV > CV, BitcastAVH > ConstantAVH); - EXPECT_EQ(BV >= CV, BitcastAVH >= ConstantAVH); - - EXPECT_EQ(BV < CV, BitcastV.get() < ConstantAVH); - EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantAVH); - EXPECT_EQ(BV > CV, BitcastV.get() > ConstantAVH); - EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantAVH); - - EXPECT_EQ(BV < CV, BitcastAVH < ConstantV); - EXPECT_EQ(BV <= CV, BitcastAVH <= ConstantV); - EXPECT_EQ(BV > CV, BitcastAVH > ConstantV); - EXPECT_EQ(BV >= CV, BitcastAVH >= ConstantV); -} - -TEST_F(ValueHandle, AssertingVH_DoesNotFollowRAUW) { - AssertingVH AVH(BitcastV.get()); - BitcastV->replaceAllUsesWith(ConstantV); - EXPECT_EQ(BitcastV.get(), AVH); -} - -#ifdef NDEBUG - -TEST_F(ValueHandle, AssertingVH_ReducesToPointer) { - EXPECT_EQ(sizeof(CastInst *), sizeof(AssertingVH)); -} - -#else // !NDEBUG - -#ifdef GTEST_HAS_DEATH_TEST - -TEST_F(ValueHandle, AssertingVH_Asserts) { - AssertingVH AVH(BitcastV.get()); - EXPECT_DEATH({BitcastV.reset();}, - "An asserting value handle still pointed to this value!"); - AssertingVH Copy(AVH); - AVH = NULL; - EXPECT_DEATH({BitcastV.reset();}, - "An asserting value handle still pointed to this value!"); - Copy = NULL; - BitcastV.reset(); -} - -#endif // GTEST_HAS_DEATH_TEST - -#endif // NDEBUG - -TEST_F(ValueHandle, CallbackVH_BasicOperation) { - ConcreteCallbackVH CVH(BitcastV.get()); - EXPECT_EQ(BitcastV.get(), CVH); - CVH = ConstantV; - EXPECT_EQ(ConstantV, CVH); - - // Make sure I can call a method on the underlying Value. It - // doesn't matter which method. - EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), CVH->getType()); - EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (*CVH).getType()); -} - -TEST_F(ValueHandle, CallbackVH_Comparisons) { - ConcreteCallbackVH BitcastCVH(BitcastV.get()); - ConcreteCallbackVH ConstantCVH(ConstantV); - - EXPECT_TRUE(BitcastCVH == BitcastCVH); - EXPECT_TRUE(BitcastV.get() == BitcastCVH); - EXPECT_TRUE(BitcastCVH == BitcastV.get()); - EXPECT_FALSE(BitcastCVH == ConstantCVH); - - EXPECT_TRUE(BitcastCVH != ConstantCVH); - EXPECT_TRUE(BitcastV.get() != ConstantCVH); - EXPECT_TRUE(BitcastCVH != ConstantV); - EXPECT_FALSE(BitcastCVH != BitcastCVH); - - // Cast to Value* so comparisons work. - Value *BV = BitcastV.get(); - Value *CV = ConstantV; - EXPECT_EQ(BV < CV, BitcastCVH < ConstantCVH); - EXPECT_EQ(BV <= CV, BitcastCVH <= ConstantCVH); - EXPECT_EQ(BV > CV, BitcastCVH > ConstantCVH); - EXPECT_EQ(BV >= CV, BitcastCVH >= ConstantCVH); - - EXPECT_EQ(BV < CV, BitcastV.get() < ConstantCVH); - EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantCVH); - EXPECT_EQ(BV > CV, BitcastV.get() > ConstantCVH); - EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantCVH); - - EXPECT_EQ(BV < CV, BitcastCVH < ConstantV); - EXPECT_EQ(BV <= CV, BitcastCVH <= ConstantV); - EXPECT_EQ(BV > CV, BitcastCVH > ConstantV); - EXPECT_EQ(BV >= CV, BitcastCVH >= ConstantV); -} - -TEST_F(ValueHandle, CallbackVH_CallbackOnDeletion) { - class RecordingVH : public CallbackVH { - public: - int DeletedCalls; - int AURWCalls; - - RecordingVH() : DeletedCalls(0), AURWCalls(0) {} - RecordingVH(Value *V) : CallbackVH(V), DeletedCalls(0), AURWCalls(0) {} - - private: - virtual void deleted() { DeletedCalls++; CallbackVH::deleted(); } - virtual void allUsesReplacedWith(Value *) { AURWCalls++; } - }; - - RecordingVH RVH; - RVH = BitcastV.get(); - EXPECT_EQ(0, RVH.DeletedCalls); - EXPECT_EQ(0, RVH.AURWCalls); - BitcastV.reset(); - EXPECT_EQ(1, RVH.DeletedCalls); - EXPECT_EQ(0, RVH.AURWCalls); -} - -TEST_F(ValueHandle, CallbackVH_CallbackOnRAUW) { - class RecordingVH : public CallbackVH { - public: - int DeletedCalls; - Value *AURWArgument; - - RecordingVH() : DeletedCalls(0), AURWArgument(NULL) {} - RecordingVH(Value *V) - : CallbackVH(V), DeletedCalls(0), AURWArgument(NULL) {} - - private: - virtual void deleted() { DeletedCalls++; CallbackVH::deleted(); } - virtual void allUsesReplacedWith(Value *new_value) { - EXPECT_EQ(NULL, AURWArgument); - AURWArgument = new_value; - } - }; - - RecordingVH RVH; - RVH = BitcastV.get(); - EXPECT_EQ(0, RVH.DeletedCalls); - EXPECT_EQ(NULL, RVH.AURWArgument); - BitcastV->replaceAllUsesWith(ConstantV); - EXPECT_EQ(0, RVH.DeletedCalls); - EXPECT_EQ(ConstantV, RVH.AURWArgument); -} - -TEST_F(ValueHandle, CallbackVH_DeletionCanRAUW) { - class RecoveringVH : public CallbackVH { - public: - int DeletedCalls; - Value *AURWArgument; - LLVMContext *Context; - - RecoveringVH() : DeletedCalls(0), AURWArgument(NULL), - Context(&getGlobalContext()) {} - RecoveringVH(Value *V) - : CallbackVH(V), DeletedCalls(0), AURWArgument(NULL), - Context(&getGlobalContext()) {} - - private: - virtual void deleted() { - getValPtr()->replaceAllUsesWith(Constant::getNullValue(Type::getInt32Ty(getGlobalContext()))); - setValPtr(NULL); - } - virtual void allUsesReplacedWith(Value *new_value) { - ASSERT_TRUE(NULL != getValPtr()); - EXPECT_EQ(1U, getValPtr()->getNumUses()); - EXPECT_EQ(NULL, AURWArgument); - AURWArgument = new_value; - } - }; - - // Normally, if a value has uses, deleting it will crash. However, we can use - // a CallbackVH to remove the uses before the check for no uses. - RecoveringVH RVH; - RVH = BitcastV.get(); - std::auto_ptr BitcastUser( - BinaryOperator::CreateAdd(RVH, - Constant::getNullValue(Type::getInt32Ty(getGlobalContext())))); - EXPECT_EQ(BitcastV.get(), BitcastUser->getOperand(0)); - BitcastV.reset(); // Would crash without the ValueHandler. - EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(getGlobalContext())), RVH.AURWArgument); - EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(getGlobalContext())), - 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 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(ShouldBeVisited1)); - EXPECT_EQ(ConstantV, static_cast(ShouldBeVisited2)); - } - - { - WeakVH ShouldBeVisited1(BitcastV.get()); - DestroyingVH C(BitcastV.get()); - WeakVH ShouldBeVisited2(BitcastV.get()); - - BitcastV.reset(); - EXPECT_EQ(NULL, static_cast(ShouldBeVisited1)); - EXPECT_EQ(NULL, static_cast(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 *ToClear[2]; - ClearingVH(Value *V, - AssertingVH &A0, AssertingVH &A1) - : CallbackVH(V) { - ToClear[0] = &A0; - ToClear[1] = &A1; - } - - virtual void deleted() { - *ToClear[0] = 0; - *ToClear[1] = 0; - CallbackVH::deleted(); - } - }; - - AssertingVH 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(); -} - -} -- cgit v1.2.3