[cfe-commits] r69989 - in /cfe/trunk: include/clang/AST/DeclObjC.h include/clang/Basic/OnDiskHashTable.h include/clang/Frontend/PCHBitCodes.h include/clang/Frontend/PCHReader.h include/clang/Frontend/PCHWriter.h include/clang/Sema/ExternalSemaSource.h lib/Frontend/PCHReader.cpp lib/Frontend/PCHWriter.cpp lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaDeclObjC.cpp lib/Sema/SemaExprObjC.cpp test/PCH/method_pool.h test/PCH/method_pool.m

Douglas Gregor dgregor at apple.com
Fri Apr 24 14:10:56 PDT 2009


Author: dgregor
Date: Fri Apr 24 16:10:55 2009
New Revision: 69989

URL: http://llvm.org/viewvc/llvm-project?rev=69989&view=rev
Log:
PCH support for the global method pool (= instance and factory method
pools, combined). The methods in the global method pool are lazily
loaded from an on-disk hash table when Sema looks into its version of
the hash tables.



Added:
    cfe/trunk/test/PCH/method_pool.h
    cfe/trunk/test/PCH/method_pool.m
Modified:
    cfe/trunk/include/clang/AST/DeclObjC.h
    cfe/trunk/include/clang/Basic/OnDiskHashTable.h
    cfe/trunk/include/clang/Frontend/PCHBitCodes.h
    cfe/trunk/include/clang/Frontend/PCHReader.h
    cfe/trunk/include/clang/Frontend/PCHWriter.h
    cfe/trunk/include/clang/Sema/ExternalSemaSource.h
    cfe/trunk/lib/Frontend/PCHReader.cpp
    cfe/trunk/lib/Frontend/PCHWriter.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp

Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=69989&r1=69988&r2=69989&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Fri Apr 24 16:10:55 2009
@@ -259,6 +259,21 @@
   }
 };
 
+/// 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;
+  }
+};
+
 /// ObjCContainerDecl - Represents a container for method declarations.
 /// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl, and
 /// ObjCProtocolDecl. 

Modified: cfe/trunk/include/clang/Basic/OnDiskHashTable.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/OnDiskHashTable.h?rev=69989&r1=69988&r2=69989&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/OnDiskHashTable.h (original)
+++ cfe/trunk/include/clang/Basic/OnDiskHashTable.h Fri Apr 24 16:10:55 2009
@@ -41,6 +41,11 @@
   return R + (R >> 5);
 }
 
+inline unsigned BernsteinHashPartial(const char* x, unsigned n, unsigned R) {
+  for (unsigned i = 0 ; i < n ; ++i, ++x) R = R * 33 + *x;
+  return R + (R >> 5);
+}
+
 namespace io {
 
 typedef uint32_t Offset;
@@ -199,7 +204,8 @@
       
       // Store the offset for the data of this bucket.
       B.off = out.tell();
-      
+      assert(B.off && "Cannot write a bucket at offset 0. Please add padding.");
+
       // Write out the number of items in the bucket.
       Emit16(out, B.length);
       
@@ -318,7 +324,7 @@
       
       // Read the key.
       const internal_key_type& X =
-        Info::ReadKey((const unsigned char* const) Items, L.first);
+        InfoPtr->ReadKey((const unsigned char* const) Items, L.first);
 
       // If the key doesn't match just skip reading the value.
       if (!Info::EqualKey(X, iKey)) {

Modified: cfe/trunk/include/clang/Frontend/PCHBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHBitCodes.h?rev=69989&r1=69988&r2=69989&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHBitCodes.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHBitCodes.h Fri Apr 24 16:10:55 2009
@@ -168,7 +168,10 @@
       LOCALLY_SCOPED_EXTERNAL_DECLS = 11,
       
       /// \brief Record code for the Objective-C Selector Table.
-      SELECTOR_TABLE = 12
+      SELECTOR_TABLE = 12,
+
+      /// \brief Record code for the Objective-C method pool,
+      METHOD_POOL = 13
     };
 
     /// \brief Record types used within a source manager block.

Modified: cfe/trunk/include/clang/Frontend/PCHReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHReader.h?rev=69989&r1=69988&r2=69989&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHReader.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHReader.h Fri Apr 24 16:10:55 2009
@@ -16,6 +16,7 @@
 #include "clang/Frontend/PCHBitCodes.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/Sema/ExternalSemaSource.h"
+#include "clang/AST/DeclObjC.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/IdentifierTable.h"
@@ -148,6 +149,13 @@
   /// \brief SelectorData, indexed by the selector ID minus one.
   llvm::SmallVector<Selector, 16> SelectorData;
 
+  /// \brief A pointer to an on-disk hash table of opaque type
+  /// PCHMethodPoolLookupTable.
+  ///
+  /// This hash table provides the instance and factory methods
+  /// associated with every selector known in the PCH file.
+  void *MethodPoolLookupTable;
+
   /// \brief The set of external definitions stored in the the PCH
   /// file.
   llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
@@ -223,7 +231,8 @@
 
   explicit PCHReader(Preprocessor &PP, ASTContext &Context) 
     : SemaObj(0), PP(PP), Context(Context), Consumer(0),
-      IdentifierTableData(0), NumStatementsRead(0), NumMacrosRead(0),
+      IdentifierTableData(0), IdentifierLookupTable(0),
+      MethodPoolLookupTable(0), NumStatementsRead(0), NumMacrosRead(0),
       NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0) { }
 
   ~PCHReader() {}
@@ -305,6 +314,14 @@
   /// the macro.
   virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd);
 
+  /// \brief Load the contents of the global method pool for a given
+  /// selector.
+  ///
+  /// \returns a pair of Objective-C methods lists containing the
+  /// instance and factory methods, respectively, with this selector.
+  virtual std::pair<ObjCMethodList, ObjCMethodList> 
+    ReadMethodPool(Selector Sel);
+
   void SetIdentifierInfo(unsigned ID, const IdentifierInfo *II);
 
   /// \brief Report a diagnostic.

Modified: cfe/trunk/include/clang/Frontend/PCHWriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHWriter.h?rev=69989&r1=69988&r2=69989&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHWriter.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHWriter.h Fri Apr 24 16:10:55 2009
@@ -159,6 +159,7 @@
   uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
   uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
   void WriteDeclsBlock(ASTContext &Context);
+  void WriteMethodPool(Sema &SemaRef);
   void WriteIdentifierTable(Preprocessor &PP);
   void WriteSelectorTable();
   void WriteAttributeRecord(const Attr *Attr);

Modified: cfe/trunk/include/clang/Sema/ExternalSemaSource.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ExternalSemaSource.h?rev=69989&r1=69988&r2=69989&view=diff

==============================================================================
--- cfe/trunk/include/clang/Sema/ExternalSemaSource.h (original)
+++ cfe/trunk/include/clang/Sema/ExternalSemaSource.h Fri Apr 24 16:10:55 2009
@@ -13,6 +13,7 @@
 #ifndef LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H
 #define LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H
 
+#include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExternalASTSource.h"
 
 namespace clang {
@@ -32,6 +33,16 @@
   /// being used to perform semantic analysis on the abstract syntax
   /// tree.
   virtual void InitializeSema(Sema &S) {}
+
+  /// \brief Load the contents of the global method pool for a given
+  /// selector.
+  ///
+  /// \returns a pair of Objective-C methods lists containing the
+  /// instance and factory methods, respectively, with this selector.
+  virtual std::pair<ObjCMethodList, ObjCMethodList> 
+  ReadMethodPool(Selector Sel) { 
+    return std::pair<ObjCMethodList, ObjCMethodList>();
+  }
   
   // isa/cast/dyn_cast support
   static bool classof(const ExternalASTSource *Source) { 

Modified: cfe/trunk/lib/Frontend/PCHReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReader.cpp?rev=69989&r1=69988&r2=69989&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/PCHReader.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReader.cpp Fri Apr 24 16:10:55 2009
@@ -1085,6 +1085,114 @@
 //===----------------------------------------------------------------------===//
 
 namespace {
+class VISIBILITY_HIDDEN PCHMethodPoolLookupTrait {
+  PCHReader &Reader;
+
+public:
+  typedef std::pair<ObjCMethodList, ObjCMethodList> data_type;
+
+  typedef Selector external_key_type;
+  typedef external_key_type internal_key_type;
+
+  explicit PCHMethodPoolLookupTrait(PCHReader &Reader) : Reader(Reader) { }
+  
+  static bool EqualKey(const internal_key_type& a,
+                       const internal_key_type& b) {
+    return a == b;
+  }
+  
+  static unsigned ComputeHash(Selector Sel) {
+    unsigned N = Sel.getNumArgs();
+    if (N == 0)
+      ++N;
+    unsigned R = 5381;
+    for (unsigned I = 0; I != N; ++I)
+      if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I))
+        R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R);
+    return R;
+  }
+  
+  // This hopefully will just get inlined and removed by the optimizer.
+  static const internal_key_type&
+  GetInternalKey(const external_key_type& x) { return x; }
+  
+  static std::pair<unsigned, unsigned>
+  ReadKeyDataLength(const unsigned char*& d) {
+    using namespace clang::io;
+    unsigned KeyLen = ReadUnalignedLE16(d);
+    unsigned DataLen = ReadUnalignedLE16(d);
+    return std::make_pair(KeyLen, DataLen);
+  }
+    
+  internal_key_type ReadKey(const unsigned char* d, unsigned n) {
+    using namespace clang::io;
+    SelectorTable &SelTable = Reader.getContext().Selectors;
+    unsigned N = ReadUnalignedLE16(d);
+    IdentifierInfo *FirstII 
+      = Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d));
+    if (N == 0)
+      return SelTable.getNullarySelector(FirstII);
+    else if (N == 1)
+      return SelTable.getUnarySelector(FirstII);
+
+    llvm::SmallVector<IdentifierInfo *, 16> Args;
+    Args.push_back(FirstII);
+    for (unsigned I = 1; I != N; ++I)
+      Args.push_back(Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d)));
+
+    return SelTable.getSelector(N, &Args[0]);
+  }
+    
+  data_type ReadData(Selector, const unsigned char* d, unsigned DataLen) {
+    using namespace clang::io;
+    unsigned NumInstanceMethods = ReadUnalignedLE16(d);
+    unsigned NumFactoryMethods = ReadUnalignedLE16(d);
+
+    data_type Result;
+
+    // Load instance methods
+    ObjCMethodList *Prev = 0;
+    for (unsigned I = 0; I != NumInstanceMethods; ++I) {
+      ObjCMethodDecl *Method 
+        = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d)));
+      if (!Result.first.Method) {
+        // This is the first method, which is the easy case.
+        Result.first.Method = Method;
+        Prev = &Result.first;
+        continue;
+      }
+
+      Prev->Next = new ObjCMethodList(Method, 0);
+      Prev = Prev->Next;
+    }
+
+    // Load factory methods
+    Prev = 0;
+    for (unsigned I = 0; I != NumFactoryMethods; ++I) {
+      ObjCMethodDecl *Method 
+        = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d)));
+      if (!Result.second.Method) {
+        // This is the first method, which is the easy case.
+        Result.second.Method = Method;
+        Prev = &Result.second;
+        continue;
+      }
+
+      Prev->Next = new ObjCMethodList(Method, 0);
+      Prev = Prev->Next;
+    }
+
+    return Result;
+  }
+};
+  
+} // end anonymous namespace  
+
+/// \brief The on-disk hash table used for the global method pool.
+typedef OnDiskChainedHashTable<PCHMethodPoolLookupTrait> 
+  PCHMethodPoolLookupTable;
+
+namespace {
 class VISIBILITY_HIDDEN PCHIdentifierLookupTrait {
   PCHReader &Reader;
 
@@ -1844,6 +1952,14 @@
       }
       LocallyScopedExternalDecls.swap(Record);
       break;
+
+    case pch::METHOD_POOL:
+      MethodPoolLookupTable 
+        = PCHMethodPoolLookupTable::Create(
+                        (const unsigned char *)BlobStart + Record[0],
+                        (const unsigned char *)BlobStart, 
+                        PCHMethodPoolLookupTrait(*this));
+      break;
     }
   }
   Error("Premature end of bitstream");
@@ -2539,6 +2655,7 @@
     return 0;
 
   unsigned Index = ID - 1;
+  assert(Index < DeclAlreadyLoaded.size() && "Declaration ID out of range");
   if (DeclAlreadyLoaded[Index])
     return reinterpret_cast<Decl *>(DeclOffsets[Index]);
 
@@ -2679,7 +2796,8 @@
 
 void PCHReader::InitializeSema(Sema &S) {
   SemaObj = &S;
- 
+  S.ExternalSource = this;
+
   // Makes sure any declarations that were deserialized "too early"
   // still get added to the identifier's declaration chains.
   for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) {
@@ -2719,6 +2837,21 @@
   return *Pos;
 }
 
+std::pair<ObjCMethodList, ObjCMethodList> 
+PCHReader::ReadMethodPool(Selector Sel) {
+  if (!MethodPoolLookupTable)
+    return std::pair<ObjCMethodList, ObjCMethodList>();
+
+  // Try to find this selector within our on-disk hash table.
+  PCHMethodPoolLookupTable *PoolTable
+    = (PCHMethodPoolLookupTable*)MethodPoolLookupTable;
+  PCHMethodPoolLookupTable::iterator Pos = PoolTable->find(Sel);
+  if (Pos == PoolTable->end())
+    return std::pair<ObjCMethodList, ObjCMethodList>();;
+
+  return *Pos;
+}
+
 void PCHReader::SetIdentifierInfo(unsigned ID, const IdentifierInfo *II) {
   assert(ID && "Non-zero identifier ID required");
   IdentifierData[ID - 1] = reinterpret_cast<uint64_t>(II);

Modified: cfe/trunk/lib/Frontend/PCHWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriter.cpp?rev=69989&r1=69988&r2=69989&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriter.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriter.cpp Fri Apr 24 16:10:55 2009
@@ -1774,6 +1774,176 @@
 }
 
 namespace {
+// Trait used for the on-disk hash table used in the method pool.
+class VISIBILITY_HIDDEN PCHMethodPoolTrait {
+  PCHWriter &Writer;
+
+public:
+  typedef Selector key_type;
+  typedef key_type key_type_ref;
+  
+  typedef std::pair<ObjCMethodList, ObjCMethodList> data_type;
+  typedef const data_type& data_type_ref;
+
+  explicit PCHMethodPoolTrait(PCHWriter &Writer) : Writer(Writer) { }
+  
+  static unsigned ComputeHash(Selector Sel) {
+    unsigned N = Sel.getNumArgs();
+    if (N == 0)
+      ++N;
+    unsigned R = 5381;
+    for (unsigned I = 0; I != N; ++I)
+      if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I))
+        R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R);
+    return R;
+  }
+  
+  std::pair<unsigned,unsigned> 
+    EmitKeyDataLength(llvm::raw_ostream& Out, Selector Sel,
+                      data_type_ref Methods) {
+    unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4);
+    clang::io::Emit16(Out, KeyLen);
+    unsigned DataLen = 2 + 2; // 2 bytes for each of the method counts
+    for (const ObjCMethodList *Method = &Methods.first; Method; 
+         Method = Method->Next)
+      if (Method->Method)
+        DataLen += 4;
+    for (const ObjCMethodList *Method = &Methods.second; Method; 
+         Method = Method->Next)
+      if (Method->Method)
+        DataLen += 4;
+    clang::io::Emit16(Out, DataLen);
+    return std::make_pair(KeyLen, DataLen);
+  }
+  
+  void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned) {
+    // FIXME: Keep track of the location of the key data (the
+    // selector), so we can fold the selector table's storage into
+    // this hash table.
+    unsigned N = Sel.getNumArgs();
+    clang::io::Emit16(Out, N);
+    if (N == 0)
+      N = 1;
+    for (unsigned I = 0; I != N; ++I)
+      clang::io::Emit32(Out, 
+                    Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I)));
+  }
+  
+  void EmitData(llvm::raw_ostream& Out, key_type_ref,
+                data_type_ref Methods, unsigned) {
+    unsigned NumInstanceMethods = 0;
+    for (const ObjCMethodList *Method = &Methods.first; Method; 
+         Method = Method->Next)
+      if (Method->Method)
+        ++NumInstanceMethods;
+
+    unsigned NumFactoryMethods = 0;
+    for (const ObjCMethodList *Method = &Methods.second; Method; 
+         Method = Method->Next)
+      if (Method->Method)
+        ++NumFactoryMethods;
+
+    clang::io::Emit16(Out, NumInstanceMethods);
+    clang::io::Emit16(Out, NumFactoryMethods);
+    for (const ObjCMethodList *Method = &Methods.first; Method; 
+         Method = Method->Next)
+      if (Method->Method)
+        clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
+    clang::io::Emit16(Out, NumFactoryMethods);
+    for (const ObjCMethodList *Method = &Methods.second; Method; 
+         Method = Method->Next)
+      if (Method->Method)
+        clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
+  }
+};
+} // end anonymous namespace
+
+/// \brief Write the method pool into the PCH file.
+///
+/// The method pool contains both instance and factory methods, stored
+/// in an on-disk hash table indexed by the selector.
+void PCHWriter::WriteMethodPool(Sema &SemaRef) {
+  using namespace llvm;
+
+  // Create and write out the blob that contains the instance and
+  // factor method pools.
+  bool Empty = true;
+  {
+    OnDiskChainedHashTableGenerator<PCHMethodPoolTrait> Generator;
+    
+    // Create the on-disk hash table representation. Start by
+    // iterating through the instance method pool.
+    PCHMethodPoolTrait::key_type Key;
+    for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
+           Instance = SemaRef.InstanceMethodPool.begin(), 
+           InstanceEnd = SemaRef.InstanceMethodPool.end();
+         Instance != InstanceEnd; ++Instance) {
+      // Check whether there is a factory method with the same
+      // selector.
+      llvm::DenseMap<Selector, ObjCMethodList>::iterator Factory
+        = SemaRef.FactoryMethodPool.find(Instance->first);
+
+      if (Factory == SemaRef.FactoryMethodPool.end())
+        Generator.insert(Instance->first,
+                         std::make_pair(Instance->second, 
+                                        ObjCMethodList()));
+      else
+        Generator.insert(Instance->first,
+                         std::make_pair(Instance->second, Factory->second));
+
+      Empty = false;
+    }
+
+    // Now iterate through the factory method pool, to pick up any
+    // selectors that weren't already in the instance method pool.
+    for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
+           Factory = SemaRef.FactoryMethodPool.begin(), 
+           FactoryEnd = SemaRef.FactoryMethodPool.end();
+         Factory != FactoryEnd; ++Factory) {
+      // Check whether there is an instance method with the same
+      // selector. If so, there is no work to do here.
+      llvm::DenseMap<Selector, ObjCMethodList>::iterator Instance
+        = SemaRef.InstanceMethodPool.find(Factory->first);
+
+      if (Instance == SemaRef.InstanceMethodPool.end())
+        Generator.insert(Factory->first,
+                         std::make_pair(ObjCMethodList(), Factory->second));
+
+      Empty = false;
+    }
+
+    if (Empty)
+      return;
+
+    // Create the on-disk hash table in a buffer.
+    llvm::SmallVector<char, 4096> MethodPool; 
+    uint32_t BucketOffset;
+    {
+      PCHMethodPoolTrait Trait(*this);
+      llvm::raw_svector_ostream Out(MethodPool);
+      // Make sure that no bucket is at offset 0
+      clang::io::Emit16(Out, 0);
+      BucketOffset = Generator.Emit(Out, Trait);
+    }
+
+    // Create a blob abbreviation
+    BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+    Abbrev->Add(BitCodeAbbrevOp(pch::METHOD_POOL));
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+    unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev);
+
+    // Write the identifier table
+    RecordData Record;
+    Record.push_back(pch::METHOD_POOL);
+    Record.push_back(BucketOffset);
+    Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, 
+                              &MethodPool.front(), 
+                              MethodPool.size());
+  }
+}
+
+namespace {
 class VISIBILITY_HIDDEN PCHIdentifierTableTrait {
   PCHWriter &Writer;
   Preprocessor &PP;
@@ -1880,6 +2050,8 @@
     {
       PCHIdentifierTableTrait Trait(*this, PP);
       llvm::raw_svector_ostream Out(IdentifierTable);
+      // Make sure that no bucket is at offset 0
+      clang::io::Emit16(Out, 0);
       BucketOffset = Generator.Emit(Out, Trait);
     }
 
@@ -2113,6 +2285,7 @@
   WritePreprocessor(PP);
   WriteTypesBlock(Context);
   WriteDeclsBlock(Context);
+  WriteMethodPool(SemaRef);
   WriteSelectorTable();
   WriteIdentifierTable(PP);
   Stream.EmitRecord(pch::TYPE_OFFSET, TypeOffsets);

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=69989&r1=69988&r2=69989&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Fri Apr 24 16:10:55 2009
@@ -163,8 +163,8 @@
 Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
            bool CompleteTranslationUnit)
   : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
-    Diags(PP.getDiagnostics()),
-    SourceMgr(PP.getSourceManager()), CurContext(0), PreDeclaratorDC(0),
+    Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), 
+    ExternalSource(0), CurContext(0), PreDeclaratorDC(0),
     CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()),
     GlobalNewDeleteDeclared(false), 
     CompleteTranslationUnit(CompleteTranslationUnit) {

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=69989&r1=69988&r2=69989&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Apr 24 16:10:55 2009
@@ -19,13 +19,13 @@
 #include "CXXFieldCollector.h"
 #include "SemaOverload.h"
 #include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclObjC.h"
 #include "clang/Parse/Action.h"
 #include "clang/Sema/SemaDiagnostic.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/OwningPtr.h"
-#include "clang/AST/DeclObjC.h"
 #include <string>
 #include <vector>
 
@@ -40,6 +40,7 @@
   class Decl;
   class DeclContext;
   class DeclSpec;
+  class ExternalSemaSource;
   class NamedDecl;
   class Stmt;
   class Expr;
@@ -128,6 +129,9 @@
   Diagnostic &Diags;
   SourceManager &SourceMgr;
 
+  /// \brief Source of additional semantic information.
+  ExternalSemaSource *ExternalSource;
+
   /// CurContext - This is the current declaration context of parsing.
   DeclContext *CurContext;
 
@@ -243,27 +247,17 @@
   /// unit.
   bool CompleteTranslationUnit;
 
-  /// 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;
-    }
-  };
+  typedef llvm::DenseMap<Selector, ObjCMethodList> MethodPool;
+
   /// Instance/Factory Method Pools - allows efficient lookup when typechecking
   /// messages to "id". 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").
-  llvm::DenseMap<Selector, ObjCMethodList> InstanceMethodPool;
-  llvm::DenseMap<Selector, ObjCMethodList> FactoryMethodPool;
+  MethodPool InstanceMethodPool;
+  MethodPool FactoryMethodPool;
   
+  MethodPool::iterator ReadMethodPool(Selector Sel, bool isInstance);
+
   /// Private Helper predicate to check for 'self'.
   bool isSelfExpr(Expr *RExpr);
 public:
@@ -1126,6 +1120,10 @@
   /// LookupInstanceMethodInGlobalPool - Returns the method and warns if
   /// there are multiple signatures.
   ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R);
+
+  /// LookupFactoryMethodInGlobalPool - Returns the method and warns if
+  /// there are multiple signatures.
+  ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R);
   
   /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods.
   void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method);

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=69989&r1=69988&r2=69989&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Fri Apr 24 16:10:55 2009
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Sema.h"
+#include "clang/Sema/ExternalSemaSource.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
@@ -1090,8 +1091,47 @@
   return true;
 }
 
+/// \brief Read the contents of the instance and factory method pools
+/// for a given selector from external storage.
+///
+/// This routine should only be called once, when neither the instance
+/// nor the factory method pool has an entry for this selector.
+Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel, 
+                                                bool isInstance) {
+  assert(ExternalSource && "We need an external AST source");
+  assert(InstanceMethodPool.find(Sel) == InstanceMethodPool.end() &&
+         "Selector data already loaded into the instance method pool");
+  assert(FactoryMethodPool.find(Sel) == FactoryMethodPool.end() &&
+         "Selector data already loaded into the factory method pool");
+
+  // Read the method list from the external source.
+  std::pair<ObjCMethodList, ObjCMethodList> Methods
+    = ExternalSource->ReadMethodPool(Sel);
+  
+  if (isInstance) {
+    if (Methods.second.Method)
+      FactoryMethodPool[Sel] = Methods.second;
+    return InstanceMethodPool.insert(std::make_pair(Sel, Methods.first)).first;
+  } 
+
+  if (Methods.first.Method)
+    InstanceMethodPool[Sel] = Methods.first;
+
+  return FactoryMethodPool.insert(std::make_pair(Sel, Methods.second)).first;
+}
+
 void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) {
-  ObjCMethodList &Entry = InstanceMethodPool[Method->getSelector()];
+  llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
+    = InstanceMethodPool.find(Method->getSelector());
+  if (Pos == InstanceMethodPool.end()) {
+    if (ExternalSource && !FactoryMethodPool.count(Method->getSelector()))
+      Pos = ReadMethodPool(Method->getSelector(), /*isInstance=*/true);
+    else
+      Pos = InstanceMethodPool.insert(std::make_pair(Method->getSelector(),
+                                                     ObjCMethodList())).first;
+  }
+
+  ObjCMethodList &Entry = Pos->second;
   if (Entry.Method == 0) {
     // Haven't seen a method with this selector name yet - add it.
     Entry.Method = Method;
@@ -1113,7 +1153,16 @@
 // FIXME: Finish implementing -Wno-strict-selector-match.
 ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel, 
                                                        SourceRange R) {
-  ObjCMethodList &MethList = InstanceMethodPool[Sel];
+  llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
+    = InstanceMethodPool.find(Sel);
+  if (Pos == InstanceMethodPool.end() && !FactoryMethodPool.count(Sel)) {
+    if (ExternalSource)
+      Pos = ReadMethodPool(Sel, /*isInstance=*/true);
+    else
+      return 0;
+  }
+
+  ObjCMethodList &MethList = Pos->second;
   bool issueWarning = false;
   
   if (MethList.Method && MethList.Next) {
@@ -1134,7 +1183,17 @@
 }
 
 void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
-  ObjCMethodList &FirstMethod = FactoryMethodPool[Method->getSelector()];
+  llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
+    = FactoryMethodPool.find(Method->getSelector());
+  if (Pos == FactoryMethodPool.end()) {
+    if (ExternalSource && !InstanceMethodPool.count(Method->getSelector()))
+      Pos = ReadMethodPool(Method->getSelector(), /*isInstance=*/false);
+    else
+      Pos = FactoryMethodPool.insert(std::make_pair(Method->getSelector(),
+                                                    ObjCMethodList())).first;
+  }
+
+  ObjCMethodList &FirstMethod = Pos->second;
   if (!FirstMethod.Method) {
     // Haven't seen a method with this selector name yet - add it.
     FirstMethod.Method = Method;
@@ -1156,6 +1215,37 @@
   }
 }
 
+ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel, 
+                                                      SourceRange R) {
+  llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
+    = FactoryMethodPool.find(Sel);
+  if (Pos == FactoryMethodPool.end()) {
+    if (ExternalSource && !InstanceMethodPool.count(Sel)) 
+      Pos = ReadMethodPool(Sel, /*isInstance=*/false);
+    else
+      return 0;
+  }
+
+  ObjCMethodList &MethList = Pos->second;
+  bool issueWarning = false;
+  
+  if (MethList.Method && MethList.Next) {
+    for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
+      // This checks if the methods differ by size & alignment.
+      if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true))
+        issueWarning = true;
+  }
+  if (issueWarning && (MethList.Method && MethList.Next)) {
+    Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
+    Diag(MethList.Method->getLocStart(), diag::note_using_decl)
+      << MethList.Method->getSourceRange();
+    for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
+      Diag(Next->Method->getLocStart(), diag::note_also_found_decl)
+        << Next->Method->getSourceRange();
+  }
+  return MethList.Method;
+}
+
 /// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods 
 /// have the property type and issue diagnostics if they don't.
 /// Also synthesize a getter/setter method if none exist (and update the

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=69989&r1=69988&r2=69989&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Fri Apr 24 16:10:55 2009
@@ -497,7 +497,7 @@
     ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(
                                Sel, SourceRange(lbrac,rbrac));
     if (!Method)
-      Method = FactoryMethodPool[Sel].Method;
+      Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac, rbrac));
     if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, 
                                   lbrac, rbrac, returnType))
       return true;
@@ -523,7 +523,7 @@
     if (!Method) {
       // If not messaging 'self', look for any factory method named 'Sel'.
       if (!isSelfExpr(RExpr)) {
-        Method = FactoryMethodPool[Sel].Method;
+        Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac));
         if (!Method) {
           Method = LookupInstanceMethodInGlobalPool(
                                    Sel, SourceRange(lbrac,rbrac));

Added: cfe/trunk/test/PCH/method_pool.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/method_pool.h?rev=69989&view=auto

==============================================================================
--- cfe/trunk/test/PCH/method_pool.h (added)
+++ cfe/trunk/test/PCH/method_pool.h Fri Apr 24 16:10:55 2009
@@ -0,0 +1,37 @@
+/* For use with the method_pool.m test */
+
+/* Whitespace below is significant */
+
+
+
+
+
+
+
+
+
+
+
+ at interface TestMethodPool1
++ alloc;
+- (double)instMethod:(int)foo;
+ at end
+
+ at interface TestMethodPool2
+- (char)instMethod:(int)foo;
+ at end
+
+ at implementation TestMethodPool1
++ alloc {
+}
+
+- (double)instMethod:(int)foo {
+  return foo;
+}
+ at end
+
+ at implementation TestMethodPool2
+- (char)instMethod:(int)foo {
+  return foo;
+}
+ at end

Added: cfe/trunk/test/PCH/method_pool.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/method_pool.m?rev=69989&view=auto

==============================================================================
--- cfe/trunk/test/PCH/method_pool.m (added)
+++ cfe/trunk/test/PCH/method_pool.m Fri Apr 24 16:10:55 2009
@@ -0,0 +1,21 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/method_pool.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -x=objective-c -emit-pch -o %t %S/method_pool.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s 
+
+int message_id(id x) {
+   return [x instMethod:17]; // expected-warning{{multiple methods}}
+}
+
+
+
+
+
+/* Whitespace below is significant */
+/* expected-note{{using}} */
+
+
+
+/* expected-note{{also}} */





More information about the cfe-commits mailing list