From: Reid Kleckner Date: Fri, 20 Jul 2018 20:20:45 +0000 (+0000) Subject: Revert r337595 "[ORC] Add new symbol lookup methods to ExecutionSessionBase in prepar... X-Git-Tag: android-x86-8.1-r1~544 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=1f565f54cd4767e2105b5a94470bee1049bf1091;p=android-x86%2Fexternal-llvm.git Revert r337595 "[ORC] Add new symbol lookup methods to ExecutionSessionBase in preparation for" Breaks the build with LLVM_ENABLE_THREADS=OFF. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@337608 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/ExecutionEngine/Orc/Core.h b/include/llvm/ExecutionEngine/Orc/Core.h index a6c0806a840..5060f84c241 100644 --- a/include/llvm/ExecutionEngine/Orc/Core.h +++ b/include/llvm/ExecutionEngine/Orc/Core.h @@ -69,23 +69,8 @@ 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: @@ -137,9 +122,6 @@ 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 @@ -241,9 +223,6 @@ 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 @@ -343,9 +322,6 @@ 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; @@ -396,50 +372,11 @@ public: void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */ } - 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. + /// Cause the given query to fail with the given Error. /// - /// - /// 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); + /// This should only be used by legacy APIs and will be deprecated in the + /// future. + void failQuery(AsynchronousSymbolQuery &Q, Error Err); /// Materialize the given unit. void dispatchMaterialization(VSO &V, @@ -457,20 +394,12 @@ 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 @@ -482,6 +411,21 @@ 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. @@ -541,7 +485,6 @@ private: class VSO { friend class AsynchronousSymbolQuery; friend class ExecutionSession; - friend class ExecutionSessionBase; friend class MaterializationResponsibility; public: using FallbackDefinitionGeneratorFunction = @@ -550,6 +493,9 @@ public: using AsynchronousSymbolQuerySet = std::set>; + using MaterializationUnitList = + std::vector>; + VSO(const VSO &) = delete; VSO &operator=(const VSO &) = delete; VSO(VSO &&) = delete; @@ -601,10 +547,8 @@ public: void removeFromSearchOrder(VSO &V); /// Do something with the search order (run under the session lock). - template - auto withSearchOrderDo(Func &&F) - -> decltype(F(std::declval())) { - return ES.runSessionLocked([&]() { return F(SearchOrder); }); + template void withSearchOrderDo(Func F) { + ES.runSessionLocked([&]() { F(SearchOrder); }); } /// Define all symbols provided by the materialization unit to be part @@ -635,10 +579,6 @@ 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. /// @@ -646,8 +586,11 @@ 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 legacyLookup(std::shared_ptr Q, - SymbolNameSet Names); + SymbolNameSet lookup(std::shared_ptr Q, + SymbolNameSet Names); + + /// Dump current VSO state to OS. + void dump(raw_ostream &OS); private: using AsynchronousSymbolQueryList = @@ -686,12 +629,6 @@ 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, @@ -710,8 +647,8 @@ private: SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags); - void addDependencies(const SymbolStringPtr &Name, - const SymbolDependenceMap &Dependants); + void addDependencies(const SymbolFlagsMap &Dependents, + const SymbolDependenceMap &Dependencies); void resolve(const SymbolMap &Resolved); @@ -719,6 +656,8 @@ private: void notifyFailed(const SymbolNameSet &FailedSymbols); + void runOutstandingMUs(); + ExecutionSessionBase &ES; std::string VSOName; SymbolMap Symbols; @@ -726,6 +665,11 @@ 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. @@ -749,6 +693,15 @@ 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/include/llvm/ExecutionEngine/Orc/Legacy.h b/include/llvm/ExecutionEngine/Orc/Legacy.h index 52c8c162ff0..e97f98edcdf 100644 --- a/include/llvm/ExecutionEngine/Orc/Legacy.h +++ b/include/llvm/ExecutionEngine/Orc/Legacy.h @@ -146,11 +146,11 @@ lookupWithLegacyFn(ExecutionSession &ES, AsynchronousSymbolQuery &Query, Query.notifySymbolReady(); NewSymbolsResolved = true; } else { - ES.legacyFailQuery(Query, Addr.takeError()); + ES.failQuery(Query, Addr.takeError()); return SymbolNameSet(); } } else if (auto Err = Sym.takeError()) { - ES.legacyFailQuery(Query, std::move(Err)); + ES.failQuery(Query, std::move(Err)); return SymbolNameSet(); } else SymbolsNotFound.insert(S); diff --git a/lib/ExecutionEngine/Orc/Core.cpp b/lib/ExecutionEngine/Orc/Core.cpp index dc6a1566bd3..65f11782288 100644 --- a/lib/ExecutionEngine/Orc/Core.cpp +++ b/lib/ExecutionEngine/Orc/Core.cpp @@ -23,9 +23,6 @@ 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) { @@ -141,359 +138,18 @@ 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([&]() { +void ExecutionSessionBase::failQuery(AsynchronousSymbolQuery &Q, Error Err) { + bool DeliveredError = true; + runSessionLocked([&]() -> void { Q.detach(); - SendErrorToQuery = Q.canStillFail(); - }); - - 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)); + if (Q.canStillFail()) + Q.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)); - } + DeliveredError = false; }); - 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->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) - 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; - } + if (!DeliveredError) + reportError(std::move(Err)); } AsynchronousSymbolQuery::AsynchronousSymbolQuery( @@ -505,6 +161,12 @@ 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, @@ -521,7 +183,8 @@ void AsynchronousSymbolQuery::handleFullyResolved() { assert(NotYetResolvedCount == 0 && "Not fully resolved?"); assert(NotifySymbolsResolved && "NotifySymbolsResolved already called or error occurred"); - NotifySymbolsResolved(std::move(ResolvedSymbols)); + NotifySymbolsResolved( + ResolutionResult(std::move(ResolvedSymbols), QueryRegistrations)); NotifySymbolsResolved = SymbolsResolvedCallback(); } @@ -686,8 +349,7 @@ MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) { void MaterializationResponsibility::addDependencies( const SymbolDependenceMap &Dependencies) { - for (auto &KV : SymbolFlags) - V.addDependencies(KV.first, Dependencies); + V.addDependencies(SymbolFlags, Dependencies); } AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit( @@ -722,9 +384,8 @@ ReExportsMaterializationUnit::ReExportsMaterializationUnit( void ReExportsMaterializationUnit::materialize( MaterializationResponsibility R) { - auto &ES = R.getTargetVSO().getExecutionSession(); - VSO &TgtV = R.getTargetVSO(); - VSO &SrcV = SourceVSO ? *SourceVSO : TgtV; + VSO &SrcV = SourceVSO ? *SourceVSO : R.getTargetVSO(); + auto &ES = SrcV.getExecutionSession(); // Find the set of requested aliases and aliasees. Return any unrequested // aliases back to the VSO so as to not prematurely materialize any aliasees. @@ -773,8 +434,9 @@ void ReExportsMaterializationUnit::materialize( auto Tmp = I++; // Chain detected. Skip this symbol for this round. - if (&SrcV == &TgtV && (QueryAliases.count(Tmp->second.Aliasee) || - RequestedAliases.count(Tmp->second.Aliasee))) + if (&SrcV == &R.getTargetVSO() && + (QueryAliases.count(Tmp->second.Aliasee) || + RequestedAliases.count(Tmp->second.Aliasee))) continue; ResponsibilitySymbols.insert(Tmp->first); @@ -797,32 +459,49 @@ void ReExportsMaterializationUnit::materialize( QueryInfos.pop_back(); - auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) { - R.addDependencies(Deps); - }; + 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); + + // 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); - 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(); - } - }; + SymbolDependenceMap Deps; + Deps[&SrcV] = std::move(Resolved); + QueryInfo->R.addDependencies(Deps); + + QueryInfo->R.finalize(); + } else { + auto &ES = QueryInfo->R.getTargetVSO().getExecutionSession(); + ES.reportError(RR.takeError()); + QueryInfo->R.failMaterialization(); + } + }; auto OnReady = [&ES](Error Err) { ES.reportError(std::move(Err)); }; - ES.lookup({&SrcV}, QuerySymbols, std::move(OnResolve), std::move(OnReady), - std::move(RegisterDependencies)); + 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; + } } } @@ -963,35 +642,40 @@ SymbolNameSet VSO::getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) { }); } -void VSO::addDependencies(const SymbolStringPtr &Name, +void VSO::addDependencies(const SymbolFlagsMap &Dependants, 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) { - 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); + 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"); + + 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) { + 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 (DepsOnOtherVSO.empty()) - MI.UnfinalizedDependencies.erase(&OtherVSO); - } + }); } void VSO::resolve(const SymbolMap &Resolved) { @@ -1172,6 +856,25 @@ 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); @@ -1236,89 +939,11 @@ SymbolNameSet VSO::lookupFlagsImpl(SymbolFlagsMap &Flags, return Unresolved; } -void VSO::lodgeQuery(std::shared_ptr &Q, - SymbolNameSet &Unresolved, MaterializationUnitList &MUs) { +SymbolNameSet VSO::lookup(std::shared_ptr Q, + SymbolNameSet Names) { 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 &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(); + runOutstandingMUs(); LookupImplActionFlags ActionFlags = None; std::vector> MUs; @@ -1353,11 +978,11 @@ SymbolNameSet VSO::legacyLookup(std::shared_ptr Q, // callbacks from asynchronous queries. // Add MUs to the OutstandingMUs list. { - std::lock_guard Lock(ES.OutstandingMUsMutex); + std::lock_guard Lock(OutstandingMUsMutex); for (auto &MU : MUs) - ES.OutstandingMUs.push_back(make_pair(this, std::move(MU))); + OutstandingMUs.push_back(std::move(MU)); } - ES.runOutstandingMUs(); + runOutstandingMUs(); // Dispatch any required MaterializationUnits for materialization. // for (auto &MU : MUs) @@ -1618,6 +1243,133 @@ 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()) @@ -1625,7 +1377,18 @@ Expected lookup(const VSOList &VSOs, SymbolNameSet Names) { auto &ES = (*VSOs.begin())->getExecutionSession(); - return ES.lookup(VSOs, Names, NoDependenciesToRegister, true); + 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); } /// Look up a symbol by searching a list of VSOs. diff --git a/lib/ExecutionEngine/Orc/Legacy.cpp b/lib/ExecutionEngine/Orc/Legacy.cpp index 22775ef14f8..6fde6898a16 100644 --- a/lib/ExecutionEngine/Orc/Legacy.cpp +++ b/lib/ExecutionEngine/Orc/Legacy.cpp @@ -29,14 +29,8 @@ JITSymbolResolverAdapter::lookup(const LookupSet &Symbols) { return R.lookup(std::move(Q), std::move(Unresolved)); }; - auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) { - if (MR) - MR->addDependencies(Deps); - }; - - auto InternedResult = - ES.legacyLookup(ES, std::move(LookupFn), std::move(InternedSymbols), - false, RegisterDependencies); + auto InternedResult = blockingLookup(ES, std::move(LookupFn), + std::move(InternedSymbols), false, MR); if (!InternedResult) return InternedResult.takeError(); diff --git a/lib/ExecutionEngine/Orc/OrcCBindingsStack.h b/lib/ExecutionEngine/Orc/OrcCBindingsStack.h index b9f8a370d2f..6c44f4367ec 100644 --- a/lib/ExecutionEngine/Orc/OrcCBindingsStack.h +++ b/lib/ExecutionEngine/Orc/OrcCBindingsStack.h @@ -156,11 +156,11 @@ private: Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags())); Query->notifySymbolReady(); } else { - Stack.ES.legacyFailQuery(*Query, Addr.takeError()); + Stack.ES.failQuery(*Query, Addr.takeError()); return orc::SymbolNameSet(); } } else if (auto Err = Sym.takeError()) { - Stack.ES.legacyFailQuery(*Query, std::move(Err)); + Stack.ES.failQuery(*Query, std::move(Err)); return orc::SymbolNameSet(); } else UnresolvedSymbols.insert(S); diff --git a/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h b/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h index abe89ce70af..ded53ac3106 100644 --- a/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h +++ b/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h @@ -178,11 +178,11 @@ class OrcMCJITReplacement : public ExecutionEngine { Query->notifySymbolReady(); NewSymbolsResolved = true; } else { - M.ES.legacyFailQuery(*Query, Addr.takeError()); + M.ES.failQuery(*Query, Addr.takeError()); return SymbolNameSet(); } } else if (auto Err = Sym.takeError()) { - M.ES.legacyFailQuery(*Query, std::move(Err)); + M.ES.failQuery(*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.legacyFailQuery(*Query, Addr.takeError()); + M.ES.failQuery(*Query, Addr.takeError()); return SymbolNameSet(); } } else if (auto Err = Sym2.takeError()) { - M.ES.legacyFailQuery(*Query, std::move(Err)); + M.ES.failQuery(*Query, std::move(Err)); return SymbolNameSet(); } else UnresolvedSymbols.insert(S); diff --git a/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp b/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp index 6edf616660e..7cdc6b352d1 100644 --- a/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp +++ b/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp @@ -16,23 +16,30 @@ using namespace llvm::orc; class VSOSearchOrderResolver : public JITSymbolResolver { public: - VSOSearchOrderResolver(MaterializationResponsibility &MR) : MR(MR) {} + VSOSearchOrderResolver(ExecutionSession &ES, + MaterializationResponsibility &MR) + : ES(ES), 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 RegisterDependencies = [&](const SymbolDependenceMap &Deps) { - MR.addDependencies(Deps); + 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 InternedResult = - MR.getTargetVSO().withSearchOrderDo([&](const VSOList &VSOs) { - return ES.lookup(VSOs, InternedSymbols, RegisterDependencies, false); - }); + auto InternedResult = blockingLookup( + ES, std::move(AsyncLookup), std::move(InternedSymbols), false, &MR); if (!InternedResult) return InternedResult.takeError(); @@ -45,8 +52,6 @@ public: } Expected lookupFlags(const LookupSet &Symbols) { - auto &ES = MR.getTargetVSO().getExecutionSession(); - SymbolNameSet InternedSymbols; for (auto &S : Symbols) @@ -70,6 +75,7 @@ public: } private: + ExecutionSession &ES; MaterializationResponsibility &MR; }; @@ -100,7 +106,7 @@ void RTDyldObjectLinkingLayer2::emit(MaterializationResponsibility R, auto MemoryManager = GetMemoryManager(K); - VSOSearchOrderResolver Resolver(R); + VSOSearchOrderResolver Resolver(ES, R); auto RTDyld = llvm::make_unique(*MemoryManager, Resolver); RTDyld->setProcessAllSections(ProcessAllSections); diff --git a/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp b/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp index d53c4558e0c..c0afbc6be06 100644 --- a/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp +++ b/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp @@ -59,57 +59,51 @@ private: DestructorFunction Destructor; }; -TEST_F(CoreAPIsStandardTest, BasicSuccessfulLookup) { + +TEST_F(CoreAPIsStandardTest, AsynchronousSymbolQuerySuccessfulResolutionOnly) { bool OnResolutionRun = false; bool OnReadyRun = false; - - 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 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 OnReady = [&](Error Err) { cantFail(std::move(Err)); OnReadyRun = true; }; - std::shared_ptr FooMR; - - cantFail(V.define(llvm::make_unique( - SymbolFlagsMap({{Foo, FooSym.getFlags()}}), - [&](MaterializationResponsibility R) { - FooMR = std::make_shared(std::move(R)); - }))); - - ES.lookup({&V}, {Foo}, OnResolution, OnReady, NoDependenciesToRegister); + AsynchronousSymbolQuery Q(SymbolNameSet({Foo}), OnResolution, OnReady); - EXPECT_FALSE(OnResolutionRun) << "Should not have been resolved yet"; - EXPECT_FALSE(OnReadyRun) << "Should not have been marked ready yet"; + Q.resolve(Foo, FooSym); - FooMR->resolve({{Foo, FooSym}}); + EXPECT_TRUE(Q.isFullyResolved()) << "Expected query to be fully resolved"; - EXPECT_TRUE(OnResolutionRun) << "Should have been resolved"; - EXPECT_FALSE(OnReadyRun) << "Should not have been marked ready yet"; + if (!Q.isFullyResolved()) + return; - FooMR->finalize(); + Q.handleFullyResolved(); - EXPECT_TRUE(OnReadyRun) << "Should have been marked ready"; + EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; + EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run"; } 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; @@ -117,28 +111,62 @@ TEST_F(CoreAPIsStandardTest, ExecutionSessionFailQuery) { AsynchronousSymbolQuery Q(SymbolNameSet({Foo}), OnResolution, OnReady); - ES.legacyFailQuery(Q, - make_error("xyz", inconvertibleErrorCode())); + ES.failQuery(Q, make_error("xyz", inconvertibleErrorCode())); EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run"; } -TEST_F(CoreAPIsStandardTest, EmptyLookup) { - bool OnResolvedRun = false; +TEST_F(CoreAPIsStandardTest, SimpleAsynchronousSymbolQueryAgainstVSO) { + bool OnResolutionRun = false; bool OnReadyRun = false; - auto OnResolution = [&](Expected Result) { - cantFail(std::move(Result)); - OnResolvedRun = true; - }; + 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 OnReady = [&](Error Err) { cantFail(std::move(Err)); OnReadyRun = true; }; - ES.lookup({&V}, {}, OnResolution, OnReady, NoDependenciesToRegister); + 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), {}); EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query"; EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query"; @@ -154,8 +182,8 @@ TEST_F(CoreAPIsStandardTest, ChainedVSOLookup) { auto Q = std::make_shared( SymbolNameSet({Foo}), - [&](Expected Result) { - cantFail(std::move(Result)); + [&](Expected RR) { + cantFail(std::move(RR)); OnResolvedRun = true; }, [&](Error Err) { @@ -163,7 +191,7 @@ TEST_F(CoreAPIsStandardTest, ChainedVSOLookup) { OnReadyRun = true; }); - V2.legacyLookup(Q, V.legacyLookup(Q, {Foo})); + V2.lookup(Q, V.lookup(Q, {Foo})); EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query"; EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query"; @@ -240,15 +268,20 @@ TEST_F(CoreAPIsStandardTest, TestTrivialCircularDependency) { cantFail(V.define(FooMU)); bool FooReady = false; - auto OnResolution = [](Expected R) { cantFail(std::move(R)); }; - auto OnReady = [&](Error Err) { - cantFail(std::move(Err)); - FooReady = true; - }; + auto Q = + std::make_shared( + SymbolNameSet({ Foo }), + [](Expected R) { + cantFail(std::move(R)); + }, + [&](Error Err) { + cantFail(std::move(Err)); + FooReady = true; + }); - ES.lookup({&V}, {Foo}, std::move(OnResolution), std::move(OnReady), - NoDependenciesToRegister); + V.lookup(std::move(Q), { Foo }); + FooR->addDependencies({{&V, {Foo}}}); FooR->resolve({{Foo, FooSym}}); FooR->finalize(); @@ -290,52 +323,54 @@ TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneVSO) { // Query each of the symbols to trigger materialization. bool FooResolved = false; bool FooReady = false; - - 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); + 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\""; + } bool BarResolved = false; bool BarReady = false; - 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); + 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\""; + } bool BazResolved = false; bool BazReady = false; - - 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); + 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\""; + } // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo. FooR->addDependencies({{&V, SymbolNameSet({Bar})}}); @@ -443,23 +478,28 @@ TEST_F(CoreAPIsStandardTest, AddAndMaterializeLazySymbol) { bool OnResolutionRun = false; bool OnReadyRun = false; - 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 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 OnReady = [&](Error Err) { cantFail(std::move(Err)); OnReadyRun = true; }; - ES.lookup({&V}, Names, std::move(OnResolution), std::move(OnReady), - NoDependenciesToRegister); + auto Q = + std::make_shared(Names, OnResolution, OnReady); + 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"; @@ -674,14 +714,13 @@ TEST_F(CoreAPIsStandardTest, TestMaterializeWeakSymbol) { }); cantFail(V.define(MU)); - 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 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 MU2 = llvm::make_unique( SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), diff --git a/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp b/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp index 746ae1dca49..596584b7117 100644 --- a/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp +++ b/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.legacyLookup(std::move(Q), Symbols); + return V.lookup(std::move(Q), Symbols); }); SymbolNameSet Symbols({Foo, Bar, Baz}); @@ -42,17 +42,21 @@ TEST_F(LegacyAPIsStandardTest, TestLambdaSymbolResolver) { bool OnResolvedRun = false; - 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 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 OnReady = [&](Error Err) { EXPECT_FALSE(!!Err) << "Finalization should never fail in this test"; }; @@ -81,7 +85,7 @@ TEST(LegacyAPIInteropTest, QueryAgainstVSO) { auto Lookup = [&](std::shared_ptr Query, SymbolNameSet Symbols) { - return V.legacyLookup(std::move(Query), Symbols); + return V.lookup(std::move(Query), Symbols); }; auto UnderlyingResolver = @@ -154,18 +158,22 @@ TEST(LegacyAPIInteropTset, LegacyLookupHelpersFn) { bool OnResolvedRun = false; bool OnReadyRun = false; - auto OnResolved = [&](Expected Result) { - OnResolvedRun = true; - EXPECT_TRUE(!!Result) << "lookuWithLegacy failed to resolve"; - - 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 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"; + }; auto OnReady = [&](Error Err) { EXPECT_FALSE(!!Err) << "Finalization unexpectedly failed"; OnReadyRun = true;