OSDN Git Service

[ORC] Remove symbols from dependency lists when failing materialization.
authorLang Hames <lhames@gmail.com>
Thu, 25 Apr 2019 23:31:33 +0000 (23:31 +0000)
committerLang Hames <lhames@gmail.com>
Thu, 25 Apr 2019 23:31:33 +0000 (23:31 +0000)
When failing materialization of a symbol X, remove X from the dependants list
of any of X's dependencies. This ensures that when X's dependencies are
emitted (or fail themselves) they do not try to access the no-longer-existing
MaterializationInfo for X.

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

lib/ExecutionEngine/Orc/Core.cpp
unittests/ExecutionEngine/Orc/CMakeLists.txt
unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp

index cc52b56..4aa763f 100644 (file)
@@ -390,8 +390,8 @@ SymbolNameSet MaterializationResponsibility::getRequestedSymbols() const {
 }
 
 void MaterializationResponsibility::resolve(const SymbolMap &Symbols) {
-  LLVM_DEBUG(dbgs() << "In " << JD.getName() << " resolving " << Symbols
-                    << "\n");
+  LLVM_DEBUG(
+      { dbgs() << "In " << JD.getName() << " resolving " << Symbols << "\n"; });
 #ifndef NDEBUG
   for (auto &KV : Symbols) {
     auto I = SymbolFlags.find(KV.first);
@@ -412,6 +412,11 @@ void MaterializationResponsibility::resolve(const SymbolMap &Symbols) {
 }
 
 void MaterializationResponsibility::emit() {
+
+  LLVM_DEBUG({
+    dbgs() << "In " << JD.getName() << " emitting " << SymbolFlags << "\n";
+  });
+
 #ifndef NDEBUG
   for (auto &KV : SymbolFlags)
     assert(!KV.second.isMaterializing() &&
@@ -441,6 +446,11 @@ Error MaterializationResponsibility::defineMaterializing(
 
 void MaterializationResponsibility::failMaterialization() {
 
+  LLVM_DEBUG({
+    dbgs() << "In " << JD.getName() << " failing materialization for "
+           << SymbolFlags << "\n";
+  });
+
   SymbolNameSet FailedSymbols;
   for (auto &KV : SymbolFlags)
     FailedSymbols.insert(KV.first);
@@ -1025,6 +1035,23 @@ void JITDylib::notifyFailed(const SymbolNameSet &FailedSymbols) {
       if (MII == MaterializingInfos.end())
         continue;
 
+      // Remove this symbol from the dependants list of any dependencies.
+      for (auto &KV : MII->second.UnemittedDependencies) {
+        auto *DependencyJD = KV.first;
+        auto &Dependencies = KV.second;
+        for (auto &DependencyName : Dependencies) {
+          auto DependencyMII =
+              DependencyJD->MaterializingInfos.find(DependencyName);
+          assert(DependencyMII != DependencyJD->MaterializingInfos.end() &&
+                 "Unemitted dependency must have a MaterializingInfo entry");
+          assert(DependencyMII->second.Dependants.count(this) &&
+                 "Dependency's dependants list does not contain this JITDylib");
+          assert(DependencyMII->second.Dependants[this].count(Name) &&
+                 "Dependency's dependants list does not contain dependant");
+          DependencyMII->second.Dependants[this].erase(Name);
+        }
+      }
+
       // Copy all the queries to the FailedQueries list, then abandon them.
       // This has to be a copy, and the copy has to come before the abandon
       // operation: Each Q.detach() call will reach back into this
index 019437d..76b18fd 100644 (file)
@@ -30,4 +30,6 @@ add_llvm_unittest(OrcJITTests
   ThreadSafeModuleTest.cpp
   )
 
-target_link_libraries(OrcJITTests PRIVATE ${ORC_JIT_TEST_LIBS})
+target_link_libraries(OrcJITTests PRIVATE
+                        LLVMTestingSupport
+                        ${ORC_JIT_TEST_LIBS})
index 84b19ec..7b29f4c 100644 (file)
@@ -10,6 +10,7 @@
 #include "llvm/Config/llvm-config.h"
 #include "llvm/ExecutionEngine/Orc/Core.h"
 #include "llvm/ExecutionEngine/Orc/OrcError.h"
+#include "llvm/Testing/Support/Error.h"
 
 #include <set>
 #include <thread>
@@ -730,6 +731,41 @@ TEST_F(CoreAPIsStandardTest, FailResolution) {
   }
 }
 
+TEST_F(CoreAPIsStandardTest, FailEmissionEarly) {
+
+  cantFail(JD.define(absoluteSymbols({{Baz, BazSym}})));
+
+  auto MU = llvm::make_unique<SimpleMaterializationUnit>(
+      SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
+      [&](MaterializationResponsibility R) {
+        R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}));
+
+        ES.lookup(
+            JITDylibSearchList({{&JD, false}}), SymbolNameSet({Baz}),
+            [&R](Expected<SymbolMap> Result) {
+              // Called when "baz" is resolved. We don't actually depend
+              // on or care about baz, but use it to trigger failure of
+              // this materialization before Baz has been finalized in
+              // order to test that error propagation is correct in this
+              // scenario.
+              cantFail(std::move(Result));
+              R.failMaterialization();
+            },
+            [](Error Err) { cantFail(std::move(Err)); },
+            [&](const SymbolDependenceMap &Deps) {
+              R.addDependenciesForAll(Deps);
+            });
+      });
+
+  cantFail(JD.define(MU));
+
+  SymbolNameSet Names({Foo, Bar});
+  auto Result = ES.lookup(JITDylibSearchList({{&JD, false}}), Names);
+
+  EXPECT_THAT_EXPECTED(std::move(Result), Failed())
+      << "Unexpected success while trying to test error propagation";
+}
+
 TEST_F(CoreAPIsStandardTest, TestLookupWithUnthreadedMaterialization) {
   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
       SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),