Add support for ObjC keyword selectors.

- Add SelectorInfo/SelectorTable classes, modeled after IdentifierInfo/IdentifierTable.
- Add SelectorTable instance to ASTContext, created lazily through ASTContext::getSelectorInfo().
- Add SelectorInfo slot to ObjcMethodDecl.
- Add helper function to derive a SelectorInfo from ObjcKeywordInfo.

Misc: Got the Decl stats stuff up and running again...it was missing support for ObjC AST's.
llvm-svn: 42023
This commit is contained in:
Steve Naroff 2007-09-17 14:16:13 +00:00
parent ffb47d0679
commit 73d534a2e0
8 changed files with 190 additions and 39 deletions

View File

@ -16,6 +16,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallVector.h"
#include "clang/Lex/IdentifierTable.h"
using namespace clang;
enum FloatingRank {
@ -44,6 +45,7 @@ void ASTContext::PrintStats() const {
unsigned NumFunctionNP = 0, NumTypeName = 0, NumTagged = 0, NumReference = 0;
unsigned NumTagStruct = 0, NumTagUnion = 0, NumTagEnum = 0, NumTagClass = 0;
unsigned NumObjcInterfaces = 0;
for (unsigned i = 0, e = Types.size(); i != e; ++i) {
Type *T = Types[i];
@ -74,7 +76,9 @@ void ASTContext::PrintStats() const {
case Decl::Class: ++NumTagClass; break;
case Decl::Enum: ++NumTagEnum; break;
}
} else {
} else if (isa<ObjcInterfaceType>(T))
++NumObjcInterfaces;
else {
assert(0 && "Unknown type!");
}
}
@ -93,12 +97,16 @@ void ASTContext::PrintStats() const {
fprintf(stderr, " %d union types\n", NumTagUnion);
fprintf(stderr, " %d class types\n", NumTagClass);
fprintf(stderr, " %d enum types\n", NumTagEnum);
fprintf(stderr, " %d interface types\n", NumObjcInterfaces);
fprintf(stderr, "Total bytes = %d\n", int(NumBuiltin*sizeof(BuiltinType)+
NumPointer*sizeof(PointerType)+NumArray*sizeof(ArrayType)+
NumComplex*sizeof(ComplexType)+NumVector*sizeof(VectorType)+
NumFunctionP*sizeof(FunctionTypeProto)+
NumFunctionNP*sizeof(FunctionTypeNoProto)+
NumTypeName*sizeof(TypedefType)+NumTagged*sizeof(TagType)));
if (Selectors)
Selectors->PrintStats();
}
@ -801,3 +809,11 @@ QualType ASTContext::getCFConstantStringType() {
return getTagDeclType(CFConstantStringTypeDecl);
}
SelectorInfo &ASTContext::getSelectorInfo(const char *NameStart,
const char *NameEnd) {
if (!Selectors) // create the table lazily
Selectors = new SelectorTable();
return Selectors->get(NameStart, NameEnd);
}

View File

@ -26,6 +26,11 @@ static unsigned nEnumDecls = 0;
static unsigned nTypedef = 0;
static unsigned nFieldDecls = 0;
static unsigned nInterfaceDecls = 0;
static unsigned nClassDecls = 0;
static unsigned nMethodDecls = 0;
static unsigned nProtocolDecls = 0;
static unsigned nIvarDecls = 0;
static bool StatSwitch = false;
const char *Decl::getDeclKindName() {
@ -73,7 +78,8 @@ void Decl::PrintStats() {
fprintf(stderr, "*** Decl Stats:\n");
fprintf(stderr, " %d decls total.\n",
int(nFuncs+nBlockVars+nFileVars+nParmVars+nFieldDecls+nSUC+
nEnumDecls+nEnumConst+nTypedef));
nEnumDecls+nEnumConst+nTypedef+nInterfaceDecls+nClassDecls+
nMethodDecls+nProtocolDecls+nIvarDecls));
fprintf(stderr, " %d function decls, %d each (%d bytes)\n",
nFuncs, (int)sizeof(FunctionDecl), int(nFuncs*sizeof(FunctionDecl)));
fprintf(stderr, " %d block variable decls, %d each (%d bytes)\n",
@ -99,12 +105,29 @@ void Decl::PrintStats() {
int(nEnumConst*sizeof(EnumConstantDecl)));
fprintf(stderr, " %d typedef decls, %d each (%d bytes)\n",
nTypedef, (int)sizeof(TypedefDecl),int(nTypedef*sizeof(TypedefDecl)));
// Objective-C decls...
fprintf(stderr, " %d interface decls, %d each (%d bytes)\n",
nInterfaceDecls, (int)sizeof(ObjcInterfaceDecl),
int(nInterfaceDecls*sizeof(ObjcInterfaceDecl)));
fprintf(stderr, " %d instance variable decls, %d each (%d bytes)\n",
nIvarDecls, (int)sizeof(ObjcIvarDecl),
int(nIvarDecls*sizeof(ObjcIvarDecl)));
fprintf(stderr, " %d class decls, %d each (%d bytes)\n",
nClassDecls, (int)sizeof(ObjcClassDecl),
int(nClassDecls*sizeof(ObjcClassDecl)));
fprintf(stderr, " %d method decls, %d each (%d bytes)\n",
nMethodDecls, (int)sizeof(ObjcMethodDecl),
int(nMethodDecls*sizeof(ObjcMethodDecl)));
fprintf(stderr, " %d protocol decls, %d each (%d bytes)\n",
nProtocolDecls, (int)sizeof(ObjcProtocolDecl),
int(nProtocolDecls*sizeof(ObjcProtocolDecl)));
fprintf(stderr, "Total bytes = %d\n",
int(nFuncs*sizeof(FunctionDecl)+nBlockVars*sizeof(BlockVarDecl)+
nFileVars*sizeof(FileVarDecl)+nParmVars*sizeof(ParmVarDecl)+
nFieldDecls*sizeof(FieldDecl)+nSUC*sizeof(RecordDecl)+
nEnumDecls*sizeof(EnumDecl)+nEnumConst*sizeof(EnumConstantDecl)+
nTypedef*sizeof(TypedefDecl)));
nTypedef*sizeof(TypedefDecl)) /* FIXME: add Objc decls */);
}
void Decl::addDeclKind(const Kind k) {
@ -142,11 +165,17 @@ void Decl::addDeclKind(const Kind k) {
nInterfaceDecls++;
break;
case ObjcClass:
nClassDecls++;
break;
case ObjcMethod:
case ObjcProtoMethod:
nMethodDecls++;
break;
case ObjcProtocol:
nProtocolDecls++;
break;
case ObjcIvar:
assert(0 && "FIXME: Count these decls!");
nIvarDecls++;
break;
}
}

View File

@ -209,3 +209,34 @@ void IdentifierTable::PrintStats() const {
// Compute statistics about the memory allocated for identifiers.
HashTable.getAllocator().PrintStats();
}
/// PrintStats - Print statistics about how well the identifier table is doing
/// at hashing identifiers.
void SelectorTable::PrintStats() const {
unsigned NumBuckets = HashTable.getNumBuckets();
unsigned NumIdentifiers = HashTable.getNumItems();
unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers;
unsigned AverageIdentifierSize = 0;
unsigned MaxIdentifierLength = 0;
// TODO: Figure out maximum times an identifier had to probe for -stats.
for (llvm::StringMap<SelectorInfo, llvm::BumpPtrAllocator>::const_iterator
I = HashTable.begin(), E = HashTable.end(); I != E; ++I) {
unsigned IdLen = I->getKeyLength();
AverageIdentifierSize += IdLen;
if (MaxIdentifierLength < IdLen)
MaxIdentifierLength = IdLen;
}
fprintf(stderr, "\n*** Selector Table Stats:\n");
fprintf(stderr, "# Selectors: %d\n", NumIdentifiers);
fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets);
fprintf(stderr, "Hash density (#selectors per bucket): %f\n",
NumIdentifiers/(double)NumBuckets);
fprintf(stderr, "Ave selector length: %f\n",
(AverageIdentifierSize/(double)NumIdentifiers));
fprintf(stderr, "Max selector length: %d\n", MaxIdentifierLength);
// Compute statistics about the memory allocated for identifiers.
HashTable.getAllocator().PrintStats();
}

View File

@ -1239,13 +1239,37 @@ void Sema::ObjcAddMethodsToClass(DeclTy *ClassDecl,
return;
}
/// Build objective-c style method name.
static SelectorInfo &
ObjcGetSelectorInfo(ObjcKeywordInfo* KeyInfo, unsigned numKeyInfo,
ASTContext &Context)
{
int len=0;
char *methodName;
for (unsigned int i = 0; i < numKeyInfo; i++) {
IdentifierInfo *selectorName = KeyInfo[i].SelectorName;
if (selectorName)
len += strlen(selectorName->getName());
len++;
}
methodName = (char *) alloca (len + 1);
methodName[0] = '\0';
for (unsigned int i = 0; i < numKeyInfo; i++) {
IdentifierInfo *selectorName = KeyInfo[i].SelectorName;
if (selectorName)
strcat(methodName, selectorName->getName());
strcat(methodName, ":");
}
return Context.getSelectorInfo(methodName, methodName+len);
}
Sema::DeclTy *Sema::ObjcBuildMethodDeclaration(SourceLocation MethodLoc,
tok::TokenKind MethodType, TypeTy *ReturnType,
ObjcKeywordInfo *Keywords, unsigned NumKeywords,
AttributeList *AttrList) {
assert(NumKeywords && "Selector must be specified");
// FIXME: SelectorName to be changed to comform to objc's abi for method names
IdentifierInfo *SelectorName = Keywords[0].SelectorName;
SelectorInfo &SelName = ObjcGetSelectorInfo(Keywords, NumKeywords, Context);
llvm::SmallVector<ParmVarDecl*, 16> Params;
for (unsigned i = 0; i < NumKeywords; i++) {
@ -1261,7 +1285,7 @@ Sema::DeclTy *Sema::ObjcBuildMethodDeclaration(SourceLocation MethodLoc,
}
QualType resultDeclType = QualType::getFromOpaquePtr(ReturnType);
ObjcMethodDecl* ObjcMethod = new ObjcMethodDecl(MethodLoc,
SelectorName, resultDeclType,
SelName, resultDeclType,
0, -1, AttrList, MethodType == tok::minus);
ObjcMethod->setMethodParams(&Params[0], NumKeywords);
return ObjcMethod;
@ -1270,9 +1294,11 @@ Sema::DeclTy *Sema::ObjcBuildMethodDeclaration(SourceLocation MethodLoc,
Sema::DeclTy *Sema::ObjcBuildMethodDeclaration(SourceLocation MethodLoc,
tok::TokenKind MethodType, TypeTy *ReturnType,
IdentifierInfo *SelectorName, AttributeList *AttrList) {
// FIXME: SelectorName to be changed to comform to objc's abi for method names
const char *methodName = SelectorName->getName();
SelectorInfo &SelName = Context.getSelectorInfo(methodName,
methodName+strlen(methodName));
QualType resultDeclType = QualType::getFromOpaquePtr(ReturnType);
return new ObjcMethodDecl(MethodLoc, SelectorName, resultDeclType, 0, -1,
return new ObjcMethodDecl(MethodLoc, SelName, resultDeclType, 0, -1,
AttrList, MethodType == tok::minus);
}

View File

@ -227,7 +227,7 @@
35AE0F680C9B4CC200CC1279 /* UnintializedValues.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnintializedValues.cpp; path = Analysis/UnintializedValues.cpp; sourceTree = "<group>"; };
84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = Parse/AttributeList.cpp; sourceTree = "<group>"; };
84D9A88B0C1A581300AC7ABC /* AttributeList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = AttributeList.h; path = clang/Parse/AttributeList.h; sourceTree = "<group>"; };
8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "compiled.mach-o.executable"; path = clang; sourceTree = BUILT_PRODUCTS_DIR; };
8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; };
DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = "<group>"; };
DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = Parse/ParseExprCXX.cpp; sourceTree = "<group>"; };
DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = "<group>"; };

View File

@ -24,6 +24,7 @@
namespace clang {
class TargetInfo;
class SelectorTable;
/// ASTContext - This class holds long-lived AST nodes (such as types and
/// decls) that can be referred to throughout the semantic analysis of a file.
@ -38,7 +39,7 @@ class ASTContext {
llvm::FoldingSet<FunctionTypeProto> FunctionTypeProtos;
llvm::DenseMap<const RecordDecl*, const RecordLayout*> RecordLayoutInfo;
RecordDecl *CFConstantStringTypeDecl;
llvm::StringMap<char> SelectorNames;
SelectorTable *Selectors;
public:
SourceManager &SourceMgr;
TargetInfo &Target;
@ -56,7 +57,8 @@ public:
QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
ASTContext(SourceManager &SM, TargetInfo &t, IdentifierTable &idents) :
CFConstantStringTypeDecl(0), SourceMgr(SM), Target(t), Idents(idents) {
CFConstantStringTypeDecl(0), Selectors(0),
SourceMgr(SM), Target(t), Idents(idents) {
InitBuiltinTypes();
BuiltinInfo.InitializeBuiltins(idents, Target);
}
@ -182,10 +184,8 @@ public:
// Objective-C
//===--------------------------------------------------------------------===//
/// getSelectorName - Return a uniqued character string for the selector.
char &getSelectorName(const char *NameStart, const char *NameEnd) {
return SelectorNames.GetOrCreateValue(NameStart, NameEnd).getValue();
}
/// getSelectorInfo - Return a uniqued character string for the selector.
SelectorInfo &getSelectorInfo(const char *NameStart, const char *NameEnd);
private:
ASTContext(const ASTContext&); // DO NOT IMPLEMENT

View File

@ -23,10 +23,11 @@ class IdentifierInfo;
class Expr;
class Stmt;
class FunctionDecl;
class AttributeList;
class ObjcIvarDecl;
class ObjcMethodDecl;
class AttributeList;
class ObjcProtoMethodDecl;
class SelectorInfo;
/// Decl - This represents one declaration (or definition), e.g. a variable,
@ -614,20 +615,35 @@ public:
/// ObjcMethodDecl - An instance of this class is created to represent an instance
/// or class method declaration.
class ObjcMethodDecl : public Decl {
// A unigue name for this method.
SelectorInfo &Selector;
// Type of this method.
QualType MethodDeclType;
/// ParamInfo - new[]'d array of pointers to VarDecls for the formal
/// parameters of this Method. This is null if there are no formals.
ParmVarDecl **ParamInfo;
int NumMethodParams; // -1 if no parameters
/// List of attributes for this method declaration.
AttributeList *MethodAttrs;
/// instance (true) or class (false) method.
bool IsInstance : 1;
public:
ObjcMethodDecl(SourceLocation L, IdentifierInfo *Id, QualType T,
ObjcMethodDecl(SourceLocation L, SelectorInfo &SelId, QualType T,
ParmVarDecl **paramInfo = 0, int numParams=-1,
AttributeList *M = 0, bool isInstance = true,
Decl *PrevDecl = 0)
: Decl(ObjcMethod), MethodDeclType(T),
: Decl(ObjcMethod), Selector(SelId), MethodDeclType(T),
ParamInfo(paramInfo), NumMethodParams(numParams),
MethodAttrs(M), IsInstance(isInstance) {}
ObjcMethodDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T,
ObjcMethodDecl(Kind DK, SourceLocation L, SelectorInfo &SelId, QualType T,
ParmVarDecl **paramInfo = 0, int numParams=-1,
AttributeList *M = 0, bool isInstance = true,
Decl *PrevDecl = 0)
: Decl(DK), MethodDeclType(T),
: Decl(DK), Selector(SelId), MethodDeclType(T),
ParamInfo(paramInfo), NumMethodParams(numParams),
MethodAttrs(M), IsInstance(isInstance) {}
@ -649,20 +665,6 @@ public:
|| D->getKind() == ObjcProtoMethod;
}
static bool classof(const ObjcMethodDecl *D) { return true; }
private:
// Type of this method.
QualType MethodDeclType;
/// ParamInfo - new[]'d array of pointers to VarDecls for the formal
/// parameters of this Method. This is null if there are no formals.
ParmVarDecl **ParamInfo;
int NumMethodParams; // -1 if no parameters
/// List of attributes for this method declaration.
AttributeList *MethodAttrs;
/// instance (true) or class (false) method.
bool IsInstance : 1;
};
/// ObjcProtoMethodDecl - Each instance represents a method declared
@ -670,7 +672,7 @@ private:
///
class ObjcProtoMethodDecl : ObjcMethodDecl {
public:
ObjcProtoMethodDecl(SourceLocation L, IdentifierInfo *Id, QualType T,
ObjcProtoMethodDecl(SourceLocation L, SelectorInfo &Id, QualType T,
ParmVarDecl **paramInfo = 0, int numParams=-1,
AttributeList *M = 0, bool isInstance = true,
Decl *PrevDecl = 0) :

View File

@ -45,9 +45,8 @@ public:
IdentifierInfo();
~IdentifierInfo();
/// getName - Return the actual string for this identifier. The length of
/// this string is stored in NameLen, and the returned string is properly null
/// terminated.
/// getName - Return the actual string for this identifier. The returned
/// string is properly null terminated.
///
const char *getName() const {
// String data is stored immediately after the IdentifierInfo object.
@ -167,6 +166,54 @@ private:
void AddKeywords(const LangOptions &LangOpts);
};
/// SelectorInfo - One of these records is kept for each selector. Selectors
/// are created as a by-product of parsing a method declaration/definition,
/// message expression, or @selector expression.
class SelectorInfo {
void *ObjcMethodDecl; // FIXME: add setter/getter.
SelectorInfo(const SelectorInfo&); // NONCOPYABLE.
public:
SelectorInfo() : ObjcMethodDecl(0) {}
/// getName - Return the actual string for this selector. The returned
/// string is properly null terminated.
///
const char *getName() const {
// String data is stored immediately after the IdentifierInfo object.
return (const char*)(this+1);
}
};
/// SelectorTable - This table implements an efficient mapping from strings to
/// SelectorInfo nodes.
class SelectorTable {
// Shark shows that using MallocAllocator is *much* slower than using this
// BumpPtrAllocator!
typedef llvm::StringMap<SelectorInfo, llvm::BumpPtrAllocator> HashTableTy;
HashTableTy HashTable;
public:
SelectorTable() : HashTable(4096) { }
/// get - Return the selector info for the specified name.
///
SelectorInfo &get(const char *NameStart, const char *NameEnd) {
return HashTable.GetOrCreateValue(NameStart, NameEnd).getValue();
}
SelectorInfo &get(const char *Name) {
return get(Name, Name+strlen(Name));
}
typedef HashTableTy::const_iterator iterator;
typedef HashTableTy::const_iterator const_iterator;
iterator begin() const { return HashTable.begin(); }
iterator end() const { return HashTable.end(); }
/// PrintStats - Print some statistics to stderr that indicate how well the
/// hashing is doing.
void PrintStats() const;
};
} // end namespace clang
#endif