diff --git a/include/clang/Sema/ObjCMethodList.h b/include/clang/Sema/ObjCMethodList.h index 225c13776c59edd60b0b9db5ea604a6827490de7..94e380721de26666288847a80421bfd2e496b24d 100644 --- a/include/clang/Sema/ObjCMethodList.h +++ b/include/clang/Sema/ObjCMethodList.h @@ -14,6 +14,8 @@ #ifndef LLVM_CLANG_SEMA_OBJC_METHOD_LIST_H #define LLVM_CLANG_SEMA_OBJC_METHOD_LIST_H +#include "llvm/ADT/PointerIntPair.h" + namespace clang { class ObjCMethodDecl; @@ -21,16 +23,17 @@ class ObjCMethodDecl; /// ObjCMethodList - a linked list of methods with different signatures. struct ObjCMethodList { ObjCMethodDecl *Method; - ObjCMethodList *Next; - - ObjCMethodList() { - Method = 0; - Next = 0; - } - ObjCMethodList(ObjCMethodDecl *M, ObjCMethodList *C) { - Method = M; - Next = C; - } + /// \brief The next list object and 2 bits for extra info. + llvm::PointerIntPair<ObjCMethodList *, 2> NextAndExtraBits; + + ObjCMethodList() : Method(0) { } + ObjCMethodList(ObjCMethodDecl *M, ObjCMethodList *C) + : Method(M), NextAndExtraBits(C, 0) { } + + ObjCMethodList *getNext() const { return NextAndExtraBits.getPointer(); } + unsigned getBits() const { return NextAndExtraBits.getInt(); } + void setNext(ObjCMethodList *L) { NextAndExtraBits.setPointer(L); } + void setBits(unsigned B) { NextAndExtraBits.setInt(B); } }; } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index f95d6a4321d256f0f05162ba7749dc9eae7ecca1..b188ef36ae4e3bc2bfbf3f285f4e8c2675eecc9d 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -770,6 +770,8 @@ public: /// We need to maintain a list, since selectors can have differing signatures /// across classes. In Cocoa, this happens to be extremely uncommon (only 1% /// of selectors are "overloaded"). + /// At the head of the list it is recorded whether there were 0, 1, or >= 2 + /// methods inside categories with a particular selector. GlobalMethodPool MethodPool; /// Method selectors used in a \@selector expression. Used for implementation diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index a72e74b5aa9e6143ec09138575f653d38a7843a2..fd2ce1749fe87929f5da634c0715091a6ac6aad6 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -5471,7 +5471,7 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, M != MEnd; ++M) { for (ObjCMethodList *MethList = &M->second.second; MethList && MethList->Method; - MethList = MethList->Next) { + MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) continue; @@ -5644,7 +5644,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, M != MEnd; ++M) { for (ObjCMethodList *MethList = &M->second.first; MethList && MethList->Method; - MethList = MethList->Next) { + MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) continue; @@ -7085,7 +7085,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, for (ObjCMethodList *MethList = IsInstanceMethod ? &M->second.first : &M->second.second; MethList && MethList->Method; - MethList = MethList->Next) { + MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) continue; diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 48f0decc2c896e4b755aa43c39f25ae0f0cc3633..a6f8bf7f57466dc4c62731905447bdf14f6ec495 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -2085,17 +2085,23 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left, } void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { + // Record at the head of the list whether there were 0, 1, or >= 2 methods + // inside categories. + if (isa<ObjCCategoryDecl>(Method->getDeclContext())) + if (List->getBits() < 2) + List->setBits(List->getBits()+1); + // If the list is empty, make it a singleton list. if (List->Method == 0) { List->Method = Method; - List->Next = 0; + List->setNext(0); return; } // We've seen a method with this name, see if we have already seen this type // signature. ObjCMethodList *Previous = List; - for (; List; Previous = List, List = List->Next) { + for (; List; Previous = List, List = List->getNext()) { if (!MatchTwoMethodDeclarations(Method, List->Method)) continue; @@ -2124,7 +2130,7 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { // We have a new signature for an existing method - add it. // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>(); - Previous->Next = new (Mem) ObjCMethodList(Method, 0); + Previous->setNext(new (Mem) ObjCMethodList(Method, 0)); } /// \brief Read the contents of the method pool for a given selector from @@ -2186,7 +2192,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, // Gather the non-hidden methods. ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; llvm::SmallVector<ObjCMethodDecl *, 4> Methods; - for (ObjCMethodList *M = &MethList; M; M = M->Next) { + for (ObjCMethodList *M = &MethList; M; M = M->getNext()) { if (M->Method && !M->Method->isHidden()) { // If we're not supposed to warn about mismatches, we're done. if (!warn) diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 4302f8bb53be4082b6e1988c761b2bc1d2e40d02..9893823a122a11912aa7e46dc7a1d73de435ad1c 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -428,8 +428,12 @@ ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d, data_type Result; Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d)); - unsigned NumInstanceMethods = ReadUnalignedLE16(d); - unsigned NumFactoryMethods = ReadUnalignedLE16(d); + unsigned NumInstanceMethodsAndBits = ReadUnalignedLE16(d); + unsigned NumFactoryMethodsAndBits = ReadUnalignedLE16(d); + Result.InstanceBits = NumInstanceMethodsAndBits & 0x3; + Result.FactoryBits = NumFactoryMethodsAndBits & 0x3; + unsigned NumInstanceMethods = NumInstanceMethodsAndBits >> 2; + unsigned NumFactoryMethods = NumFactoryMethodsAndBits >> 2; // Load instance methods for (unsigned I = 0; I != NumInstanceMethods; ++I) { @@ -2736,7 +2740,7 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) { ObjCMethodList &Start = Method->isInstanceMethod()? Known->second.first : Known->second.second; bool Found = false; - for (ObjCMethodList *List = &Start; List; List = List->Next) { + for (ObjCMethodList *List = &Start; List; List = List->getNext()) { if (!Found) { if (List->Method == Method) { Found = true; @@ -2746,8 +2750,8 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) { } } - if (List->Next) - List->Method = List->Next->Method; + if (List->getNext()) + List->Method = List->getNext()->Method; else List->Method = Method; } @@ -6114,13 +6118,16 @@ namespace clang { namespace serialization { ASTReader &Reader; Selector Sel; unsigned PriorGeneration; + unsigned InstanceBits; + unsigned FactoryBits; SmallVector<ObjCMethodDecl *, 4> InstanceMethods; SmallVector<ObjCMethodDecl *, 4> FactoryMethods; public: ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel, unsigned PriorGeneration) - : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration) { } + : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration), + InstanceBits(0), FactoryBits(0) { } static bool visit(ModuleFile &M, void *UserData) { ReadMethodPoolVisitor *This @@ -6153,6 +6160,8 @@ namespace clang { namespace serialization { This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end()); This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end()); + This->InstanceBits = Data.InstanceBits; + This->FactoryBits = Data.FactoryBits; return true; } @@ -6165,6 +6174,9 @@ namespace clang { namespace serialization { ArrayRef<ObjCMethodDecl *> getFactoryMethods() const { return FactoryMethods; } + + unsigned getInstanceBits() const { return InstanceBits; } + unsigned getFactoryBits() const { return FactoryBits; } }; } } // end namespace clang::serialization @@ -6202,6 +6214,8 @@ void ASTReader::ReadMethodPool(Selector Sel) { addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first); addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second); + Pos->second.first.setBits(Visitor.getInstanceBits()); + Pos->second.second.setBits(Visitor.getFactoryBits()); } void ASTReader::ReadKnownNamespaces( diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h index 327da4403a3a48fc270388c6e054e283f684236f..9149b18480f96685016ec42a52af7e0586b232db 100644 --- a/lib/Serialization/ASTReaderInternals.h +++ b/lib/Serialization/ASTReaderInternals.h @@ -152,6 +152,8 @@ class ASTSelectorLookupTrait { public: struct data_type { SelectorID ID; + unsigned InstanceBits; + unsigned FactoryBits; SmallVector<ObjCMethodDecl *, 2> Instance; SmallVector<ObjCMethodDecl *, 2> Factory; }; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index e98708d8f5ed8e0a38663cba9717025a6ee51567..b6d25d22d59e9bedec5a3f2cb4a97708a947f853 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -2692,11 +2692,11 @@ public: clang::io::Emit16(Out, KeyLen); unsigned DataLen = 4 + 2 + 2; // 2 bytes for each of the method counts for (const ObjCMethodList *Method = &Methods.Instance; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) DataLen += 4; for (const ObjCMethodList *Method = &Methods.Factory; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) DataLen += 4; clang::io::Emit16(Out, DataLen); @@ -2722,24 +2722,31 @@ public: clang::io::Emit32(Out, Methods.ID); unsigned NumInstanceMethods = 0; for (const ObjCMethodList *Method = &Methods.Instance; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) ++NumInstanceMethods; unsigned NumFactoryMethods = 0; for (const ObjCMethodList *Method = &Methods.Factory; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) ++NumFactoryMethods; - clang::io::Emit16(Out, NumInstanceMethods); - clang::io::Emit16(Out, NumFactoryMethods); + unsigned InstanceBits = Methods.Instance.getBits(); + assert(InstanceBits < 4); + unsigned NumInstanceMethodsAndBits = + (NumInstanceMethods << 2) | InstanceBits; + unsigned FactoryBits = Methods.Factory.getBits(); + assert(FactoryBits < 4); + unsigned NumFactoryMethodsAndBits = (NumFactoryMethods << 2) | FactoryBits; + clang::io::Emit16(Out, NumInstanceMethodsAndBits); + clang::io::Emit16(Out, NumFactoryMethodsAndBits); for (const ObjCMethodList *Method = &Methods.Instance; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); for (const ObjCMethodList *Method = &Methods.Factory; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); @@ -2788,12 +2795,12 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { // Selector already exists. Did it change? bool changed = false; for (ObjCMethodList *M = &Data.Instance; !changed && M && M->Method; - M = M->Next) { + M = M->getNext()) { if (!M->Method->isFromASTFile()) changed = true; } for (ObjCMethodList *M = &Data.Factory; !changed && M && M->Method; - M = M->Next) { + M = M->getNext()) { if (!M->Method->isFromASTFile()) changed = true; }