[llvm] bb72f07 - Re-apply bb27e456435 and 5629afea910 with fixes.
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 11 21:32:02 PDT 2021
Author: Lang Hames
Date: 2021-09-12T14:23:22+10:00
New Revision: bb72f073808a42e35ddc52cb0810470ffeb3cce3
URL: https://github.com/llvm/llvm-project/commit/bb72f073808a42e35ddc52cb0810470ffeb3cce3
DIFF: https://github.com/llvm/llvm-project/commit/bb72f073808a42e35ddc52cb0810470ffeb3cce3.diff
LOG: Re-apply bb27e456435 and 5629afea910 with fixes.
This reapplies bb27e4564355243e479cab40885d6e0f7f640572 (SimpleRemoteEPC
support) and 2269a941a450a0d395161cfb792be58870b2875b (#include <mutex>
fix) with further fixes to support building with LLVM_ENABLE_THREADS=Off.
Added:
llvm/include/llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h
llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h
llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h
llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp
llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp
Modified:
llvm/include/llvm/ExecutionEngine/Orc/Core.h
llvm/include/llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h
llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h
llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp
llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
llvm/tools/llvm-jitlink/llvm-jitlink.cpp
llvm/tools/llvm-jitlink/llvm-jitlink.h
Removed:
llvm/lib/ExecutionEngine/Orc/EPCGenericMemoryAccess.cpp
################################################################################
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Core.h b/llvm/include/llvm/ExecutionEngine/Orc/Core.h
index 331a921c8abe..062b1f3e93e6 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Core.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Core.h
@@ -1302,7 +1302,8 @@ class ExecutionSession {
/// object.
ExecutionSession(std::unique_ptr<ExecutorProcessControl> EPC);
- /// End the session. Closes all JITDylibs.
+ /// End the session. Closes all JITDylibs and disconnects from the
+ /// executor.
Error endSession();
/// Get the ExecutorProcessControl object associated with this
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h
index 0dd1e6a7562a..48007129fd9f 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h
@@ -38,11 +38,6 @@ class EPCGenericJITLinkMemoryManager : public jitlink::JITLinkMemoryManager {
EPCGenericJITLinkMemoryManager(ExecutorProcessControl &EPC, FuncAddrs FAs)
: EPC(EPC), FAs(FAs) {}
- /// Create using the standard memory allocation function names from the
- /// ORCTargetProcess library.
- static Expected<std::unique_ptr<EPCGenericJITLinkMemoryManager>>
- CreateUsingOrcRTFuncs(ExecutorProcessControl &EPC);
-
Expected<std::unique_ptr<Allocation>>
allocate(const jitlink::JITLinkDylib *JD,
const SegmentsRequestMap &Request) override;
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h
index fe9d1c13881c..80a84ce9d013 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h
@@ -39,11 +39,6 @@ class EPCGenericMemoryAccess : public ExecutorProcessControl::MemoryAccess {
EPCGenericMemoryAccess(ExecutorProcessControl &EPC, FuncAddrs FAs)
: EPC(EPC), FAs(FAs) {}
- /// Create using the standard memory access function names from the
- /// ORCTargetProcess library.
- static Expected<std::unique_ptr<EPCGenericMemoryAccess>>
- CreateUsingOrcRTFuncs(ExecutorProcessControl &EPC);
-
void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
WriteResultFn OnWriteComplete) override {
using namespace shared;
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h
new file mode 100644
index 000000000000..7d1df1632b36
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h
@@ -0,0 +1,250 @@
+//===--- SimpleRemoteEPCUtils.h - Utils for Simple Remote EPC ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Message definitions and other utilities for SimpleRemoteEPC and
+// SimpleRemoteEPCServer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H
+#define LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
+#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
+#include "llvm/Support/Error.h"
+
+#include <mutex>
+#include <string>
+#include <thread>
+
+namespace llvm {
+namespace orc {
+
+namespace SimpleRemoteEPCDefaultBootstrapSymbolNames {
+extern const char *ExecutorSessionObjectName;
+extern const char *DispatchFnName;
+} // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
+
+enum class SimpleRemoteEPCOpcode : uint8_t {
+ FirstOpC,
+ Setup = FirstOpC,
+ Hangup,
+ Result,
+ CallWrapper,
+ LastOpC = CallWrapper
+};
+
+struct SimpleRemoteEPCExecutorInfo {
+ std::string TargetTriple;
+ uint64_t PageSize;
+ StringMap<ExecutorAddress> BootstrapSymbols;
+
+ Expected<ExecutorAddress> getBootstrapSymbol(StringRef Name) const {
+ auto I = BootstrapSymbols.find(Name);
+ if (I == BootstrapSymbols.end())
+ return make_error<StringError>("Symbol \"" + Name +
+ "\" not found in "
+ "bootstrap symbols map",
+ inconvertibleErrorCode());
+ return I->second;
+ }
+
+ Error getBootstrapSymbols(
+ ArrayRef<std::pair<ExecutorAddress &, StringRef>> Pairs) const {
+ for (auto &KV : Pairs) {
+ if (auto A = getBootstrapSymbol(KV.second))
+ KV.first = *A;
+ else
+ return A.takeError();
+ }
+ return Error::success();
+ }
+};
+
+using SimpleRemoteEPCArgBytesVector = SmallVector<char, 128>;
+
+class SimpleRemoteEPCTransportClient {
+public:
+ enum HandleMessageAction { ContinueSession, EndSession };
+
+ virtual ~SimpleRemoteEPCTransportClient();
+
+ /// Handle receipt of a message.
+ ///
+ /// Returns an Error if the message cannot be handled, 'EndSession' if the
+ /// client will not accept any further messages, and 'ContinueSession'
+ /// otherwise.
+ virtual Expected<HandleMessageAction>
+ handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
+ ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes) = 0;
+
+ /// Handle a disconnection from the underlying transport. No further messages
+ /// should be sent to handleMessage after this is called.
+ /// Err may contain an Error value indicating unexpected disconnection. This
+ /// allows clients to log such errors, but no attempt should be made at
+ /// recovery (which should be handled inside the transport class, if it is
+ /// supported at all).
+ virtual void handleDisconnect(Error Err) = 0;
+};
+
+class SimpleRemoteEPCTransport {
+public:
+ virtual ~SimpleRemoteEPCTransport();
+
+ /// Send a SimpleRemoteEPC message.
+ ///
+ /// This function may be called concurrently. Subclasses should implement
+ /// locking if required for the underlying transport.
+ virtual Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
+ ExecutorAddress TagAddr,
+ ArrayRef<char> ArgBytes) = 0;
+
+ /// Trigger disconnection from the transport. The implementation should
+ /// respond by calling handleDisconnect on the client once disconnection
+ /// is complete.
+ virtual void disconnect() = 0;
+};
+
+/// Uses read/write on FileDescriptors for transport.
+class FDSimpleRemoteEPCTransport : public SimpleRemoteEPCTransport {
+public:
+ /// Create a FDSimpleRemoteEPCTransport using the given FDs for
+ /// reading (InFD) and writing (OutFD).
+ static Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
+ Create(SimpleRemoteEPCTransportClient &C, int InFD, int OutFD);
+
+ /// Create a FDSimpleRemoteEPCTransport using the given FD for both
+ /// reading and writing.
+ static Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
+ Create(SimpleRemoteEPCTransportClient &C, int FD) {
+ return Create(C, FD, FD);
+ }
+
+ ~FDSimpleRemoteEPCTransport() override;
+
+ Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
+ ExecutorAddress TagAddr, ArrayRef<char> ArgBytes) override;
+
+ void disconnect() override;
+
+private:
+ FDSimpleRemoteEPCTransport(SimpleRemoteEPCTransportClient &C, int InFD,
+ int OutFD);
+
+ Error readBytes(char *Dst, size_t Size, bool *IsEOF = nullptr);
+ int writeBytes(const char *Src, size_t Size);
+ void listenLoop();
+
+ std::mutex M;
+ SimpleRemoteEPCTransportClient &C;
+ std::thread ListenerThread;
+ int InFD, OutFD;
+};
+
+struct RemoteSymbolLookupSetElement {
+ std::string Name;
+ bool Required;
+};
+
+using RemoteSymbolLookupSet = std::vector<RemoteSymbolLookupSetElement>;
+
+struct RemoteSymbolLookup {
+ uint64_t H;
+ RemoteSymbolLookupSet Symbols;
+};
+
+namespace shared {
+
+using SPSRemoteSymbolLookupSetElement = SPSTuple<SPSString, bool>;
+
+using SPSRemoteSymbolLookupSet = SPSSequence<SPSRemoteSymbolLookupSetElement>;
+
+using SPSRemoteSymbolLookup = SPSTuple<uint64_t, SPSRemoteSymbolLookupSet>;
+
+/// Tuple containing target triple, page size, and bootstrap symbols.
+using SPSSimpleRemoteEPCExecutorInfo =
+ SPSTuple<SPSString, uint64_t,
+ SPSSequence<SPSTuple<SPSString, SPSExecutorAddress>>>;
+
+template <>
+class SPSSerializationTraits<SPSRemoteSymbolLookupSetElement,
+ RemoteSymbolLookupSetElement> {
+public:
+ static size_t size(const RemoteSymbolLookupSetElement &V) {
+ return SPSArgList<SPSString, bool>::size(V.Name, V.Required);
+ }
+
+ static size_t serialize(SPSOutputBuffer &OB,
+ const RemoteSymbolLookupSetElement &V) {
+ return SPSArgList<SPSString, bool>::serialize(OB, V.Name, V.Required);
+ }
+
+ static size_t deserialize(SPSInputBuffer &IB,
+ RemoteSymbolLookupSetElement &V) {
+ return SPSArgList<SPSString, bool>::deserialize(IB, V.Name, V.Required);
+ }
+};
+
+template <>
+class SPSSerializationTraits<SPSRemoteSymbolLookup, RemoteSymbolLookup> {
+public:
+ static size_t size(const RemoteSymbolLookup &V) {
+ return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::size(V.H, V.Symbols);
+ }
+
+ static size_t serialize(SPSOutputBuffer &OB, const RemoteSymbolLookup &V) {
+ return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::serialize(OB, V.H,
+ V.Symbols);
+ }
+
+ static size_t deserialize(SPSInputBuffer &IB, RemoteSymbolLookup &V) {
+ return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::deserialize(
+ IB, V.H, V.Symbols);
+ }
+};
+
+template <>
+class SPSSerializationTraits<SPSSimpleRemoteEPCExecutorInfo,
+ SimpleRemoteEPCExecutorInfo> {
+public:
+ static size_t size(const SimpleRemoteEPCExecutorInfo &SI) {
+ return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::size(
+ SI.TargetTriple, SI.PageSize, SI.BootstrapSymbols);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB,
+ const SimpleRemoteEPCExecutorInfo &SI) {
+ return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::serialize(
+ OB, SI.TargetTriple, SI.PageSize, SI.BootstrapSymbols);
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, SimpleRemoteEPCExecutorInfo &SI) {
+ return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::deserialize(
+ IB, SI.TargetTriple, SI.PageSize, SI.BootstrapSymbols);
+ }
+};
+
+using SPSRunAsMainSignature = int64_t(SPSExecutorAddress,
+ SPSSequence<SPSString>);
+
+using SPSLoadDylibSignature =
+ SPSExpected<SPSExecutorAddress>(SPSExecutorAddress, SPSString, uint64_t);
+
+using SPSLookupSymbolsSignature =
+ SPSExpected<SPSSequence<SPSSequence<SPSExecutorAddress>>>(
+ SPSExecutorAddress, SPSSequence<SPSRemoteSymbolLookup>);
+
+} // end namespace shared
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h b/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h
new file mode 100644
index 000000000000..252474abecbd
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h
@@ -0,0 +1,136 @@
+//===---- SimpleRemoteEPC.h - Simple remote executor control ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Simple remote executor process control.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_SIMPLEREMOTEEPC_H
+#define LLVM_EXECUTIONENGINE_ORC_SIMPLEREMOTEEPC_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FunctionExtras.h"
+#include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"
+#include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h"
+#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
+#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MSVCErrorWorkarounds.h"
+
+#include <future>
+
+namespace llvm {
+namespace orc {
+
+class SimpleRemoteEPC : public ExecutorProcessControl,
+ public SimpleRemoteEPCTransportClient {
+public:
+ /// Create a SimpleRemoteEPC using the given transport type and args.
+ template <typename TransportT, typename... TransportTCtorArgTs>
+ static Expected<std::unique_ptr<SimpleRemoteEPC>>
+ Create(TransportTCtorArgTs &&...TransportTCtorArgs) {
+ std::unique_ptr<SimpleRemoteEPC> SREPC(
+ new SimpleRemoteEPC(std::make_shared<SymbolStringPool>()));
+
+ // Prepare for setup packet.
+ std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
+ auto EIF = EIP.get_future();
+ SREPC->prepareToReceiveSetupMessage(EIP);
+ auto T = TransportT::Create(
+ *SREPC, std::forward<TransportTCtorArgTs>(TransportTCtorArgs)...);
+ if (!T)
+ return T.takeError();
+ auto EI = EIF.get();
+ if (!EI) {
+ (*T)->disconnect();
+ return EI.takeError();
+ }
+ if (auto Err = SREPC->setup(std::move(*T), std::move(*EI)))
+ return joinErrors(std::move(Err), SREPC->disconnect());
+ return std::move(SREPC);
+ }
+
+ SimpleRemoteEPC(const SimpleRemoteEPC &) = delete;
+ SimpleRemoteEPC &operator=(const SimpleRemoteEPC &) = delete;
+ SimpleRemoteEPC(SimpleRemoteEPC &&) = delete;
+ SimpleRemoteEPC &operator=(SimpleRemoteEPC &) = delete;
+ ~SimpleRemoteEPC();
+
+ /// Called at the end of the construction process to set up the instance.
+ ///
+ /// Override to set up custom memory manager and/or memory access objects.
+ /// This method must be called at the *end* of the subclass's
+ /// implementation.
+ virtual Error setup(std::unique_ptr<SimpleRemoteEPCTransport> T,
+ const SimpleRemoteEPCExecutorInfo &EI);
+
+ Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;
+
+ Expected<std::vector<tpctypes::LookupResult>>
+ lookupSymbols(ArrayRef<LookupRequest> Request) override;
+
+ Expected<int32_t> runAsMain(JITTargetAddress MainFnAddr,
+ ArrayRef<std::string> Args) override;
+
+ void callWrapperAsync(SendResultFunction OnComplete,
+ JITTargetAddress WrapperFnAddr,
+ ArrayRef<char> ArgBuffer) override;
+
+ Error disconnect() override;
+
+ Expected<HandleMessageAction>
+ handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
+ ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes) override;
+
+ void handleDisconnect(Error Err) override;
+
+protected:
+ void setMemoryManager(std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
+ void setMemoryAccess(std::unique_ptr<MemoryAccess> MemAccess);
+
+private:
+ SimpleRemoteEPC(std::shared_ptr<SymbolStringPool> SSP)
+ : ExecutorProcessControl(std::move(SSP)) {}
+
+ Error setupDefaultMemoryManager(const SimpleRemoteEPCExecutorInfo &EI);
+ Error setupDefaultMemoryAccess(const SimpleRemoteEPCExecutorInfo &EI);
+
+ Error handleSetup(uint64_t SeqNo, ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes);
+ void prepareToReceiveSetupMessage(
+ std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> &ExecInfoP);
+
+ Error handleResult(uint64_t SeqNo, ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes);
+ void handleCallWrapper(uint64_t RemoteSeqNo, ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes);
+
+ uint64_t getNextSeqNo() { return NextSeqNo++; }
+ void releaseSeqNo(uint64_t SeqNo) {}
+
+ using PendingCallWrapperResultsMap = DenseMap<uint64_t, SendResultFunction>;
+
+ std::atomic_bool Disconnected{false};
+ std::mutex SimpleRemoteEPCMutex;
+ std::unique_ptr<SimpleRemoteEPCTransport> T;
+ std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
+ std::unique_ptr<MemoryAccess> OwnedMemAccess;
+
+ ExecutorAddress LoadDylibAddr;
+ ExecutorAddress LookupSymbolsAddr;
+ ExecutorAddress RunAsMainAddr;
+
+ uint64_t NextSeqNo = 0;
+ PendingCallWrapperResultsMap PendingCallWrapperResults;
+};
+
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_SIMPLEREMOTEEPC_H
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h
new file mode 100644
index 000000000000..121d8d472824
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h
@@ -0,0 +1,149 @@
+//===---- SimpleRemoteEPCServer.h - EPC over abstract channel ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// EPC over simple abstract channel.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEREMOTEEPCSERVER_H
+#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEREMOTEEPCSERVER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FunctionExtras.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
+#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
+#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+
+#include <condition_variable>
+#include <future>
+#include <memory>
+#include <mutex>
+
+namespace llvm {
+namespace orc {
+
+/// A simple EPC server implementation.
+class SimpleRemoteEPCServer : public SimpleRemoteEPCTransportClient {
+public:
+ using ReportErrorFunction = unique_function<void(Error)>;
+
+ class Dispatcher {
+ public:
+ virtual ~Dispatcher();
+ virtual void dispatch(unique_function<void()> Work) = 0;
+ virtual void shutdown() = 0;
+ };
+
+#if LLVM_ENABLE_THREADS
+ class ThreadDispatcher : public Dispatcher {
+ public:
+ void dispatch(unique_function<void()> Work) override;
+ void shutdown() override;
+
+ private:
+ std::mutex DispatchMutex;
+ bool Running = true;
+ size_t Outstanding = 0;
+ std::condition_variable OutstandingCV;
+ };
+#endif
+
+ static StringMap<ExecutorAddress> defaultBootstrapSymbols();
+
+ template <typename TransportT, typename... TransportTCtorArgTs>
+ static Expected<std::unique_ptr<SimpleRemoteEPCServer>>
+ Create(std::unique_ptr<Dispatcher> D,
+ StringMap<ExecutorAddress> BootstrapSymbols,
+ TransportTCtorArgTs &&...TransportTCtorArgs) {
+ auto SREPCServer = std::make_unique<SimpleRemoteEPCServer>();
+ SREPCServer->D = std::move(D);
+ SREPCServer->ReportError = [](Error Err) {
+ logAllUnhandledErrors(std::move(Err), errs(), "SimpleRemoteEPCServer ");
+ };
+ auto T = TransportT::Create(
+ *SREPCServer, std::forward<TransportTCtorArgTs>(TransportTCtorArgs)...);
+ if (!T)
+ return T.takeError();
+ SREPCServer->T = std::move(*T);
+ if (auto Err = SREPCServer->sendSetupMessage(std::move(BootstrapSymbols)))
+ return std::move(Err);
+ return std::move(SREPCServer);
+ }
+
+ /// Set an error reporter for this server.
+ void setErrorReporter(ReportErrorFunction ReportError) {
+ this->ReportError = std::move(ReportError);
+ }
+
+ /// Call to handle an incoming message.
+ ///
+ /// Returns 'Disconnect' if the message is a 'detach' message from the remote
+ /// otherwise returns 'Continue'. If the server has moved to an error state,
+ /// returns an error, which should be reported and treated as a 'Disconnect'.
+ Expected<HandleMessageAction>
+ handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
+ ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes) override;
+
+ Error waitForDisconnect();
+
+ void handleDisconnect(Error Err) override;
+
+private:
+ Error sendSetupMessage(StringMap<ExecutorAddress> BootstrapSymbols);
+
+ Error handleResult(uint64_t SeqNo, ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes);
+ void handleCallWrapper(uint64_t RemoteSeqNo, ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes);
+
+ static shared::detail::CWrapperFunctionResult
+ loadDylibWrapper(const char *ArgData, size_t ArgSize);
+
+ static shared::detail::CWrapperFunctionResult
+ lookupSymbolsWrapper(const char *ArgData, size_t ArgSize);
+
+ Expected<tpctypes::DylibHandle> loadDylib(const std::string &Path,
+ uint64_t Mode);
+
+ Expected<std::vector<std::vector<ExecutorAddress>>>
+ lookupSymbols(const std::vector<RemoteSymbolLookup> &L);
+
+ shared::WrapperFunctionResult
+ doJITDispatch(const void *FnTag, const char *ArgData, size_t ArgSize);
+
+ static shared::detail::CWrapperFunctionResult
+ jitDispatchEntry(void *DispatchCtx, const void *FnTag, const char *ArgData,
+ size_t ArgSize);
+
+ uint64_t getNextSeqNo() { return NextSeqNo++; }
+ void releaseSeqNo(uint64_t) {}
+
+ using PendingJITDispatchResultsMap =
+ DenseMap<uint64_t, std::promise<shared::WrapperFunctionResult> *>;
+
+ std::mutex ServerStateMutex;
+ std::condition_variable ShutdownCV;
+ enum { ServerRunning, ServerShuttingDown, ServerShutDown } RunState;
+ Error ShutdownErr = Error::success();
+ std::unique_ptr<SimpleRemoteEPCTransport> T;
+ std::unique_ptr<Dispatcher> D;
+ ReportErrorFunction ReportError;
+
+ uint64_t NextSeqNo = 0;
+ PendingJITDispatchResultsMap PendingJITDispatchResults;
+ std::vector<sys::DynamicLibrary> Dylibs;
+};
+
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEREMOTEEPCSERVER_H
diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
index 982a93cc60c0..8e8e0d3ea794 100644
--- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
@@ -8,7 +8,6 @@ add_llvm_component_library(LLVMOrcJIT
EPCDebugObjectRegistrar.cpp
EPCEHFrameRegistrar.cpp
EPCGenericJITLinkMemoryManager.cpp
- EPCGenericMemoryAccess.cpp
EPCIndirectionUtils.cpp
ExecutionUtils.cpp
IndirectionUtils.cpp
@@ -27,6 +26,7 @@ add_llvm_component_library(LLVMOrcJIT
OrcABISupport.cpp
OrcV2CBindings.cpp
RTDyldObjectLinkingLayer.cpp
+ SimpleRemoteEPC.cpp
Speculation.cpp
SpeculateAnalyses.cpp
ExecutorProcessControl.cpp
diff --git a/llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp b/llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp
index ac6de224c9c5..5303b7cf2e5a 100644
--- a/llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp
@@ -86,32 +86,6 @@ class EPCGenericJITLinkMemoryManager::Alloc
SegInfoMap Segs;
};
-/// Create from a ExecutorProcessControl instance.
-Expected<std::unique_ptr<EPCGenericJITLinkMemoryManager>>
-EPCGenericJITLinkMemoryManager::CreateUsingOrcRTFuncs(
- ExecutorProcessControl &EPC) {
-
- auto H = EPC.loadDylib("");
- if (!H)
- return H.takeError();
-
- StringRef GlobalPrefix = "";
- if (EPC.getTargetTriple().isOSBinFormatMachO())
- GlobalPrefix = "_";
-
- FuncAddrs FAs;
- if (auto Err = lookupAndRecordAddrs(
- EPC, *H,
- {{EPC.intern((GlobalPrefix + "__orc_rt_reserve").str()), &FAs.Reserve},
- {EPC.intern((GlobalPrefix + "__orc_rt_finalize").str()),
- &FAs.Finalize},
- {EPC.intern((GlobalPrefix + "__orc_rt_deallocate").str()),
- &FAs.Deallocate}}))
- return std::move(Err);
-
- return std::make_unique<EPCGenericJITLinkMemoryManager>(EPC, std::move(FAs));
-}
-
Expected<std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation>>
EPCGenericJITLinkMemoryManager::allocate(const jitlink::JITLinkDylib *JD,
const SegmentsRequestMap &Request) {
diff --git a/llvm/lib/ExecutionEngine/Orc/EPCGenericMemoryAccess.cpp b/llvm/lib/ExecutionEngine/Orc/EPCGenericMemoryAccess.cpp
deleted file mode 100644
index e4ecd479e22d..000000000000
--- a/llvm/lib/ExecutionEngine/Orc/EPCGenericMemoryAccess.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-//===----- EPCGenericMemoryAccess.cpp - Generic EPC MemoryAccess impl -----===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h"
-#include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
-
-namespace llvm {
-namespace orc {
-
-/// Create from a ExecutorProcessControl instance.
-Expected<std::unique_ptr<EPCGenericMemoryAccess>>
-EPCGenericMemoryAccess::CreateUsingOrcRTFuncs(ExecutorProcessControl &EPC) {
-
- auto H = EPC.loadDylib("");
- if (!H)
- return H.takeError();
-
- StringRef GlobalPrefix = "";
- if (EPC.getTargetTriple().isOSBinFormatMachO())
- GlobalPrefix = "_";
-
- FuncAddrs FAs;
- if (auto Err = lookupAndRecordAddrs(
- EPC, *H,
- {{EPC.intern((GlobalPrefix + "__orc_rt_write_uint8s_wrapper").str()),
- &FAs.WriteUInt8s},
- {EPC.intern((GlobalPrefix + "__orc_rt_write_uint16s_wrapper").str()),
- &FAs.WriteUInt16s},
- {EPC.intern((GlobalPrefix + "__orc_rt_write_uint32s_wrapper").str()),
- &FAs.WriteUInt32s},
- {EPC.intern((GlobalPrefix + "__orc_rt_write_uint64s_wrapper").str()),
- &FAs.WriteUInt64s},
- {EPC.intern((GlobalPrefix + "__orc_rt_write_buffers_wrapper").str()),
- &FAs.WriteBuffers}}))
- return std::move(Err);
-
- return std::make_unique<EPCGenericMemoryAccess>(EPC, std::move(FAs));
-}
-
-} // end namespace orc
-} // end namespace llvm
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
index dddfda1a8953..74805720678c 100644
--- a/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
@@ -1,6 +1,7 @@
add_llvm_component_library(LLVMOrcShared
OrcError.cpp
RPCError.cpp
+ SimpleRemoteEPCUtils.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp
new file mode 100644
index 000000000000..a99bfd2e00d3
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp
@@ -0,0 +1,252 @@
+//===------ SimpleRemoteEPCUtils.cpp - Utils for Simple Remote EPC --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Message definitions and other utilities for SimpleRemoteEPC and
+// SimpleRemoteEPCServer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FormatVariadic.h"
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+namespace {
+
+struct FDMsgHeader {
+ static constexpr unsigned MsgSizeOffset = 0;
+ static constexpr unsigned OpCOffset = MsgSizeOffset + sizeof(uint64_t);
+ static constexpr unsigned SeqNoOffset = OpCOffset + sizeof(uint64_t);
+ static constexpr unsigned TagAddrOffset = SeqNoOffset + sizeof(uint64_t);
+ static constexpr unsigned Size = TagAddrOffset + sizeof(uint64_t);
+};
+
+} // namespace
+
+namespace llvm {
+namespace orc {
+namespace SimpleRemoteEPCDefaultBootstrapSymbolNames {
+
+const char *ExecutorSessionObjectName =
+ "__llvm_orc_SimpleRemoteEPC_dispatch_ctx";
+const char *DispatchFnName = "__llvm_orc_SimpleRemoteEPC_dispatch_fn";
+
+} // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
+
+SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient() {}
+SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport() {}
+
+Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
+FDSimpleRemoteEPCTransport::Create(SimpleRemoteEPCTransportClient &C, int InFD,
+ int OutFD) {
+#if LLVM_ENABLE_THREADS
+ if (InFD == -1)
+ return make_error<StringError>("Invalid input file descriptor " +
+ Twine(InFD),
+ inconvertibleErrorCode());
+ if (OutFD == -1)
+ return make_error<StringError>("Invalid output file descriptor " +
+ Twine(OutFD),
+ inconvertibleErrorCode());
+ std::unique_ptr<FDSimpleRemoteEPCTransport> FDT(
+ new FDSimpleRemoteEPCTransport(C, InFD, OutFD));
+ return FDT;
+#else
+ return make_error<StringError>("FD-based SimpleRemoteEPC transport requires "
+ "thread support, but llvm was built with "
+ "LLVM_ENABLE_THREADS=Off",
+ inconvertibleErrorCode());
+#endif
+}
+
+FDSimpleRemoteEPCTransport::FDSimpleRemoteEPCTransport(
+ SimpleRemoteEPCTransportClient &C, int InFD, int OutFD)
+ : C(C), InFD(InFD), OutFD(OutFD) {
+#if LLVM_ENABLE_THREADS
+ ListenerThread = std::thread([this]() { listenLoop(); });
+#endif
+}
+
+FDSimpleRemoteEPCTransport::~FDSimpleRemoteEPCTransport() {
+#if LLVM_ENABLE_THREADS
+ ListenerThread.join();
+#endif
+}
+
+Error FDSimpleRemoteEPCTransport::sendMessage(SimpleRemoteEPCOpcode OpC,
+ uint64_t SeqNo,
+ ExecutorAddress TagAddr,
+ ArrayRef<char> ArgBytes) {
+ char HeaderBuffer[FDMsgHeader::Size];
+
+ *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset)) =
+ FDMsgHeader::Size + ArgBytes.size();
+ *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset)) =
+ static_cast<uint64_t>(OpC);
+ *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset)) = SeqNo;
+ *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)) =
+ TagAddr.getValue();
+
+ std::lock_guard<std::mutex> Lock(M);
+ if (OutFD == -1)
+ return make_error<StringError>("FD-transport disconnected",
+ inconvertibleErrorCode());
+ if (int ErrNo = writeBytes(HeaderBuffer, FDMsgHeader::Size))
+ return errorCodeToError(std::error_code(ErrNo, std::generic_category()));
+ if (int ErrNo = writeBytes(ArgBytes.data(), ArgBytes.size()))
+ return errorCodeToError(std::error_code(ErrNo, std::generic_category()));
+ return Error::success();
+}
+
+void FDSimpleRemoteEPCTransport::disconnect() {
+ int CloseInFD = -1, CloseOutFD = -1;
+ {
+ std::lock_guard<std::mutex> Lock(M);
+ std::swap(InFD, CloseInFD);
+ std::swap(OutFD, CloseOutFD);
+ }
+
+ // If CloseOutFD == CloseInFD then set CloseOutFD to -1 up-front so that we
+ // don't double-close.
+ if (CloseOutFD == CloseInFD)
+ CloseOutFD = -1;
+
+ // Close InFD.
+ if (CloseInFD != -1)
+ while (close(CloseInFD) == -1) {
+ if (errno == EBADF)
+ break;
+ }
+
+ // Close OutFD.
+ if (CloseOutFD != -1) {
+ while (close(CloseOutFD) == -1) {
+ if (errno == EBADF)
+ break;
+ }
+ }
+}
+
+static Error makeUnexpectedEOFError() {
+ return make_error<StringError>("Unexpected end-of-file",
+ inconvertibleErrorCode());
+}
+
+Error FDSimpleRemoteEPCTransport::readBytes(char *Dst, size_t Size,
+ bool *IsEOF) {
+ assert(Dst && "Attempt to read into null.");
+ ssize_t Completed = 0;
+ while (Completed < static_cast<ssize_t>(Size)) {
+ ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed);
+ if (Read <= 0) {
+ auto ErrNo = errno;
+ if (Read == 0) {
+ if (Completed == 0 && IsEOF) {
+ *IsEOF = true;
+ return Error::success();
+ } else
+ return makeUnexpectedEOFError();
+ } else if (ErrNo == EAGAIN || ErrNo == EINTR)
+ continue;
+ else {
+ std::lock_guard<std::mutex> Lock(M);
+ if (InFD == -1 && IsEOF) { // Disconnected locally. Pretend this is EOF.
+ *IsEOF = true;
+ return Error::success();
+ }
+ return errorCodeToError(
+ std::error_code(ErrNo, std::generic_category()));
+ }
+ }
+ Completed += Read;
+ }
+ return Error::success();
+}
+
+int FDSimpleRemoteEPCTransport::writeBytes(const char *Src, size_t Size) {
+ assert(Src && "Attempt to append from null.");
+ ssize_t Completed = 0;
+ while (Completed < static_cast<ssize_t>(Size)) {
+ ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed);
+ if (Written < 0) {
+ auto ErrNo = errno;
+ if (ErrNo == EAGAIN || ErrNo == EINTR)
+ continue;
+ else
+ return ErrNo;
+ }
+ Completed += Written;
+ }
+ return 0;
+}
+
+void FDSimpleRemoteEPCTransport::listenLoop() {
+ Error Err = Error::success();
+ do {
+
+ char HeaderBuffer[FDMsgHeader::Size];
+ // Read the header buffer.
+ {
+ bool IsEOF;
+ if (auto Err2 = readBytes(HeaderBuffer, FDMsgHeader::Size, &IsEOF)) {
+ Err = joinErrors(std::move(Err), std::move(Err2));
+ break;
+ }
+ if (IsEOF)
+ break;
+ }
+
+ // Decode header buffer.
+ uint64_t MsgSize;
+ SimpleRemoteEPCOpcode OpC;
+ uint64_t SeqNo;
+ ExecutorAddress TagAddr;
+
+ MsgSize =
+ *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset));
+ OpC = static_cast<SimpleRemoteEPCOpcode>(static_cast<uint64_t>(
+ *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset))));
+ SeqNo =
+ *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset));
+ TagAddr.setValue(
+ *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)));
+
+ if (MsgSize < FDMsgHeader::Size) {
+ Err = joinErrors(std::move(Err),
+ make_error<StringError>("Mesasge size too small",
+ inconvertibleErrorCode()));
+ break;
+ }
+
+ // Read the argument bytes.
+ SimpleRemoteEPCArgBytesVector ArgBytes;
+ ArgBytes.resize(MsgSize - FDMsgHeader::Size);
+ if (auto Err2 = readBytes(ArgBytes.data(), ArgBytes.size())) {
+ Err = joinErrors(std::move(Err), std::move(Err2));
+ break;
+ }
+
+ if (auto Action = C.handleMessage(OpC, SeqNo, TagAddr, ArgBytes)) {
+ if (*Action == SimpleRemoteEPCTransportClient::EndSession)
+ break;
+ } else {
+ Err = joinErrors(std::move(Err), Action.takeError());
+ break;
+ }
+ } while (true);
+
+ C.handleDisconnect(std::move(Err));
+}
+
+} // end namespace orc
+} // end namespace llvm
diff --git a/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
new file mode 100644
index 000000000000..d60a6a2d0690
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
@@ -0,0 +1,324 @@
+//===------- SimpleRemoteEPC.cpp -- Simple remote executor control --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
+#include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"
+#include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h"
+#include "llvm/Support/FormatVariadic.h"
+
+#define DEBUG_TYPE "orc"
+
+namespace llvm {
+namespace orc {
+namespace shared {
+
+template <>
+class SPSSerializationTraits<SPSRemoteSymbolLookupSetElement,
+ SymbolLookupSet::value_type> {
+public:
+ static size_t size(const SymbolLookupSet::value_type &V) {
+ return SPSArgList<SPSString, bool>::size(
+ *V.first, V.second == SymbolLookupFlags::RequiredSymbol);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB,
+ const SymbolLookupSet::value_type &V) {
+ return SPSArgList<SPSString, bool>::serialize(
+ OB, *V.first, V.second == SymbolLookupFlags::RequiredSymbol);
+ }
+};
+
+template <>
+class TrivialSPSSequenceSerialization<SPSRemoteSymbolLookupSetElement,
+ SymbolLookupSet> {
+public:
+ static constexpr bool available = true;
+};
+
+template <>
+class SPSSerializationTraits<SPSRemoteSymbolLookup,
+ ExecutorProcessControl::LookupRequest> {
+ using MemberSerialization =
+ SPSArgList<SPSExecutorAddress, SPSRemoteSymbolLookupSet>;
+
+public:
+ static size_t size(const ExecutorProcessControl::LookupRequest &LR) {
+ return MemberSerialization::size(ExecutorAddress(LR.Handle), LR.Symbols);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB,
+ const ExecutorProcessControl::LookupRequest &LR) {
+ return MemberSerialization::serialize(OB, ExecutorAddress(LR.Handle),
+ LR.Symbols);
+ }
+};
+
+} // end namespace shared
+
+SimpleRemoteEPC::~SimpleRemoteEPC() {
+ assert(Disconnected && "Destroyed without disconnection");
+}
+
+Error SimpleRemoteEPC::setup(std::unique_ptr<SimpleRemoteEPCTransport> T,
+ const SimpleRemoteEPCExecutorInfo &EI) {
+ using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
+ LLVM_DEBUG({
+ dbgs() << "SimpleRemoteEPC received setup message:\n"
+ << " Triple: " << EI.TargetTriple << "\n"
+ << " Page size: " << EI.PageSize << "\n"
+ << " Bootstrap symbols:\n";
+ for (const auto &KV : EI.BootstrapSymbols)
+ dbgs() << " " << KV.first() << ": "
+ << formatv("{0:x16}", KV.second.getValue()) << "\n";
+ });
+ this->T = std::move(T);
+ TargetTriple = Triple(EI.TargetTriple);
+ PageSize = EI.PageSize;
+
+ if (auto Err = EI.getBootstrapSymbols(
+ {{JDI.JITDispatchContextAddress, ExecutorSessionObjectName},
+ {JDI.JITDispatchFunctionAddress, DispatchFnName},
+ {LoadDylibAddr, "__llvm_orc_load_dylib"},
+ {LookupSymbolsAddr, "__llvm_orc_lookup_symbols"},
+ {RunAsMainAddr, "__llvm_orc_run_as_main"}}))
+ return Err;
+
+ if (!MemMgr)
+ if (auto Err = setupDefaultMemoryManager(EI))
+ return Err;
+ if (!MemAccess)
+ if (auto Err = setupDefaultMemoryAccess(EI))
+ return Err;
+
+ return Error::success();
+}
+
+Expected<tpctypes::DylibHandle>
+SimpleRemoteEPC::loadDylib(const char *DylibPath) {
+ Expected<tpctypes::DylibHandle> H((tpctypes::DylibHandle()));
+ if (auto Err = callSPSWrapper<shared::SPSLoadDylibSignature>(
+ LoadDylibAddr.getValue(), H, JDI.JITDispatchContextAddress,
+ StringRef(DylibPath), (uint64_t)0))
+ return std::move(Err);
+ return H;
+}
+
+Expected<std::vector<tpctypes::LookupResult>>
+SimpleRemoteEPC::lookupSymbols(ArrayRef<LookupRequest> Request) {
+ Expected<std::vector<tpctypes::LookupResult>> R(
+ (std::vector<tpctypes::LookupResult>()));
+
+ if (auto Err = callSPSWrapper<shared::SPSLookupSymbolsSignature>(
+ LookupSymbolsAddr.getValue(), R, JDI.JITDispatchContextAddress,
+ Request))
+ return std::move(Err);
+ return R;
+}
+
+Expected<int32_t> SimpleRemoteEPC::runAsMain(JITTargetAddress MainFnAddr,
+ ArrayRef<std::string> Args) {
+ int64_t Result = 0;
+ if (auto Err = callSPSWrapper<shared::SPSRunAsMainSignature>(
+ RunAsMainAddr.getValue(), Result, ExecutorAddress(MainFnAddr), Args))
+ return std::move(Err);
+ return Result;
+}
+
+void SimpleRemoteEPC::callWrapperAsync(SendResultFunction OnComplete,
+ JITTargetAddress WrapperFnAddr,
+ ArrayRef<char> ArgBuffer) {
+ uint64_t SeqNo;
+ {
+ std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
+ SeqNo = getNextSeqNo();
+ assert(!PendingCallWrapperResults.count(SeqNo) && "SeqNo already in use");
+ PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
+ }
+
+ if (auto Err = T->sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
+ ExecutorAddress(WrapperFnAddr), ArgBuffer)) {
+ getExecutionSession().reportError(std::move(Err));
+ }
+}
+
+Error SimpleRemoteEPC::disconnect() {
+ Disconnected = true;
+ T->disconnect();
+ return Error::success();
+}
+
+Expected<SimpleRemoteEPCTransportClient::HandleMessageAction>
+SimpleRemoteEPC::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
+ ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes) {
+ using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
+ if (static_cast<UT>(OpC) < static_cast<UT>(SimpleRemoteEPCOpcode::FirstOpC) ||
+ static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
+ return make_error<StringError>("Unexpected opcode",
+ inconvertibleErrorCode());
+
+ switch (OpC) {
+ case SimpleRemoteEPCOpcode::Setup:
+ if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
+ return std::move(Err);
+ break;
+ case SimpleRemoteEPCOpcode::Hangup:
+ // FIXME: Put EPC into 'detached' state.
+ return SimpleRemoteEPCTransportClient::EndSession;
+ case SimpleRemoteEPCOpcode::Result:
+ if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
+ return std::move(Err);
+ break;
+ case SimpleRemoteEPCOpcode::CallWrapper:
+ handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
+ break;
+ }
+ return ContinueSession;
+}
+
+void SimpleRemoteEPC::handleDisconnect(Error Err) {
+ PendingCallWrapperResultsMap TmpPending;
+
+ {
+ std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
+ std::swap(TmpPending, PendingCallWrapperResults);
+ }
+
+ for (auto &KV : TmpPending)
+ KV.second(
+ shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
+
+ if (Err) {
+ // FIXME: Move ReportError to EPC.
+ if (ES)
+ ES->reportError(std::move(Err));
+ else
+ logAllUnhandledErrors(std::move(Err), errs(), "SimpleRemoteEPC: ");
+ }
+}
+
+void SimpleRemoteEPC::setMemoryManager(
+ std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
+ OwnedMemMgr = std::move(MemMgr);
+ this->MemMgr = OwnedMemMgr.get();
+}
+
+void SimpleRemoteEPC::setMemoryAccess(std::unique_ptr<MemoryAccess> MemAccess) {
+ OwnedMemAccess = std::move(MemAccess);
+ this->MemAccess = OwnedMemAccess.get();
+}
+
+Error SimpleRemoteEPC::setupDefaultMemoryManager(
+ const SimpleRemoteEPCExecutorInfo &EI) {
+
+ EPCGenericJITLinkMemoryManager::FuncAddrs FAs;
+
+ if (auto Err = EI.getBootstrapSymbols(
+ {{FAs.Reserve, "__llvm_orc_memory_reserve"},
+ {FAs.Finalize, "__llvm_orc_memory_finalize"},
+ {FAs.Deallocate, "__llvm_orc_memory_deallocate"}}))
+ return Err;
+
+ setMemoryManager(
+ std::make_unique<EPCGenericJITLinkMemoryManager>(*this, FAs));
+ return Error::success();
+}
+
+Error SimpleRemoteEPC::setupDefaultMemoryAccess(
+ const SimpleRemoteEPCExecutorInfo &EI) {
+
+ return Error::success();
+}
+
+Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes) {
+ if (SeqNo != 0)
+ return make_error<StringError>("Setup packet SeqNo not zero",
+ inconvertibleErrorCode());
+
+ if (TagAddr)
+ return make_error<StringError>("Setup packet TagAddr not zero",
+ inconvertibleErrorCode());
+
+ std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
+ auto I = PendingCallWrapperResults.find(0);
+ assert(PendingCallWrapperResults.size() == 1 &&
+ I != PendingCallWrapperResults.end() &&
+ "Setup message handler not connectly set up");
+ auto SetupMsgHandler = std::move(I->second);
+ PendingCallWrapperResults.erase(I);
+
+ auto WFR =
+ shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
+ SetupMsgHandler(std::move(WFR));
+ return Error::success();
+}
+
+void SimpleRemoteEPC::prepareToReceiveSetupMessage(
+ std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> &ExecInfoP) {
+ PendingCallWrapperResults[0] =
+ [&](shared::WrapperFunctionResult SetupMsgBytes) {
+ if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
+ ExecInfoP.set_value(
+ make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
+ return;
+ }
+ using SPSSerialize =
+ shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
+ shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());
+ SimpleRemoteEPCExecutorInfo EI;
+ if (SPSSerialize::deserialize(IB, EI))
+ ExecInfoP.set_value(EI);
+ else
+ ExecInfoP.set_value(make_error<StringError>(
+ "Could not deserialize setup message", inconvertibleErrorCode()));
+ };
+}
+
+Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes) {
+ SendResultFunction SendResult;
+
+ if (TagAddr)
+ return make_error<StringError>("Unexpected TagAddr in result message",
+ inconvertibleErrorCode());
+
+ {
+ std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
+ auto I = PendingCallWrapperResults.find(SeqNo);
+ if (I == PendingCallWrapperResults.end())
+ return make_error<StringError>("No call for sequence number " +
+ Twine(SeqNo),
+ inconvertibleErrorCode());
+ SendResult = std::move(I->second);
+ PendingCallWrapperResults.erase(I);
+ releaseSeqNo(SeqNo);
+ }
+
+ auto WFR =
+ shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
+ SendResult(std::move(WFR));
+ return Error::success();
+}
+
+void SimpleRemoteEPC::handleCallWrapper(
+ uint64_t RemoteSeqNo, ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes) {
+ assert(ES && "No ExecutionSession attached");
+ ES->runJITDispatchHandler(
+ [this, RemoteSeqNo](shared::WrapperFunctionResult WFR) {
+ if (auto Err =
+ T->sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
+ ExecutorAddress(), {WFR.data(), WFR.size()}))
+ getExecutionSession().reportError(std::move(Err));
+ },
+ TagAddr.getValue(), ArgBytes);
+}
+
+} // end namespace orc
+} // end namespace llvm
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
index b04c09c50244..548bf947974a 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
@@ -1,6 +1,7 @@
add_llvm_component_library(LLVMOrcTargetProcess
JITLoaderGDB.cpp
RegisterEHFrames.cpp
+ SimpleRemoteEPCServer.cpp
TargetExecutionUtils.cpp
ADDITIONAL_HEADER_DIRS
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp
new file mode 100644
index 000000000000..d3180ccf1ae3
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp
@@ -0,0 +1,404 @@
+//===------- SimpleEPCServer.cpp - EPC over simple abstract channel -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h"
+
+#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Process.h"
+
+#define DEBUG_TYPE "orc"
+
+using namespace llvm::orc::shared;
+
+namespace llvm {
+namespace orc {
+
+static llvm::orc::shared::detail::CWrapperFunctionResult
+reserveWrapper(const char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSOrcTargetProcessAllocate>::handle(
+ ArgData, ArgSize,
+ [](uint64_t Size) -> Expected<ExecutorAddress> {
+ std::error_code EC;
+ auto MB = sys::Memory::allocateMappedMemory(
+ Size, 0, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
+ if (EC)
+ return errorCodeToError(EC);
+ return ExecutorAddress::fromPtr(MB.base());
+ })
+ .release();
+}
+
+static llvm::orc::shared::detail::CWrapperFunctionResult
+finalizeWrapper(const char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSOrcTargetProcessFinalize>::handle(
+ ArgData, ArgSize,
+ [](const tpctypes::FinalizeRequest &FR) -> Error {
+ for (auto &Seg : FR) {
+ char *Mem = Seg.Addr.toPtr<char *>();
+ memcpy(Mem, Seg.Content.data(), Seg.Content.size());
+ memset(Mem + Seg.Content.size(), 0,
+ Seg.Size - Seg.Content.size());
+ assert(Seg.Size <= std::numeric_limits<size_t>::max());
+ if (auto EC = sys::Memory::protectMappedMemory(
+ {Mem, static_cast<size_t>(Seg.Size)},
+ tpctypes::fromWireProtectionFlags(Seg.Prot)))
+ return errorCodeToError(EC);
+ if (Seg.Prot & tpctypes::WPF_Exec)
+ sys::Memory::InvalidateInstructionCache(Mem, Seg.Size);
+ }
+ return Error::success();
+ })
+ .release();
+}
+
+static llvm::orc::shared::detail::CWrapperFunctionResult
+deallocateWrapper(const char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSOrcTargetProcessDeallocate>::handle(
+ ArgData, ArgSize,
+ [](ExecutorAddress Base, uint64_t Size) -> Error {
+ sys::MemoryBlock MB(Base.toPtr<void *>(), Size);
+ if (auto EC = sys::Memory::releaseMappedMemory(MB))
+ return errorCodeToError(EC);
+ return Error::success();
+ })
+ .release();
+}
+
+template <typename WriteT, typename SPSWriteT>
+static llvm::orc::shared::detail::CWrapperFunctionResult
+writeUIntsWrapper(const char *ArgData, size_t ArgSize) {
+ return WrapperFunction<void(SPSSequence<SPSWriteT>)>::handle(
+ ArgData, ArgSize,
+ [](std::vector<WriteT> Ws) {
+ for (auto &W : Ws)
+ *jitTargetAddressToPointer<decltype(W.Value) *>(W.Address) =
+ W.Value;
+ })
+ .release();
+}
+
+static llvm::orc::shared::detail::CWrapperFunctionResult
+writeBuffersWrapper(const char *ArgData, size_t ArgSize) {
+ return WrapperFunction<void(SPSSequence<SPSMemoryAccessBufferWrite>)>::handle(
+ ArgData, ArgSize,
+ [](std::vector<tpctypes::BufferWrite> Ws) {
+ for (auto &W : Ws)
+ memcpy(jitTargetAddressToPointer<char *>(W.Address),
+ W.Buffer.data(), W.Buffer.size());
+ })
+ .release();
+}
+
+static llvm::orc::shared::detail::CWrapperFunctionResult
+runAsMainWrapper(const char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSRunAsMainSignature>::handle(
+ ArgData, ArgSize,
+ [](ExecutorAddress MainAddr,
+ std::vector<std::string> Args) -> int64_t {
+ return runAsMain(MainAddr.toPtr<int (*)(int, char *[])>(), Args);
+ })
+ .release();
+}
+
+SimpleRemoteEPCServer::Dispatcher::~Dispatcher() {}
+
+#if LLVM_ENABLE_THREADS
+void SimpleRemoteEPCServer::ThreadDispatcher::dispatch(
+ unique_function<void()> Work) {
+ {
+ std::lock_guard<std::mutex> Lock(DispatchMutex);
+ if (!Running)
+ return;
+ ++Outstanding;
+ }
+
+ std::thread([this, Work = std::move(Work)]() mutable {
+ Work();
+ std::lock_guard<std::mutex> Lock(DispatchMutex);
+ --Outstanding;
+ OutstandingCV.notify_all();
+ }).detach();
+}
+
+void SimpleRemoteEPCServer::ThreadDispatcher::shutdown() {
+ std::unique_lock<std::mutex> Lock(DispatchMutex);
+ Running = false;
+ OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; });
+}
+#endif
+
+StringMap<ExecutorAddress> SimpleRemoteEPCServer::defaultBootstrapSymbols() {
+ StringMap<ExecutorAddress> DBS;
+
+ DBS["__llvm_orc_memory_reserve"] = ExecutorAddress::fromPtr(&reserveWrapper);
+ DBS["__llvm_orc_memory_finalize"] =
+ ExecutorAddress::fromPtr(&finalizeWrapper);
+ DBS["__llvm_orc_memory_deallocate"] =
+ ExecutorAddress::fromPtr(&deallocateWrapper);
+ DBS["__llvm_orc_memory_write_uint8s"] = ExecutorAddress::fromPtr(
+ &writeUIntsWrapper<tpctypes::UInt8Write,
+ shared::SPSMemoryAccessUInt8Write>);
+ DBS["__llvm_orc_memory_write_uint16s"] = ExecutorAddress::fromPtr(
+ &writeUIntsWrapper<tpctypes::UInt16Write,
+ shared::SPSMemoryAccessUInt16Write>);
+ DBS["__llvm_orc_memory_write_uint32s"] = ExecutorAddress::fromPtr(
+ &writeUIntsWrapper<tpctypes::UInt32Write,
+ shared::SPSMemoryAccessUInt32Write>);
+ DBS["__llvm_orc_memory_write_uint64s"] = ExecutorAddress::fromPtr(
+ &writeUIntsWrapper<tpctypes::UInt64Write,
+ shared::SPSMemoryAccessUInt64Write>);
+ DBS["__llvm_orc_memory_write_buffers"] =
+ ExecutorAddress::fromPtr(&writeBuffersWrapper);
+ DBS["__llvm_orc_run_as_main"] = ExecutorAddress::fromPtr(&runAsMainWrapper);
+ DBS["__llvm_orc_load_dylib"] = ExecutorAddress::fromPtr(&loadDylibWrapper);
+ DBS["__llvm_orc_lookup_symbols"] =
+ ExecutorAddress::fromPtr(&lookupSymbolsWrapper);
+ return DBS;
+}
+
+Expected<SimpleRemoteEPCTransportClient::HandleMessageAction>
+SimpleRemoteEPCServer::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
+ ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes) {
+ using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
+ if (static_cast<UT>(OpC) < static_cast<UT>(SimpleRemoteEPCOpcode::FirstOpC) ||
+ static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
+ return make_error<StringError>("Unexpected opcode",
+ inconvertibleErrorCode());
+
+ // TODO: Clean detach message?
+ switch (OpC) {
+ case SimpleRemoteEPCOpcode::Setup:
+ return make_error<StringError>("Unexpected Setup opcode",
+ inconvertibleErrorCode());
+ case SimpleRemoteEPCOpcode::Hangup:
+ return SimpleRemoteEPCTransportClient::EndSession;
+ case SimpleRemoteEPCOpcode::Result:
+ if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
+ return std::move(Err);
+ break;
+ case SimpleRemoteEPCOpcode::CallWrapper:
+ handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
+ break;
+ }
+ return ContinueSession;
+}
+
+Error SimpleRemoteEPCServer::waitForDisconnect() {
+ std::unique_lock<std::mutex> Lock(ServerStateMutex);
+ ShutdownCV.wait(Lock, [this]() { return RunState == ServerShutDown; });
+ return std::move(ShutdownErr);
+}
+
+void SimpleRemoteEPCServer::handleDisconnect(Error Err) {
+ PendingJITDispatchResultsMap TmpPending;
+
+ {
+ std::lock_guard<std::mutex> Lock(ServerStateMutex);
+ std::swap(TmpPending, PendingJITDispatchResults);
+ RunState = ServerShuttingDown;
+ }
+
+ // Send out-of-band errors to any waiting threads.
+ for (auto &KV : TmpPending)
+ KV.second->set_value(
+ shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
+
+ // TODO: Free attached resources.
+ // 1. Close libraries in DylibHandles.
+
+ // Wait for dispatcher to clear.
+ D->shutdown();
+
+ std::lock_guard<std::mutex> Lock(ServerStateMutex);
+ ShutdownErr = joinErrors(std::move(ShutdownErr), std::move(Err));
+ RunState = ServerShutDown;
+ ShutdownCV.notify_all();
+}
+
+Error SimpleRemoteEPCServer::sendSetupMessage(
+ StringMap<ExecutorAddress> BootstrapSymbols) {
+
+ using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
+
+ std::vector<char> SetupPacket;
+ SimpleRemoteEPCExecutorInfo EI;
+ EI.TargetTriple = sys::getProcessTriple();
+ if (auto PageSize = sys::Process::getPageSize())
+ EI.PageSize = *PageSize;
+ else
+ return PageSize.takeError();
+ EI.BootstrapSymbols = std::move(BootstrapSymbols);
+
+ assert(!EI.BootstrapSymbols.count(ExecutorSessionObjectName) &&
+ "Dispatch context name should not be set");
+ assert(!EI.BootstrapSymbols.count(DispatchFnName) &&
+ "Dispatch function name should not be set");
+ EI.BootstrapSymbols[ExecutorSessionObjectName] =
+ ExecutorAddress::fromPtr(this);
+ EI.BootstrapSymbols[DispatchFnName] =
+ ExecutorAddress::fromPtr(jitDispatchEntry);
+
+ using SPSSerialize =
+ shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
+ auto SetupPacketBytes =
+ shared::WrapperFunctionResult::allocate(SPSSerialize::size(EI));
+ shared::SPSOutputBuffer OB(SetupPacketBytes.data(), SetupPacketBytes.size());
+ if (!SPSSerialize::serialize(OB, EI))
+ return make_error<StringError>("Could not send setup packet",
+ inconvertibleErrorCode());
+
+ return T->sendMessage(SimpleRemoteEPCOpcode::Setup, 0, ExecutorAddress(),
+ {SetupPacketBytes.data(), SetupPacketBytes.size()});
+}
+
+Error SimpleRemoteEPCServer::handleResult(
+ uint64_t SeqNo, ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes) {
+ std::promise<shared::WrapperFunctionResult> *P = nullptr;
+ {
+ std::lock_guard<std::mutex> Lock(ServerStateMutex);
+ auto I = PendingJITDispatchResults.find(SeqNo);
+ if (I == PendingJITDispatchResults.end())
+ return make_error<StringError>("No call for sequence number " +
+ Twine(SeqNo),
+ inconvertibleErrorCode());
+ P = I->second;
+ PendingJITDispatchResults.erase(I);
+ releaseSeqNo(SeqNo);
+ }
+ auto R = shared::WrapperFunctionResult::allocate(ArgBytes.size());
+ memcpy(R.data(), ArgBytes.data(), ArgBytes.size());
+ P->set_value(std::move(R));
+ return Error::success();
+}
+
+void SimpleRemoteEPCServer::handleCallWrapper(
+ uint64_t RemoteSeqNo, ExecutorAddress TagAddr,
+ SimpleRemoteEPCArgBytesVector ArgBytes) {
+ D->dispatch([this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() {
+ using WrapperFnTy =
+ shared::detail::CWrapperFunctionResult (*)(const char *, size_t);
+ auto *Fn = TagAddr.toPtr<WrapperFnTy>();
+ shared::WrapperFunctionResult ResultBytes(
+ Fn(ArgBytes.data(), ArgBytes.size()));
+ if (auto Err = T->sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
+ ExecutorAddress(),
+ {ResultBytes.data(), ResultBytes.size()}))
+ ReportError(std::move(Err));
+ });
+}
+
+shared::detail::CWrapperFunctionResult
+SimpleRemoteEPCServer::loadDylibWrapper(const char *ArgData, size_t ArgSize) {
+ return shared::WrapperFunction<shared::SPSLoadDylibSignature>::handle(
+ ArgData, ArgSize,
+ [](ExecutorAddress ExecutorSessionObj, std::string Path,
+ uint64_t Flags) -> Expected<uint64_t> {
+ return ExecutorSessionObj.toPtr<SimpleRemoteEPCServer *>()
+ ->loadDylib(Path, Flags);
+ })
+ .release();
+}
+
+shared::detail::CWrapperFunctionResult
+SimpleRemoteEPCServer::lookupSymbolsWrapper(const char *ArgData,
+ size_t ArgSize) {
+ return shared::WrapperFunction<shared::SPSLookupSymbolsSignature>::handle(
+ ArgData, ArgSize,
+ [](ExecutorAddress ExecutorSessionObj,
+ std::vector<RemoteSymbolLookup> Lookup) {
+ return ExecutorSessionObj.toPtr<SimpleRemoteEPCServer *>()
+ ->lookupSymbols(Lookup);
+ })
+ .release();
+}
+
+Expected<tpctypes::DylibHandle>
+SimpleRemoteEPCServer::loadDylib(const std::string &Path, uint64_t Mode) {
+ std::string ErrMsg;
+ const char *P = Path.empty() ? nullptr : Path.c_str();
+ auto DL = sys::DynamicLibrary::getPermanentLibrary(P, &ErrMsg);
+ if (!DL.isValid())
+ return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
+ std::lock_guard<std::mutex> Lock(ServerStateMutex);
+ uint64_t Id = Dylibs.size();
+ Dylibs.push_back(std::move(DL));
+ return Id;
+}
+
+Expected<std::vector<std::vector<ExecutorAddress>>>
+SimpleRemoteEPCServer::lookupSymbols(const std::vector<RemoteSymbolLookup> &L) {
+ std::vector<std::vector<ExecutorAddress>> Result;
+
+ for (const auto &E : L) {
+ if (E.H >= Dylibs.size())
+ return make_error<StringError>("Unrecognized handle",
+ inconvertibleErrorCode());
+ auto &DL = Dylibs[E.H];
+ Result.push_back({});
+
+ for (const auto &Sym : E.Symbols) {
+
+ const char *DemangledSymName = Sym.Name.c_str();
+#ifdef __APPLE__
+ if (*DemangledSymName == '_')
+ ++DemangledSymName;
+#endif
+
+ void *Addr = DL.getAddressOfSymbol(DemangledSymName);
+ if (!Addr && Sym.Required)
+ return make_error<StringError>(Twine("Missing definition for ") +
+ DemangledSymName,
+ inconvertibleErrorCode());
+
+ Result.back().push_back(ExecutorAddress::fromPtr(Addr));
+ }
+ }
+
+ return std::move(Result);
+}
+
+shared::WrapperFunctionResult
+SimpleRemoteEPCServer::doJITDispatch(const void *FnTag, const char *ArgData,
+ size_t ArgSize) {
+ uint64_t SeqNo;
+ std::promise<shared::WrapperFunctionResult> ResultP;
+ auto ResultF = ResultP.get_future();
+ {
+ std::lock_guard<std::mutex> Lock(ServerStateMutex);
+ if (RunState != ServerRunning)
+ return shared::WrapperFunctionResult::createOutOfBandError(
+ "jit_dispatch not available (EPC server shut down)");
+
+ SeqNo = getNextSeqNo();
+ assert(!PendingJITDispatchResults.count(SeqNo) && "SeqNo already in use");
+ PendingJITDispatchResults[SeqNo] = &ResultP;
+ }
+
+ if (auto Err =
+ T->sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
+ ExecutorAddress::fromPtr(FnTag), {ArgData, ArgSize}))
+ ReportError(std::move(Err));
+
+ return ResultF.get();
+}
+
+shared::detail::CWrapperFunctionResult
+SimpleRemoteEPCServer::jitDispatchEntry(void *DispatchCtx, const void *FnTag,
+ const char *ArgData, size_t ArgSize) {
+ return reinterpret_cast<SimpleRemoteEPCServer *>(DispatchCtx)
+ ->doJITDispatch(FnTag, ArgData, ArgSize)
+ .release();
+}
+
+} // end namespace orc
+} // end namespace llvm
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
index 7f197a50c390..2fb4cb365146 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
@@ -13,8 +13,8 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ExecutionEngine/Orc/Shared/FDRawByteChannel.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
-#include "llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MathExtras.h"
@@ -90,8 +90,6 @@ int openListener(std::string Host, std::string PortStr) {
static constexpr int ConnectionQueueLen = 1;
listen(SockFD, ConnectionQueueLen);
- outs() << "Listening at " << Host << ":" << PortStr << "\n";
-
#if defined(_AIX)
assert(Hi_32(AI->ai_addrlen) == 0 && "Field is a size_t on 64-bit AIX");
socklen_t AddrLen = Lo_32(AI->ai_addrlen);
@@ -104,6 +102,7 @@ int openListener(std::string Host, std::string PortStr) {
}
int main(int argc, char *argv[]) {
+#if LLVM_ENABLE_THREADS
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
@@ -133,24 +132,22 @@ int main(int argc, char *argv[]) {
"' is not a valid integer");
InFD = OutFD = openListener(Host.str(), PortStr.str());
- outs() << "Connection established. Running OrcRPCTPCServer...\n";
} else
printErrorAndExit("invalid specifier type \"" + SpecifierType + "\"");
}
- ExitOnErr.setBanner(std::string(argv[0]) + ":");
-
- using JITLinkExecutorEndpoint =
- shared::SingleThreadedRPCEndpoint<shared::FDRawByteChannel>;
-
- shared::registerStringError<shared::FDRawByteChannel>();
-
- shared::FDRawByteChannel C(InFD, OutFD);
- JITLinkExecutorEndpoint EP(C, true);
- OrcRPCTPCServer<JITLinkExecutorEndpoint> Server(EP);
- Server.setProgramName(std::string("llvm-jitlink-executor"));
-
- ExitOnErr(Server.run());
+ auto Server =
+ ExitOnErr(SimpleRemoteEPCServer::Create<FDSimpleRemoteEPCTransport>(
+ std::make_unique<SimpleRemoteEPCServer::ThreadDispatcher>(),
+ SimpleRemoteEPCServer::defaultBootstrapSymbols(), InFD, OutFD));
+ ExitOnErr(Server->waitForDisconnect());
return 0;
+
+#else
+ errs() << argv[0]
+ << " error: this tool requires threads, but LLVM was "
+ "built with LLVM_ENABLE_THREADS=Off\n";
+ return 1;
+#endif
}
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
index dd97bafbdfe2..2e4b9cfc0d7f 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
@@ -635,8 +635,7 @@ static Error loadDylibs(Session &S) {
return Error::success();
}
-Expected<std::unique_ptr<ExecutorProcessControl>>
-LLVMJITLinkRemoteExecutorProcessControl::LaunchExecutor() {
+static Expected<std::unique_ptr<ExecutorProcessControl>> launchExecutor() {
#ifndef LLVM_ON_UNIX
// FIXME: Add support for Windows.
return make_error<StringError>("-" + OutOfProcessExecutor.ArgStr +
@@ -644,8 +643,6 @@ LLVMJITLinkRemoteExecutorProcessControl::LaunchExecutor() {
inconvertibleErrorCode());
#else
- shared::registerStringError<LLVMJITLinkChannel>();
-
constexpr int ReadEnd = 0;
constexpr int WriteEnd = 1;
@@ -697,24 +694,8 @@ LLVMJITLinkRemoteExecutorProcessControl::LaunchExecutor() {
close(ToExecutor[ReadEnd]);
close(FromExecutor[WriteEnd]);
- // Return an RPC channel connected to our end of the pipes.
- auto SSP = std::make_shared<SymbolStringPool>();
- auto Channel = std::make_unique<shared::FDRawByteChannel>(
+ return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
- auto Endpoint = std::make_unique<LLVMJITLinkRPCEndpoint>(*Channel, true);
-
- auto ReportError = [](Error Err) {
- logAllUnhandledErrors(std::move(Err), errs(), "");
- };
-
- Error Err = Error::success();
- std::unique_ptr<LLVMJITLinkRemoteExecutorProcessControl> REPC(
- new LLVMJITLinkRemoteExecutorProcessControl(
- std::move(SSP), std::move(Channel), std::move(Endpoint),
- std::move(ReportError), Err));
- if (Err)
- return std::move(Err);
- return std::move(REPC);
#endif
}
@@ -764,8 +745,7 @@ static Expected<int> connectTCPSocket(std::string Host, std::string PortStr) {
}
#endif
-Expected<std::unique_ptr<ExecutorProcessControl>>
-LLVMJITLinkRemoteExecutorProcessControl::ConnectToExecutor() {
+static Expected<std::unique_ptr<ExecutorProcessControl>> connectToExecutor() {
#ifndef LLVM_ON_UNIX
// FIXME: Add TCP support for Windows.
return make_error<StringError>("-" + OutOfProcessExecutorConnect.ArgStr +
@@ -773,8 +753,6 @@ LLVMJITLinkRemoteExecutorProcessControl::ConnectToExecutor() {
inconvertibleErrorCode());
#else
- shared::registerStringError<LLVMJITLinkChannel>();
-
StringRef Host, PortStr;
std::tie(Host, PortStr) = StringRef(OutOfProcessExecutorConnect).split(':');
if (Host.empty())
@@ -794,37 +772,10 @@ LLVMJITLinkRemoteExecutorProcessControl::ConnectToExecutor() {
if (!SockFD)
return SockFD.takeError();
- auto SSP = std::make_shared<SymbolStringPool>();
- auto Channel = std::make_unique<shared::FDRawByteChannel>(*SockFD, *SockFD);
- auto Endpoint = std::make_unique<LLVMJITLinkRPCEndpoint>(*Channel, true);
-
- auto ReportError = [](Error Err) {
- logAllUnhandledErrors(std::move(Err), errs(), "");
- };
-
- Error Err = Error::success();
- std::unique_ptr<LLVMJITLinkRemoteExecutorProcessControl> REPC(
- new LLVMJITLinkRemoteExecutorProcessControl(
- std::move(SSP), std::move(Channel), std::move(Endpoint),
- std::move(ReportError), Err));
- if (Err)
- return std::move(Err);
- return std::move(REPC);
+ return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(*SockFD, *SockFD);
#endif
}
-Error LLVMJITLinkRemoteExecutorProcessControl::disconnect() {
- std::promise<MSVCPError> P;
- auto F = P.get_future();
- auto Err = closeConnection([&](Error Err) -> Error {
- P.set_value(std::move(Err));
- Finished = true;
- return Error::success();
- });
- ListenerThread.join();
- return joinErrors(std::move(Err), F.get());
-}
-
class PhonyExternalsGenerator : public DefinitionGenerator {
public:
Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
@@ -846,14 +797,13 @@ Expected<std::unique_ptr<Session>> Session::Create(Triple TT) {
std::unique_ptr<ExecutorProcessControl> EPC;
if (OutOfProcessExecutor.getNumOccurrences()) {
/// If -oop-executor is passed then launch the executor.
- if (auto REPC = LLVMJITLinkRemoteExecutorProcessControl::LaunchExecutor())
+ if (auto REPC = launchExecutor())
EPC = std::move(*REPC);
else
return REPC.takeError();
} else if (OutOfProcessExecutorConnect.getNumOccurrences()) {
/// If -oop-executor-connect is passed then connect to the executor.
- if (auto REPC =
- LLVMJITLinkRemoteExecutorProcessControl::ConnectToExecutor())
+ if (auto REPC = connectToExecutor())
EPC = std::move(*REPC);
else
return REPC.takeError();
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.h b/llvm/tools/llvm-jitlink/llvm-jitlink.h
index acb64a9a39ca..0a4654a8c864 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink.h
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink.h
@@ -19,9 +19,9 @@
#include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
-#include "llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h"
#include "llvm/ExecutionEngine/Orc/Shared/FDRawByteChannel.h"
#include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h"
+#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
#include "llvm/ExecutionEngine/RuntimeDyldChecker.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Regex.h"
@@ -48,66 +48,6 @@ class LLVMJITLinkObjectLinkingLayer : public orc::ObjectLinkingLayer {
Session &S;
};
-using LLVMJITLinkChannel = orc::shared::FDRawByteChannel;
-using LLVMJITLinkRPCEndpoint =
- orc::shared::MultiThreadedRPCEndpoint<LLVMJITLinkChannel>;
-using LLVMJITLinkRemoteMemoryAccess =
- orc::OrcRPCEPCMemoryAccess<LLVMJITLinkRPCEndpoint>;
-
-class LLVMJITLinkRemoteExecutorProcessControl
- : public orc::OrcRPCExecutorProcessControlBase<LLVMJITLinkRPCEndpoint> {
-public:
- using BaseT = orc::OrcRPCExecutorProcessControlBase<LLVMJITLinkRPCEndpoint>;
- static Expected<std::unique_ptr<ExecutorProcessControl>> LaunchExecutor();
-
- static Expected<std::unique_ptr<ExecutorProcessControl>> ConnectToExecutor();
-
- Error disconnect() override;
-
-private:
- using LLVMJITLinkRemoteMemoryAccess =
- orc::OrcRPCEPCMemoryAccess<LLVMJITLinkRemoteExecutorProcessControl>;
-
- using LLVMJITLinkRemoteMemoryManager = orc::OrcRPCEPCJITLinkMemoryManager<
- LLVMJITLinkRemoteExecutorProcessControl>;
-
- LLVMJITLinkRemoteExecutorProcessControl(
- std::shared_ptr<orc::SymbolStringPool> SSP,
- std::unique_ptr<LLVMJITLinkChannel> Channel,
- std::unique_ptr<LLVMJITLinkRPCEndpoint> Endpoint,
- ErrorReporter ReportError, Error &Err)
- : BaseT(std::move(SSP), *Endpoint, std::move(ReportError)),
- Channel(std::move(Channel)), Endpoint(std::move(Endpoint)) {
- ErrorAsOutParameter _(&Err);
-
- ListenerThread = std::thread([&]() {
- while (!Finished) {
- if (auto Err = this->Endpoint->handleOne()) {
- reportError(std::move(Err));
- return;
- }
- }
- });
-
- if (auto Err2 = initializeORCRPCEPCBase()) {
- Err = joinErrors(std::move(Err2), disconnect());
- return;
- }
-
- OwnedMemAccess = std::make_unique<LLVMJITLinkRemoteMemoryAccess>(*this);
- MemAccess = OwnedMemAccess.get();
- OwnedMemMgr = std::make_unique<LLVMJITLinkRemoteMemoryManager>(*this);
- MemMgr = OwnedMemMgr.get();
- }
-
- std::unique_ptr<LLVMJITLinkChannel> Channel;
- std::unique_ptr<LLVMJITLinkRPCEndpoint> Endpoint;
- std::unique_ptr<ExecutorProcessControl::MemoryAccess> OwnedMemAccess;
- std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
- std::atomic<bool> Finished{false};
- std::thread ListenerThread;
-};
-
struct Session {
orc::ExecutionSession ES;
orc::JITDylib *MainJD = nullptr;
More information about the llvm-commits
mailing list