[llvm] r336741 - [ORC] Generalize alias materialization to support re-exports (i.e. aliasing of

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 10 16:34:56 PDT 2018


Author: lhames
Date: Tue Jul 10 16:34:56 2018
New Revision: 336741

URL: http://llvm.org/viewvc/llvm-project?rev=336741&view=rev
Log:
[ORC] Generalize alias materialization to support re-exports (i.e. aliasing of
symbols in another VSO).

Also fixes a bug where chained aliases within a single VSO would deadlock on
materialization.

Modified:
    llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h
    llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp
    llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp

Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h?rev=336741&r1=336740&r2=336741&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h Tue Jul 10 16:34:56 2018
@@ -251,6 +251,10 @@ absoluteSymbols(SymbolMap Symbols) {
 }
 
 struct SymbolAliasMapEntry {
+  SymbolAliasMapEntry() = default;
+  SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
+      : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {}
+
   SymbolStringPtr Aliasee;
   JITSymbolFlags AliasFlags;
 };
@@ -260,19 +264,27 @@ using SymbolAliasMap = std::map<SymbolSt
 
 /// A materialization unit for symbol aliases. Allows existing symbols to be
 /// aliased with alternate flags.
-class SymbolAliasesMaterializationUnit : public MaterializationUnit {
+class ReExportsMaterializationUnit : public MaterializationUnit {
 public:
-  SymbolAliasesMaterializationUnit(SymbolAliasMap Aliases);
+  /// SourceVSO is allowed to be nullptr, in which case the source VSO is
+  /// taken to be whatever VSO these definitions are materialized in. This
+  /// is useful for defining aliases within a VSO.
+  ///
+  /// Note: Care must be taken that no sets of aliases form a cycle, as such
+  ///       a cycle will result in a deadlock when any symbol in the cycle is
+  ///       resolved.
+  ReExportsMaterializationUnit(VSO *SourceVSO, SymbolAliasMap Aliases);
 
 private:
   void materialize(MaterializationResponsibility R) override;
   void discard(const VSO &V, SymbolStringPtr Name) override;
   static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
 
+  VSO *SourceVSO = nullptr;
   SymbolAliasMap Aliases;
 };
 
-/// Create a SymbolAliasesMaterializationUnit with the given aliases.
+/// Create a ReExportsMaterializationUnit with the given aliases.
 /// Useful for defining symbol aliases.: E.g., given a VSO V containing symbols
 /// "foo" and "bar", we can define aliases "baz" (for "foo") and "qux" (for
 /// "bar") with:
@@ -284,12 +296,25 @@ private:
 ///       {Qux, { Bar, JITSymbolFlags::Weak }}}))
 ///     return Err;
 /// \endcode
-inline std::unique_ptr<SymbolAliasesMaterializationUnit>
+inline std::unique_ptr<ReExportsMaterializationUnit>
 symbolAliases(SymbolAliasMap Aliases) {
-  return llvm::make_unique<SymbolAliasesMaterializationUnit>(
-      std::move(Aliases));
+  return llvm::make_unique<ReExportsMaterializationUnit>(nullptr,
+                                                         std::move(Aliases));
+}
+
+/// Create a materialization unit for re-exporting symbols from another VSO
+/// with alternative names/flags.
+inline std::unique_ptr<ReExportsMaterializationUnit>
+reexports(VSO &SourceV, SymbolAliasMap Aliases) {
+  return llvm::make_unique<ReExportsMaterializationUnit>(&SourceV,
+                                                         std::move(Aliases));
 }
 
+/// Build a SymbolAliasMap for the common case where you want to re-export
+/// symbols from another VSO with the same linkage/flags.
+Expected<SymbolAliasMap>
+buildSimpleReexportsAliasMap(VSO &SourceV, const SymbolNameSet &Symbols);
+
 /// Base utilities for ExecutionSession.
 class ExecutionSessionBase {
 public:

Modified: llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp?rev=336741&r1=336740&r2=336741&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp (original)
+++ llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp Tue Jul 10 16:34:56 2018
@@ -363,62 +363,143 @@ AbsoluteSymbolsMaterializationUnit::extr
   return Flags;
 }
 
-SymbolAliasesMaterializationUnit::SymbolAliasesMaterializationUnit(
-    SymbolAliasMap Aliases)
-    : MaterializationUnit(extractFlags(Aliases)), Aliases(std::move(Aliases)) {}
+ReExportsMaterializationUnit::ReExportsMaterializationUnit(
+    VSO *SourceVSO, SymbolAliasMap Aliases)
+    : MaterializationUnit(extractFlags(Aliases)), SourceVSO(SourceVSO),
+      Aliases(std::move(Aliases)) {}
 
-void SymbolAliasesMaterializationUnit::materialize(
+void ReExportsMaterializationUnit::materialize(
     MaterializationResponsibility R) {
-  auto &V = R.getTargetVSO();
-  auto &ES = V.getExecutionSession();
 
-  // FIXME: Use a unique_ptr when we move to C++14 and have generalized lambda
-  // capture.
-  auto SharedR = std::make_shared<MaterializationResponsibility>(std::move(R));
-
-  auto OnResolve = [this, SharedR](
-                       Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
-    if (RR) {
-      SymbolMap ResolutionMap;
-      for (auto &KV : Aliases) {
-        assert(RR->Symbols.count(KV.second.Aliasee) &&
-               "Result map missing entry?");
-        ResolutionMap[KV.first] = JITEvaluatedSymbol(
-            RR->Symbols[KV.second.Aliasee].getAddress(), KV.second.AliasFlags);
-      }
-
-      SharedR->resolve(ResolutionMap);
-      SharedR->finalize();
-    } else {
-      auto &ES = SharedR->getTargetVSO().getExecutionSession();
-      ES.reportError(RR.takeError());
-      SharedR->failMaterialization();
-    }
-  };
+  VSO &SrcV = SourceVSO ? *SourceVSO : R.getTargetVSO();
+  auto &ES = SrcV.getExecutionSession();
 
-  auto OnReady = [&ES](Error Err) { ES.reportError(std::move(Err)); };
+  // Find the set of requested aliases and aliasees. Return any unrequested
+  // aliases back to the VSO so as to not prematurely materialize any aliasees.
+  auto RequestedSymbols = R.getRequestedSymbols();
+  SymbolAliasMap RequestedAliases;
+
+  for (auto &Name : RequestedSymbols) {
+    auto I = Aliases.find(Name);
+    assert(I != Aliases.end() && "Symbol not found in aliases map?");
+    RequestedAliases[Name] = std::move(I->second);
+    Aliases.erase(I);
+  }
+
+  if (!Aliases.empty()) {
+    if (SourceVSO)
+      R.replace(reexports(*SourceVSO, std::move(Aliases)));
+    else
+      R.replace(symbolAliases(std::move(Aliases)));
+  }
+
+  // The OnResolveInfo struct will hold the aliases and responsibilty for each
+  // query in the list.
+  struct OnResolveInfo {
+    OnResolveInfo(MaterializationResponsibility R, SymbolAliasMap Aliases)
+        : R(std::move(R)), Aliases(std::move(Aliases)) {}
 
-  SymbolNameSet Aliasees;
-  for (auto &KV : Aliases)
-    Aliasees.insert(KV.second.Aliasee);
+    MaterializationResponsibility R;
+    SymbolAliasMap Aliases;
+  };
 
-  auto Q = std::make_shared<AsynchronousSymbolQuery>(
-      Aliasees, std::move(OnResolve), std::move(OnReady));
-  auto Unresolved = V.lookup(Q, Aliasees);
+  // Build a list of queries to issue. In each round we build the largest set of
+  // aliases that we can resolve without encountering a chain definition of the
+  // form Foo -> Bar, Bar -> Baz. Such a form would deadlock as the query would
+  // be waitin on a symbol that it itself had to resolve. Usually this will just
+  // involve one round and a single query.
+
+  std::vector<std::pair<SymbolNameSet, std::shared_ptr<OnResolveInfo>>>
+      QueryInfos;
+  while (!RequestedAliases.empty()) {
+    SymbolNameSet ResponsibilitySymbols;
+    SymbolNameSet QuerySymbols;
+    SymbolAliasMap QueryAliases;
+
+    for (auto I = RequestedAliases.begin(), E = RequestedAliases.end();
+         I != E;) {
+      auto Tmp = I++;
+
+      // Chain detected. Skip this symbol for this round.
+      if (&SrcV == &R.getTargetVSO() &&
+          (QueryAliases.count(Tmp->second.Aliasee) ||
+           RequestedAliases.count(Tmp->second.Aliasee)))
+        continue;
+
+      ResponsibilitySymbols.insert(Tmp->first);
+      QuerySymbols.insert(Tmp->second.Aliasee);
+      QueryAliases[Tmp->first] = std::move(Tmp->second);
+      RequestedAliases.erase(Tmp);
+    }
+    assert(!QuerySymbols.empty() && "Alias cycle detected!");
 
-  if (!Unresolved.empty())
-    ES.failQuery(*Q, make_error<SymbolsNotFound>(std::move(Unresolved)));
+    auto QueryInfo = std::make_shared<OnResolveInfo>(
+        R.delegate(ResponsibilitySymbols), std::move(QueryAliases));
+    QueryInfos.push_back(
+        make_pair(std::move(QuerySymbols), std::move(QueryInfo)));
+  }
+
+  // Issue the queries.
+  while (!QueryInfos.empty()) {
+    auto QuerySymbols = std::move(QueryInfos.back().first);
+    auto QueryInfo = std::move(QueryInfos.back().second);
+
+    QueryInfos.pop_back();
+
+    auto OnResolve =
+        [QueryInfo,
+         &SrcV](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
+          if (RR) {
+            SymbolMap ResolutionMap;
+            SymbolNameSet Resolved;
+            for (auto &KV : QueryInfo->Aliases) {
+              assert(RR->Symbols.count(KV.second.Aliasee) &&
+                     "Result map missing entry?");
+              ResolutionMap[KV.first] = JITEvaluatedSymbol(
+                  RR->Symbols[KV.second.Aliasee].getAddress(),
+                  KV.second.AliasFlags);
+
+              // FIXME: We're creating a SymbolFlagsMap and a std::map of
+              // std::sets just to add one dependency here. This needs a
+              // re-think.
+              Resolved.insert(KV.first);
+            }
+            QueryInfo->R.resolve(ResolutionMap);
+
+            SymbolDependenceMap Deps;
+            Deps[&SrcV] = std::move(Resolved);
+            QueryInfo->R.addDependencies(Deps);
+
+            QueryInfo->R.finalize();
+          } else {
+            auto &ES = QueryInfo->R.getTargetVSO().getExecutionSession();
+            ES.reportError(RR.takeError());
+            QueryInfo->R.failMaterialization();
+          }
+        };
+
+    auto OnReady = [&ES](Error Err) { ES.reportError(std::move(Err)); };
+
+    auto Q = std::make_shared<AsynchronousSymbolQuery>(
+        QuerySymbols, std::move(OnResolve), std::move(OnReady));
+
+    auto Unresolved = SrcV.lookup(Q, std::move(QuerySymbols));
+
+    if (!Unresolved.empty()) {
+      ES.failQuery(*Q, make_error<SymbolsNotFound>(std::move(Unresolved)));
+      return;
+    }
+  }
 }
 
-void SymbolAliasesMaterializationUnit::discard(const VSO &V,
-                                               SymbolStringPtr Name) {
+void ReExportsMaterializationUnit::discard(const VSO &V, SymbolStringPtr Name) {
   assert(Aliases.count(Name) &&
          "Symbol not covered by this MaterializationUnit");
   Aliases.erase(Name);
 }
 
 SymbolFlagsMap
-SymbolAliasesMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
+ReExportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
   SymbolFlagsMap SymbolFlags;
   for (auto &KV : Aliases)
     SymbolFlags[KV.first] = KV.second.AliasFlags;
@@ -426,6 +507,23 @@ SymbolAliasesMaterializationUnit::extrac
   return SymbolFlags;
 }
 
+Expected<SymbolAliasMap>
+buildSimpleReexportsAliasMap(VSO &SourceV, const SymbolNameSet &Symbols) {
+  SymbolFlagsMap Flags;
+  auto Unresolved = SourceV.lookupFlags(Flags, Symbols);
+
+  if (!Unresolved.empty())
+    return make_error<SymbolsNotFound>(std::move(Unresolved));
+
+  SymbolAliasMap Result;
+  for (auto &Name : Symbols) {
+    assert(Flags.count(Name) && "Missing entry in flags map");
+    Result[Name] = SymbolAliasMapEntry(Name, Flags[Name]);
+  }
+
+  return Result;
+}
+
 Error VSO::defineMaterializing(const SymbolFlagsMap &SymbolFlags) {
   return ES.runSessionLocked([&]() -> Error {
     std::vector<SymbolMap::iterator> AddedSyms;

Modified: llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp?rev=336741&r1=336740&r2=336741&view=diff
==============================================================================
--- llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp (original)
+++ llvm/trunk/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp Tue Jul 10 16:34:56 2018
@@ -259,7 +259,7 @@ TEST(CoreAPIsTest, LookupFlagsTest) {
   EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar";
 }
 
-TEST(CoreAPIsTest, TestAliases) {
+TEST(CoreAPIsTest, TestBasicAliases) {
   ExecutionSession ES;
   auto &V = ES.createVSO("V");
 
@@ -288,6 +288,31 @@ TEST(CoreAPIsTest, TestAliases) {
       << "The \"Qux\" alias should have been overriden";
 }
 
+TEST(CoreAPIsTest, TestChainedAliases) {
+  ExecutionSession ES;
+  auto &V = ES.createVSO("V");
+
+  auto Foo = ES.getSymbolStringPool().intern("foo");
+  auto FooSym = JITEvaluatedSymbol(1U, JITSymbolFlags::Exported);
+
+  auto Bar = ES.getSymbolStringPool().intern("bar");
+
+  auto Baz = ES.getSymbolStringPool().intern("baz");
+
+  cantFail(V.define(absoluteSymbols({{Foo, FooSym}})));
+  cantFail(V.define(symbolAliases({{Baz, {Bar, JITSymbolFlags::Exported}},
+                                   {Bar, {Foo, JITSymbolFlags::Exported}}})));
+
+  auto Result = lookup({&V}, {Bar, Baz});
+  EXPECT_TRUE(!!Result) << "Unexpected lookup failure";
+  EXPECT_EQ(Result->count(Bar), 1U) << "No result for \"bar\"";
+  EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\"";
+  EXPECT_EQ((*Result)[Bar].getAddress(), FooSym.getAddress())
+      << "\"Bar\"'s address should match \"Foo\"'s";
+  EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress())
+      << "\"Baz\"'s address should match \"Foo\"'s";
+}
+
 TEST(CoreAPIsTest, TestTrivialCircularDependency) {
   ExecutionSession ES;
 




More information about the llvm-commits mailing list