summaryrefslogtreecommitdiffstats
path: root/include/clang/Sema/AttributeList.h
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2011-03-24 11:26:52 +0000
committerJohn McCall <rjmccall@apple.com>2011-03-24 11:26:52 +0000
commit0b7e678a11ece4288dc01aebb5b17e5eef8f8d2d (patch)
tree7a4b4707d5fcfeed3c2301e0c4d15647bf7f24c3 /include/clang/Sema/AttributeList.h
parentfa7b8ced6f3318879b39f44b5ace8346e979826e (diff)
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
Diffstat (limited to 'include/clang/Sema/AttributeList.h')
-rw-r--r--include/clang/Sema/AttributeList.h352
1 files changed, 272 insertions, 80 deletions
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 3657b44b02..8e05c62880 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -16,13 +16,13 @@
#define LLVM_CLANG_SEMA_ATTRLIST_H
#include "llvm/Support/Allocator.h"
-#include "clang/Sema/Ownership.h"
+#include "llvm/ADT/SmallVector.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/VersionTuple.h"
-#include "clang/AST/Expr.h"
#include <cassert>
namespace clang {
+ class ASTContext;
class IdentifierInfo;
class Expr;
@@ -51,87 +51,96 @@ struct AvailabilityChange {
/// 3: __attribute__(( format(printf, 1, 2) )). ParmName/Args/NumArgs all used.
/// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used.
///
-class AttributeList {
-public:
- class Factory;
+class AttributeList { // TODO: This should really be called ParsedAttribute
private:
IdentifierInfo *AttrName;
- SourceLocation AttrLoc;
IdentifierInfo *ScopeName;
- SourceLocation ScopeLoc;
IdentifierInfo *ParmName;
+ SourceLocation AttrLoc;
+ SourceLocation ScopeLoc;
SourceLocation ParmLoc;
- Expr **Args;
+
+ /// The number of expression arguments this attribute has.
+ /// The expressions themselves are stored after the object.
unsigned NumArgs;
- AttributeList *Next;
- bool DeclspecAttribute, CXX0XAttribute;
- // For the 'availability' attribute.
- AvailabilityChange AvailabilityIntroduced;
- AvailabilityChange AvailabilityDeprecated;
- AvailabilityChange AvailabilityObsoleted;
+ /// True if Microsoft style: declspec(foo).
+ bool DeclspecAttribute;
+
+ /// True if C++0x-style: [[foo]].
+ bool CXX0XAttribute;
/// True if already diagnosed as invalid.
mutable bool Invalid;
+ /// True if this has the extra information associated with an
+ /// availability attribute.
+ bool IsAvailability;
+
+ /// The next attribute in the current position.
+ AttributeList *NextInPosition;
+
+ /// The next attribute allocated in the current Pool.
+ AttributeList *NextInPool;
+
+ Expr **getArgsBuffer() {
+ return reinterpret_cast<Expr**>(this+1);
+ }
+ Expr * const *getArgsBuffer() const {
+ return reinterpret_cast<Expr* const *>(this+1);
+ }
+
+ enum AvailabilitySlot {
+ IntroducedSlot, DeprecatedSlot, ObsoletedSlot
+ };
+
+ AvailabilityChange &getAvailabilitySlot(AvailabilitySlot index) {
+ return reinterpret_cast<AvailabilityChange*>(this+1)[index];
+ }
+ const AvailabilityChange &getAvailabilitySlot(AvailabilitySlot index) const {
+ return reinterpret_cast<const AvailabilityChange*>(this+1)[index];
+ }
+
AttributeList(const AttributeList &); // DO NOT IMPLEMENT
void operator=(const AttributeList &); // DO NOT IMPLEMENT
void operator delete(void *); // DO NOT IMPLEMENT
~AttributeList(); // DO NOT IMPLEMENT
- AttributeList(llvm::BumpPtrAllocator &Alloc,
- IdentifierInfo *AttrName, SourceLocation AttrLoc,
- IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
- IdentifierInfo *ParmName, SourceLocation ParmLoc,
- Expr **args, unsigned numargs,
- bool declspec, bool cxx0x);
-
- 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);
+
+ size_t allocated_size() const;
+
+ AttributeList(IdentifierInfo *attrName, SourceLocation attrLoc,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ Expr **args, unsigned numArgs,
+ bool declspec, bool cxx0x)
+ : AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
+ AttrLoc(attrLoc), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
+ NumArgs(numArgs),
+ DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false),
+ IsAvailability(false), NextInPosition(0), NextInPool(0) {
+ if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*));
+ }
+
+ AttributeList(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), ScopeName(scopeName), ParmName(parmName),
+ AttrLoc(attrLoc), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
+ NumArgs(0), DeclspecAttribute(declspec), CXX0XAttribute(cxx0x),
+ Invalid(false), IsAvailability(true), NextInPosition(0), NextInPool(0) {
+ new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced);
+ new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated);
+ new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted);
+ }
+
+ friend class AttributePool;
+ friend class AttributeFactory;
+
public:
- class Factory {
- llvm::BumpPtrAllocator Alloc;
- public:
- Factory() {}
- ~Factory() {}
- AttributeList *Create(IdentifierInfo *AttrName, SourceLocation AttrLoc,
- IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
- IdentifierInfo *ParmName, SourceLocation ParmLoc,
- Expr **args, unsigned numargs, bool declspec = false, bool cxx0x = false) {
- AttributeList *Mem = Alloc.Allocate<AttributeList>();
- new (Mem) AttributeList(Alloc, AttrName, AttrLoc, ScopeName, ScopeLoc,
- ParmName, ParmLoc, args, numargs,
- declspec, cxx0x);
- return Mem;
- }
-
- AttributeList *Create(IdentifierInfo *AttrName, SourceLocation AttrLoc,
- IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
- IdentifierInfo *ParmName, SourceLocation ParmLoc,
- const AvailabilityChange &Introduced,
- const AvailabilityChange &Deprecated,
- const AvailabilityChange &Obsoleted,
- bool declspec = false, bool cxx0x = false) {
- AttributeList *Mem = Alloc.Allocate<AttributeList>();
- new (Mem) AttributeList(Alloc, AttrName, AttrLoc, ScopeName, ScopeLoc,
- ParmName, ParmLoc, Introduced, Deprecated,
- Obsoleted, declspec, cxx0x);
- return Mem;
- }
-
- AttributeList* 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);
- }
- };
-
enum Kind { // Please keep this list alphabetized.
AT_IBAction, // Clang-specific.
AT_IBOutlet, // Clang-specific.
@@ -242,8 +251,8 @@ public:
Kind getKind() const { return getKind(getName()); }
static Kind getKind(const IdentifierInfo *Name);
- AttributeList *getNext() const { return Next; }
- void setNext(AttributeList *N) { Next = N; }
+ AttributeList *getNext() const { return NextInPosition; }
+ void setNext(AttributeList *N) { NextInPosition = N; }
/// getNumArgs - Return the number of actual arguments to this attribute.
unsigned getNumArgs() const { return NumArgs; }
@@ -251,14 +260,14 @@ public:
/// getArg - Return the specified argument.
Expr *getArg(unsigned Arg) const {
assert(Arg < NumArgs && "Arg access out of range!");
- return Args[Arg];
+ return getArgsBuffer()[Arg];
}
class arg_iterator {
- Expr** X;
+ Expr * const *X;
unsigned Idx;
public:
- arg_iterator(Expr** x, unsigned idx) : X(x), Idx(idx) {}
+ arg_iterator(Expr * const *x, unsigned idx) : X(x), Idx(idx) {}
arg_iterator& operator++() {
++Idx;
@@ -285,27 +294,158 @@ public:
};
arg_iterator arg_begin() const {
- return arg_iterator(Args, 0);
+ return arg_iterator(getArgsBuffer(), 0);
}
arg_iterator arg_end() const {
- return arg_iterator(Args, NumArgs);
+ return arg_iterator(getArgsBuffer(), NumArgs);
}
const AvailabilityChange &getAvailabilityIntroduced() const {
assert(getKind() == AT_availability && "Not an availability attribute");
- return AvailabilityIntroduced;
+ return getAvailabilitySlot(IntroducedSlot);
}
const AvailabilityChange &getAvailabilityDeprecated() const {
assert(getKind() == AT_availability && "Not an availability attribute");
- return AvailabilityDeprecated;
+ return getAvailabilitySlot(DeprecatedSlot);
}
const AvailabilityChange &getAvailabilityObsoleted() const {
assert(getKind() == AT_availability && "Not an availability attribute");
- return AvailabilityObsoleted;
+ return getAvailabilitySlot(ObsoletedSlot);
+ }
+};
+
+/// A factory, from which one makes pools, from which one creates
+/// individual attributes which are deallocated with the pool.
+///
+/// Note that it's tolerably cheap to create and destroy one of
+/// these as long as you don't actually allocate anything in it.
+class AttributeFactory {
+public:
+ enum {
+ /// The required allocation size of an availability attribute,
+ /// which we want to ensure is a multiple of sizeof(void*).
+ AvailabilityAllocSize =
+ sizeof(AttributeList)
+ + ((3 * sizeof(AvailabilityChange) + sizeof(void*) - 1)
+ / sizeof(void*) * sizeof(void*))
+ };
+
+private:
+ enum {
+ /// The number of free lists we want to be sure to support
+ /// inline. This is just enough that availability attributes
+ /// don't surpass it. It's actually very unlikely we'll see an
+ /// attribute that needs more than that; on x86-64 you'd need 10
+ /// expression arguments, and on i386 you'd need 19.
+ InlineFreeListsCapacity =
+ 1 + (AvailabilityAllocSize - sizeof(AttributeList)) / sizeof(void*)
+ };
+
+ llvm::BumpPtrAllocator Alloc;
+
+ /// Free lists. The index is determined by the following formula:
+ /// (size - sizeof(AttributeList)) / sizeof(void*)
+ llvm::SmallVector<AttributeList*, InlineFreeListsCapacity> FreeLists;
+
+ // The following are the private interface used by AttributePool.
+ friend class AttributePool;
+
+ /// Allocate an attribute of the given size.
+ void *allocate(size_t size);
+
+ /// Reclaim all the attributes in the given pool chain, which is
+ /// non-empty. Note that the current implementation is safe
+ /// against reclaiming things which were not actually allocated
+ /// with the allocator, although of course it's important to make
+ /// sure that their allocator lives at least as long as this one.
+ void reclaimPool(AttributeList *head);
+
+public:
+ AttributeFactory();
+ ~AttributeFactory();
+};
+
+class AttributePool {
+ AttributeFactory &Factory;
+ AttributeList *Head;
+
+ void *allocate(size_t size) {
+ return Factory.allocate(size);
}
+
+ AttributeList *add(AttributeList *attr) {
+ // We don't care about the order of the pool.
+ attr->NextInPool = Head;
+ Head = attr;
+ return attr;
+ }
+
+ void takePool(AttributeList *pool);
+
+public:
+ /// Create a new pool for a factory.
+ AttributePool(AttributeFactory &factory) : Factory(factory), Head(0) {}
+
+ /// Move the given pool's allocations to this pool.
+ AttributePool(AttributePool &pool) : Factory(pool.Factory), Head(pool.Head) {
+ pool.Head = 0;
+ }
+
+ AttributeFactory &getFactory() const { return Factory; }
+
+ void clear() {
+ if (Head) {
+ Factory.reclaimPool(Head);
+ Head = 0;
+ }
+ }
+
+ /// Take the given pool's allocations and add them to this pool.
+ void takeAllFrom(AttributePool &pool) {
+ if (pool.Head) {
+ takePool(pool.Head);
+ pool.Head = 0;
+ }
+ }
+
+ ~AttributePool() {
+ if (Head) Factory.reclaimPool(Head);
+ }
+
+ AttributeList *create(IdentifierInfo *attrName, SourceLocation attrLoc,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ Expr **args, unsigned numArgs,
+ bool declspec = false, bool cxx0x = false) {
+ void *memory = allocate(sizeof(AttributeList)
+ + numArgs * sizeof(Expr*));
+ return add(new (memory) AttributeList(attrName, attrLoc,
+ scopeName, scopeLoc,
+ parmName, parmLoc,
+ args, numArgs,
+ declspec, cxx0x));
+ }
+
+ AttributeList *create(IdentifierInfo *attrName, SourceLocation attrLoc,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ const AvailabilityChange &introduced,
+ const AvailabilityChange &deprecated,
+ const AvailabilityChange &obsoleted,
+ bool declspec = false, bool cxx0x = false) {
+ void *memory = allocate(AttributeFactory::AvailabilityAllocSize);
+ return add(new (memory) AttributeList(attrName, attrLoc,
+ scopeName, scopeLoc,
+ parmName, parmLoc,
+ introduced, deprecated, obsoleted,
+ declspec, cxx0x));
+ }
+
+ AttributeList *createIntegerAttribute(ASTContext &C, IdentifierInfo *Name,
+ SourceLocation TokLoc, int Arg);
};
/// addAttributeLists - Add two AttributeLists together
@@ -350,7 +490,16 @@ struct CXX0XAttributeList {
/// is that this will become significantly more serious.
class ParsedAttributes {
public:
- ParsedAttributes() : list(0) {}
+ ParsedAttributes(AttributeFactory &factory)
+ : pool(factory), list(0) {
+ }
+
+ ParsedAttributes(ParsedAttributes &attrs)
+ : pool(attrs.pool), list(attrs.list) {
+ attrs.list = 0;
+ }
+
+ AttributePool &getPool() const { return pool; }
bool empty() const { return list == 0; }
@@ -361,7 +510,7 @@ public:
list = newAttr;
}
- void append(AttributeList *newList) {
+ void addAll(AttributeList *newList) {
if (!newList) return;
AttributeList *lastInNewList = newList;
@@ -376,14 +525,57 @@ public:
list = newList;
}
- void clear() { list = 0; }
+ void takeAllFrom(ParsedAttributes &attrs) {
+ addAll(attrs.list);
+ attrs.list = 0;
+ pool.takeAllFrom(attrs.pool);
+ }
+
+ void clear() { list = 0; pool.clear(); }
AttributeList *getList() const { return list; }
/// Returns a reference to the attribute list. Try not to introduce
/// dependencies on this method, it may not be long-lived.
AttributeList *&getListRef() { return list; }
+
+ AttributeList *addNew(IdentifierInfo *attrName, SourceLocation attrLoc,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ Expr **args, unsigned numArgs,
+ bool declspec = false, bool cxx0x = false) {
+ AttributeList *attr =
+ pool.create(attrName, attrLoc, scopeName, scopeLoc, parmName, parmLoc,
+ args, numArgs, declspec, cxx0x);
+ add(attr);
+ return attr;
+ }
+
+ AttributeList *addNew(IdentifierInfo *attrName, SourceLocation attrLoc,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ const AvailabilityChange &introduced,
+ const AvailabilityChange &deprecated,
+ const AvailabilityChange &obsoleted,
+ bool declspec = false, bool cxx0x = false) {
+ AttributeList *attr =
+ pool.create(attrName, attrLoc, scopeName, scopeLoc, parmName, parmLoc,
+ introduced, deprecated, obsoleted, declspec, cxx0x);
+ add(attr);
+ return attr;
+ }
+
+ AttributeList *addNewInteger(ASTContext &C, IdentifierInfo *name,
+ SourceLocation loc, int arg) {
+ AttributeList *attr =
+ pool.createIntegerAttribute(C, name, loc, arg);
+ add(attr);
+ return attr;
+ }
+
+
private:
+ mutable AttributePool pool;
AttributeList *list;
};