aboutsummaryrefslogtreecommitdiff
path: root/lib/ExecutionEngine/Orc/Core.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
commiteb11fae6d08f479c0799db45860a98af528fa6e7 (patch)
tree44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/ExecutionEngine/Orc/Core.cpp
parentb8a2042aa938069e862750553db0e4d82d25822c (diff)
downloadsrc-eb11fae6d08f479c0799db45860a98af528fa6e7.tar.gz
src-eb11fae6d08f479c0799db45860a98af528fa6e7.zip
Vendor import of llvm trunk r338150:vendor/llvm/llvm-trunk-r338150
Notes
Notes: svn path=/vendor/llvm/dist/; revision=336809 svn path=/vendor/llvm/llvm-trunk-r338150/; revision=336814; tag=vendor/llvm/llvm-trunk-r338150
Diffstat (limited to 'lib/ExecutionEngine/Orc/Core.cpp')
-rw-r--r--lib/ExecutionEngine/Orc/Core.cpp1690
1 files changed, 1690 insertions, 0 deletions
diff --git a/lib/ExecutionEngine/Orc/Core.cpp b/lib/ExecutionEngine/Orc/Core.cpp
new file mode 100644
index 000000000000..4325d57f73d0
--- /dev/null
+++ b/lib/ExecutionEngine/Orc/Core.cpp
@@ -0,0 +1,1690 @@
+//===----- Core.cpp - Core ORC APIs (MaterializationUnit, VSO, etc.) ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/ExecutionEngine/Orc/OrcError.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+
+#if LLVM_ENABLE_THREADS
+#include <future>
+#endif
+
+namespace llvm {
+namespace orc {
+
+char FailedToMaterialize::ID = 0;
+char SymbolsNotFound::ID = 0;
+
+RegisterDependenciesFunction NoDependenciesToRegister =
+ RegisterDependenciesFunction();
+
+void MaterializationUnit::anchor() {}
+
+raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) {
+ if (Flags.isWeak())
+ OS << 'W';
+ else if (Flags.isCommon())
+ OS << 'C';
+ else
+ OS << 'S';
+
+ if (Flags.isExported())
+ OS << 'E';
+ else
+ OS << 'H';
+
+ return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const JITEvaluatedSymbol &Sym) {
+ OS << format("0x%016x", Sym.getAddress()) << " " << Sym.getFlags();
+ return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV) {
+ OS << "\"" << *KV.first << "\": " << KV.second;
+ return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols) {
+ OS << "{";
+ if (!Symbols.empty()) {
+ OS << " \"" << **Symbols.begin() << "\"";
+ for (auto &Sym : make_range(std::next(Symbols.begin()), Symbols.end()))
+ OS << ", \"" << *Sym << "\"";
+ }
+ OS << " }";
+ return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols) {
+ OS << "{";
+ if (!Symbols.empty()) {
+ OS << " {" << *Symbols.begin() << "}";
+ for (auto &Sym : make_range(std::next(Symbols.begin()), Symbols.end()))
+ OS << ", {" << Sym << "}";
+ }
+ OS << " }";
+ return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags) {
+ OS << "{";
+ if (!SymbolFlags.empty()) {
+ OS << " {\"" << *SymbolFlags.begin()->first
+ << "\": " << SymbolFlags.begin()->second << "}";
+ for (auto &KV :
+ make_range(std::next(SymbolFlags.begin()), SymbolFlags.end()))
+ OS << ", {\"" << *KV.first << "\": " << KV.second << "}";
+ }
+ OS << " }";
+ return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps) {
+ OS << "{";
+ if (!Deps.empty()) {
+ OS << " { " << Deps.begin()->first->getName() << ": "
+ << Deps.begin()->second << " }";
+ for (auto &KV : make_range(std::next(Deps.begin()), Deps.end()))
+ OS << ", { " << KV.first->getName() << ": " << KV.second << " }";
+ }
+ OS << " }";
+ return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const VSOList &VSOs) {
+ OS << "[";
+ if (!VSOs.empty()) {
+ assert(VSOs.front() && "VSOList entries must not be null");
+ OS << " " << VSOs.front()->getName();
+ for (auto *V : make_range(std::next(VSOs.begin()), VSOs.end())) {
+ assert(V && "VSOList entries must not be null");
+ OS << ", " << V->getName();
+ }
+ }
+ OS << " ]";
+ return OS;
+}
+
+FailedToMaterialize::FailedToMaterialize(SymbolNameSet Symbols)
+ : Symbols(std::move(Symbols)) {
+ assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
+}
+
+std::error_code FailedToMaterialize::convertToErrorCode() const {
+ return orcError(OrcErrorCode::UnknownORCError);
+}
+
+void FailedToMaterialize::log(raw_ostream &OS) const {
+ OS << "Failed to materialize symbols: " << Symbols;
+}
+
+SymbolsNotFound::SymbolsNotFound(SymbolNameSet Symbols)
+ : Symbols(std::move(Symbols)) {
+ assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
+}
+
+std::error_code SymbolsNotFound::convertToErrorCode() const {
+ return orcError(OrcErrorCode::UnknownORCError);
+}
+
+void SymbolsNotFound::log(raw_ostream &OS) const {
+ OS << "Symbols not found: " << Symbols;
+}
+
+void ExecutionSessionBase::legacyFailQuery(AsynchronousSymbolQuery &Q,
+ Error Err) {
+ assert(!!Err && "Error should be in failure state");
+
+ bool SendErrorToQuery;
+ runSessionLocked([&]() {
+ Q.detach();
+ SendErrorToQuery = Q.canStillFail();
+ });
+
+ if (SendErrorToQuery)
+ Q.handleFailed(std::move(Err));
+ else
+ reportError(std::move(Err));
+}
+
+Expected<SymbolMap> ExecutionSessionBase::legacyLookup(
+ ExecutionSessionBase &ES, LegacyAsyncLookupFunction AsyncLookup,
+ SymbolNameSet Names, bool WaitUntilReady,
+ RegisterDependenciesFunction RegisterDependencies) {
+#if LLVM_ENABLE_THREADS
+ // In the threaded case we use promises to return the results.
+ std::promise<SymbolMap> PromisedResult;
+ std::mutex ErrMutex;
+ Error ResolutionError = Error::success();
+ std::promise<void> PromisedReady;
+ Error ReadyError = Error::success();
+ auto OnResolve = [&](Expected<SymbolMap> R) {
+ if (R)
+ PromisedResult.set_value(std::move(*R));
+ else {
+ {
+ ErrorAsOutParameter _(&ResolutionError);
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ ResolutionError = R.takeError();
+ }
+ PromisedResult.set_value(SymbolMap());
+ }
+ };
+
+ std::function<void(Error)> OnReady;
+ if (WaitUntilReady) {
+ OnReady = [&](Error Err) {
+ if (Err) {
+ ErrorAsOutParameter _(&ReadyError);
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ ReadyError = std::move(Err);
+ }
+ PromisedReady.set_value();
+ };
+ } else {
+ OnReady = [&](Error Err) {
+ if (Err)
+ ES.reportError(std::move(Err));
+ };
+ }
+
+#else
+ SymbolMap Result;
+ Error ResolutionError = Error::success();
+ Error ReadyError = Error::success();
+
+ auto OnResolve = [&](Expected<SymbolMap> R) {
+ ErrorAsOutParameter _(&ResolutionError);
+ if (R)
+ Result = std::move(*R);
+ else
+ ResolutionError = R.takeError();
+ };
+
+ std::function<void(Error)> OnReady;
+ if (WaitUntilReady) {
+ OnReady = [&](Error Err) {
+ ErrorAsOutParameter _(&ReadyError);
+ if (Err)
+ ReadyError = std::move(Err);
+ };
+ } else {
+ OnReady = [&](Error Err) {
+ if (Err)
+ ES.reportError(std::move(Err));
+ };
+ }
+#endif
+
+ auto Query = std::make_shared<AsynchronousSymbolQuery>(
+ Names, std::move(OnResolve), std::move(OnReady));
+ // FIXME: This should be run session locked along with the registration code
+ // and error reporting below.
+ SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names));
+
+ // If the query was lodged successfully then register the dependencies,
+ // otherwise fail it with an error.
+ if (UnresolvedSymbols.empty())
+ RegisterDependencies(Query->QueryRegistrations);
+ else {
+ bool DeliverError = runSessionLocked([&]() {
+ Query->detach();
+ return Query->canStillFail();
+ });
+ auto Err = make_error<SymbolsNotFound>(std::move(UnresolvedSymbols));
+ if (DeliverError)
+ Query->handleFailed(std::move(Err));
+ else
+ ES.reportError(std::move(Err));
+ }
+
+#if LLVM_ENABLE_THREADS
+ auto ResultFuture = PromisedResult.get_future();
+ auto Result = ResultFuture.get();
+
+ {
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ if (ResolutionError) {
+ // ReadyError will never be assigned. Consume the success value.
+ cantFail(std::move(ReadyError));
+ return std::move(ResolutionError);
+ }
+ }
+
+ if (WaitUntilReady) {
+ auto ReadyFuture = PromisedReady.get_future();
+ ReadyFuture.get();
+
+ {
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ if (ReadyError)
+ return std::move(ReadyError);
+ }
+ } else
+ cantFail(std::move(ReadyError));
+
+ return std::move(Result);
+
+#else
+ if (ResolutionError) {
+ // ReadyError will never be assigned. Consume the success value.
+ cantFail(std::move(ReadyError));
+ return std::move(ResolutionError);
+ }
+
+ if (ReadyError)
+ return std::move(ReadyError);
+
+ return Result;
+#endif
+}
+
+void ExecutionSessionBase::lookup(
+ const VSOList &VSOs, const SymbolNameSet &Symbols,
+ SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady,
+ RegisterDependenciesFunction RegisterDependencies) {
+
+ // lookup can be re-entered recursively if running on a single thread. Run any
+ // outstanding MUs in case this query depends on them, otherwise the main
+ // thread will starve waiting for a result from an MU that it failed to run.
+ runOutstandingMUs();
+
+ auto Unresolved = std::move(Symbols);
+ std::map<VSO *, MaterializationUnitList> MUsMap;
+ auto Q = std::make_shared<AsynchronousSymbolQuery>(
+ Symbols, std::move(OnResolve), std::move(OnReady));
+ bool QueryIsFullyResolved = false;
+ bool QueryIsFullyReady = false;
+ bool QueryFailed = false;
+
+ runSessionLocked([&]() {
+ for (auto *V : VSOs) {
+ assert(V && "VSOList entries must not be null");
+ assert(!MUsMap.count(V) &&
+ "VSOList should not contain duplicate entries");
+ V->lodgeQuery(Q, Unresolved, MUsMap[V]);
+ }
+
+ if (Unresolved.empty()) {
+ // Query lodged successfully.
+
+ // Record whether this query is fully ready / resolved. We will use
+ // this to call handleFullyResolved/handleFullyReady outside the session
+ // lock.
+ QueryIsFullyResolved = Q->isFullyResolved();
+ QueryIsFullyReady = Q->isFullyReady();
+
+ // Call the register dependencies function.
+ if (RegisterDependencies && !Q->QueryRegistrations.empty())
+ RegisterDependencies(Q->QueryRegistrations);
+ } else {
+ // Query failed due to unresolved symbols.
+ QueryFailed = true;
+
+ // Disconnect the query from its dependencies.
+ Q->detach();
+
+ // Replace the MUs.
+ for (auto &KV : MUsMap)
+ for (auto &MU : KV.second)
+ KV.first->replace(std::move(MU));
+ }
+ });
+
+ if (QueryFailed) {
+ Q->handleFailed(make_error<SymbolsNotFound>(std::move(Unresolved)));
+ return;
+ } else {
+ if (QueryIsFullyResolved)
+ Q->handleFullyResolved();
+ if (QueryIsFullyReady)
+ Q->handleFullyReady();
+ }
+
+ // Move the MUs to the OutstandingMUs list, then materialize.
+ {
+ std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
+
+ for (auto &KV : MUsMap)
+ for (auto &MU : KV.second)
+ OutstandingMUs.push_back(std::make_pair(KV.first, std::move(MU)));
+ }
+
+ runOutstandingMUs();
+}
+
+Expected<SymbolMap>
+ExecutionSessionBase::lookup(const VSOList &VSOs, const SymbolNameSet &Symbols,
+ RegisterDependenciesFunction RegisterDependencies,
+ bool WaitUntilReady) {
+#if LLVM_ENABLE_THREADS
+ // In the threaded case we use promises to return the results.
+ std::promise<SymbolMap> PromisedResult;
+ std::mutex ErrMutex;
+ Error ResolutionError = Error::success();
+ std::promise<void> PromisedReady;
+ Error ReadyError = Error::success();
+ auto OnResolve = [&](Expected<SymbolMap> R) {
+ if (R)
+ PromisedResult.set_value(std::move(*R));
+ else {
+ {
+ ErrorAsOutParameter _(&ResolutionError);
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ ResolutionError = R.takeError();
+ }
+ PromisedResult.set_value(SymbolMap());
+ }
+ };
+
+ std::function<void(Error)> OnReady;
+ if (WaitUntilReady) {
+ OnReady = [&](Error Err) {
+ if (Err) {
+ ErrorAsOutParameter _(&ReadyError);
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ ReadyError = std::move(Err);
+ }
+ PromisedReady.set_value();
+ };
+ } else {
+ OnReady = [&](Error Err) {
+ if (Err)
+ reportError(std::move(Err));
+ };
+ }
+
+#else
+ SymbolMap Result;
+ Error ResolutionError = Error::success();
+ Error ReadyError = Error::success();
+
+ auto OnResolve = [&](Expected<SymbolMap> R) {
+ ErrorAsOutParameter _(&ResolutionError);
+ if (R)
+ Result = std::move(*R);
+ else
+ ResolutionError = R.takeError();
+ };
+
+ std::function<void(Error)> OnReady;
+ if (WaitUntilReady) {
+ OnReady = [&](Error Err) {
+ ErrorAsOutParameter _(&ReadyError);
+ if (Err)
+ ReadyError = std::move(Err);
+ };
+ } else {
+ OnReady = [&](Error Err) {
+ if (Err)
+ reportError(std::move(Err));
+ };
+ }
+#endif
+
+ // Perform the asynchronous lookup.
+ lookup(VSOs, Symbols, OnResolve, OnReady, RegisterDependencies);
+
+#if LLVM_ENABLE_THREADS
+ auto ResultFuture = PromisedResult.get_future();
+ auto Result = ResultFuture.get();
+
+ {
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ if (ResolutionError) {
+ // ReadyError will never be assigned. Consume the success value.
+ cantFail(std::move(ReadyError));
+ return std::move(ResolutionError);
+ }
+ }
+
+ if (WaitUntilReady) {
+ auto ReadyFuture = PromisedReady.get_future();
+ ReadyFuture.get();
+
+ {
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ if (ReadyError)
+ return std::move(ReadyError);
+ }
+ } else
+ cantFail(std::move(ReadyError));
+
+ return std::move(Result);
+
+#else
+ if (ResolutionError) {
+ // ReadyError will never be assigned. Consume the success value.
+ cantFail(std::move(ReadyError));
+ return std::move(ResolutionError);
+ }
+
+ if (ReadyError)
+ return std::move(ReadyError);
+
+ return Result;
+#endif
+}
+
+void ExecutionSessionBase::runOutstandingMUs() {
+ while (1) {
+ std::pair<VSO *, std::unique_ptr<MaterializationUnit>> VSOAndMU;
+
+ {
+ std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
+ if (!OutstandingMUs.empty()) {
+ VSOAndMU = std::move(OutstandingMUs.back());
+ OutstandingMUs.pop_back();
+ }
+ }
+
+ if (VSOAndMU.first) {
+ assert(VSOAndMU.second && "VSO, but no MU?");
+ dispatchMaterialization(*VSOAndMU.first, std::move(VSOAndMU.second));
+ } else
+ break;
+ }
+}
+
+AsynchronousSymbolQuery::AsynchronousSymbolQuery(
+ const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
+ SymbolsReadyCallback NotifySymbolsReady)
+ : NotifySymbolsResolved(std::move(NotifySymbolsResolved)),
+ NotifySymbolsReady(std::move(NotifySymbolsReady)) {
+ NotYetResolvedCount = NotYetReadyCount = Symbols.size();
+
+ for (auto &S : Symbols)
+ ResolvedSymbols[S] = nullptr;
+}
+
+void AsynchronousSymbolQuery::resolve(const SymbolStringPtr &Name,
+ JITEvaluatedSymbol Sym) {
+ auto I = ResolvedSymbols.find(Name);
+ assert(I != ResolvedSymbols.end() &&
+ "Resolving symbol outside the requested set");
+ assert(I->second.getAddress() == 0 && "Redundantly resolving symbol Name");
+ I->second = std::move(Sym);
+ --NotYetResolvedCount;
+}
+
+void AsynchronousSymbolQuery::handleFullyResolved() {
+ assert(NotYetResolvedCount == 0 && "Not fully resolved?");
+ assert(NotifySymbolsResolved &&
+ "NotifySymbolsResolved already called or error occurred");
+ NotifySymbolsResolved(std::move(ResolvedSymbols));
+ NotifySymbolsResolved = SymbolsResolvedCallback();
+}
+
+void AsynchronousSymbolQuery::notifySymbolReady() {
+ assert(NotYetReadyCount != 0 && "All symbols already finalized");
+ --NotYetReadyCount;
+}
+
+void AsynchronousSymbolQuery::handleFullyReady() {
+ assert(QueryRegistrations.empty() &&
+ "Query is still registered with some symbols");
+ assert(!NotifySymbolsResolved && "Resolution not applied yet");
+ NotifySymbolsReady(Error::success());
+ NotifySymbolsReady = SymbolsReadyCallback();
+}
+
+bool AsynchronousSymbolQuery::canStillFail() {
+ return (NotifySymbolsResolved || NotifySymbolsReady);
+}
+
+void AsynchronousSymbolQuery::handleFailed(Error Err) {
+ assert(QueryRegistrations.empty() && ResolvedSymbols.empty() &&
+ NotYetResolvedCount == 0 && NotYetReadyCount == 0 &&
+ "Query should already have been abandoned");
+ if (NotifySymbolsResolved) {
+ NotifySymbolsResolved(std::move(Err));
+ NotifySymbolsResolved = SymbolsResolvedCallback();
+ } else {
+ assert(NotifySymbolsReady && "Failed after both callbacks issued?");
+ NotifySymbolsReady(std::move(Err));
+ }
+ NotifySymbolsReady = SymbolsReadyCallback();
+}
+
+void AsynchronousSymbolQuery::addQueryDependence(VSO &V, SymbolStringPtr Name) {
+ bool Added = QueryRegistrations[&V].insert(std::move(Name)).second;
+ (void)Added;
+ assert(Added && "Duplicate dependence notification?");
+}
+
+void AsynchronousSymbolQuery::removeQueryDependence(
+ VSO &V, const SymbolStringPtr &Name) {
+ auto QRI = QueryRegistrations.find(&V);
+ assert(QRI != QueryRegistrations.end() && "No dependencies registered for V");
+ assert(QRI->second.count(Name) && "No dependency on Name in V");
+ QRI->second.erase(Name);
+ if (QRI->second.empty())
+ QueryRegistrations.erase(QRI);
+}
+
+void AsynchronousSymbolQuery::detach() {
+ ResolvedSymbols.clear();
+ NotYetResolvedCount = 0;
+ NotYetReadyCount = 0;
+ for (auto &KV : QueryRegistrations)
+ KV.first->detachQueryHelper(*this, KV.second);
+ QueryRegistrations.clear();
+}
+
+MaterializationResponsibility::MaterializationResponsibility(
+ VSO &V, SymbolFlagsMap SymbolFlags)
+ : V(V), SymbolFlags(std::move(SymbolFlags)) {
+ assert(!this->SymbolFlags.empty() && "Materializing nothing?");
+
+#ifndef NDEBUG
+ for (auto &KV : this->SymbolFlags)
+ KV.second |= JITSymbolFlags::Materializing;
+#endif
+}
+
+MaterializationResponsibility::~MaterializationResponsibility() {
+ assert(SymbolFlags.empty() &&
+ "All symbols should have been explicitly materialized or failed");
+}
+
+SymbolNameSet MaterializationResponsibility::getRequestedSymbols() {
+ return V.getRequestedSymbols(SymbolFlags);
+}
+
+void MaterializationResponsibility::resolve(const SymbolMap &Symbols) {
+#ifndef NDEBUG
+ for (auto &KV : Symbols) {
+ auto I = SymbolFlags.find(KV.first);
+ assert(I != SymbolFlags.end() &&
+ "Resolving symbol outside this responsibility set");
+ assert(I->second.isMaterializing() && "Duplicate resolution");
+ I->second &= ~JITSymbolFlags::Materializing;
+ if (I->second.isWeak())
+ assert(I->second == (KV.second.getFlags() | JITSymbolFlags::Weak) &&
+ "Resolving symbol with incorrect flags");
+ else
+ assert(I->second == KV.second.getFlags() &&
+ "Resolving symbol with incorrect flags");
+ }
+#endif
+
+ V.resolve(Symbols);
+}
+
+void MaterializationResponsibility::finalize() {
+#ifndef NDEBUG
+ for (auto &KV : SymbolFlags)
+ assert(!KV.second.isMaterializing() &&
+ "Failed to resolve symbol before finalization");
+#endif // NDEBUG
+
+ V.finalize(SymbolFlags);
+ SymbolFlags.clear();
+}
+
+Error MaterializationResponsibility::defineMaterializing(
+ const SymbolFlagsMap &NewSymbolFlags) {
+ // Add the given symbols to this responsibility object.
+ // It's ok if we hit a duplicate here: In that case the new version will be
+ // discarded, and the VSO::defineMaterializing method will return a duplicate
+ // symbol error.
+ for (auto &KV : NewSymbolFlags) {
+ auto I = SymbolFlags.insert(KV).first;
+ (void)I;
+#ifndef NDEBUG
+ I->second |= JITSymbolFlags::Materializing;
+#endif
+ }
+
+ return V.defineMaterializing(NewSymbolFlags);
+}
+
+void MaterializationResponsibility::failMaterialization() {
+
+ SymbolNameSet FailedSymbols;
+ for (auto &KV : SymbolFlags)
+ FailedSymbols.insert(KV.first);
+
+ V.notifyFailed(FailedSymbols);
+ SymbolFlags.clear();
+}
+
+void MaterializationResponsibility::replace(
+ std::unique_ptr<MaterializationUnit> MU) {
+ for (auto &KV : MU->getSymbols())
+ SymbolFlags.erase(KV.first);
+
+ V.replace(std::move(MU));
+}
+
+MaterializationResponsibility
+MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) {
+ SymbolFlagsMap DelegatedFlags;
+
+ for (auto &Name : Symbols) {
+ auto I = SymbolFlags.find(Name);
+ assert(I != SymbolFlags.end() &&
+ "Symbol is not tracked by this MaterializationResponsibility "
+ "instance");
+
+ DelegatedFlags[Name] = std::move(I->second);
+ SymbolFlags.erase(I);
+ }
+
+ return MaterializationResponsibility(V, std::move(DelegatedFlags));
+}
+
+void MaterializationResponsibility::addDependencies(
+ const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) {
+ assert(SymbolFlags.count(Name) &&
+ "Symbol not covered by this MaterializationResponsibility instance");
+ V.addDependencies(Name, Dependencies);
+}
+
+void MaterializationResponsibility::addDependenciesForAll(
+ const SymbolDependenceMap &Dependencies) {
+ for (auto &KV : SymbolFlags)
+ V.addDependencies(KV.first, Dependencies);
+}
+
+AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit(
+ SymbolMap Symbols)
+ : MaterializationUnit(extractFlags(Symbols)), Symbols(std::move(Symbols)) {}
+
+void AbsoluteSymbolsMaterializationUnit::materialize(
+ MaterializationResponsibility R) {
+ R.resolve(Symbols);
+ R.finalize();
+}
+
+void AbsoluteSymbolsMaterializationUnit::discard(const VSO &V,
+ SymbolStringPtr Name) {
+ assert(Symbols.count(Name) && "Symbol is not part of this MU");
+ Symbols.erase(Name);
+}
+
+SymbolFlagsMap
+AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) {
+ SymbolFlagsMap Flags;
+ for (const auto &KV : Symbols)
+ Flags[KV.first] = KV.second.getFlags();
+ return Flags;
+}
+
+ReExportsMaterializationUnit::ReExportsMaterializationUnit(
+ VSO *SourceVSO, SymbolAliasMap Aliases)
+ : MaterializationUnit(extractFlags(Aliases)), SourceVSO(SourceVSO),
+ Aliases(std::move(Aliases)) {}
+
+void ReExportsMaterializationUnit::materialize(
+ MaterializationResponsibility R) {
+
+ auto &ES = R.getTargetVSO().getExecutionSession();
+ VSO &TgtV = R.getTargetVSO();
+ VSO &SrcV = SourceVSO ? *SourceVSO : TgtV;
+
+ // 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)) {}
+
+ MaterializationResponsibility R;
+ SymbolAliasMap Aliases;
+ };
+
+ // 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 == &TgtV && (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!");
+
+ 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 RegisterDependencies = [QueryInfo,
+ &SrcV](const SymbolDependenceMap &Deps) {
+ // If there were no materializing symbols, just bail out.
+ if (Deps.empty())
+ return;
+
+ // Otherwise the only deps should be on SrcV.
+ assert(Deps.size() == 1 && Deps.count(&SrcV) &&
+ "Unexpected dependencies for reexports");
+
+ auto &SrcVDeps = Deps.find(&SrcV)->second;
+ SymbolDependenceMap PerAliasDepsMap;
+ auto &PerAliasDeps = PerAliasDepsMap[&SrcV];
+
+ for (auto &KV : QueryInfo->Aliases)
+ if (SrcVDeps.count(KV.second.Aliasee)) {
+ PerAliasDeps = {KV.second.Aliasee};
+ QueryInfo->R.addDependencies(KV.first, PerAliasDepsMap);
+ }
+ };
+
+ auto OnResolve = [QueryInfo](Expected<SymbolMap> Result) {
+ if (Result) {
+ SymbolMap ResolutionMap;
+ for (auto &KV : QueryInfo->Aliases) {
+ assert(Result->count(KV.second.Aliasee) &&
+ "Result map missing entry?");
+ ResolutionMap[KV.first] = JITEvaluatedSymbol(
+ (*Result)[KV.second.Aliasee].getAddress(), KV.second.AliasFlags);
+ }
+ QueryInfo->R.resolve(ResolutionMap);
+ QueryInfo->R.finalize();
+ } else {
+ auto &ES = QueryInfo->R.getTargetVSO().getExecutionSession();
+ ES.reportError(Result.takeError());
+ QueryInfo->R.failMaterialization();
+ }
+ };
+
+ auto OnReady = [&ES](Error Err) { ES.reportError(std::move(Err)); };
+
+ ES.lookup({&SrcV}, QuerySymbols, std::move(OnResolve), std::move(OnReady),
+ std::move(RegisterDependencies));
+ }
+}
+
+void ReExportsMaterializationUnit::discard(const VSO &V, SymbolStringPtr Name) {
+ assert(Aliases.count(Name) &&
+ "Symbol not covered by this MaterializationUnit");
+ Aliases.erase(Name);
+}
+
+SymbolFlagsMap
+ReExportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
+ SymbolFlagsMap SymbolFlags;
+ for (auto &KV : Aliases)
+ SymbolFlags[KV.first] = KV.second.AliasFlags;
+
+ return SymbolFlags;
+}
+
+Expected<SymbolAliasMap>
+buildSimpleReexportsAliasMap(VSO &SourceV, const SymbolNameSet &Symbols) {
+ auto Flags = SourceV.lookupFlags(Symbols);
+
+ if (Flags.size() != Symbols.size()) {
+ SymbolNameSet Unresolved = Symbols;
+ for (auto &KV : Flags)
+ Unresolved.erase(KV.first);
+ 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;
+
+ for (auto &KV : SymbolFlags) {
+ SymbolMap::iterator EntryItr;
+ bool Added;
+
+ auto NewFlags = KV.second;
+ NewFlags |= JITSymbolFlags::Materializing;
+
+ std::tie(EntryItr, Added) = Symbols.insert(
+ std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags)));
+
+ if (Added)
+ AddedSyms.push_back(EntryItr);
+ else {
+ // Remove any symbols already added.
+ for (auto &SI : AddedSyms)
+ Symbols.erase(SI);
+
+ // FIXME: Return all duplicates.
+ return make_error<DuplicateDefinition>(*KV.first);
+ }
+ }
+
+ return Error::success();
+ });
+}
+
+void VSO::replace(std::unique_ptr<MaterializationUnit> MU) {
+ assert(MU != nullptr && "Can not replace with a null MaterializationUnit");
+
+ auto MustRunMU =
+ ES.runSessionLocked([&, this]() -> std::unique_ptr<MaterializationUnit> {
+
+#ifndef NDEBUG
+ for (auto &KV : MU->getSymbols()) {
+ auto SymI = Symbols.find(KV.first);
+ assert(SymI != Symbols.end() && "Replacing unknown symbol");
+ assert(!SymI->second.getFlags().isLazy() &&
+ SymI->second.getFlags().isMaterializing() &&
+ "Can not replace symbol that is not materializing");
+ assert(UnmaterializedInfos.count(KV.first) == 0 &&
+ "Symbol being replaced should have no UnmaterializedInfo");
+ }
+#endif // NDEBUG
+
+ // If any symbol has pending queries against it then we need to
+ // materialize MU immediately.
+ for (auto &KV : MU->getSymbols()) {
+ auto MII = MaterializingInfos.find(KV.first);
+ if (MII != MaterializingInfos.end()) {
+ if (!MII->second.PendingQueries.empty())
+ return std::move(MU);
+ }
+ }
+
+ // Otherwise, make MU responsible for all the symbols.
+ auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
+ for (auto &KV : UMI->MU->getSymbols()) {
+ assert(!KV.second.isLazy() &&
+ "Lazy flag should be managed internally.");
+ assert(!KV.second.isMaterializing() &&
+ "Materializing flags should be managed internally.");
+
+ auto SymI = Symbols.find(KV.first);
+ JITSymbolFlags ReplaceFlags = KV.second;
+ ReplaceFlags |= JITSymbolFlags::Lazy;
+ SymI->second = JITEvaluatedSymbol(SymI->second.getAddress(),
+ std::move(ReplaceFlags));
+ UnmaterializedInfos[KV.first] = UMI;
+ }
+
+ return nullptr;
+ });
+
+ if (MustRunMU)
+ ES.dispatchMaterialization(*this, std::move(MustRunMU));
+}
+
+SymbolNameSet VSO::getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) {
+ return ES.runSessionLocked([&]() {
+ SymbolNameSet RequestedSymbols;
+
+ for (auto &KV : SymbolFlags) {
+ assert(Symbols.count(KV.first) && "VSO does not cover this symbol?");
+ assert(Symbols[KV.first].getFlags().isMaterializing() &&
+ "getRequestedSymbols can only be called for materializing "
+ "symbols");
+ auto I = MaterializingInfos.find(KV.first);
+ if (I == MaterializingInfos.end())
+ continue;
+
+ if (!I->second.PendingQueries.empty())
+ RequestedSymbols.insert(KV.first);
+ }
+
+ return RequestedSymbols;
+ });
+}
+
+void VSO::addDependencies(const SymbolStringPtr &Name,
+ const SymbolDependenceMap &Dependencies) {
+ assert(Symbols.count(Name) && "Name not in symbol table");
+ assert((Symbols[Name].getFlags().isLazy() ||
+ Symbols[Name].getFlags().isMaterializing()) &&
+ "Symbol is not lazy or materializing");
+
+ auto &MI = MaterializingInfos[Name];
+ assert(!MI.IsFinalized && "Can not add dependencies to finalized symbol");
+
+ for (auto &KV : Dependencies) {
+ assert(KV.first && "Null VSO in dependency?");
+ auto &OtherVSO = *KV.first;
+ auto &DepsOnOtherVSO = MI.UnfinalizedDependencies[&OtherVSO];
+
+ for (auto &OtherSymbol : KV.second) {
+#ifndef NDEBUG
+ // Assert that this symbol exists and has not been finalized already.
+ auto SymI = OtherVSO.Symbols.find(OtherSymbol);
+ assert(SymI != OtherVSO.Symbols.end() &&
+ (SymI->second.getFlags().isLazy() ||
+ SymI->second.getFlags().isMaterializing()) &&
+ "Dependency on finalized symbol");
+#endif
+
+ auto &OtherMI = OtherVSO.MaterializingInfos[OtherSymbol];
+
+ if (OtherMI.IsFinalized)
+ transferFinalizedNodeDependencies(MI, Name, OtherMI);
+ else if (&OtherVSO != this || OtherSymbol != Name) {
+ OtherMI.Dependants[this].insert(Name);
+ DepsOnOtherVSO.insert(OtherSymbol);
+ }
+ }
+
+ if (DepsOnOtherVSO.empty())
+ MI.UnfinalizedDependencies.erase(&OtherVSO);
+ }
+}
+
+void VSO::resolve(const SymbolMap &Resolved) {
+ auto FullyResolvedQueries = ES.runSessionLocked([&, this]() {
+ AsynchronousSymbolQuerySet FullyResolvedQueries;
+ for (const auto &KV : Resolved) {
+ auto &Name = KV.first;
+ auto Sym = KV.second;
+
+ assert(!Sym.getFlags().isLazy() && !Sym.getFlags().isMaterializing() &&
+ "Materializing flags should be managed internally");
+
+ auto I = Symbols.find(Name);
+
+ assert(I != Symbols.end() && "Symbol not found");
+ assert(!I->second.getFlags().isLazy() &&
+ I->second.getFlags().isMaterializing() &&
+ "Symbol should be materializing");
+ assert(I->second.getAddress() == 0 && "Symbol has already been resolved");
+
+ assert((Sym.getFlags() & ~JITSymbolFlags::Weak) ==
+ (JITSymbolFlags::stripTransientFlags(I->second.getFlags()) &
+ ~JITSymbolFlags::Weak) &&
+ "Resolved flags should match the declared flags");
+
+ // Once resolved, symbols can never be weak.
+ JITSymbolFlags ResolvedFlags = Sym.getFlags();
+ ResolvedFlags &= ~JITSymbolFlags::Weak;
+ ResolvedFlags |= JITSymbolFlags::Materializing;
+ I->second = JITEvaluatedSymbol(Sym.getAddress(), ResolvedFlags);
+
+ auto &MI = MaterializingInfos[Name];
+ for (auto &Q : MI.PendingQueries) {
+ Q->resolve(Name, Sym);
+ if (Q->isFullyResolved())
+ FullyResolvedQueries.insert(Q);
+ }
+ }
+
+ return FullyResolvedQueries;
+ });
+
+ for (auto &Q : FullyResolvedQueries) {
+ assert(Q->isFullyResolved() && "Q not fully resolved");
+ Q->handleFullyResolved();
+ }
+}
+
+void VSO::finalize(const SymbolFlagsMap &Finalized) {
+ auto FullyReadyQueries = ES.runSessionLocked([&, this]() {
+ AsynchronousSymbolQuerySet ReadyQueries;
+
+ for (const auto &KV : Finalized) {
+ const auto &Name = KV.first;
+
+ auto MII = MaterializingInfos.find(Name);
+ assert(MII != MaterializingInfos.end() &&
+ "Missing MaterializingInfo entry");
+
+ auto &MI = MII->second;
+
+ // For each dependant, transfer this node's unfinalized dependencies to
+ // it. If the dependant node is fully finalized then notify any pending
+ // queries.
+ for (auto &KV : MI.Dependants) {
+ auto &DependantVSO = *KV.first;
+ for (auto &DependantName : KV.second) {
+ auto DependantMII =
+ DependantVSO.MaterializingInfos.find(DependantName);
+ assert(DependantMII != DependantVSO.MaterializingInfos.end() &&
+ "Dependant should have MaterializingInfo");
+
+ auto &DependantMI = DependantMII->second;
+
+ // Remove the dependant's dependency on this node.
+ assert(DependantMI.UnfinalizedDependencies[this].count(Name) &&
+ "Dependant does not count this symbol as a dependency?");
+ DependantMI.UnfinalizedDependencies[this].erase(Name);
+ if (DependantMI.UnfinalizedDependencies[this].empty())
+ DependantMI.UnfinalizedDependencies.erase(this);
+
+ // Transfer unfinalized dependencies from this node to the dependant.
+ DependantVSO.transferFinalizedNodeDependencies(DependantMI,
+ DependantName, MI);
+
+ // If the dependant is finalized and this node was the last of its
+ // unfinalized dependencies then notify any pending queries on the
+ // dependant node.
+ if (DependantMI.IsFinalized &&
+ DependantMI.UnfinalizedDependencies.empty()) {
+ assert(DependantMI.Dependants.empty() &&
+ "Dependants should be empty by now");
+ for (auto &Q : DependantMI.PendingQueries) {
+ Q->notifySymbolReady();
+ if (Q->isFullyReady())
+ ReadyQueries.insert(Q);
+ Q->removeQueryDependence(DependantVSO, DependantName);
+ }
+
+ // If this dependant node was fully finalized we can erase its
+ // MaterializingInfo and update its materializing state.
+ assert(DependantVSO.Symbols.count(DependantName) &&
+ "Dependant has no entry in the Symbols table");
+ auto &DependantSym = DependantVSO.Symbols[DependantName];
+ DependantSym.setFlags(static_cast<JITSymbolFlags::FlagNames>(
+ DependantSym.getFlags() & ~JITSymbolFlags::Materializing));
+ DependantVSO.MaterializingInfos.erase(DependantMII);
+ }
+ }
+ }
+ MI.Dependants.clear();
+ MI.IsFinalized = true;
+
+ if (MI.UnfinalizedDependencies.empty()) {
+ for (auto &Q : MI.PendingQueries) {
+ Q->notifySymbolReady();
+ if (Q->isFullyReady())
+ ReadyQueries.insert(Q);
+ Q->removeQueryDependence(*this, Name);
+ }
+ assert(Symbols.count(Name) &&
+ "Symbol has no entry in the Symbols table");
+ auto &Sym = Symbols[Name];
+ Sym.setFlags(static_cast<JITSymbolFlags::FlagNames>(
+ Sym.getFlags() & ~JITSymbolFlags::Materializing));
+ MaterializingInfos.erase(MII);
+ }
+ }
+
+ return ReadyQueries;
+ });
+
+ for (auto &Q : FullyReadyQueries) {
+ assert(Q->isFullyReady() && "Q is not fully ready");
+ Q->handleFullyReady();
+ }
+}
+
+void VSO::notifyFailed(const SymbolNameSet &FailedSymbols) {
+
+ // FIXME: This should fail any transitively dependant symbols too.
+
+ auto FailedQueriesToNotify = ES.runSessionLocked([&, this]() {
+ AsynchronousSymbolQuerySet FailedQueries;
+
+ for (auto &Name : FailedSymbols) {
+ auto I = Symbols.find(Name);
+ assert(I != Symbols.end() && "Symbol not present in this VSO");
+ Symbols.erase(I);
+
+ auto MII = MaterializingInfos.find(Name);
+
+ // If we have not created a MaterializingInfo for this symbol yet then
+ // there is nobody to notify.
+ if (MII == MaterializingInfos.end())
+ continue;
+
+ // 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
+ // PendingQueries list to remove Q.
+ for (auto &Q : MII->second.PendingQueries)
+ FailedQueries.insert(Q);
+
+ for (auto &Q : FailedQueries)
+ Q->detach();
+
+ assert(MII->second.PendingQueries.empty() &&
+ "Queries remain after symbol was failed");
+
+ MaterializingInfos.erase(MII);
+ }
+
+ return FailedQueries;
+ });
+
+ for (auto &Q : FailedQueriesToNotify)
+ Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols));
+}
+
+void VSO::setSearchOrder(VSOList NewSearchOrder, bool SearchThisVSOFirst) {
+ if (SearchThisVSOFirst && NewSearchOrder.front() != this)
+ NewSearchOrder.insert(NewSearchOrder.begin(), this);
+
+ ES.runSessionLocked([&]() { SearchOrder = std::move(NewSearchOrder); });
+}
+
+void VSO::addToSearchOrder(VSO &V) {
+ ES.runSessionLocked([&]() { SearchOrder.push_back(&V); });
+}
+
+void VSO::replaceInSearchOrder(VSO &OldV, VSO &NewV) {
+ ES.runSessionLocked([&]() {
+ auto I = std::find(SearchOrder.begin(), SearchOrder.end(), &OldV);
+
+ if (I != SearchOrder.end())
+ *I = &NewV;
+ });
+}
+
+void VSO::removeFromSearchOrder(VSO &V) {
+ ES.runSessionLocked([&]() {
+ auto I = std::find(SearchOrder.begin(), SearchOrder.end(), &V);
+ if (I != SearchOrder.end())
+ SearchOrder.erase(I);
+ });
+}
+
+SymbolFlagsMap VSO::lookupFlags(const SymbolNameSet &Names) {
+ return ES.runSessionLocked([&, this]() {
+ SymbolFlagsMap Result;
+ auto Unresolved = lookupFlagsImpl(Result, Names);
+ if (FallbackDefinitionGenerator && !Unresolved.empty()) {
+ auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved);
+ if (!FallbackDefs.empty()) {
+ auto Unresolved2 = lookupFlagsImpl(Result, FallbackDefs);
+ (void)Unresolved2;
+ assert(Unresolved2.empty() &&
+ "All fallback defs should have been found by lookupFlagsImpl");
+ }
+ };
+ return Result;
+ });
+}
+
+SymbolNameSet VSO::lookupFlagsImpl(SymbolFlagsMap &Flags,
+ const SymbolNameSet &Names) {
+ SymbolNameSet Unresolved;
+
+ for (auto &Name : Names) {
+ auto I = Symbols.find(Name);
+
+ if (I == Symbols.end()) {
+ Unresolved.insert(Name);
+ continue;
+ }
+
+ assert(!Flags.count(Name) && "Symbol already present in Flags map");
+ Flags[Name] = JITSymbolFlags::stripTransientFlags(I->second.getFlags());
+ }
+
+ return Unresolved;
+}
+
+void VSO::lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
+ SymbolNameSet &Unresolved, MaterializationUnitList &MUs) {
+ assert(Q && "Query can not be null");
+
+ lodgeQueryImpl(Q, Unresolved, MUs);
+ if (FallbackDefinitionGenerator && !Unresolved.empty()) {
+ auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved);
+ if (!FallbackDefs.empty()) {
+ for (auto &D : FallbackDefs)
+ Unresolved.erase(D);
+ lodgeQueryImpl(Q, FallbackDefs, MUs);
+ assert(FallbackDefs.empty() &&
+ "All fallback defs should have been found by lookupImpl");
+ }
+ }
+}
+
+void VSO::lodgeQueryImpl(
+ std::shared_ptr<AsynchronousSymbolQuery> &Q, SymbolNameSet &Unresolved,
+ std::vector<std::unique_ptr<MaterializationUnit>> &MUs) {
+ for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) {
+ auto TmpI = I++;
+ auto Name = *TmpI;
+
+ // Search for the name in Symbols. Skip it if not found.
+ auto SymI = Symbols.find(Name);
+ if (SymI == Symbols.end())
+ continue;
+
+ // If we found Name in V, remove it frome the Unresolved set and add it
+ // to the added set.
+ Unresolved.erase(TmpI);
+
+ // If the symbol has an address then resolve it.
+ if (SymI->second.getAddress() != 0)
+ Q->resolve(Name, SymI->second);
+
+ // If the symbol is lazy, get the MaterialiaztionUnit for it.
+ if (SymI->second.getFlags().isLazy()) {
+ assert(SymI->second.getAddress() == 0 &&
+ "Lazy symbol should not have a resolved address");
+ assert(!SymI->second.getFlags().isMaterializing() &&
+ "Materializing and lazy should not both be set");
+ auto UMII = UnmaterializedInfos.find(Name);
+ assert(UMII != UnmaterializedInfos.end() &&
+ "Lazy symbol should have UnmaterializedInfo");
+ auto MU = std::move(UMII->second->MU);
+ assert(MU != nullptr && "Materializer should not be null");
+
+ // Move all symbols associated with this MaterializationUnit into
+ // materializing state.
+ for (auto &KV : MU->getSymbols()) {
+ auto SymK = Symbols.find(KV.first);
+ auto Flags = SymK->second.getFlags();
+ Flags &= ~JITSymbolFlags::Lazy;
+ Flags |= JITSymbolFlags::Materializing;
+ SymK->second.setFlags(Flags);
+ UnmaterializedInfos.erase(KV.first);
+ }
+
+ // Add MU to the list of MaterializationUnits to be materialized.
+ MUs.push_back(std::move(MU));
+ } else if (!SymI->second.getFlags().isMaterializing()) {
+ // The symbol is neither lazy nor materializing. Finalize it and
+ // continue.
+ Q->notifySymbolReady();
+ continue;
+ }
+
+ // Add the query to the PendingQueries list.
+ assert(SymI->second.getFlags().isMaterializing() &&
+ "By this line the symbol should be materializing");
+ auto &MI = MaterializingInfos[Name];
+ MI.PendingQueries.push_back(Q);
+ Q->addQueryDependence(*this, Name);
+ }
+}
+
+SymbolNameSet VSO::legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
+ SymbolNameSet Names) {
+ assert(Q && "Query can not be null");
+
+ ES.runOutstandingMUs();
+
+ LookupImplActionFlags ActionFlags = None;
+ std::vector<std::unique_ptr<MaterializationUnit>> MUs;
+
+ SymbolNameSet Unresolved = std::move(Names);
+ ES.runSessionLocked([&, this]() {
+ ActionFlags = lookupImpl(Q, MUs, Unresolved);
+ if (FallbackDefinitionGenerator && !Unresolved.empty()) {
+ assert(ActionFlags == None &&
+ "ActionFlags set but unresolved symbols remain?");
+ auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved);
+ if (!FallbackDefs.empty()) {
+ for (auto &D : FallbackDefs)
+ Unresolved.erase(D);
+ ActionFlags = lookupImpl(Q, MUs, FallbackDefs);
+ assert(FallbackDefs.empty() &&
+ "All fallback defs should have been found by lookupImpl");
+ }
+ }
+ });
+
+ assert((MUs.empty() || ActionFlags == None) &&
+ "If action flags are set, there should be no work to do (so no MUs)");
+
+ if (ActionFlags & NotifyFullyResolved)
+ Q->handleFullyResolved();
+
+ if (ActionFlags & NotifyFullyReady)
+ Q->handleFullyReady();
+
+ // FIXME: Swap back to the old code below once RuntimeDyld works with
+ // callbacks from asynchronous queries.
+ // Add MUs to the OutstandingMUs list.
+ {
+ std::lock_guard<std::recursive_mutex> Lock(ES.OutstandingMUsMutex);
+ for (auto &MU : MUs)
+ ES.OutstandingMUs.push_back(make_pair(this, std::move(MU)));
+ }
+ ES.runOutstandingMUs();
+
+ // Dispatch any required MaterializationUnits for materialization.
+ // for (auto &MU : MUs)
+ // ES.dispatchMaterialization(*this, std::move(MU));
+
+ return Unresolved;
+}
+
+VSO::LookupImplActionFlags
+VSO::lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
+ std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
+ SymbolNameSet &Unresolved) {
+ LookupImplActionFlags ActionFlags = None;
+
+ for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) {
+ auto TmpI = I++;
+ auto Name = *TmpI;
+
+ // Search for the name in Symbols. Skip it if not found.
+ auto SymI = Symbols.find(Name);
+ if (SymI == Symbols.end())
+ continue;
+
+ // If we found Name in V, remove it frome the Unresolved set and add it
+ // to the dependencies set.
+ Unresolved.erase(TmpI);
+
+ // If the symbol has an address then resolve it.
+ if (SymI->second.getAddress() != 0) {
+ Q->resolve(Name, SymI->second);
+ if (Q->isFullyResolved())
+ ActionFlags |= NotifyFullyResolved;
+ }
+
+ // If the symbol is lazy, get the MaterialiaztionUnit for it.
+ if (SymI->second.getFlags().isLazy()) {
+ assert(SymI->second.getAddress() == 0 &&
+ "Lazy symbol should not have a resolved address");
+ assert(!SymI->second.getFlags().isMaterializing() &&
+ "Materializing and lazy should not both be set");
+ auto UMII = UnmaterializedInfos.find(Name);
+ assert(UMII != UnmaterializedInfos.end() &&
+ "Lazy symbol should have UnmaterializedInfo");
+ auto MU = std::move(UMII->second->MU);
+ assert(MU != nullptr && "Materializer should not be null");
+
+ // Kick all symbols associated with this MaterializationUnit into
+ // materializing state.
+ for (auto &KV : MU->getSymbols()) {
+ auto SymK = Symbols.find(KV.first);
+ auto Flags = SymK->second.getFlags();
+ Flags &= ~JITSymbolFlags::Lazy;
+ Flags |= JITSymbolFlags::Materializing;
+ SymK->second.setFlags(Flags);
+ UnmaterializedInfos.erase(KV.first);
+ }
+
+ // Add MU to the list of MaterializationUnits to be materialized.
+ MUs.push_back(std::move(MU));
+ } else if (!SymI->second.getFlags().isMaterializing()) {
+ // The symbol is neither lazy nor materializing. Finalize it and
+ // continue.
+ Q->notifySymbolReady();
+ if (Q->isFullyReady())
+ ActionFlags |= NotifyFullyReady;
+ continue;
+ }
+
+ // Add the query to the PendingQueries list.
+ assert(SymI->second.getFlags().isMaterializing() &&
+ "By this line the symbol should be materializing");
+ auto &MI = MaterializingInfos[Name];
+ MI.PendingQueries.push_back(Q);
+ Q->addQueryDependence(*this, Name);
+ }
+
+ return ActionFlags;
+}
+
+void VSO::dump(raw_ostream &OS) {
+ ES.runSessionLocked([&, this]() {
+ OS << "VSO \"" << VSOName
+ << "\" (ES: " << format("0x%016x", reinterpret_cast<uintptr_t>(&ES))
+ << "):\n"
+ << "Symbol table:\n";
+
+ for (auto &KV : Symbols) {
+ OS << " \"" << *KV.first
+ << "\": " << format("0x%016x", KV.second.getAddress());
+ if (KV.second.getFlags().isLazy() ||
+ KV.second.getFlags().isMaterializing()) {
+ OS << " (";
+ if (KV.second.getFlags().isLazy()) {
+ auto I = UnmaterializedInfos.find(KV.first);
+ assert(I != UnmaterializedInfos.end() &&
+ "Lazy symbol should have UnmaterializedInfo");
+ OS << " Lazy (MU=" << I->second->MU.get() << ")";
+ }
+ if (KV.second.getFlags().isMaterializing())
+ OS << " Materializing";
+ OS << " )\n";
+ } else
+ OS << "\n";
+ }
+
+ if (!MaterializingInfos.empty())
+ OS << " MaterializingInfos entries:\n";
+ for (auto &KV : MaterializingInfos) {
+ OS << " \"" << *KV.first << "\":\n"
+ << " IsFinalized = " << (KV.second.IsFinalized ? "true" : "false")
+ << "\n"
+ << " " << KV.second.PendingQueries.size()
+ << " pending queries: { ";
+ for (auto &Q : KV.second.PendingQueries)
+ OS << Q.get() << " ";
+ OS << "}\n Dependants:\n";
+ for (auto &KV2 : KV.second.Dependants)
+ OS << " " << KV2.first->getName() << ": " << KV2.second << "\n";
+ OS << " Unfinalized Dependencies:\n";
+ for (auto &KV2 : KV.second.UnfinalizedDependencies)
+ OS << " " << KV2.first->getName() << ": " << KV2.second << "\n";
+ }
+ });
+}
+
+VSO::VSO(ExecutionSessionBase &ES, std::string Name)
+ : ES(ES), VSOName(std::move(Name)) {
+ SearchOrder.push_back(this);
+}
+
+Error VSO::defineImpl(MaterializationUnit &MU) {
+ SymbolNameSet Duplicates;
+ SymbolNameSet MUDefsOverridden;
+
+ struct ExistingDefOverriddenEntry {
+ SymbolMap::iterator ExistingDefItr;
+ JITSymbolFlags NewFlags;
+ };
+ std::vector<ExistingDefOverriddenEntry> ExistingDefsOverridden;
+
+ for (auto &KV : MU.getSymbols()) {
+ assert(!KV.second.isLazy() && "Lazy flag should be managed internally.");
+ assert(!KV.second.isMaterializing() &&
+ "Materializing flags should be managed internally.");
+
+ SymbolMap::iterator EntryItr;
+ bool Added;
+
+ auto NewFlags = KV.second;
+ NewFlags |= JITSymbolFlags::Lazy;
+
+ std::tie(EntryItr, Added) = Symbols.insert(
+ std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags)));
+
+ if (!Added) {
+ if (KV.second.isStrong()) {
+ if (EntryItr->second.getFlags().isStrong() ||
+ (EntryItr->second.getFlags() & JITSymbolFlags::Materializing))
+ Duplicates.insert(KV.first);
+ else
+ ExistingDefsOverridden.push_back({EntryItr, NewFlags});
+ } else
+ MUDefsOverridden.insert(KV.first);
+ }
+ }
+
+ if (!Duplicates.empty()) {
+ // We need to remove the symbols we added.
+ for (auto &KV : MU.getSymbols()) {
+ if (Duplicates.count(KV.first))
+ continue;
+
+ bool Found = false;
+ for (const auto &EDO : ExistingDefsOverridden)
+ if (EDO.ExistingDefItr->first == KV.first)
+ Found = true;
+
+ if (!Found)
+ Symbols.erase(KV.first);
+ }
+
+ // FIXME: Return all duplicates.
+ return make_error<DuplicateDefinition>(**Duplicates.begin());
+ }
+
+ // Update flags on existing defs and call discard on their materializers.
+ for (auto &EDO : ExistingDefsOverridden) {
+ assert(EDO.ExistingDefItr->second.getFlags().isLazy() &&
+ !EDO.ExistingDefItr->second.getFlags().isMaterializing() &&
+ "Overridden existing def should be in the Lazy state");
+
+ EDO.ExistingDefItr->second.setFlags(EDO.NewFlags);
+
+ auto UMII = UnmaterializedInfos.find(EDO.ExistingDefItr->first);
+ assert(UMII != UnmaterializedInfos.end() &&
+ "Overridden existing def should have an UnmaterializedInfo");
+
+ UMII->second->MU->doDiscard(*this, EDO.ExistingDefItr->first);
+ }
+
+ // Discard overridden symbols povided by MU.
+ for (auto &Sym : MUDefsOverridden)
+ MU.doDiscard(*this, Sym);
+
+ return Error::success();
+}
+
+void VSO::detachQueryHelper(AsynchronousSymbolQuery &Q,
+ const SymbolNameSet &QuerySymbols) {
+ for (auto &QuerySymbol : QuerySymbols) {
+ assert(MaterializingInfos.count(QuerySymbol) &&
+ "QuerySymbol does not have MaterializingInfo");
+ auto &MI = MaterializingInfos[QuerySymbol];
+
+ auto IdenticalQuery =
+ [&](const std::shared_ptr<AsynchronousSymbolQuery> &R) {
+ return R.get() == &Q;
+ };
+
+ auto I = std::find_if(MI.PendingQueries.begin(), MI.PendingQueries.end(),
+ IdenticalQuery);
+ assert(I != MI.PendingQueries.end() &&
+ "Query Q should be in the PendingQueries list for QuerySymbol");
+ MI.PendingQueries.erase(I);
+ }
+}
+
+void VSO::transferFinalizedNodeDependencies(
+ MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName,
+ MaterializingInfo &FinalizedMI) {
+ for (auto &KV : FinalizedMI.UnfinalizedDependencies) {
+ auto &DependencyVSO = *KV.first;
+ SymbolNameSet *UnfinalizedDependenciesOnDependencyVSO = nullptr;
+
+ for (auto &DependencyName : KV.second) {
+ auto &DependencyMI = DependencyVSO.MaterializingInfos[DependencyName];
+
+ // Do not add self dependencies.
+ if (&DependencyMI == &DependantMI)
+ continue;
+
+ // If we haven't looked up the dependencies for DependencyVSO yet, do it
+ // now and cache the result.
+ if (!UnfinalizedDependenciesOnDependencyVSO)
+ UnfinalizedDependenciesOnDependencyVSO =
+ &DependantMI.UnfinalizedDependencies[&DependencyVSO];
+
+ DependencyMI.Dependants[this].insert(DependantName);
+ UnfinalizedDependenciesOnDependencyVSO->insert(DependencyName);
+ }
+ }
+}
+
+VSO &ExecutionSession::createVSO(std::string Name) {
+ return runSessionLocked([&, this]() -> VSO & {
+ VSOs.push_back(std::unique_ptr<VSO>(new VSO(*this, std::move(Name))));
+ return *VSOs.back();
+ });
+}
+
+Expected<SymbolMap> lookup(const VSOList &VSOs, SymbolNameSet Names) {
+
+ if (VSOs.empty())
+ return SymbolMap();
+
+ auto &ES = (*VSOs.begin())->getExecutionSession();
+
+ return ES.lookup(VSOs, Names, NoDependenciesToRegister, true);
+}
+
+/// Look up a symbol by searching a list of VSOs.
+Expected<JITEvaluatedSymbol> lookup(const VSOList &VSOs, SymbolStringPtr Name) {
+ SymbolNameSet Names({Name});
+ if (auto ResultMap = lookup(VSOs, std::move(Names))) {
+ assert(ResultMap->size() == 1 && "Unexpected number of results");
+ assert(ResultMap->count(Name) && "Missing result for symbol");
+ return std::move(ResultMap->begin()->second);
+ } else
+ return ResultMap.takeError();
+}
+
+MangleAndInterner::MangleAndInterner(ExecutionSessionBase &ES,
+ const DataLayout &DL)
+ : ES(ES), DL(DL) {}
+
+SymbolStringPtr MangleAndInterner::operator()(StringRef Name) {
+ std::string MangledName;
+ {
+ raw_string_ostream MangledNameStream(MangledName);
+ Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
+ }
+ return ES.getSymbolStringPool().intern(MangledName);
+}
+
+} // End namespace orc.
+} // End namespace llvm.