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.




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69989 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 62d0ba4..5a1e882 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -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);