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);
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index de4b999..581ca05 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -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);
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 3702c89..367c9f5 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -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) {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b3cb5e2..7426965 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -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);
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index f4014d1..05e471b 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -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
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index d48ba44..f2cd001 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -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));