]> granicus.if.org Git - clang/commitdiff
Method Pool in modules: we make sure that if a module contains an entry for
authorManman Ren <manman.ren@gmail.com>
Fri, 29 Apr 2016 19:04:05 +0000 (19:04 +0000)
committerManman Ren <manman.ren@gmail.com>
Fri, 29 Apr 2016 19:04:05 +0000 (19:04 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@268091 91177308-0d34-0410-b5e6-96231b3b80d8

15 files changed:
include/clang/Sema/ExternalSemaSource.h
include/clang/Sema/MultiplexExternalSemaSource.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTReader.h
lib/Sema/MultiplexExternalSemaSource.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaDeclObjC.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/Modules/Inputs/MethodPoolCombined1.h [new file with mode: 0644]
test/Modules/Inputs/MethodPoolCombined2.h [new file with mode: 0644]
test/Modules/Inputs/MethodPoolString1.h [new file with mode: 0644]
test/Modules/Inputs/MethodPoolString2.h [new file with mode: 0644]
test/Modules/Inputs/module.map
test/Modules/method_pool_write.m [new file with mode: 0644]

index 2fdc42b1ac14478410b7f5b5e377432dcba4da1a..c2b13046d7090c68bfed4e1837695b386fc39720 100644 (file)
@@ -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(
index 5f43f4051aacde8f74483f9fbdfe06ad28ac3b7c..9bf8cd3d92528f35772c948fd5d23edec2226d08 100644 (file)
@@ -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
index a0dcd701df6200d0ea9352e36927c3387314cd12..7731569fbce65422498ef3468f0be64b9b91c168 100644 (file)
@@ -1017,6 +1017,7 @@ public:
   llvm::SmallSet<SpecialMemberDecl, 4> SpecialMembersBeingDeclared;
 
   void ReadMethodPool(Selector Sel);
+  void updateOutOfDateSelector(Selector Sel);
 
   /// Private Helper predicate to check for 'self'.
   bool isSelfExpr(Expr *RExpr);
index a80989d88611e9a7181f51353a5e22dd68ea9028..6e1cb0a916c32ce498186a60a8578910e93d91e9 100644 (file)
@@ -653,6 +653,10 @@ private:
   /// global method pool for this selector.
   llvm::DenseMap<Selector, unsigned> 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<Selector, bool> 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(
index 89eec242eb1d291c79055eb69bd754829be738f8..eee4c00324baf9bb74115f0b4cf581d6f2ff99b7 100644 (file)
@@ -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<NamespaceDecl*> &Namespaces){
   for(size_t i = 0; i < Sources.size(); ++i)
index 541b3180d8c4ecbfa5f44bdf1c1d301a0f899cfc..d8d10b637ec0d5ea295de71326f9f27c88badb03 100644 (file)
@@ -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<NamespaceDecl *> &Namespaces) {
index 8090bec4fab211cbdb4850db19b5c177c788d414..400dc637754b1fd17b51d2642b6a7fa5ff0c87ac 100644 (file)
@@ -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.
index 910f5dcf779cbc4679ea5eace72f4c094d68fe66..aa672b3a7ecf0f2ee4e65aa174a4aba57d887197 100644 (file)
@@ -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<NamespaceDecl *> &Namespaces) {
   Namespaces.clear();
index 32c9c4787c4e0c2f6028f0f83fc9cef2d5207464..606228af75369c4cef3bca10ddf76c5063292b21 100644 (file)
@@ -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<Selector, 256> 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/test/Modules/Inputs/MethodPoolCombined1.h b/test/Modules/Inputs/MethodPoolCombined1.h
new file mode 100644 (file)
index 0000000..057b738
--- /dev/null
@@ -0,0 +1,6 @@
+
+@import MethodPoolString1;
+@interface A
+- (int)stringValue;
+@end
+
diff --git a/test/Modules/Inputs/MethodPoolCombined2.h b/test/Modules/Inputs/MethodPoolCombined2.h
new file mode 100644 (file)
index 0000000..166906e
--- /dev/null
@@ -0,0 +1 @@
+@import MethodPoolString2;
diff --git a/test/Modules/Inputs/MethodPoolString1.h b/test/Modules/Inputs/MethodPoolString1.h
new file mode 100644 (file)
index 0000000..c64ad95
--- /dev/null
@@ -0,0 +1,4 @@
+
+@interface S1
+- (int)stringValue;
+@end
diff --git a/test/Modules/Inputs/MethodPoolString2.h b/test/Modules/Inputs/MethodPoolString2.h
new file mode 100644 (file)
index 0000000..30e9bfb
--- /dev/null
@@ -0,0 +1,4 @@
+
+@interface S2
+- (int)stringValue;
+@end
index 632517dd363fbe80a0b9c4d62c1aa2e2a2eada53..1249387b9d9fddd159638f2b16b4e08871bb6752 100644 (file)
@@ -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/test/Modules/method_pool_write.m b/test/Modules/method_pool_write.m
new file mode 100644 (file)
index 0000000..b7f8ac6
--- /dev/null
@@ -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];
+}
+