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/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));