Re-apply bb27e456435 and 5629afea910 with fixes.
authorLang Hames <lhames@gmail.com>
Sat, 11 Sep 2021 09:07:16 +0000 (19:07 +1000)
committerLang Hames <lhames@gmail.com>
Sun, 12 Sep 2021 04:23:22 +0000 (14:23 +1000)
This reapplies bb27e4564355243e479cab40885d6e0f7f640572 (SimpleRemoteEPC
support) and 2269a941a450a0d395161cfb792be58870b2875b (#include <mutex>
fix) with further fixes to support building with LLVM_ENABLE_THREADS=Off.

17 files changed:
llvm/include/llvm/ExecutionEngine/Orc/Core.h
llvm/include/llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h
llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h
llvm/include/llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h [new file with mode: 0644]
llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h [new file with mode: 0644]
llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h [new file with mode: 0644]
llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp
llvm/lib/ExecutionEngine/Orc/EPCGenericMemoryAccess.cpp [deleted file]
llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp [new file with mode: 0644]
llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp [new file with mode: 0644]
llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp [new file with mode: 0644]
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

index 331a921..062b1f3 100644 (file)
@@ -1302,7 +1302,8 @@ public:
   /// 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
index 0dd1e6a..4800712 100644 (file)
@@ -38,11 +38,6 @@ public:
   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;
index fe9d1c1..80a84ce 100644 (file)
@@ -39,11 +39,6 @@ public:
   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 (file)
index 0000000..7d1df16
--- /dev/null
@@ -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 (file)
index 0000000..252474a
--- /dev/null
@@ -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 (file)
index 0000000..121d8d4
--- /dev/null
@@ -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
index 982a93c..8e8e0d3 100644 (file)
@@ -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
index ac6de22..5303b7c 100644 (file)
@@ -86,32 +86,6 @@ private:
   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 (file)
index e4ecd47..0000000
+++ /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
index dddfda1..7480572 100644 (file)
@@ -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 (file)
index 0000000..a99bfd2
--- /dev/null
@@ -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 (file)
index 0000000..d60a6a2
--- /dev/null
@@ -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
index b04c09c..548bf94 100644 (file)
@@ -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 (file)
index 0000000..d3180cc
--- /dev/null
@@ -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
index 7f197a5..2fb4cb3 100644 (file)
@@ -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
 }
index dd97baf..2e4b9cf 100644 (file)
@@ -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();
index acb64a9..0a4654a 100644 (file)
@@ -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 @@ private:
   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;