Insomniac refactoring:  change how the parser allocates attributes so that
AttributeLists do not accumulate over the lifetime of parsing, but are
instead reused.  Also make the arguments array not require a separate
allocation, and make availability attributes store their stuff in
augmented memory, too.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@128209 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index ae5ea67..792ab4e 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -12,46 +12,89 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Sema/AttributeList.h"
+#include "clang/AST/Expr.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "llvm/ADT/StringSwitch.h"
 using namespace clang;
 
-AttributeList::AttributeList(llvm::BumpPtrAllocator &Alloc,
-                             IdentifierInfo *aName, SourceLocation aLoc,
-                             IdentifierInfo *sName, SourceLocation sLoc,
-                             IdentifierInfo *pName, SourceLocation pLoc,
-                             Expr **ExprList, unsigned numArgs,
-                             bool declspec, bool cxx0x)
-  : AttrName(aName), AttrLoc(aLoc), ScopeName(sName),
-    ScopeLoc(sLoc),
-    ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(0),
-    DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false) {
-
-  if (numArgs == 0)
-    Args = 0;
-  else {
-    // Allocate the Args array using the BumpPtrAllocator.
-    Args = Alloc.Allocate<Expr*>(numArgs);
-    memcpy(Args, ExprList, numArgs*sizeof(Args[0]));
-  }
+size_t AttributeList::allocated_size() const {
+  if (IsAvailability) return AttributeFactory::AvailabilityAllocSize;
+  return (sizeof(AttributeList) + NumArgs * sizeof(Expr*));
 }
 
-AttributeList::AttributeList(llvm::BumpPtrAllocator &Alloc,
-                             IdentifierInfo *AttrName, SourceLocation AttrLoc,
-                             IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
-                             IdentifierInfo *ParmName, SourceLocation ParmLoc,
-                             const AvailabilityChange &Introduced,
-                             const AvailabilityChange &Deprecated,
-                             const AvailabilityChange &Obsoleted,
-                             bool declspec, bool cxx0x)
-  : AttrName(AttrName), AttrLoc(AttrLoc), ScopeName(ScopeName), 
-    ScopeLoc(ScopeLoc), ParmName(ParmName), ParmLoc(ParmLoc), 
-    Args(0), NumArgs(0), Next(0),
-    DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), 
-    AvailabilityIntroduced(Introduced),
-    AvailabilityDeprecated(Deprecated),
-    AvailabilityObsoleted(Obsoleted),
-    Invalid(false) {
+AttributeFactory::AttributeFactory() {
+  // Go ahead and configure all the inline capacity.  This is just a memset.
+  FreeLists.resize(InlineFreeListsCapacity);
+}
+AttributeFactory::~AttributeFactory() {}
+
+static size_t getFreeListIndexForSize(size_t size) {
+  assert(size >= sizeof(AttributeList));
+  assert((size % sizeof(void*)) == 0);
+  return ((size - sizeof(AttributeList)) / sizeof(void*));
+}
+
+void *AttributeFactory::allocate(size_t size) {
+  // Check for a previously reclaimed attribute.
+  size_t index = getFreeListIndexForSize(size);
+  if (index < FreeLists.size()) {
+    if (AttributeList *attr = FreeLists[index]) {
+      FreeLists[index] = attr->NextInPool;
+      return attr;
+    }
+  }
+
+  // Otherwise, allocate something new.
+  return Alloc.Allocate(size, llvm::AlignOf<AttributeFactory>::Alignment);
+}
+
+void AttributeFactory::reclaimPool(AttributeList *cur) {
+  assert(cur && "reclaiming empty pool!");
+  do {
+    // Read this here, because we're going to overwrite NextInPool
+    // when we toss 'cur' into the appropriate queue.
+    AttributeList *next = cur->NextInPool;
+
+    size_t size = cur->allocated_size();
+    size_t freeListIndex = getFreeListIndexForSize(size);
+
+    // Expand FreeLists to the appropriate size, if required.
+    if (freeListIndex >= FreeLists.size())
+      FreeLists.resize(freeListIndex+1);
+
+    // Add 'cur' to the appropriate free-list.
+    cur->NextInPool = FreeLists[freeListIndex];
+    FreeLists[freeListIndex] = cur;
+    
+    cur = next;
+  } while (cur);
+}
+
+void AttributePool::takePool(AttributeList *pool) {
+  assert(pool);
+
+  // Fast path:  this pool is empty.
+  if (!Head) {
+    Head = pool;
+    return;
+  }
+
+  // Reverse the pool onto the current head.  This optimizes for the
+  // pattern of pulling a lot of pools into a single pool.
+  do {
+    AttributeList *next = pool->NextInPool;
+    pool->NextInPool = Head;
+    Head = pool;
+    pool = next;
+  } while (pool);
+}
+
+AttributeList *
+AttributePool::createIntegerAttribute(ASTContext &C, IdentifierInfo *Name,
+                                      SourceLocation TokLoc, int Arg) {
+  Expr *IArg = IntegerLiteral::Create(C, llvm::APInt(32, (uint64_t) Arg),
+                                      C.IntTy, TokLoc);
+  return create(Name, TokLoc, 0, TokLoc, 0, TokLoc, &IArg, 1, 0);
 }
 
 AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 8cbf9d9..9bbeef7 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -134,8 +134,7 @@
 
 /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
 /// "TheDeclarator" is the declarator that this will be added to.
-DeclaratorChunk DeclaratorChunk::getFunction(const ParsedAttributes &attrs,
-                                             bool hasProto, bool isVariadic,
+DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
                                              SourceLocation EllipsisLoc,
                                              ParamInfo *ArgInfo,
                                              unsigned NumArgs,
@@ -157,7 +156,7 @@
   I.Kind                        = Function;
   I.Loc                         = LocalRangeBegin;
   I.EndLoc                      = LocalRangeEnd;
-  I.Fun.AttrList                = attrs.getList();
+  I.Fun.AttrList                = 0;
   I.Fun.hasPrototype            = hasProto;
   I.Fun.isVariadic              = isVariadic;
   I.Fun.EllipsisLoc             = EllipsisLoc.getRawEncoding();
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 544d1ae..a6c1543 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -5502,7 +5502,8 @@
 
         // Implicitly declare the argument as type 'int' for lack of a better
         // type.
-        DeclSpec DS;
+        AttributeFactory attrs;
+        DeclSpec DS(attrs);
         const char* PrevSpec; // unused
         unsigned DiagID; // unused
         DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc,
@@ -5838,17 +5839,18 @@
 
   // Set a Declarator for the implicit definition: int foo();
   const char *Dummy;
-  DeclSpec DS;
+  AttributeFactory attrFactory;
+  DeclSpec DS(attrFactory);
   unsigned DiagID;
   bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID);
   (void)Error; // Silence warning.
   assert(!Error && "Error setting up implicit decl!");
   Declarator D(DS, Declarator::BlockContext);
-  D.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(),
-                                             false, false, SourceLocation(), 0,
+  D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0,
                                              0, 0, true, SourceLocation(),
                                              EST_None, SourceLocation(),
                                              0, 0, 0, 0, Loc, Loc, D),
+                DS.getAttributes(),
                 SourceLocation());
   D.SetIdentifier(&II, Loc);
 
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index b3cdbb2..5324229 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -536,7 +536,6 @@
 
   // ...and *prepend* it to the declarator.
   declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction(
-                             ParsedAttributes(),
                              /*proto*/ true,
                              /*variadic*/ false, SourceLocation(),
                              /*args*/ 0, 0,