From a0f31a01f34dbde84b331cf49685c04cf02c8250 Mon Sep 17 00:00:00 2001 From: Manman Ren Date: Fri, 29 Apr 2016 19:04:05 +0000 Subject: [PATCH] Method Pool in modules: we make sure that if a module contains an entry for a selector, the entry should be complete, containing everything introduced by that module and all modules it imports. Before writing out the method pool of a module, we sync up the out of date selectors by pulling in methods for the selectors, from all modules it imports. In ReadMethodPool, after pulling in the method pool entry for module A, this lets us skip the modules that module A imports. rdar://problem/25900131 llvm-svn: 268091 --- clang/include/clang/Sema/ExternalSemaSource.h | 4 ++++ .../clang/Sema/MultiplexExternalSemaSource.h | 4 ++++ clang/include/clang/Sema/Sema.h | 1 + clang/include/clang/Serialization/ASTReader.h | 8 ++++++++ clang/lib/Sema/MultiplexExternalSemaSource.cpp | 5 +++++ clang/lib/Sema/Sema.cpp | 1 + clang/lib/Sema/SemaDeclObjC.cpp | 6 ++++++ clang/lib/Serialization/ASTReader.cpp | 9 +++++++++ clang/lib/Serialization/ASTWriter.cpp | 13 +++++++++++++ clang/test/Modules/Inputs/MethodPoolCombined1.h | 6 ++++++ clang/test/Modules/Inputs/MethodPoolCombined2.h | 1 + clang/test/Modules/Inputs/MethodPoolString1.h | 4 ++++ clang/test/Modules/Inputs/MethodPoolString2.h | 4 ++++ clang/test/Modules/Inputs/module.map | 17 +++++++++++++++++ clang/test/Modules/method_pool_write.m | 11 +++++++++++ 15 files changed, 94 insertions(+) create mode 100644 clang/test/Modules/Inputs/MethodPoolCombined1.h create mode 100644 clang/test/Modules/Inputs/MethodPoolCombined2.h create mode 100644 clang/test/Modules/Inputs/MethodPoolString1.h create mode 100644 clang/test/Modules/Inputs/MethodPoolString2.h create mode 100644 clang/test/Modules/method_pool_write.m diff --git a/clang/include/clang/Sema/ExternalSemaSource.h b/clang/include/clang/Sema/ExternalSemaSource.h index 2fdc42b1ac14..c2b13046d709 100644 --- a/clang/include/clang/Sema/ExternalSemaSource.h +++ b/clang/include/clang/Sema/ExternalSemaSource.h @@ -70,6 +70,10 @@ public: /// selector. virtual void ReadMethodPool(Selector Sel); + /// Load the contents of the global method pool for a given + /// selector if necessary. + virtual void updateOutOfDateSelector(Selector Sel); + /// \brief Load the set of namespaces that are known to the external source, /// which will be used during typo correction. virtual void ReadKnownNamespaces( diff --git a/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/clang/include/clang/Sema/MultiplexExternalSemaSource.h index 5f43f4051aac..9bf8cd3d9252 100644 --- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h +++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h @@ -203,6 +203,10 @@ public: /// selector. void ReadMethodPool(Selector Sel) override; + /// Load the contents of the global method pool for a given + /// selector if necessary. + void updateOutOfDateSelector(Selector Sel) override; + /// \brief Load the set of namespaces that are known to the external source, /// which will be used during typo correction. void diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a0dcd701df62..7731569fbce6 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1017,6 +1017,7 @@ public: llvm::SmallSet SpecialMembersBeingDeclared; void ReadMethodPool(Selector Sel); + void updateOutOfDateSelector(Selector Sel); /// Private Helper predicate to check for 'self'. bool isSelfExpr(Expr *RExpr); diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index a80989d88611..6e1cb0a916c3 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -653,6 +653,10 @@ private: /// global method pool for this selector. llvm::DenseMap SelectorGeneration; + /// Whether a selector is out of date. We mark a selector as out of date + /// if we load another module after the method pool entry was pulled in. + llvm::DenseMap SelectorOutOfDate; + struct PendingMacroInfo { ModuleFile *M; uint64_t MacroDirectivesOffset; @@ -1781,6 +1785,10 @@ public: /// selector. void ReadMethodPool(Selector Sel) override; + /// Load the contents of the global method pool for a given + /// selector if necessary. + void updateOutOfDateSelector(Selector Sel) override; + /// \brief Load the set of namespaces that are known to the external source, /// which will be used during typo correction. void ReadKnownNamespaces( diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 89eec242eb1d..eee4c00324ba 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -197,6 +197,11 @@ void MultiplexExternalSemaSource::ReadMethodPool(Selector Sel) { Sources[i]->ReadMethodPool(Sel); } +void MultiplexExternalSemaSource::updateOutOfDateSelector(Selector Sel) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->updateOutOfDateSelector(Sel); +} + void MultiplexExternalSemaSource::ReadKnownNamespaces( SmallVectorImpl &Namespaces){ for(size_t i = 0; i < Sources.size(); ++i) diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 541b3180d8c4..d8d10b637ec0 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1237,6 +1237,7 @@ void Sema::ActOnComment(SourceRange Comment) { ExternalSemaSource::~ExternalSemaSource() {} void ExternalSemaSource::ReadMethodPool(Selector Sel) { } +void ExternalSemaSource::updateOutOfDateSelector(Selector Sel) { } void ExternalSemaSource::ReadKnownNamespaces( SmallVectorImpl &Namespaces) { diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 8090bec4fab2..400dc637754b 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -3305,6 +3305,12 @@ void Sema::ReadMethodPool(Selector Sel) { ExternalSource->ReadMethodPool(Sel); } +void Sema::updateOutOfDateSelector(Selector Sel) { + if (!ExternalSource) + return; + ExternalSource->updateOutOfDateSelector(Sel); +} + void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool instance) { // Ignore methods of invalid containers. diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 910f5dcf779c..aa672b3a7ecf 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -3606,6 +3606,9 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, Id != IdEnd; ++Id) Id->second->setOutOfDate(true); } + // Mark selectors as out of date. + for (auto Sel : SelectorGeneration) + SelectorOutOfDate[Sel.first] = true; // Resolve any unresolved module exports. for (unsigned I = 0, N = UnresolvedModuleRefs.size(); I != N; ++I) { @@ -7139,6 +7142,7 @@ void ASTReader::ReadMethodPool(Selector Sel) { unsigned &Generation = SelectorGeneration[Sel]; unsigned PriorGeneration = Generation; Generation = getGeneration(); + SelectorOutOfDate[Sel] = false; // Search for methods defined with this selector. ++NumMethodPoolLookups; @@ -7170,6 +7174,11 @@ void ASTReader::ReadMethodPool(Selector Sel) { addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second); } +void ASTReader::updateOutOfDateSelector(Selector Sel) { + if (SelectorOutOfDate[Sel]) + ReadMethodPool(Sel); +} + void ASTReader::ReadKnownNamespaces( SmallVectorImpl &Namespaces) { Namespaces.clear(); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 32c9c4787c4e..606228af7536 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4387,6 +4387,19 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, } } + // For method pool in the module, if it contains an entry for a selector, + // the entry should be complete, containing everything introduced by that + // module and all modules it imports. It's possible that the entry is out of + // date, so we need to pull in the new content here. + + // It's possible that updateOutOfDateSelector can update SelectorIDs. To be + // safe, we copy all selectors out. + llvm::SmallVector AllSelectors; + for (auto &SelectorAndID : SelectorIDs) + AllSelectors.push_back(SelectorAndID.first); + for (auto &Selector : AllSelectors) + SemaRef.updateOutOfDateSelector(Selector); + // Form the record of special types. RecordData SpecialTypes; AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes); diff --git a/clang/test/Modules/Inputs/MethodPoolCombined1.h b/clang/test/Modules/Inputs/MethodPoolCombined1.h new file mode 100644 index 000000000000..057b7388b35f --- /dev/null +++ b/clang/test/Modules/Inputs/MethodPoolCombined1.h @@ -0,0 +1,6 @@ + +@import MethodPoolString1; +@interface A +- (int)stringValue; +@end + diff --git a/clang/test/Modules/Inputs/MethodPoolCombined2.h b/clang/test/Modules/Inputs/MethodPoolCombined2.h new file mode 100644 index 000000000000..166906e32e39 --- /dev/null +++ b/clang/test/Modules/Inputs/MethodPoolCombined2.h @@ -0,0 +1 @@ +@import MethodPoolString2; diff --git a/clang/test/Modules/Inputs/MethodPoolString1.h b/clang/test/Modules/Inputs/MethodPoolString1.h new file mode 100644 index 000000000000..c64ad950033e --- /dev/null +++ b/clang/test/Modules/Inputs/MethodPoolString1.h @@ -0,0 +1,4 @@ + +@interface S1 +- (int)stringValue; +@end diff --git a/clang/test/Modules/Inputs/MethodPoolString2.h b/clang/test/Modules/Inputs/MethodPoolString2.h new file mode 100644 index 000000000000..30e9bfb0027d --- /dev/null +++ b/clang/test/Modules/Inputs/MethodPoolString2.h @@ -0,0 +1,4 @@ + +@interface S2 +- (int)stringValue; +@end diff --git a/clang/test/Modules/Inputs/module.map b/clang/test/Modules/Inputs/module.map index 632517dd363f..1249387b9d9f 100644 --- a/clang/test/Modules/Inputs/module.map +++ b/clang/test/Modules/Inputs/module.map @@ -393,3 +393,20 @@ module ElaboratedTypeStructs { header "elaborated-type-structs.h" } } + +// We import a module, then declare a method with selector stringValue in +// MethodPoolCombined1.h. In MethodPoolCombined2.h, we import another module +// that also contains a method for selector stringValue. We make sure that +// the method pool entry for stringValue in this module is complete. +module MethodPoolCombined { + header "MethodPoolCombined1.h" + header "MethodPoolCombined2.h" +} + +module MethodPoolString1 { + header "MethodPoolString1.h" +} + +module MethodPoolString2 { + header "MethodPoolString2.h" +} diff --git a/clang/test/Modules/method_pool_write.m b/clang/test/Modules/method_pool_write.m new file mode 100644 index 000000000000..b7f8ac64b4d3 --- /dev/null +++ b/clang/test/Modules/method_pool_write.m @@ -0,0 +1,11 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -fsyntax-only -I %S/Inputs %s -verify +// expected-no-diagnostics + +@import MethodPoolCombined; +@import MethodPoolString2; + +void message_kindof_object(__kindof S2 *kindof_S2) { + [kindof_S2 stringValue]; +} +