For PR1209:
authorReid Spencer <rspencer@reidspencer.com>
Fri, 6 Apr 2007 02:02:20 +0000 (02:02 +0000)
committerReid Spencer <rspencer@reidspencer.com>
Fri, 6 Apr 2007 02:02:20 +0000 (02:02 +0000)
Implement Type class's ContainedTys without using a std::vector.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@35693 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/DerivedTypes.h
include/llvm/Type.h
lib/VMCore/Type.cpp

index 21ff3d690f8c0c718e4e1f193ed1deb2afed8cd1..ced84fd541782632679c9182f5f24beca827b631 100644 (file)
@@ -163,6 +163,7 @@ private:
                bool IsVarArgs, const ParamAttrsList &Attrs);
 
 public:
+  virtual ~FunctionType() { delete ParamAttrs; }
   /// FunctionType::get - This static method is the primary way of constructing
   /// a FunctionType. 
   ///
@@ -179,9 +180,9 @@ public:
   inline bool isVarArg() const { return isVarArgs; }
   inline const Type *getReturnType() const { return ContainedTys[0]; }
 
-  typedef std::vector<PATypeHandle>::const_iterator param_iterator;
-  param_iterator param_begin() const { return ContainedTys.begin()+1; }
-  param_iterator param_end() const { return ContainedTys.end(); }
+  typedef Type::subtype_iterator param_iterator;
+  param_iterator param_begin() const { return ContainedTys + 1; }
+  param_iterator param_end() const { return &ContainedTys[NumContainedTys]; }
 
   // Parameter type accessors...
   const Type *getParamType(unsigned i) const { return ContainedTys[i+1]; }
@@ -189,7 +190,7 @@ public:
   /// getNumParams - Return the number of fixed parameters this function type
   /// requires.  This does not consider varargs.
   ///
-  unsigned getNumParams() const { return unsigned(ContainedTys.size()-1); }
+  unsigned getNumParams() const { return NumContainedTys - 1; }
 
   bool isStructReturn() const {
     return (getNumParams() && paramHasAttr(1, StructRetAttribute));
@@ -265,14 +266,14 @@ public:
                          bool isPacked=false);
 
   // Iterator access to the elements
-  typedef std::vector<PATypeHandle>::const_iterator element_iterator;
-  element_iterator element_begin() const { return ContainedTys.begin(); }
-  element_iterator element_end() const { return ContainedTys.end(); }
+  typedef Type::subtype_iterator element_iterator;
+  element_iterator element_begin() const { return ContainedTys; }
+  element_iterator element_end() const { return &ContainedTys[NumContainedTys];}
 
   // Random access to the elements
-  unsigned getNumElements() const { return unsigned(ContainedTys.size()); }
+  unsigned getNumElements() const { return NumContainedTys; }
   const Type *getElementType(unsigned N) const {
-    assert(N < ContainedTys.size() && "Element number out of range!");
+    assert(N < NumContainedTys && "Element number out of range!");
     return ContainedTys[N];
   }
 
@@ -305,12 +306,14 @@ public:
 /// components out in memory identically.
 ///
 class SequentialType : public CompositeType {
+  PATypeHandle ContainedType; ///< Storage for the single contained type
   SequentialType(const SequentialType &);                  // Do not implement!
   const SequentialType &operator=(const SequentialType &); // Do not implement!
 protected:
-  SequentialType(TypeID TID, const Type *ElType) : CompositeType(TID) {
-    ContainedTys.reserve(1);
-    ContainedTys.push_back(PATypeHandle(ElType, this));
+  SequentialType(TypeID TID, const Type *ElType) 
+    : CompositeType(TID), ContainedType(ElType, this) {
+    ContainedTys = &ContainedType; 
+    NumContainedTys = 1;
   }
 
 public:
index 439ac18bf4cecafb0cbb576e8f2428d8f4f1e6a9..a763c65c852b45a323886185d92ab24e43bd5a6e 100644 (file)
@@ -101,12 +101,18 @@ private:
   mutable unsigned RefCount;
 
   const Type *getForwardedTypeInternal() const;
+
+  // Some Type instances are allocated as arrays, some aren't. So we provide
+  // this method to get the right kind of destruction for the type of Type.
+  void destroy() const; // const is a lie, this does "delete this"!
+
 protected:
   Type(const char *Name, TypeID id);
   explicit Type(TypeID id) : ID(id), Abstract(false), SubclassData(0),
-                             RefCount(0), ForwardType(0) {}
+                             RefCount(0), ForwardType(0), NumContainedTys(0),
+                             ContainedTys(0) {}
   virtual ~Type() {
-    assert(AbstractTypeUsers.empty());
+    assert(AbstractTypeUsers.empty() && "Abstract types remain");
   }
 
   /// Types can become nonabstract later, if they are refined.
@@ -123,19 +129,31 @@ protected:
   /// to the more refined type.  Only abstract types can be forwarded.
   mutable const Type *ForwardType;
 
-  /// ContainedTys - The list of types contained by this one.  For example, this
-  /// includes the arguments of a function type, the elements of the structure,
-  /// the pointee of a pointer, etc.  Note that keeping this vector in the Type
-  /// class wastes some space for types that do not contain anything (such as
-  /// primitive types).  However, keeping it here allows the subtype_* members
-  /// to be implemented MUCH more efficiently, and dynamically very few types do
-  /// not contain any elements (most are derived).
-  std::vector<PATypeHandle> ContainedTys;
 
   /// 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.
   ///
   mutable std::vector<AbstractTypeUser *> AbstractTypeUsers;
+
+  /// NumContainedTys - Keeps track of how many PATypeHandle instances there
+  /// are at the end of this type instance for the list of contained types. It
+  /// is the subclasses responsibility to set this up. Set to 0 if there are no
+  /// contained types in this type.
+  unsigned NumContainedTys;
+
+  /// ContainedTys - A pointer to the array of Types (PATypeHandle) contained 
+  /// by this Type.  For example, this includes the arguments of a function 
+  /// type, the elements of a structure, the pointee of a pointer, the element
+  /// type of an array, etc.  This pointer may be 0 for types that don't 
+  /// contain other types (Integer, Double, Float).  In general, the subclass 
+  /// should arrange for space for the PATypeHandles to be included in the 
+  /// allocation of the type object and set this pointer to the address of the 
+  /// first element. This allows the Type class to manipulate the ContainedTys 
+  /// without understanding the subclass's placement for this array.  keeping 
+  /// it here also allows the subtype_* members to be implemented MUCH more 
+  /// efficiently, and dynamically very few types do not contain any elements.
+  PATypeHandle *ContainedTys;
+
 public:
   void print(std::ostream &O) const;
   void print(std::ostream *O) const { if (O) print(*O); }
@@ -235,23 +253,22 @@ public:
   //===--------------------------------------------------------------------===//
   // Type Iteration support
   //
-  typedef std::vector<PATypeHandle>::const_iterator subtype_iterator;
-  subtype_iterator subtype_begin() const { return ContainedTys.begin(); }
-  subtype_iterator subtype_end() const { return ContainedTys.end(); }
+  typedef PATypeHandle *subtype_iterator;
+  subtype_iterator subtype_begin() const { return ContainedTys; }
+  subtype_iterator subtype_end() const { return &ContainedTys[NumContainedTys];}
 
   /// getContainedType - This method is used to implement the type iterator
   /// (defined a the end of the file).  For derived types, this returns the
   /// types 'contained' in the derived type.
   ///
   const Type *getContainedType(unsigned i) const {
-    assert(i < ContainedTys.size() && "Index out of range!");
-    return ContainedTys[i];
+    assert(i < NumContainedTys && "Index out of range!");
+    return ContainedTys[i].get();
   }
 
   /// getNumContainedTypes - Return the number of types in the derived type.
   ///
-  typedef std::vector<PATypeHandle>::size_type size_type;
-  size_type getNumContainedTypes() const { return ContainedTys.size(); }
+  unsigned getNumContainedTypes() const { return NumContainedTys; }
 
   //===--------------------------------------------------------------------===//
   // Static members exported by the Type class itself.  Useful for getting
@@ -282,7 +299,7 @@ public:
     // 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;
+      this->destroy();
   }
   
   /// addAbstractTypeUser - Notify an abstract type that there is a new user of
index 63d90ceec99cc7993f217a0342a8337d607a787e..a195437e7c3e37463fe3a7fd07ece9304b86d6c2 100644 (file)
@@ -63,11 +63,52 @@ static ManagedStatic<std::map<const Type*,
                               std::string> > AbstractTypeDescriptions;
 
 Type::Type(const char *Name, TypeID id)
-  : ID(id), Abstract(false),  SubclassData(0), RefCount(0), ForwardType(0) {
+  : ID(id), Abstract(false),  SubclassData(0), RefCount(0), ForwardType(0),
+    NumContainedTys(0),  ContainedTys(0) {
   assert(Name && Name[0] && "Should use other ctor if no name!");
   (*ConcreteTypeDescriptions)[this] = Name;
 }
 
+/// Because of the way Type subclasses are allocated, this function is necessary
+/// to use the correct kind of "delete" operator to deallocate the Type object.
+/// Some type objects (FunctionTy, StructTy) allocate additional space after 
+/// the space for their derived type to hold the contained types array of
+/// PATypeHandles. Using this allocation scheme means all the PATypeHandles are
+/// allocated with the type object, decreasing allocations and eliminating the
+/// need for a std::vector to be used in the Type class itself. 
+/// @brief Type destruction function
+void Type::destroy() const {
+
+  // Structures and Functions allocate their contained types past the end of
+  // the type object itself. These need to be destroyed differently than the
+  // other types.
+  if (isa<FunctionType>(this) || isa<StructType>(this)) {
+    // First, make sure we destruct any PATypeHandles allocated by these
+    // subclasses.  They must be manually destructed. 
+    for (unsigned i = 0; i < NumContainedTys; ++i)
+      ContainedTys[i].PATypeHandle::~PATypeHandle();
+
+    // Now call the destructor for the subclass directly because we're going
+    // to delete this as an array of char.
+    if (isa<FunctionType>(this))
+      ((FunctionType*)this)->FunctionType::~FunctionType();
+    else
+      ((StructType*)this)->StructType::~StructType();
+
+    // Finally, remove the memory as an array deallocation of the chars it was
+    // constructed from.
+    delete [] reinterpret_cast<const char*>(this); 
+
+    return;
+  }
+
+  // For all the other type subclasses, there is either no contained types or 
+  // just one (all Sequentials). For Sequentials, the PATypeHandle is not
+  // allocated past the type object, its included directly in the SequentialType
+  // class. This means we can safely just do "normal" delete of this object and
+  // all the destructors that need to run will be run.
+  delete this; 
+}
 
 const Type *Type::getPrimitiveType(TypeID IDNumber) {
   switch (IDNumber) {
@@ -330,7 +371,7 @@ bool StructType::indexValid(const Value *V) const {
   // Structure indexes require 32-bit integer constants.
   if (V->getType() == Type::Int32Ty)
     if (const ConstantInt *CU = dyn_cast<ConstantInt>(V))
-      return CU->getZExtValue() < ContainedTys.size();
+      return CU->getZExtValue() < NumContainedTys;
   return false;
 }
 
@@ -371,19 +412,19 @@ const IntegerType *Type::Int64Ty = new BuiltinIntegerType(64);
 FunctionType::FunctionType(const Type *Result,
                            const std::vector<const Type*> &Params,
                            bool IsVarArgs, const ParamAttrsList &Attrs) 
-  : DerivedType(FunctionTyID), isVarArgs(IsVarArgs) {
+  : DerivedType(FunctionTyID), isVarArgs(IsVarArgs), ParamAttrs(0) {
+  ContainedTys = reinterpret_cast<PATypeHandle*>(this+1);
+  NumContainedTys = Params.size() + 1; // + 1 for result type
   assert((Result->isFirstClassType() || Result == Type::VoidTy ||
          isa<OpaqueType>(Result)) &&
          "LLVM functions cannot return aggregates");
   bool isAbstract = Result->isAbstract();
-  ContainedTys.reserve(Params.size()+1);
-  ContainedTys.push_back(PATypeHandle(Result, this));
+  new (&ContainedTys[0]) PATypeHandle(Result, this);
 
   for (unsigned i = 0; i != Params.size(); ++i) {
     assert((Params[i]->isFirstClassType() || isa<OpaqueType>(Params[i])) &&
            "Function arguments must be value types!");
-
-    ContainedTys.push_back(PATypeHandle(Params[i], this));
+    new (&ContainedTys[i+1]) PATypeHandle(Params[i],this);
     isAbstract |= Params[i]->isAbstract();
   }
 
@@ -400,12 +441,13 @@ FunctionType::FunctionType(const Type *Result,
 
 StructType::StructType(const std::vector<const Type*> &Types, bool isPacked)
   : CompositeType(StructTyID) {
+  ContainedTys = reinterpret_cast<PATypeHandle*>(this + 1);
+  NumContainedTys = Types.size();
   setSubclassData(isPacked);
-  ContainedTys.reserve(Types.size());
   bool isAbstract = false;
   for (unsigned i = 0; i < Types.size(); ++i) {
     assert(Types[i] != Type::VoidTy && "Void type for structure field!!");
-    ContainedTys.push_back(PATypeHandle(Types[i], this));
+     new (&ContainedTys[i]) PATypeHandle(Types[i], this);
     isAbstract |= Types[i]->isAbstract();
   }
 
@@ -449,17 +491,17 @@ OpaqueType::OpaqueType() : DerivedType(OpaqueTyID) {
 // another (more concrete) type, we must eliminate all references to other
 // types, to avoid some circular reference problems.
 void DerivedType::dropAllTypeUses() {
-  if (!ContainedTys.empty()) {
+  if (NumContainedTys != 0) {
     // The type must stay abstract.  To do this, we insert a pointer to a type
     // that will never get resolved, thus will always be abstract.
     static Type *AlwaysOpaqueTy = OpaqueType::get();
     static PATypeHolder Holder(AlwaysOpaqueTy);
     ContainedTys[0] = AlwaysOpaqueTy;
 
-    // Change the rest of the types to be intty's.  It doesn't matter what we
+    // Change the rest of the types to be Int32Ty's.  It doesn't matter what we
     // pick so long as it doesn't point back to this type.  We choose something
     // concrete to avoid overhead for adding to AbstracTypeUser lists and stuff.
-    for (unsigned i = 1, e = ContainedTys.size(); i != e; ++i)
+    for (unsigned i = 1, e = NumContainedTys; i != e; ++i)
       ContainedTys[i] = Type::Int32Ty;
   }
 }
@@ -812,7 +854,7 @@ public:
     unsigned OldTypeHash = ValType::hashTypeStructure(Ty);
 
     // Find the type element we are refining... and change it now!
-    for (unsigned i = 0, e = Ty->ContainedTys.size(); i != e; ++i)
+    for (unsigned i = 0, e = Ty->getNumContainedTypes(); i != e; ++i)
       if (Ty->ContainedTys[i] == OldType)
         Ty->ContainedTys[i] = NewType;
     unsigned NewTypeHash = ValType::hashTypeStructure(Ty);
@@ -1047,7 +1089,9 @@ FunctionType *FunctionType::get(const Type *ReturnType,
   FunctionType *MT = FunctionTypes->get(VT);
   if (MT) return MT;
 
-  MT = new FunctionType(ReturnType, Params, isVarArg, *TheAttrs);
+  MT = (FunctionType*) new char[sizeof(FunctionType) + 
+                                sizeof(PATypeHandle)*(Params.size()+1)];
+  new (MT) FunctionType(ReturnType, Params, isVarArg, *TheAttrs);
   FunctionTypes->add(VT, MT);
 
 #ifdef DEBUG_MERGE_TYPES
@@ -1214,7 +1258,10 @@ StructType *StructType::get(const std::vector<const Type*> &ETypes,
   if (ST) return ST;
 
   // Value not found.  Derive a new type!
-  StructTypes->add(STV, ST = new StructType(ETypes, isPacked));
+  ST = (StructType*) new char[sizeof(StructType) + 
+                              sizeof(PATypeHandle) * ETypes.size()];
+  new (ST) StructType(ETypes, isPacked);
+  StructTypes->add(STV, ST);
 
 #ifdef DEBUG_MERGE_TYPES
   DOUT << "Derived new type: " << *ST << "\n";
@@ -1304,11 +1351,10 @@ void Type::removeAbstractTypeUser(AbstractTypeUser *U) const {
     DOUT << "DELETEing unused abstract type: <" << *this
          << ">[" << (void*)this << "]" << "\n";
 #endif
-    delete this;                  // No users of this abstract type!
+    this->destroy();
   }
 }
 
-
 // refineAbstractTypeTo - This function is used when it is discovered that
 // the 'this' abstract type is actually equivalent to the NewType specified.
 // This causes all users of 'this' to switch to reference the more concrete type