Skip to content

Commit

Permalink
[ORC] Make EPCDynamicLibrarySearchGenerator async
Browse files Browse the repository at this point in the history
Switch the primary implementation of EPC lookupSymbols to be async,
keeping a synchronous wrapper for compatibility. Use the new async
implementation inside EPCDynamicLibrarySearchGenerator to work
working towards a fully async search generator.

Provide an asynchronous lookup API for EPCGenericDylibManager and adopt
that from the SimpleRemoteEPC. This enables an end-to-end async
EPCDynamicLibrarySearchGenerator. Note: currently we keep the current
per-dlhandle lookup model, but a future improvement could do a single
async call for a given lookup operation.
  • Loading branch information
benlangmuir committed Feb 12, 2024
1 parent 50b8a3c commit 54226e2
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 74 deletions.
25 changes: 23 additions & 2 deletions llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,32 @@ class EPCGenericDylibManager {

/// Looks up symbols within the given dylib.
Expected<std::vector<ExecutorSymbolDef>>
lookup(tpctypes::DylibHandle H, const SymbolLookupSet &Lookup);
lookup(tpctypes::DylibHandle H, const SymbolLookupSet &Lookup) {
std::promise<MSVCPExpected<std::vector<ExecutorSymbolDef>>> RP;
auto RF = RP.get_future();
lookupAsync(H, Lookup, [&RP](auto R) { RP.set_value(std::move(R)); });
return RF.get();
}

/// Looks up symbols within the given dylib.
Expected<std::vector<ExecutorSymbolDef>>
lookup(tpctypes::DylibHandle H, const RemoteSymbolLookupSet &Lookup);
lookup(tpctypes::DylibHandle H, const RemoteSymbolLookupSet &Lookup) {
std::promise<MSVCPExpected<std::vector<ExecutorSymbolDef>>> RP;
auto RF = RP.get_future();
lookupAsync(H, Lookup, [&RP](auto R) { RP.set_value(std::move(R)); });
return RF.get();
}

using SymbolLookupCompleteFn =
unique_function<void(Expected<std::vector<ExecutorSymbolDef>>)>;

/// Looks up symbols within the given dylib.
void lookupAsync(tpctypes::DylibHandle H, const SymbolLookupSet &Lookup,
SymbolLookupCompleteFn Complete);

/// Looks up symbols within the given dylib.
void lookupAsync(tpctypes::DylibHandle H, const RemoteSymbolLookupSet &Lookup,
SymbolLookupCompleteFn Complete);

private:
ExecutorProcessControl &EPC;
Expand Down
30 changes: 24 additions & 6 deletions llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,26 @@ class ExecutorProcessControl {
/// that correspond to the lookup order. If a required symbol is not
/// found then this method will return an error. If a weakly referenced
/// symbol is not found then it be assigned a '0' value.
virtual Expected<std::vector<tpctypes::LookupResult>>
lookupSymbols(ArrayRef<LookupRequest> Request) = 0;
Expected<std::vector<tpctypes::LookupResult>>
lookupSymbols(ArrayRef<LookupRequest> Request) {
std::promise<MSVCPExpected<std::vector<tpctypes::LookupResult>>> RP;
auto RF = RP.get_future();
lookupSymbolsAsync(Request,
[&RP](auto Result) { RP.set_value(std::move(Result)); });
return RF.get();
}

using SymbolLookupCompleteFn =
unique_function<void(Expected<std::vector<tpctypes::LookupResult>>)>;

/// Search for symbols in the target process.
///
/// The result of the lookup is a 2-dimensional array of target addresses
/// that correspond to the lookup order. If a required symbol is not
/// found then this method will return an error. If a weakly referenced
/// symbol is not found then it be assigned a '0' value.
virtual void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
SymbolLookupCompleteFn F) = 0;

/// Run function with a main-like signature.
virtual Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
Expand Down Expand Up @@ -462,8 +480,8 @@ class UnsupportedExecutorProcessControl : public ExecutorProcessControl,
llvm_unreachable("Unsupported");
}

Expected<std::vector<tpctypes::LookupResult>>
lookupSymbols(ArrayRef<LookupRequest> Request) override {
void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
SymbolLookupCompleteFn F) override {
llvm_unreachable("Unsupported");
}

Expand Down Expand Up @@ -510,8 +528,8 @@ class SelfExecutorProcessControl : public ExecutorProcessControl,

Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;

Expected<std::vector<tpctypes::LookupResult>>
lookupSymbols(ArrayRef<LookupRequest> Request) override;
void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
SymbolLookupCompleteFn F) override;

Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
ArrayRef<std::string> Args) override;
Expand Down
4 changes: 2 additions & 2 deletions llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ class SimpleRemoteEPC : public ExecutorProcessControl,

Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;

Expected<std::vector<tpctypes::LookupResult>>
lookupSymbols(ArrayRef<LookupRequest> Request) override;
void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
SymbolLookupCompleteFn F) override;

Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
ArrayRef<std::string> Args) override;
Expand Down
53 changes: 30 additions & 23 deletions llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
#include "llvm/Support/Error.h"

namespace llvm {
namespace orc {
Expand Down Expand Up @@ -39,32 +40,38 @@ Error EPCDynamicLibrarySearchGenerator::tryToGenerate(
LookupSymbols.add(KV.first, SymbolLookupFlags::WeaklyReferencedSymbol);
}

SymbolMap NewSymbols;

ExecutorProcessControl::LookupRequest Request(H, LookupSymbols);
auto Result = EPC.lookupSymbols(Request);
if (!Result)
return Result.takeError();

assert(Result->size() == 1 && "Results for more than one library returned");
assert(Result->front().size() == LookupSymbols.size() &&
"Result has incorrect number of elements");

auto ResultI = Result->front().begin();
for (auto &KV : LookupSymbols) {
if (ResultI->getAddress())
NewSymbols[KV.first] = *ResultI;
++ResultI;
}
// Copy-capture LookupSymbols, since LookupRequest keeps a reference.
EPC.lookupSymbolsAsync(Request, [this, &JD, LS = std::move(LS),
LookupSymbols](auto Result) mutable {
if (!Result)
return LS.continueLookup(Result.takeError());

// If there were no resolved symbols bail out.
if (NewSymbols.empty())
return Error::success();
assert(Result->size() == 1 && "Results for more than one library returned");
assert(Result->front().size() == LookupSymbols.size() &&
"Result has incorrect number of elements");

SymbolMap NewSymbols;
auto ResultI = Result->front().begin();
for (auto &KV : LookupSymbols) {
if (ResultI->getAddress())
NewSymbols[KV.first] = *ResultI;
++ResultI;
}

// If there were no resolved symbols bail out.
if (NewSymbols.empty())
return LS.continueLookup(Error::success());

// Define resolved symbols.
Error Err = AddAbsoluteSymbols
? AddAbsoluteSymbols(JD, std::move(NewSymbols))
: JD.define(absoluteSymbols(std::move(NewSymbols)));

LS.continueLookup(std::move(Err));
});

// Define resolved symbols.
if (AddAbsoluteSymbols)
return AddAbsoluteSymbols(JD, std::move(NewSymbols));
return JD.define(absoluteSymbols(std::move(NewSymbols)));
return Error::success();
}

} // end namespace orc
Expand Down
50 changes: 30 additions & 20 deletions llvm/lib/ExecutionEngine/Orc/EPCGenericDylibManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,28 +81,38 @@ Expected<tpctypes::DylibHandle> EPCGenericDylibManager::open(StringRef Path,
return H;
}

Expected<std::vector<ExecutorSymbolDef>>
EPCGenericDylibManager::lookup(tpctypes::DylibHandle H,
const SymbolLookupSet &Lookup) {
Expected<std::vector<ExecutorSymbolDef>> Result(
(std::vector<ExecutorSymbolDef>()));
if (auto Err =
EPC.callSPSWrapper<rt::SPSSimpleExecutorDylibManagerLookupSignature>(
SAs.Lookup, Result, SAs.Instance, H, Lookup))
return std::move(Err);
return Result;
void EPCGenericDylibManager::lookupAsync(tpctypes::DylibHandle H,
const SymbolLookupSet &Lookup,
SymbolLookupCompleteFn Complete) {
EPC.callSPSWrapperAsync<rt::SPSSimpleExecutorDylibManagerLookupSignature>(
SAs.Lookup,
[Complete = std::move(Complete)](
Error SerializationErr,
Expected<std::vector<ExecutorSymbolDef>> Result) mutable {
if (SerializationErr) {
cantFail(Result.takeError());
Complete(std::move(SerializationErr));
}
Complete(std::move(Result));
},
SAs.Instance, H, Lookup);
}

Expected<std::vector<ExecutorSymbolDef>>
EPCGenericDylibManager::lookup(tpctypes::DylibHandle H,
const RemoteSymbolLookupSet &Lookup) {
Expected<std::vector<ExecutorSymbolDef>> Result(
(std::vector<ExecutorSymbolDef>()));
if (auto Err =
EPC.callSPSWrapper<rt::SPSSimpleExecutorDylibManagerLookupSignature>(
SAs.Lookup, Result, SAs.Instance, H, Lookup))
return std::move(Err);
return Result;
void EPCGenericDylibManager::lookupAsync(tpctypes::DylibHandle H,
const RemoteSymbolLookupSet &Lookup,
SymbolLookupCompleteFn Complete) {
EPC.callSPSWrapperAsync<rt::SPSSimpleExecutorDylibManagerLookupSignature>(
SAs.Lookup,
[Complete = std::move(Complete)](
Error SerializationErr,
Expected<std::vector<ExecutorSymbolDef>> Result) mutable {
if (SerializationErr) {
cantFail(Result.takeError());
Complete(std::move(SerializationErr));
}
Complete(std::move(Result));
},
SAs.Instance, H, Lookup);
}

} // end namespace orc
Expand Down
10 changes: 6 additions & 4 deletions llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@ SelfExecutorProcessControl::loadDylib(const char *DylibPath) {
return ExecutorAddr::fromPtr(Dylib.getOSSpecificHandle());
}

Expected<std::vector<tpctypes::LookupResult>>
SelfExecutorProcessControl::lookupSymbols(ArrayRef<LookupRequest> Request) {
void SelfExecutorProcessControl::lookupSymbolsAsync(
ArrayRef<LookupRequest> Request,
ExecutorProcessControl::SymbolLookupCompleteFn Complete) {
std::vector<tpctypes::LookupResult> R;

for (auto &Elem : Request) {
Expand All @@ -105,15 +106,16 @@ SelfExecutorProcessControl::lookupSymbols(ArrayRef<LookupRequest> Request) {
// FIXME: Collect all failing symbols before erroring out.
SymbolNameVector MissingSymbols;
MissingSymbols.push_back(Sym);
return make_error<SymbolsNotFound>(SSP, std::move(MissingSymbols));
return Complete(
make_error<SymbolsNotFound>(SSP, std::move(MissingSymbols)));
}
// FIXME: determine accurate JITSymbolFlags.
R.back().push_back(
{ExecutorAddr::fromPtr(Addr), JITSymbolFlags::Exported});
}
}

return R;
Complete(std::move(R));
}

Expected<int32_t>
Expand Down
45 changes: 31 additions & 14 deletions llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,37 @@ SimpleRemoteEPC::loadDylib(const char *DylibPath) {
return DylibMgr->open(DylibPath, 0);
}

Expected<std::vector<tpctypes::LookupResult>>
SimpleRemoteEPC::lookupSymbols(ArrayRef<LookupRequest> Request) {
std::vector<tpctypes::LookupResult> Result;

for (auto &Element : Request) {
if (auto R = DylibMgr->lookup(Element.Handle, Element.Symbols)) {
Result.push_back({});
Result.back().reserve(R->size());
for (auto Addr : *R)
Result.back().push_back(Addr);
} else
return R.takeError();
}
return std::move(Result);
/// Async helper to chain together calls to DylibMgr::lookupAsync to fulfill all
/// all the requests.
/// FIXME: The dylib manager should support multiple LookupRequests natively.
static void
lookupSymbolsAsyncHelper(EPCGenericDylibManager &DylibMgr,
ArrayRef<SimpleRemoteEPC::LookupRequest> Request,
std::vector<tpctypes::LookupResult> Result,
SimpleRemoteEPC::SymbolLookupCompleteFn Complete) {
if (Request.empty())
return Complete(std::move(Result));

auto &Element = Request.front();
DylibMgr.lookupAsync(Element.Handle, Element.Symbols,
[&DylibMgr, Request, Complete = std::move(Complete),
Result = std::move(Result)](auto R) mutable {
if (!R)
return Complete(R.takeError());
Result.push_back({});
Result.back().reserve(R->size());
for (auto Addr : *R)
Result.back().push_back(Addr);

lookupSymbolsAsyncHelper(
DylibMgr, Request.drop_front(), std::move(Result),
std::move(Complete));
});
}

void SimpleRemoteEPC::lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
SymbolLookupCompleteFn Complete) {
lookupSymbolsAsyncHelper(*DylibMgr, Request, {}, std::move(Complete));
}

Expected<int32_t> SimpleRemoteEPC::runAsMain(ExecutorAddr MainFnAddr,
Expand Down
6 changes: 3 additions & 3 deletions llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ TEST(ObjectLinkingLayerSearchGeneratorTest, AbsoluteSymbolsObjectLayer) {
return ExecutorAddr::fromPtr((void *)nullptr);
}

Expected<std::vector<tpctypes::LookupResult>>
lookupSymbols(ArrayRef<LookupRequest> Request) override {
void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
SymbolLookupCompleteFn Complete) override {
std::vector<ExecutorSymbolDef> Result;
EXPECT_EQ(Request.size(), 1u);
for (auto &LR : Request) {
Expand All @@ -205,7 +205,7 @@ TEST(ObjectLinkingLayerSearchGeneratorTest, AbsoluteSymbolsObjectLayer) {
}
}
}
return std::vector<tpctypes::LookupResult>{1, Result};
Complete(std::vector<tpctypes::LookupResult>{1, Result});
}
};

Expand Down

0 comments on commit 54226e2

Please sign in to comment.