diff --git a/include/llvm/Support/ValueHandle.h b/include/llvm/Support/ValueHandle.h index 91b05b13257..d22b30af489 100644 --- a/include/llvm/Support/ValueHandle.h +++ b/include/llvm/Support/ValueHandle.h @@ -45,8 +45,9 @@ protected: /// fully general Callback version does have a vtable. enum HandleBaseKind { Assert, - Weak, - Callback + Callback, + Tracking, + Weak }; private: @@ -92,13 +93,13 @@ public: protected: Value *getValPtr() const { return VP; } -private: static bool isValid(Value *V) { return V && V != DenseMapInfo::getEmptyKey() && V != DenseMapInfo::getTombstoneKey(); } +private: // Callbacks made from Value. static void ValueIsDeleted(Value *V); static void ValueIsRAUWd(Value *Old, Value *New); @@ -223,6 +224,88 @@ template<> struct simplify_type > { template<> struct simplify_type > : public simplify_type > {}; +/// TrackingVH - This is a value handle that tracks a Value (or Value subclass), +/// even across RAUW operations. +/// +/// TrackingVH is designed for situations where a client needs to hold a handle +/// to a Value (or subclass) across some operations which may move that value, +/// but should never destroy it or replace it with some unacceptable type. +/// +/// It is an error to do anything with a TrackingVH whose value has been +/// destroyed, except to destruct it. +/// +/// It is an error to attempt to replace a value with one of a type which is +/// incompatible with any of its outstanding TrackingVHs. +template +class TrackingVH : public ValueHandleBase { + void CheckValidity() const { + Value *VP = ValueHandleBase::getValPtr(); + + // Null is always ok. + if (!VP) + return; + + // Check that this value is valid (i.e., it hasn't been deleted). We + // explicitly delay this check until access to avoid requiring clients to be + // unnecessarily careful w.r.t. destruction. + assert(ValueHandleBase::isValid(VP) && "Tracked Value was deleted!"); + + // Check that the value is a member of the correct subclass. We would like + // to check this property on assignment for better debugging, but we don't + // want to require a virtual interface on this VH. Instead we allow RAUW to + // replace this value with a value of an invalid type, and check it here. + assert(isa(VP) && + "Tracked Value was replaced by one with an invalid type!"); + } + + ValueTy *getValPtr() const { + CheckValidity(); + return static_cast(ValueHandleBase::getValPtr()); + } + void setValPtr(ValueTy *P) { + CheckValidity(); + ValueHandleBase::operator=(GetAsValue(P)); + } + + // Convert a ValueTy*, which may be const, to the type the base + // class expects. + static Value *GetAsValue(Value *V) { return V; } + static Value *GetAsValue(const Value *V) { return const_cast(V); } + +public: + TrackingVH() : ValueHandleBase(Tracking) {} + TrackingVH(ValueTy *P) : ValueHandleBase(Tracking, P) {} + TrackingVH(const TrackingVH &RHS) : ValueHandleBase(Tracking, RHS) {} + + operator ValueTy*() const { + return getValPtr(); + } + + ValueTy *operator=(ValueTy *RHS) { + setValPtr(RHS); + return getValPtr(); + } + ValueTy *operator=(const TrackingVH &RHS) { + setValPtr(RHS.getValPtr()); + return getValPtr(); + } + + ValueTy *operator->() const { return getValPtr(); } + ValueTy &operator*() const { return *getValPtr(); } +}; + +// Specialize simplify_type to allow TrackingVH to participate in +// dyn_cast, isa, etc. +template struct simplify_type; +template<> struct simplify_type > { + typedef Value* SimpleType; + static SimpleType getSimplifiedValue(const TrackingVH &AVH) { + return static_cast(AVH); + } +}; +template<> struct simplify_type > + : public simplify_type > {}; + /// CallbackVH - This is a value handle that allows subclasses to define /// callbacks that run when the underlying Value has RAUW called on it or is /// destroyed. This class can be used as the key of a map, as long as the user diff --git a/lib/VMCore/Value.cpp b/lib/VMCore/Value.cpp index 773623b8bb4..6d9256fac52 100644 --- a/lib/VMCore/Value.cpp +++ b/lib/VMCore/Value.cpp @@ -503,6 +503,11 @@ void ValueHandleBase::ValueIsDeleted(Value *V) { #endif llvm_unreachable("An asserting value handle still pointed to this" " value!"); + case Tracking: + // Mark that this value has been deleted by setting it to an invalid Value + // pointer. + ThisNode->operator=(DenseMapInfo::getTombstoneKey()); + break; case Weak: // Weak just goes to null, which will unlink it from the list. ThisNode->operator=(0); @@ -539,6 +544,14 @@ void ValueHandleBase::ValueIsRAUWd(Value *Old, Value *New) { case Assert: // Asserting handle does not follow RAUW implicitly. break; + case Tracking: + // Tracking goes to new value like a WeakVH. Note that this may make it + // something incompatible with its templated type. We don't want to have a + // virtual (or inline) interface to handle this though, so instead we make + // the TrackingVH accessors guarantee that a client never seesl this + // value. + + // FALLTHROUGH case Weak: // Weak goes to the new value, which will unlink it from Old's list. ThisNode->operator=(New);