diff options
author | Steve Naroff <snaroff@apple.com> | 2007-09-17 14:16:13 +0000 |
---|---|---|
committer | Steve Naroff <snaroff@apple.com> | 2007-09-17 14:16:13 +0000 |
commit | 3f128ad2691d299b96663da85a9e069c4081ea7c (patch) | |
tree | dd6d3313ba38b90d71adfcf7b1d135465b54aaa2 | |
parent | 3860c11a3f8a862db25014d555745d8cfd3aaec9 (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42023 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | AST/ASTContext.cpp | 18 | ||||
-rw-r--r-- | AST/Decl.cpp | 35 | ||||
-rw-r--r-- | Lex/IdentifierTable.cpp | 31 | ||||
-rw-r--r-- | Sema/SemaDecl.cpp | 36 | ||||
-rw-r--r-- | clang.xcodeproj/project.pbxproj | 2 | ||||
-rw-r--r-- | include/clang/AST/ASTContext.h | 12 | ||||
-rw-r--r-- | include/clang/AST/Decl.h | 42 | ||||
-rw-r--r-- | include/clang/Lex/IdentifierTable.h | 53 |
8 files changed, 190 insertions, 39 deletions
diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp index 89da7dc867..df0398cd1b 100644 --- a/AST/ASTContext.cpp +++ b/AST/ASTContext.cpp @@ -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); +} + diff --git a/AST/Decl.cpp b/AST/Decl.cpp index 285b184217..ee5b073918 100644 --- a/AST/Decl.cpp +++ b/AST/Decl.cpp @@ -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; } } diff --git a/Lex/IdentifierTable.cpp b/Lex/IdentifierTable.cpp index d3faeb58db..c1c00d232b 100644 --- a/Lex/IdentifierTable.cpp +++ b/Lex/IdentifierTable.cpp @@ -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(); +} diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 16d72130f5..22a7c0418d 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -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); } diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 985c974dba..05e0bf8ace 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -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>"; }; diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index cc7ac8e0a9..5d753aa6fc 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -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 diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index e1829b90cc..4e064675b7 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -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) : diff --git a/include/clang/Lex/IdentifierTable.h b/include/clang/Lex/IdentifierTable.h index f18924c9d0..9a6a93ec36 100644 --- a/include/clang/Lex/IdentifierTable.h +++ b/include/clang/Lex/IdentifierTable.h @@ -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 |