diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Core.h b/llvm/include/llvm/ExecutionEngine/Orc/Core.h index 5060f84c2413..a6c0806a8408 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Core.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Core.h @@ -69,8 +69,23 @@ raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps); /// A list of VSO pointers. using VSOList = std::vector; +/// Render a VSOList. raw_ostream &operator<<(raw_ostream &OS, const VSOList &VSOs); +/// Callback to notify client that symbols have been resolved. +using SymbolsResolvedCallback = std::function)>; + +/// Callback to notify client that symbols are ready for execution. +using SymbolsReadyCallback = std::function; + +/// Callback to register the dependencies for a given query. +using RegisterDependenciesFunction = + std::function; + +/// This can be used as the value for a RegisterDependenciesFunction if there +/// are no dependants to register with. +extern RegisterDependenciesFunction NoDependenciesToRegister; + /// Used to notify a VSO that the given set of symbols failed to materialize. class FailedToMaterialize : public ErrorInfo { public: @@ -122,6 +137,9 @@ public: /// into. VSO &getTargetVSO() const { return V; } + /// Returns the symbol flags map for this responsibility instance. + SymbolFlagsMap getSymbols() { return SymbolFlags; } + /// Returns the names of any symbols covered by this /// MaterializationResponsibility object that have queries pending. This /// information can be used to return responsibility for unrequested symbols @@ -223,6 +241,9 @@ private: virtual void discard(const VSO &V, SymbolStringPtr Name) = 0; }; +using MaterializationUnitList = + std::vector>; + /// A MaterializationUnit implementation for pre-existing absolute symbols. /// /// All symbols will be resolved and marked ready as soon as the unit is @@ -322,6 +343,9 @@ buildSimpleReexportsAliasMap(VSO &SourceV, const SymbolNameSet &Symbols); /// Base utilities for ExecutionSession. class ExecutionSessionBase { + // FIXME: Remove this when we remove the old ORC layers. + friend class VSO; + public: /// For reporting errors. using ErrorReporter = std::function; @@ -372,11 +396,50 @@ public: void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */ } - /// Cause the given query to fail with the given Error. + void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err); + + using LegacyAsyncLookupFunction = std::function Q, SymbolNameSet Names)>; + + /// A legacy lookup function for JITSymbolResolverAdapter. + /// Do not use -- this will be removed soon. + Expected + legacyLookup(ExecutionSessionBase &ES, LegacyAsyncLookupFunction AsyncLookup, + SymbolNameSet Names, bool WaiUntilReady, + RegisterDependenciesFunction RegisterDependencies); + + /// Search the given VSO list for the given symbols. /// - /// This should only be used by legacy APIs and will be deprecated in the - /// future. - void failQuery(AsynchronousSymbolQuery &Q, Error Err); + /// + /// The OnResolve callback will be called once all requested symbols are + /// resolved, or if an error occurs prior to resolution. + /// + /// The OnReady callback will be called once all requested symbols are ready, + /// or if an error occurs after resolution but before all symbols are ready. + /// + /// If all symbols are found, the RegisterDependencies function will be called + /// while the session lock is held. This gives clients a chance to register + /// dependencies for on the queried symbols for any symbols they are + /// materializing (if a MaterializationResponsibility instance is present, + /// this can be implemented by calling + /// MaterializationResponsibility::addDependencies). If there are no + /// dependenant symbols for this query (e.g. it is being made by a top level + /// client to get an address to call) then the value NoDependenciesToRegister + /// can be used. + void lookup(const VSOList &VSOs, const SymbolNameSet &Symbols, + SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady, + RegisterDependenciesFunction RegisterDependencies); + + /// Blocking version of lookup above. Returns the resolved symbol map. + /// If WaitUntilReady is true (the default), will not return until all + /// requested symbols are ready (or an error occurs). If WaitUntilReady is + /// false, will return as soon as all requested symbols are resolved, + /// or an error occurs. If WaitUntilReady is false and an error occurs + /// after resolution, the function will return a success value, but the + /// error will be reported via reportErrors. + Expected lookup(const VSOList &VSOs, const SymbolNameSet &Symbols, + RegisterDependenciesFunction RegisterDependencies, + bool WaitUntilReady = true); /// Materialize the given unit. void dispatchMaterialization(VSO &V, @@ -394,12 +457,20 @@ private: MU->doMaterialize(V); } + void runOutstandingMUs(); + mutable std::recursive_mutex SessionMutex; std::shared_ptr SSP; VModuleKey LastKey = 0; ErrorReporter ReportError = logErrorsToStdErr; DispatchMaterializationFunction DispatchMaterialization = materializeOnCurrentThread; + + // FIXME: Remove this (and runOutstandingMUs) once the linking layer works + // with callbacks from asynchronous queries. + mutable std::recursive_mutex OutstandingMUsMutex; + std::vector>> + OutstandingMUs; }; /// A symbol query that returns results via a callback when results are @@ -411,21 +482,6 @@ class AsynchronousSymbolQuery { friend class VSO; public: - class ResolutionResult { - public: - ResolutionResult(SymbolMap Symbols, const SymbolDependenceMap &Dependencies) - : Symbols(std::move(Symbols)), Dependencies(Dependencies) {} - - SymbolMap Symbols; - const SymbolDependenceMap &Dependencies; - }; - - /// Callback to notify client that symbols have been resolved. - using SymbolsResolvedCallback = - std::function)>; - - /// Callback to notify client that symbols are ready for execution. - using SymbolsReadyCallback = std::function; /// Create a query for the given symbols, notify-resolved and /// notify-ready callbacks. @@ -485,6 +541,7 @@ private: class VSO { friend class AsynchronousSymbolQuery; friend class ExecutionSession; + friend class ExecutionSessionBase; friend class MaterializationResponsibility; public: using FallbackDefinitionGeneratorFunction = @@ -493,9 +550,6 @@ public: using AsynchronousSymbolQuerySet = std::set>; - using MaterializationUnitList = - std::vector>; - VSO(const VSO &) = delete; VSO &operator=(const VSO &) = delete; VSO(VSO &&) = delete; @@ -547,8 +601,10 @@ public: void removeFromSearchOrder(VSO &V); /// Do something with the search order (run under the session lock). - template void withSearchOrderDo(Func F) { - ES.runSessionLocked([&]() { F(SearchOrder); }); + template + auto withSearchOrderDo(Func &&F) + -> decltype(F(std::declval())) { + return ES.runSessionLocked([&]() { return F(SearchOrder); }); } /// Define all symbols provided by the materialization unit to be part @@ -579,6 +635,10 @@ public: /// the flags for each symbol in Flags. Returns any unresolved symbols. SymbolFlagsMap lookupFlags(const SymbolNameSet &Names); + /// Dump current VSO state to OS. + void dump(raw_ostream &OS); + + /// FIXME: Remove this when we remove the old ORC layers. /// Search the given VSOs in order for the symbols in Symbols. Results /// (once they become available) will be returned via the given Query. /// @@ -586,11 +646,8 @@ public: /// and the query will not be applied. The Query is not failed and can be /// re-used in a subsequent lookup once the symbols have been added, or /// manually failed. - SymbolNameSet lookup(std::shared_ptr Q, - SymbolNameSet Names); - - /// Dump current VSO state to OS. - void dump(raw_ostream &OS); + SymbolNameSet legacyLookup(std::shared_ptr Q, + SymbolNameSet Names); private: using AsynchronousSymbolQueryList = @@ -629,6 +686,12 @@ private: SymbolNameSet lookupFlagsImpl(SymbolFlagsMap &Flags, const SymbolNameSet &Names); + void lodgeQuery(std::shared_ptr &Q, + SymbolNameSet &Unresolved, MaterializationUnitList &MUs); + + void lodgeQueryImpl(std::shared_ptr &Q, + SymbolNameSet &Unresolved, MaterializationUnitList &MUs); + LookupImplActionFlags lookupImpl(std::shared_ptr &Q, std::vector> &MUs, @@ -647,8 +710,8 @@ private: SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags); - void addDependencies(const SymbolFlagsMap &Dependents, - const SymbolDependenceMap &Dependencies); + void addDependencies(const SymbolStringPtr &Name, + const SymbolDependenceMap &Dependants); void resolve(const SymbolMap &Resolved); @@ -656,8 +719,6 @@ private: void notifyFailed(const SymbolNameSet &FailedSymbols); - void runOutstandingMUs(); - ExecutionSessionBase &ES; std::string VSOName; SymbolMap Symbols; @@ -665,11 +726,6 @@ private: MaterializingInfosMap MaterializingInfos; FallbackDefinitionGeneratorFunction FallbackDefinitionGenerator; VSOList SearchOrder; - - // FIXME: Remove this (and runOutstandingMUs) once the linking layer works - // with callbacks from asynchronous queries. - mutable std::recursive_mutex OutstandingMUsMutex; - std::vector> OutstandingMUs; }; /// An ExecutionSession represents a running JIT program. @@ -693,15 +749,6 @@ private: std::vector> VSOs; }; -using AsynchronousLookupFunction = std::function Q, SymbolNameSet Names)>; - -/// Perform a blocking lookup on the given symbols. -Expected blockingLookup(ExecutionSessionBase &ES, - AsynchronousLookupFunction AsyncLookup, - SymbolNameSet Names, bool WaiUntilReady, - MaterializationResponsibility *MR = nullptr); - /// Look up the given names in the given VSOs. /// VSOs will be searched in order and no VSO pointer may be null. /// All symbols must be found within the given VSOs or an error diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Legacy.h b/llvm/include/llvm/ExecutionEngine/Orc/Legacy.h index e97f98edcdfa..52c8c162ff0b 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Legacy.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Legacy.h @@ -146,11 +146,11 @@ lookupWithLegacyFn(ExecutionSession &ES, AsynchronousSymbolQuery &Query, Query.notifySymbolReady(); NewSymbolsResolved = true; } else { - ES.failQuery(Query, Addr.takeError()); + ES.legacyFailQuery(Query, Addr.takeError()); return SymbolNameSet(); } } else if (auto Err = Sym.takeError()) { - ES.failQuery(Query, std::move(Err)); + ES.legacyFailQuery(Query, std::move(Err)); return SymbolNameSet(); } else SymbolsNotFound.insert(S); diff --git a/llvm/lib/ExecutionEngine/Orc/Core.cpp b/llvm/lib/ExecutionEngine/Orc/Core.cpp index 65f117822884..2bfe0803a535 100644 --- a/llvm/lib/ExecutionEngine/Orc/Core.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Core.cpp @@ -23,6 +23,9 @@ 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) { @@ -138,20 +141,361 @@ void SymbolsNotFound::log(raw_ostream &OS) const { OS << "Symbols not found: " << Symbols; } -void ExecutionSessionBase::failQuery(AsynchronousSymbolQuery &Q, Error Err) { - bool DeliveredError = true; - runSessionLocked([&]() -> void { +void ExecutionSessionBase::legacyFailQuery(AsynchronousSymbolQuery &Q, + Error Err) { + assert(!!Err && "Error should be in failure state"); + + bool SendErrorToQuery; + runSessionLocked([&]() { Q.detach(); - if (Q.canStillFail()) - Q.handleFailed(std::move(Err)); - else - DeliveredError = false; + SendErrorToQuery = Q.canStillFail(); }); - if (!DeliveredError) + if (SendErrorToQuery) + Q.handleFailed(std::move(Err)); + else reportError(std::move(Err)); } +Expected 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 PromisedResult; + std::mutex ErrMutex; + Error ResolutionError = Error::success(); + std::promise PromisedReady; + Error ReadyError = Error::success(); + auto OnResolve = [&](Expected R) { + if (R) + PromisedResult.set_value(std::move(*R)); + else { + { + ErrorAsOutParameter _(&ResolutionError); + std::lock_guard Lock(ErrMutex); + ResolutionError = R.takeError(); + } + PromisedResult.set_value(SymbolMap()); + } + }; + + std::function OnReady; + if (WaitUntilReady) { + OnReady = [&](Error Err) { + if (Err) { + ErrorAsOutParameter _(&ReadyError); + std::lock_guard 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 R) { + ErrorAsOutParameter _(&ResolutionError); + if (R) + Result = std::move(*R); + else + ResolutionError = R.takeError(); + }; + + std::function 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( + 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(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 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 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 MUsMap; + auto Q = std::make_shared( + 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(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 Lock(OutstandingMUsMutex); + + for (auto &KV : MUsMap) + for (auto &MU : KV.second) + OutstandingMUs.push_back(std::make_pair(KV.first, std::move(MU))); + } + + runOutstandingMUs(); +} + +Expected +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 PromisedResult; + std::mutex ErrMutex; + Error ResolutionError = Error::success(); + std::promise PromisedReady; + Error ReadyError = Error::success(); + auto OnResolve = [&](Expected R) { + if (R) + PromisedResult.set_value(std::move(*R)); + else { + { + ErrorAsOutParameter _(&ResolutionError); + std::lock_guard Lock(ErrMutex); + ResolutionError = R.takeError(); + } + PromisedResult.set_value(SymbolMap()); + } + }; + + std::function OnReady; + if (WaitUntilReady) { + OnReady = [&](Error Err) { + if (Err) { + ErrorAsOutParameter _(&ReadyError); + std::lock_guard 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 R) { + ErrorAsOutParameter _(&ResolutionError); + if (R) + Result = std::move(*R); + else + ResolutionError = R.takeError(); + }; + + std::function 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 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 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> VSOAndMU; + + { + std::lock_guard 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) @@ -161,12 +505,6 @@ AsynchronousSymbolQuery::AsynchronousSymbolQuery( for (auto &S : Symbols) ResolvedSymbols[S] = nullptr; - - // If the query is empty it is trivially resolved/ready. - if (Symbols.empty()) { - handleFullyResolved(); - handleFullyReady(); - } } void AsynchronousSymbolQuery::resolve(const SymbolStringPtr &Name, @@ -183,8 +521,7 @@ void AsynchronousSymbolQuery::handleFullyResolved() { assert(NotYetResolvedCount == 0 && "Not fully resolved?"); assert(NotifySymbolsResolved && "NotifySymbolsResolved already called or error occurred"); - NotifySymbolsResolved( - ResolutionResult(std::move(ResolvedSymbols), QueryRegistrations)); + NotifySymbolsResolved(std::move(ResolvedSymbols)); NotifySymbolsResolved = SymbolsResolvedCallback(); } @@ -349,7 +686,8 @@ MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) { void MaterializationResponsibility::addDependencies( const SymbolDependenceMap &Dependencies) { - V.addDependencies(SymbolFlags, Dependencies); + for (auto &KV : SymbolFlags) + V.addDependencies(KV.first, Dependencies); } AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit( @@ -384,8 +722,9 @@ ReExportsMaterializationUnit::ReExportsMaterializationUnit( void ReExportsMaterializationUnit::materialize( MaterializationResponsibility R) { - VSO &SrcV = SourceVSO ? *SourceVSO : R.getTargetVSO(); - auto &ES = SrcV.getExecutionSession(); + 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. @@ -434,9 +773,8 @@ void ReExportsMaterializationUnit::materialize( 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))) + if (&SrcV == &TgtV && (QueryAliases.count(Tmp->second.Aliasee) || + RequestedAliases.count(Tmp->second.Aliasee))) continue; ResponsibilitySymbols.insert(Tmp->first); @@ -459,49 +797,32 @@ void ReExportsMaterializationUnit::materialize( QueryInfos.pop_back(); - auto OnResolve = - [QueryInfo, - &SrcV](Expected 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); + auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) { + R.addDependencies(Deps); + }; - // 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 OnResolve = [QueryInfo](Expected 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)); }; - auto Q = std::make_shared( - QuerySymbols, std::move(OnResolve), std::move(OnReady)); - - auto Unresolved = SrcV.lookup(Q, std::move(QuerySymbols)); - - if (!Unresolved.empty()) { - ES.failQuery(*Q, make_error(std::move(Unresolved))); - return; - } + ES.lookup({&SrcV}, QuerySymbols, std::move(OnResolve), std::move(OnReady), + std::move(RegisterDependencies)); } } @@ -642,40 +963,35 @@ SymbolNameSet VSO::getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) { }); } -void VSO::addDependencies(const SymbolFlagsMap &Dependants, +void VSO::addDependencies(const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) { - ES.runSessionLocked([&, this]() { - for (auto &KV : Dependants) { - const auto &Name = KV.first; - assert(Symbols.count(Name) && "Name not in symbol table"); - assert((Symbols[Name].getFlags().isLazy() || - Symbols[Name].getFlags().isMaterializing()) && - "Symbol is not lazy or materializing"); + 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"); + 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 &KV : Dependencies) { + assert(KV.first && "Null VSO in dependency?"); + auto &OtherVSO = *KV.first; + auto &DepsOnOtherVSO = MI.UnfinalizedDependencies[&OtherVSO]; - for (auto &OtherSymbol : KV.second) { - auto &OtherMI = OtherVSO.MaterializingInfos[OtherSymbol]; + for (auto &OtherSymbol : KV.second) { + 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); + 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) { @@ -856,25 +1172,6 @@ void VSO::notifyFailed(const SymbolNameSet &FailedSymbols) { Q->handleFailed(make_error(FailedSymbols)); } -void VSO::runOutstandingMUs() { - while (1) { - std::unique_ptr MU; - - { - std::lock_guard Lock(OutstandingMUsMutex); - if (!OutstandingMUs.empty()) { - MU = std::move(OutstandingMUs.back()); - OutstandingMUs.pop_back(); - } - } - - if (MU) - ES.dispatchMaterialization(*this, std::move(MU)); - else - break; - } -} - void VSO::setSearchOrder(VSOList NewSearchOrder, bool SearchThisVSOFirst) { if (SearchThisVSOFirst && NewSearchOrder.front() != this) NewSearchOrder.insert(NewSearchOrder.begin(), this); @@ -939,11 +1236,89 @@ SymbolNameSet VSO::lookupFlagsImpl(SymbolFlagsMap &Flags, return Unresolved; } -SymbolNameSet VSO::lookup(std::shared_ptr Q, - SymbolNameSet Names) { +void VSO::lodgeQuery(std::shared_ptr &Q, + SymbolNameSet &Unresolved, MaterializationUnitList &MUs) { assert(Q && "Query can not be null"); - runOutstandingMUs(); + 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 &Q, SymbolNameSet &Unresolved, + std::vector> &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 Q, + SymbolNameSet Names) { + assert(Q && "Query can not be null"); + + ES.runOutstandingMUs(); LookupImplActionFlags ActionFlags = None; std::vector> MUs; @@ -978,11 +1353,11 @@ SymbolNameSet VSO::lookup(std::shared_ptr Q, // callbacks from asynchronous queries. // Add MUs to the OutstandingMUs list. { - std::lock_guard Lock(OutstandingMUsMutex); + std::lock_guard Lock(ES.OutstandingMUsMutex); for (auto &MU : MUs) - OutstandingMUs.push_back(std::move(MU)); + ES.OutstandingMUs.push_back(make_pair(this, std::move(MU))); } - runOutstandingMUs(); + ES.runOutstandingMUs(); // Dispatch any required MaterializationUnits for materialization. // for (auto &MU : MUs) @@ -1243,133 +1618,6 @@ VSO &ExecutionSession::createVSO(std::string Name) { }); } -Expected blockingLookup(ExecutionSessionBase &ES, - AsynchronousLookupFunction AsyncLookup, - SymbolNameSet Names, bool WaitUntilReady, - MaterializationResponsibility *MR) { - -#if LLVM_ENABLE_THREADS - // In the threaded case we use promises to return the results. - std::promise PromisedResult; - std::mutex ErrMutex; - Error ResolutionError = Error::success(); - std::promise PromisedReady; - Error ReadyError = Error::success(); - auto OnResolve = - [&](Expected Result) { - if (Result) { - if (MR) - MR->addDependencies(Result->Dependencies); - PromisedResult.set_value(std::move(Result->Symbols)); - } else { - { - ErrorAsOutParameter _(&ResolutionError); - std::lock_guard Lock(ErrMutex); - ResolutionError = Result.takeError(); - } - PromisedResult.set_value(SymbolMap()); - } - }; - - std::function OnReady; - if (WaitUntilReady) { - OnReady = [&](Error Err) { - if (Err) { - ErrorAsOutParameter _(&ReadyError); - std::lock_guard 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 R) { - ErrorAsOutParameter _(&ResolutionError); - if (R) { - if (MR) - MR->addDependencies(R->Dependencies); - Result = std::move(R->Symbols); - } else - ResolutionError = R.takeError(); - }; - - std::function 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( - Names, std::move(OnResolve), std::move(OnReady)); - - SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names)); - - // If there are unresolved symbols then the query will never return. - // Fail it with ES.failQuery. - if (!UnresolvedSymbols.empty()) - ES.failQuery(*Query, - make_error(std::move(UnresolvedSymbols))); - -#if LLVM_ENABLE_THREADS - auto ResultFuture = PromisedResult.get_future(); - auto Result = ResultFuture.get(); - - { - std::lock_guard 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 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 -} - Expected lookup(const VSOList &VSOs, SymbolNameSet Names) { if (VSOs.empty()) @@ -1377,18 +1625,7 @@ Expected lookup(const VSOList &VSOs, SymbolNameSet Names) { auto &ES = (*VSOs.begin())->getExecutionSession(); - auto LookupFn = [&](std::shared_ptr Q, - SymbolNameSet Unresolved) { - for (auto *V : VSOs) { - assert(V && "VSOs entries must not be null"); - if (Unresolved.empty()) - break; - Unresolved = V->lookup(Q, std::move(Unresolved)); - } - return Unresolved; - }; - - return blockingLookup(ES, std::move(LookupFn), Names, true); + return ES.lookup(VSOs, Names, NoDependenciesToRegister, true); } /// Look up a symbol by searching a list of VSOs. diff --git a/llvm/lib/ExecutionEngine/Orc/Legacy.cpp b/llvm/lib/ExecutionEngine/Orc/Legacy.cpp index 6fde6898a16c..22775ef14f86 100644 --- a/llvm/lib/ExecutionEngine/Orc/Legacy.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Legacy.cpp @@ -29,8 +29,14 @@ JITSymbolResolverAdapter::lookup(const LookupSet &Symbols) { return R.lookup(std::move(Q), std::move(Unresolved)); }; - auto InternedResult = blockingLookup(ES, std::move(LookupFn), - std::move(InternedSymbols), false, MR); + auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) { + if (MR) + MR->addDependencies(Deps); + }; + + auto InternedResult = + ES.legacyLookup(ES, std::move(LookupFn), std::move(InternedSymbols), + false, RegisterDependencies); if (!InternedResult) return InternedResult.takeError(); diff --git a/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h b/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h index 6c44f4367ec0..b9f8a370d2f0 100644 --- a/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h +++ b/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h @@ -156,11 +156,11 @@ private: Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags())); Query->notifySymbolReady(); } else { - Stack.ES.failQuery(*Query, Addr.takeError()); + Stack.ES.legacyFailQuery(*Query, Addr.takeError()); return orc::SymbolNameSet(); } } else if (auto Err = Sym.takeError()) { - Stack.ES.failQuery(*Query, std::move(Err)); + Stack.ES.legacyFailQuery(*Query, std::move(Err)); return orc::SymbolNameSet(); } else UnresolvedSymbols.insert(S); diff --git a/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h b/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h index ded53ac3106b..abe89ce70af9 100644 --- a/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h +++ b/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h @@ -178,11 +178,11 @@ class OrcMCJITReplacement : public ExecutionEngine { Query->notifySymbolReady(); NewSymbolsResolved = true; } else { - M.ES.failQuery(*Query, Addr.takeError()); + M.ES.legacyFailQuery(*Query, Addr.takeError()); return SymbolNameSet(); } } else if (auto Err = Sym.takeError()) { - M.ES.failQuery(*Query, std::move(Err)); + M.ES.legacyFailQuery(*Query, std::move(Err)); return SymbolNameSet(); } else { if (auto Sym2 = M.ClientResolver->findSymbol(*S)) { @@ -191,11 +191,11 @@ class OrcMCJITReplacement : public ExecutionEngine { Query->notifySymbolReady(); NewSymbolsResolved = true; } else { - M.ES.failQuery(*Query, Addr.takeError()); + M.ES.legacyFailQuery(*Query, Addr.takeError()); return SymbolNameSet(); } } else if (auto Err = Sym2.takeError()) { - M.ES.failQuery(*Query, std::move(Err)); + M.ES.legacyFailQuery(*Query, std::move(Err)); return SymbolNameSet(); } else UnresolvedSymbols.insert(S); diff --git a/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp index 7cdc6b352d11..6edf616660e7 100644 --- a/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp @@ -16,30 +16,23 @@ using namespace llvm::orc; class VSOSearchOrderResolver : public JITSymbolResolver { public: - VSOSearchOrderResolver(ExecutionSession &ES, - MaterializationResponsibility &MR) - : ES(ES), MR(MR) {} + VSOSearchOrderResolver(MaterializationResponsibility &MR) : MR(MR) {} Expected lookup(const LookupSet &Symbols) { + auto &ES = MR.getTargetVSO().getExecutionSession(); SymbolNameSet InternedSymbols; for (auto &S : Symbols) InternedSymbols.insert(ES.getSymbolStringPool().intern(S)); - auto AsyncLookup = [&](std::shared_ptr Q, - SymbolNameSet Names) { - SymbolNameSet Unresolved = std::move(Names); - MR.getTargetVSO().withSearchOrderDo([&](const VSOList &SearchOrder) { - for (auto *V : SearchOrder) { - assert(V && "VSOList entry can not be null"); - Unresolved = V->lookup(Q, std::move(Unresolved)); - } - }); - return Unresolved; + auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) { + MR.addDependencies(Deps); }; - auto InternedResult = blockingLookup( - ES, std::move(AsyncLookup), std::move(InternedSymbols), false, &MR); + auto InternedResult = + MR.getTargetVSO().withSearchOrderDo([&](const VSOList &VSOs) { + return ES.lookup(VSOs, InternedSymbols, RegisterDependencies, false); + }); if (!InternedResult) return InternedResult.takeError(); @@ -52,6 +45,8 @@ public: } Expected lookupFlags(const LookupSet &Symbols) { + auto &ES = MR.getTargetVSO().getExecutionSession(); + SymbolNameSet InternedSymbols; for (auto &S : Symbols) @@ -75,7 +70,6 @@ public: } private: - ExecutionSession &ES; MaterializationResponsibility &MR; }; @@ -106,7 +100,7 @@ void RTDyldObjectLinkingLayer2::emit(MaterializationResponsibility R, auto MemoryManager = GetMemoryManager(K); - VSOSearchOrderResolver Resolver(ES, R); + VSOSearchOrderResolver Resolver(R); auto RTDyld = llvm::make_unique(*MemoryManager, Resolver); RTDyld->setProcessAllSections(ProcessAllSections); diff --git a/llvm/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp b/llvm/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp index c0afbc6be06a..d53c4558e0c8 100644 --- a/llvm/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp @@ -59,51 +59,57 @@ private: DestructorFunction Destructor; }; - -TEST_F(CoreAPIsStandardTest, AsynchronousSymbolQuerySuccessfulResolutionOnly) { +TEST_F(CoreAPIsStandardTest, BasicSuccessfulLookup) { bool OnResolutionRun = false; bool OnReadyRun = false; - auto OnResolution = - [&](Expected Result) { - EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; - auto &Resolved = Result->Symbols; - auto I = Resolved.find(Foo); - EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition"; - EXPECT_EQ(I->second.getAddress(), FooAddr) - << "Resolution returned incorrect result"; - OnResolutionRun = true; - }; + + auto OnResolution = [&](Expected Result) { + EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; + auto &Resolved = *Result; + auto I = Resolved.find(Foo); + EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition"; + EXPECT_EQ(I->second.getAddress(), FooAddr) + << "Resolution returned incorrect result"; + OnResolutionRun = true; + }; auto OnReady = [&](Error Err) { cantFail(std::move(Err)); OnReadyRun = true; }; - AsynchronousSymbolQuery Q(SymbolNameSet({Foo}), OnResolution, OnReady); + std::shared_ptr FooMR; - Q.resolve(Foo, FooSym); + cantFail(V.define(llvm::make_unique( + SymbolFlagsMap({{Foo, FooSym.getFlags()}}), + [&](MaterializationResponsibility R) { + FooMR = std::make_shared(std::move(R)); + }))); - EXPECT_TRUE(Q.isFullyResolved()) << "Expected query to be fully resolved"; + ES.lookup({&V}, {Foo}, OnResolution, OnReady, NoDependenciesToRegister); - if (!Q.isFullyResolved()) - return; + EXPECT_FALSE(OnResolutionRun) << "Should not have been resolved yet"; + EXPECT_FALSE(OnReadyRun) << "Should not have been marked ready yet"; - Q.handleFullyResolved(); + FooMR->resolve({{Foo, FooSym}}); - EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; - EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run"; + EXPECT_TRUE(OnResolutionRun) << "Should have been resolved"; + EXPECT_FALSE(OnReadyRun) << "Should not have been marked ready yet"; + + FooMR->finalize(); + + EXPECT_TRUE(OnReadyRun) << "Should have been marked ready"; } TEST_F(CoreAPIsStandardTest, ExecutionSessionFailQuery) { bool OnResolutionRun = false; bool OnReadyRun = false; - auto OnResolution = - [&](Expected Result) { - EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success"; - auto Msg = toString(Result.takeError()); - EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result"; - OnResolutionRun = true; - }; + auto OnResolution = [&](Expected Result) { + EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success"; + auto Msg = toString(Result.takeError()); + EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result"; + OnResolutionRun = true; + }; auto OnReady = [&](Error Err) { cantFail(std::move(Err)); OnReadyRun = true; @@ -111,62 +117,28 @@ TEST_F(CoreAPIsStandardTest, ExecutionSessionFailQuery) { AsynchronousSymbolQuery Q(SymbolNameSet({Foo}), OnResolution, OnReady); - ES.failQuery(Q, make_error("xyz", inconvertibleErrorCode())); + ES.legacyFailQuery(Q, + make_error("xyz", inconvertibleErrorCode())); EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run"; } -TEST_F(CoreAPIsStandardTest, SimpleAsynchronousSymbolQueryAgainstVSO) { - bool OnResolutionRun = false; +TEST_F(CoreAPIsStandardTest, EmptyLookup) { + bool OnResolvedRun = false; bool OnReadyRun = false; - auto OnResolution = - [&](Expected Result) { - EXPECT_TRUE(!!Result) << "Query unexpectedly returned error"; - auto &Resolved = Result->Symbols; - auto I = Resolved.find(Foo); - EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition"; - EXPECT_EQ(I->second.getAddress(), FooSym.getAddress()) - << "Resolution returned incorrect result"; - OnResolutionRun = true; - }; + auto OnResolution = [&](Expected Result) { + cantFail(std::move(Result)); + OnResolvedRun = true; + }; auto OnReady = [&](Error Err) { cantFail(std::move(Err)); OnReadyRun = true; }; - SymbolNameSet Names({Foo}); - - auto Q = - std::make_shared(Names, OnResolution, OnReady); - - auto Defs = absoluteSymbols({{Foo, FooSym}}); - cantFail(V.define(Defs)); - assert(Defs == nullptr && "Defs should have been accepted"); - V.lookup(Q, Names); - - EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; - EXPECT_TRUE(OnReadyRun) << "OnReady was not run"; -} - -TEST_F(CoreAPIsStandardTest, EmptyVSOAndQueryLookup) { - bool OnResolvedRun = false; - bool OnReadyRun = false; - - auto Q = std::make_shared( - SymbolNameSet(), - [&](Expected RR) { - cantFail(std::move(RR)); - OnResolvedRun = true; - }, - [&](Error Err) { - cantFail(std::move(Err)); - OnReadyRun = true; - }); - - V.lookup(std::move(Q), {}); + ES.lookup({&V}, {}, OnResolution, OnReady, NoDependenciesToRegister); EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query"; EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query"; @@ -182,8 +154,8 @@ TEST_F(CoreAPIsStandardTest, ChainedVSOLookup) { auto Q = std::make_shared( SymbolNameSet({Foo}), - [&](Expected RR) { - cantFail(std::move(RR)); + [&](Expected Result) { + cantFail(std::move(Result)); OnResolvedRun = true; }, [&](Error Err) { @@ -191,7 +163,7 @@ TEST_F(CoreAPIsStandardTest, ChainedVSOLookup) { OnReadyRun = true; }); - V2.lookup(Q, V.lookup(Q, {Foo})); + V2.legacyLookup(Q, V.legacyLookup(Q, {Foo})); EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query"; EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query"; @@ -268,20 +240,15 @@ TEST_F(CoreAPIsStandardTest, TestTrivialCircularDependency) { cantFail(V.define(FooMU)); bool FooReady = false; - auto Q = - std::make_shared( - SymbolNameSet({ Foo }), - [](Expected R) { - cantFail(std::move(R)); - }, - [&](Error Err) { - cantFail(std::move(Err)); - FooReady = true; - }); + auto OnResolution = [](Expected R) { cantFail(std::move(R)); }; + auto OnReady = [&](Error Err) { + cantFail(std::move(Err)); + FooReady = true; + }; - V.lookup(std::move(Q), { Foo }); + ES.lookup({&V}, {Foo}, std::move(OnResolution), std::move(OnReady), + NoDependenciesToRegister); - FooR->addDependencies({{&V, {Foo}}}); FooR->resolve({{Foo, FooSym}}); FooR->finalize(); @@ -323,54 +290,52 @@ TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneVSO) { // Query each of the symbols to trigger materialization. bool FooResolved = false; bool FooReady = false; - auto FooQ = std::make_shared( - SymbolNameSet({Foo}), - [&](Expected RR) { - cantFail(std::move(RR)); - FooResolved = true; - }, - [&](Error Err) { - cantFail(std::move(Err)); - FooReady = true; - }); - { - auto Unresolved = V.lookup(FooQ, {Foo}); - EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Foo\""; - } + + auto OnFooResolution = [&](Expected Result) { + cantFail(std::move(Result)); + FooResolved = true; + }; + + auto OnFooReady = [&](Error Err) { + cantFail(std::move(Err)); + FooReady = true; + }; + + // Issue a lookup for Foo. Use NoDependenciesToRegister: We're going to add + // the dependencies manually below. + ES.lookup({&V}, {Foo}, std::move(OnFooResolution), std::move(OnFooReady), + NoDependenciesToRegister); bool BarResolved = false; bool BarReady = false; - auto BarQ = std::make_shared( - SymbolNameSet({Bar}), - [&](Expected RR) { - cantFail(std::move(RR)); - BarResolved = true; - }, - [&](Error Err) { - cantFail(std::move(Err)); - BarReady = true; - }); - { - auto Unresolved = V.lookup(BarQ, {Bar}); - EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Bar\""; - } + auto OnBarResolution = [&](Expected Result) { + cantFail(std::move(Result)); + BarResolved = true; + }; + + auto OnBarReady = [&](Error Err) { + cantFail(std::move(Err)); + BarReady = true; + }; + + ES.lookup({&V}, {Bar}, std::move(OnBarResolution), std::move(OnBarReady), + NoDependenciesToRegister); bool BazResolved = false; bool BazReady = false; - auto BazQ = std::make_shared( - SymbolNameSet({Baz}), - [&](Expected RR) { - cantFail(std::move(RR)); - BazResolved = true; - }, - [&](Error Err) { - cantFail(std::move(Err)); - BazReady = true; - }); - { - auto Unresolved = V.lookup(BazQ, {Baz}); - EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Baz\""; - } + + auto OnBazResolution = [&](Expected Result) { + cantFail(std::move(Result)); + BazResolved = true; + }; + + auto OnBazReady = [&](Error Err) { + cantFail(std::move(Err)); + BazReady = true; + }; + + ES.lookup({&V}, {Baz}, std::move(OnBazResolution), std::move(OnBazReady), + NoDependenciesToRegister); // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo. FooR->addDependencies({{&V, SymbolNameSet({Bar})}}); @@ -478,28 +443,23 @@ TEST_F(CoreAPIsStandardTest, AddAndMaterializeLazySymbol) { bool OnResolutionRun = false; bool OnReadyRun = false; - auto OnResolution = - [&](Expected Result) { - EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; - auto I = Result->Symbols.find(Foo); - EXPECT_NE(I, Result->Symbols.end()) - << "Could not find symbol definition"; - EXPECT_EQ(I->second.getAddress(), FooSym.getAddress()) - << "Resolution returned incorrect result"; - OnResolutionRun = true; - }; + auto OnResolution = [&](Expected Result) { + EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; + auto I = Result->find(Foo); + EXPECT_NE(I, Result->end()) << "Could not find symbol definition"; + EXPECT_EQ(I->second.getAddress(), FooSym.getAddress()) + << "Resolution returned incorrect result"; + OnResolutionRun = true; + }; auto OnReady = [&](Error Err) { cantFail(std::move(Err)); OnReadyRun = true; }; - auto Q = - std::make_shared(Names, OnResolution, OnReady); + ES.lookup({&V}, Names, std::move(OnResolution), std::move(OnReady), + NoDependenciesToRegister); - auto Unresolved = V.lookup(std::move(Q), Names); - - EXPECT_TRUE(Unresolved.empty()) << "Could not find Foo in dylib"; EXPECT_TRUE(FooMaterialized) << "Foo was not materialized"; EXPECT_TRUE(BarDiscarded) << "Bar was not discarded"; EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; @@ -714,13 +674,14 @@ TEST_F(CoreAPIsStandardTest, TestMaterializeWeakSymbol) { }); cantFail(V.define(MU)); - auto Q = std::make_shared( - SymbolNameSet({Foo}), - [](Expected R) { - cantFail(std::move(R)); - }, - [](Error Err) { cantFail(std::move(Err)); }); - V.lookup(std::move(Q), SymbolNameSet({Foo})); + auto OnResolution = [](Expected Result) { + cantFail(std::move(Result)); + }; + + auto OnReady = [](Error Err) { cantFail(std::move(Err)); }; + + ES.lookup({&V}, {Foo}, std::move(OnResolution), std::move(OnReady), + NoDependenciesToRegister); auto MU2 = llvm::make_unique( SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), diff --git a/llvm/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp b/llvm/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp index 596584b7117e..746ae1dca490 100644 --- a/llvm/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp @@ -24,7 +24,7 @@ TEST_F(LegacyAPIsStandardTest, TestLambdaSymbolResolver) { auto Resolver = createSymbolResolver( [&](const SymbolNameSet &Symbols) { return V.lookupFlags(Symbols); }, [&](std::shared_ptr Q, SymbolNameSet Symbols) { - return V.lookup(std::move(Q), Symbols); + return V.legacyLookup(std::move(Q), Symbols); }); SymbolNameSet Symbols({Foo, Bar, Baz}); @@ -42,21 +42,17 @@ TEST_F(LegacyAPIsStandardTest, TestLambdaSymbolResolver) { bool OnResolvedRun = false; - auto OnResolved = - [&](Expected Result) { - OnResolvedRun = true; - EXPECT_TRUE(!!Result) << "Unexpected error"; - EXPECT_EQ(Result->Symbols.size(), 2U) - << "Unexpected number of resolved symbols"; - EXPECT_EQ(Result->Symbols.count(Foo), 1U) - << "Missing lookup result for foo"; - EXPECT_EQ(Result->Symbols.count(Bar), 1U) - << "Missing lookup result for bar"; - EXPECT_EQ(Result->Symbols[Foo].getAddress(), FooSym.getAddress()) - << "Incorrect address for foo"; - EXPECT_EQ(Result->Symbols[Bar].getAddress(), BarSym.getAddress()) - << "Incorrect address for bar"; - }; + auto OnResolved = [&](Expected Result) { + OnResolvedRun = true; + EXPECT_TRUE(!!Result) << "Unexpected error"; + EXPECT_EQ(Result->size(), 2U) << "Unexpected number of resolved symbols"; + EXPECT_EQ(Result->count(Foo), 1U) << "Missing lookup result for foo"; + EXPECT_EQ(Result->count(Bar), 1U) << "Missing lookup result for bar"; + EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress()) + << "Incorrect address for foo"; + EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress()) + << "Incorrect address for bar"; + }; auto OnReady = [&](Error Err) { EXPECT_FALSE(!!Err) << "Finalization should never fail in this test"; }; @@ -85,7 +81,7 @@ TEST(LegacyAPIInteropTest, QueryAgainstVSO) { auto Lookup = [&](std::shared_ptr Query, SymbolNameSet Symbols) { - return V.lookup(std::move(Query), Symbols); + return V.legacyLookup(std::move(Query), Symbols); }; auto UnderlyingResolver = @@ -158,22 +154,18 @@ TEST(LegacyAPIInteropTset, LegacyLookupHelpersFn) { bool OnResolvedRun = false; bool OnReadyRun = false; - auto OnResolved = - [&](Expected Result) { - OnResolvedRun = true; - EXPECT_TRUE(!!Result) << "lookuWithLegacy failed to resolve"; + auto OnResolved = [&](Expected Result) { + OnResolvedRun = true; + EXPECT_TRUE(!!Result) << "lookuWithLegacy failed to resolve"; - auto &Resolved = Result->Symbols; - EXPECT_EQ(Resolved.size(), 2U) << "Wrong number of symbols resolved"; - EXPECT_EQ(Resolved.count(Foo), 1U) << "Result for foo missing"; - EXPECT_EQ(Resolved.count(Bar), 1U) << "Result for bar missing"; - EXPECT_EQ(Resolved[Foo].getAddress(), FooAddr) - << "Wrong address for foo"; - EXPECT_EQ(Resolved[Foo].getFlags(), FooFlags) << "Wrong flags for foo"; - EXPECT_EQ(Resolved[Bar].getAddress(), BarAddr) - << "Wrong address for bar"; - EXPECT_EQ(Resolved[Bar].getFlags(), BarFlags) << "Wrong flags for bar"; - }; + EXPECT_EQ(Result->size(), 2U) << "Wrong number of symbols resolved"; + EXPECT_EQ(Result->count(Foo), 1U) << "Result for foo missing"; + EXPECT_EQ(Result->count(Bar), 1U) << "Result for bar missing"; + EXPECT_EQ((*Result)[Foo].getAddress(), FooAddr) << "Wrong address for foo"; + EXPECT_EQ((*Result)[Foo].getFlags(), FooFlags) << "Wrong flags for foo"; + EXPECT_EQ((*Result)[Bar].getAddress(), BarAddr) << "Wrong address for bar"; + EXPECT_EQ((*Result)[Bar].getFlags(), BarFlags) << "Wrong flags for bar"; + }; auto OnReady = [&](Error Err) { EXPECT_FALSE(!!Err) << "Finalization unexpectedly failed"; OnReadyRun = true;