diff --git a/include/llvm/AbstractTypeUser.h b/include/llvm/AbstractTypeUser.h index 64fcd33a78a..b9e5f1c6593 100644 --- a/include/llvm/AbstractTypeUser.h +++ b/include/llvm/AbstractTypeUser.h @@ -61,9 +61,9 @@ public: }; -// PATypeHandle - Handle to a Type subclass. This class is used to keep the use -// list of abstract types up-to-date. -// +/// PATypeHandle - Handle to a Type subclass. This class is used to keep the +/// use list of abstract types up-to-date. +/// class PATypeHandle { const Type *Ty; AbstractTypeUser * const User; @@ -123,50 +123,43 @@ public: }; -// PATypeHolder - Holder class for a potentially abstract type. This functions -// as both a handle (as above) and an AbstractTypeUser. It uses the callback to -// keep its pointer member updated to the current version of the type. -// -class PATypeHolder : public AbstractTypeUser { - PATypeHandle Handle; +/// PATypeHolder - Holder class for a potentially abstract type. This uses +/// efficient union-find techniques to handle dynamic type resolution. Unless +/// you need to do custom processing when types are resolved, you should always +/// use PATypeHolders in preference to PATypeHandles. +/// +class PATypeHolder { + mutable const Type *Ty; public: - PATypeHolder(const Type *ty) : Handle(ty, this) {} - PATypeHolder(const PATypeHolder &T) : AbstractTypeUser(), Handle(T, this) {} + PATypeHolder(const Type *ty) : Ty(ty) { + addRef(); + } + PATypeHolder(const PATypeHolder &T) : Ty(T.Ty) { + addRef(); + } - operator const Type *() const { return Handle; } - const Type *get() const { return Handle; } + operator const Type *() const { return get(); } + const Type *get() const; // operator-> - Allow user to dereference handle naturally... - inline const Type *operator->() const { return Handle; } - - // refineAbstractType - All we do is update our PATypeHandle member to point - // to the new type. - // - virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy) { - assert(get() == (const Type*)OldTy && "Can't refine to unknown value!"); - - // Check to see if the type just became concrete. If so, we have to - // removeUser to get off its AbstractTypeUser list - Handle.removeUserFromConcrete(); - - if ((const Type*)OldTy != NewTy) - Handle.operator=(NewTy); - } + const Type *operator->() const { return get(); } // operator= - Allow assignment to handle const Type *operator=(const Type *ty) { - return Handle = ty; - } - - // operator= - Allow assignment to handle - const Type *operator=(const PATypeHandle &T) { - return Handle = T; + if (Ty != ty) { // Don't accidentally drop last ref to Ty. + dropRef(); + Ty = ty; + addRef(); + } + return get(); } const Type *operator=(const PATypeHolder &H) { - return Handle = H; + return operator=(H.Ty); } - void dump() const; +private: + void addRef(); + void dropRef(); }; #endif diff --git a/include/llvm/DerivedTypes.h b/include/llvm/DerivedTypes.h index 73587b4824d..5ed30458fb8 100644 --- a/include/llvm/DerivedTypes.h +++ b/include/llvm/DerivedTypes.h @@ -20,7 +20,14 @@ class StructValType; class PointerValType; class DerivedType : public Type, public AbstractTypeUser { - char isRefining; // Used for recursive types + /// RefCount - This counts the number of PATypeHolders that are pointing to + /// this type. When this number falls to zero, if the type is abstract and + /// has no AbstractTypeUsers, the type is deleted. + /// + mutable unsigned RefCount; + + // isRefining - Used for recursive types + char isRefining; // AbstractTypeUsers - Implement a list of the users that need to be notified // if I am a type, and I get resolved into a more concrete type. @@ -29,8 +36,7 @@ class DerivedType : public Type, public AbstractTypeUser { mutable std::vector AbstractTypeUsers; protected: - inline DerivedType(PrimitiveID id) : Type("", id) { - isRefining = 0; + DerivedType(PrimitiveID id) : Type("", id), RefCount(0), isRefining(0) { } ~DerivedType() { assert(AbstractTypeUsers.empty()); @@ -61,7 +67,10 @@ public: // addAbstractTypeUser - Notify an abstract type that there is a new user of // it. This function is called primarily by the PATypeHandle class. // - void addAbstractTypeUser(AbstractTypeUser *U) const; + void addAbstractTypeUser(AbstractTypeUser *U) const { + assert(isAbstract() && "addAbstractTypeUser: Current type not abstract!"); + AbstractTypeUsers.push_back(U); + } // removeAbstractTypeUser - Notify an abstract type that a user of the class // no longer has a handle to the type. This function is called primarily by @@ -80,6 +89,22 @@ public: refineAbstractTypeToInternal(NewType, true); } + void addRef() const { + assert(isAbstract() && "Cannot add a reference to a non-abstract type!"); + ++RefCount; + } + + void dropRef() const { + assert(isAbstract() && "Cannot drop a refernce to a non-abstract type!"); + assert(RefCount && "No objects are currently referencing this object!"); + + // If this is the last PATypeHolder using this object, and there are no + // PATypeHandles using it, the type is dead, delete it now. + if (--RefCount == 0 && AbstractTypeUsers.empty()) + delete this; + } + + void dump() const { Value::dump(); } // Methods for support type inquiry through isa, cast, and dyn_cast: @@ -453,4 +478,26 @@ inline void PATypeHandle::removeUserFromConcrete() { cast(Ty)->removeAbstractTypeUser(User); } +// Define inline methods for PATypeHolder... + +inline void PATypeHolder::addRef() { + if (Ty->isAbstract()) + cast(Ty)->addRef(); +} + +inline void PATypeHolder::dropRef() { + if (Ty->isAbstract()) + cast(Ty)->dropRef(); +} + +/// get - This implements the forwarding part of the union-find algorithm for +/// abstract types. Before every access to the Type*, we check to see if the +/// type we are pointing to is forwarding to a new type. If so, we drop our +/// reference to the type. +inline const Type* PATypeHolder::get() const { + const Type *NewTy = Ty->getForwardedType(); + if (!NewTy) return Ty; + return *const_cast(this) = NewTy; +} + #endif diff --git a/include/llvm/Type.h b/include/llvm/Type.h index 30949a64577..5900b402dcc 100644 --- a/include/llvm/Type.h +++ b/include/llvm/Type.h @@ -73,6 +73,7 @@ private: unsigned UID; // The unique ID number for this class bool Abstract; // True if type contains an OpaqueType + const Type *getForwardedTypeInternal() const; protected: /// ctor is protected, so only subclasses can create Type objects... Type(const std::string &Name, PrimitiveID id); @@ -90,6 +91,12 @@ protected: /// isTypeAbstract - This method is used to calculate the Abstract bit. /// bool isTypeAbstract(); + + /// ForwardType - This field is used to implement the union find scheme for + /// abstract types. When types are refined to other types, this field is set + /// to the more refined type. Only abstract types can be forwarded. + mutable const Type *ForwardType; + public: virtual void print(std::ostream &O) const; @@ -177,6 +184,13 @@ public: /// unsigned getPrimitiveSize() const; + /// getForwaredType - Return the type that this type has been resolved to if + /// it has been resolved to anything. This is used to implement the + /// union-find algorithm for type resolution. + const Type *getForwardedType() const { + if (!ForwardType) return 0; + return getForwardedTypeInternal(); + } //===--------------------------------------------------------------------===// // Type Iteration support diff --git a/lib/VMCore/Type.cpp b/lib/VMCore/Type.cpp index eb1c99e9f41..f5c91b13755 100644 --- a/lib/VMCore/Type.cpp +++ b/lib/VMCore/Type.cpp @@ -32,13 +32,8 @@ static std::vector UIDMappings; static std::map ConcreteTypeDescriptions; static std::map AbstractTypeDescriptions; -void PATypeHolder::dump() const { - std::cerr << "PATypeHolder(" << (void*)this << ")\n"; -} - - Type::Type(const std::string &name, PrimitiveID id) - : Value(Type::TypeTy, Value::TypeVal) { + : Value(Type::TypeTy, Value::TypeVal), ForwardType(0) { if (!name.empty()) ConcreteTypeDescriptions[this] = name; ID = id; @@ -122,6 +117,30 @@ unsigned Type::getPrimitiveSize() const { } +/// getForwardedTypeInternal - This method is used to implement the union-find +/// algorithm for when a type is being forwarded to another type. +const Type *Type::getForwardedTypeInternal() const { + assert(ForwardType && "This type is not being forwarded to another type!"); + + // Check to see if the forwarded type has been forwarded on. If so, collapse + // the forwarding links. + const Type *RealForwardedType = ForwardType->getForwardedType(); + if (!RealForwardedType) + return ForwardType; // No it's not forwarded again + + // Yes, it is forwarded again. First thing, add the reference to the new + // forward type. + if (RealForwardedType->isAbstract()) + cast(RealForwardedType)->addRef(); + + // Now drop the old reference. This could cause ForwardType to get deleted. + cast(ForwardType)->dropRef(); + + // Return the updated type. + ForwardType = RealForwardedType; + return ForwardType; +} + // getTypeDescription - This is a recursive function that walks a type hierarchy // calculating the description for a type. // @@ -950,21 +969,6 @@ void debug_type_tables() { // Derived Type Refinement Functions //===----------------------------------------------------------------------===// -// addAbstractTypeUser - Notify an abstract type that there is a new user of -// it. This function is called primarily by the PATypeHandle class. -// -void DerivedType::addAbstractTypeUser(AbstractTypeUser *U) const { - assert(isAbstract() && "addAbstractTypeUser: Current type not abstract!"); - -#if DEBUG_MERGE_TYPES - std::cerr << " addAbstractTypeUser[" << (void*)this << ", " - << *this << "][" << AbstractTypeUsers.size() - << "] User = " << U << "\n"; -#endif - AbstractTypeUsers.push_back(U); -} - - // removeAbstractTypeUser - Notify an abstract type that a user of the class // no longer has a handle to the type. This function is called primarily by // the PATypeHandle class. When there are no users of the abstract type, it @@ -989,7 +993,7 @@ void DerivedType::removeAbstractTypeUser(AbstractTypeUser *U) const { << *this << "][" << i << "] User = " << U << "\n"; #endif - if (AbstractTypeUsers.empty() && isAbstract()) { + if (AbstractTypeUsers.empty() && RefCount == 0 && isAbstract()) { #ifdef DEBUG_MERGE_TYPES std::cerr << "DELETEing unused abstract type: <" << *this << ">[" << (void*)this << "]" << "\n"; @@ -1023,6 +1027,10 @@ void DerivedType::refineAbstractTypeToInternal(const Type *NewType, bool inMap){ // PATypeHolder NewTy(NewType); + ForwardType = NewType; + if (NewType->isAbstract()) + cast(NewType)->addRef(); + // Add a self use of the current type so that we don't delete ourself until // after this while loop. We are careful to never invoke refine on ourself, // so this extra reference shouldn't be a problem. Note that we must only