[PATCH] D130455: [ORC][COFF] Introduce COFFVCRuntimeBootstrapper.

Sunho Kim via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 24 19:23:17 PDT 2022


sunho created this revision.
Herald added subscribers: mstorsjo, hiraditya.
Herald added a project: All.
sunho requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/COFFVCRuntimeSupport.h b/llvm/include/llvm/ExecutionEngine/Orc/COFFVCRuntimeSupport.h
new file mode 100644
index 000000000000..4084012a64d9

- /dev/null

+++ b/llvm/include/llvm/ExecutionEngine/Orc/COFFVCRuntimeSupport.h
@@ -0,0 +1,83 @@
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_COFFCRUNTIMESUPPORT_H
+#define LLVM_EXECUTIONENGINE_ORC_COFFCRUNTIMESUPPORT_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
+#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
+
+#include <future>
+#include <memory>
+#include <thread>
+#include <vector>
+
+namespace llvm {
+namespace orc {
+
+/// Bootstraps the vc runtime within jitdylibs.
+class COFFVCRuntimeBootstrapper {
+public:
+  /// A function that will be called with the name of dll file that must be
+  /// loaded.
+  using LoadDynamicLibrary =
+      unique_function<Error(JITDylib &JD, StringRef DLLFileName)>;
+
+  /// Try to create a COFFVCRuntimeBootstrapper instance. An optional
+  /// RuntimePath can be given to specify the location of directory that
+  /// contains all vc runtime library files such as ucrt.lib and msvcrt.lib. If
+  /// not path was given, it will try to search the MSVC toolchain and Windows
+  /// SDK installation and use the found library files automatically.
+  ///
+  /// Note that depending on the build setting, a different library
+  /// file must be used. In general, if vc runtime was statically linked to the
+  /// object file that is to be jit-linked, LoadStaticVCRuntime and
+  /// InitializeStaticVCRuntime must be used with libcmt.lib, libucrt.lib,
+  /// libvcruntimelib. If vc runtime was dynamically linked LoadDynamicVCRuntime
+  /// must be used along with msvcrt.lib, ucrt.lib, vcruntime.lib.
+  ///
+  /// More information is on:
+  /// https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features
+  static Expected<std::unique_ptr<COFFVCRuntimeBootstrapper>>
+  Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
+         LoadDynamicLibrary LoadDynLibrary, const char *RuntimePath = nullptr);
+
+  /// Adds symbol definitions of static version of msvc runtime libraries.
+  Error loadStaticVCRuntime(JITDylib &JD, bool DebugVersion = false);
+
+  /// Runs the initializer of static version of msvc runtime libraries.
+  /// This must be called before calling any functions requiring c runtime (e.g.
+  /// printf) within the jit session. Note that proper initialization of vc
+  /// runtime requires ability of running static initializers. Cosider setting
+  /// up COFFPlatform.
+  Error initializeStaticVCRuntime(JITDylib &JD);
+
+  /// Adds symbol definitions of dynamic versino of msvc runtie libraries.
+  Error loadDynamicVCRuntime(JITDylib &JD, bool DebugVersion = false);
+
+private:
+  COFFVCRuntimeBootstrapper(ExecutionSession &ES,
+                            ObjectLinkingLayer &ObjLinkingLayer,
+                            LoadDynamicLibrary LoadDynLibrary,
+                            const char *RuntimePath);
+
+  ExecutionSession &ES;
+  ObjectLinkingLayer &ObjLinkingLayer;
+  std::string RuntimePath;
+  LoadDynamicLibrary LoadDynLibrary;
+
+  struct MSVCToolchainPath {
+    SmallString<256> VCToolchainLib;
+    SmallString<256> UCRTSdkLib;
+  };
+
+  static Expected<MSVCToolchainPath> getMSVCToolchainPath();
+  Error lLoadVCRuntime(JITDylib &JD, ArrayRef<StringRef> VCLibs,
+                       ArrayRef<StringRef> UCRTLibs);
+};
+
+} // namespace orc
+} // namespace llvm
+
+#endif
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
index 105dac8e8d04..98a4a05180c5 100644

- a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h

+++ b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
@@ -1,471 +1,490 @@
 //===- ExecutorProcessControl.h - Executor process control APIs -*- 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
 //
 //===----------------------------------------------------------------------===//
 //
 // Utilities for interacting with the executor processes.
 //
 //===----------------------------------------------------------------------===//

#ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H
 #define LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H

#include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
 #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
 #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
 #include "llvm/ExecutionEngine/Orc/TaskDispatch.h"
 #include "llvm/Support/DynamicLibrary.h"
 #include "llvm/Support/MSVCErrorWorkarounds.h"

#include <future>
 #include <mutex>
 #include <vector>

namespace llvm {
 namespace orc {

class ExecutionSession;
 class SymbolLookupSet;

/// ExecutorProcessControl supports interaction with a JIT target process.
 class ExecutorProcessControl {

  friend class ExecutionSession;

public:

  /// A handler or incoming WrapperFunctionResults -- either return values from
  /// callWrapper* calls, or incoming JIT-dispatch requests.
  ///
  /// IncomingWFRHandlers are constructible from
  /// unique_function<void(shared::WrapperFunctionResult)>s using the
  /// runInPlace function or a RunWithDispatch object.
  class IncomingWFRHandler {
    friend class ExecutorProcessControl;
  public:
    IncomingWFRHandler() = default;
    explicit operator bool() const { return !!H; }
    void operator()(shared::WrapperFunctionResult WFR) { H(std::move(WFR)); }
  private:
    template <typename FnT> IncomingWFRHandler(FnT &&Fn)
      : H(std::forward<FnT>(Fn)) {}
   
    unique_function<void(shared::WrapperFunctionResult)> H;
  };
   
  /// Constructs an IncomingWFRHandler from a function object that is callable
  /// as void(shared::WrapperFunctionResult). The function object will be called
  /// directly. This should be used with care as it may block listener threads
  /// in remote EPCs. It is only suitable for simple tasks (e.g. setting a
  /// future), or for performing some quick analysis before dispatching "real"
  /// work as a Task.
  class RunInPlace {
  public:
    template <typename FnT>
    IncomingWFRHandler operator()(FnT &&Fn) {
      return IncomingWFRHandler(std::forward<FnT>(Fn));
    }
  };
   
  /// Constructs an IncomingWFRHandler from a function object by creating a new
  /// function object that dispatches the original using a TaskDispatcher,
  /// wrapping the original as a GenericNamedTask.
  ///
  /// This is the default approach for running WFR handlers.
  class RunAsTask {
  public:
    RunAsTask(TaskDispatcher &D) : D(D) {}
   
    template <typename FnT>
    IncomingWFRHandler operator()(FnT &&Fn) {
      return IncomingWFRHandler(
          [&D = this->D, Fn = std::move(Fn)]
          (shared::WrapperFunctionResult WFR) mutable {
              D.dispatch(
                makeGenericNamedTask(
                    [Fn = std::move(Fn), WFR = std::move(WFR)]() mutable {
                      Fn(std::move(WFR));
                    }, "WFR handler task"));
          });
    }
  private:
    TaskDispatcher &D;
  };
   
  /// APIs for manipulating memory in the target process.
  class MemoryAccess {
  public:
    /// Callback function for asynchronous writes.
    using WriteResultFn = unique_function<void(Error)>;
   
    virtual ~MemoryAccess();
   
    virtual void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
                                  WriteResultFn OnWriteComplete) = 0;
   
    virtual void writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws,
                                   WriteResultFn OnWriteComplete) = 0;
   
    virtual void writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws,
                                   WriteResultFn OnWriteComplete) = 0;
   
    virtual void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,
                                   WriteResultFn OnWriteComplete) = 0;
   
    virtual void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,
                                   WriteResultFn OnWriteComplete) = 0;
   
    Error writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws) {
      std::promise<MSVCPError> ResultP;
      auto ResultF = ResultP.get_future();
      writeUInt8sAsync(Ws,
                       [&](Error Err) { ResultP.set_value(std::move(Err)); });
      return ResultF.get();
    }
   
    Error writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws) {
      std::promise<MSVCPError> ResultP;
      auto ResultF = ResultP.get_future();
      writeUInt16sAsync(Ws,
                        [&](Error Err) { ResultP.set_value(std::move(Err)); });
      return ResultF.get();
    }
   
    Error writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws) {
      std::promise<MSVCPError> ResultP;
      auto ResultF = ResultP.get_future();
      writeUInt32sAsync(Ws,
                        [&](Error Err) { ResultP.set_value(std::move(Err)); });
      return ResultF.get();
    }
   
    Error writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws) {
      std::promise<MSVCPError> ResultP;
      auto ResultF = ResultP.get_future();
      writeUInt64sAsync(Ws,
                        [&](Error Err) { ResultP.set_value(std::move(Err)); });
      return ResultF.get();
    }
   
    Error writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws) {
      std::promise<MSVCPError> ResultP;
      auto ResultF = ResultP.get_future();
      writeBuffersAsync(Ws,
                        [&](Error Err) { ResultP.set_value(std::move(Err)); });
      return ResultF.get();
    }
  };
   
  /// A pair of a dylib and a set of symbols to be looked up.
  struct LookupRequest {
    LookupRequest(tpctypes::DylibHandle Handle, const SymbolLookupSet &Symbols)
        : Handle(Handle), Symbols(Symbols) {}
    tpctypes::DylibHandle Handle;
    const SymbolLookupSet &Symbols;
  };
   
  /// Contains the address of the dispatch function and context that the ORC
  /// runtime can use to call functions in the JIT.
  struct JITDispatchInfo {
    ExecutorAddr JITDispatchFunction;
    ExecutorAddr JITDispatchContext;
  };
   
  ExecutorProcessControl(std::shared_ptr<SymbolStringPool> SSP,
                         std::unique_ptr<TaskDispatcher> D)
    : SSP(std::move(SSP)), D(std::move(D)) {}
   
  virtual ~ExecutorProcessControl();
   
  /// Return the ExecutionSession associated with this instance.
  /// Not callable until the ExecutionSession has been associated.
  ExecutionSession &getExecutionSession() {
    assert(ES && "No ExecutionSession associated yet");
    return *ES;
  }
   
  /// Intern a symbol name in the SymbolStringPool.
  SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
   
  /// Return a shared pointer to the SymbolStringPool for this instance.
  std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
   
  TaskDispatcher &getDispatcher() { return *D; }
   
  /// Return the Triple for the target process.
  const Triple &getTargetTriple() const { return TargetTriple; }
   
  /// Get the page size for the target process.
  unsigned getPageSize() const { return PageSize; }
   
  /// Get the JIT dispatch function and context address for the executor.
  const JITDispatchInfo &getJITDispatchInfo() const { return JDI; }
   
  /// Return a MemoryAccess object for the target process.
  MemoryAccess &getMemoryAccess() const {
    assert(MemAccess && "No MemAccess object set.");
    return *MemAccess;
  }
   
  /// Return a JITLinkMemoryManager for the target process.
  jitlink::JITLinkMemoryManager &getMemMgr() const {
    assert(MemMgr && "No MemMgr object set");
    return *MemMgr;
  }
   
  /// Returns the bootstrap symbol map.
  const StringMap<ExecutorAddr> &getBootstrapSymbolsMap() const {
    return BootstrapSymbols;
  }
   
  /// For each (ExecutorAddr&, StringRef) pair, looks up the string in the
  /// bootstrap symbols map and writes its address to the ExecutorAddr if
  /// found. If any symbol is not found then the function returns an error.
  Error getBootstrapSymbols(
      ArrayRef<std::pair<ExecutorAddr &, StringRef>> Pairs) const {
    for (auto &KV : Pairs) {
      auto I = BootstrapSymbols.find(KV.second);
      if (I == BootstrapSymbols.end())
        return make_error<StringError>("Symbol \"" + KV.second +
                                           "\" not found "
                                           "in bootstrap symbols map",
                                       inconvertibleErrorCode());
   
      KV.first = I->second;
    }
    return Error::success();
  }
   
  /// Load the dynamic library at the given path and return a handle to it.
  /// If LibraryPath is null this function will return the global handle for
  /// the target process.
  virtual Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) = 0;
   
  /// Search for symbols in the target process.
  ///
  /// The result of the lookup is a 2-dimentional array of target addresses
  /// that correspond to the lookup order. If a required symbol is not
  /// found then this method will return an error. If a weakly referenced
  /// symbol is not found then it be assigned a '0' value.
  virtual Expected<std::vector<tpctypes::LookupResult>>
  lookupSymbols(ArrayRef<LookupRequest> Request) = 0;
   
  /// Run function with a main-like signature.
  virtual Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
                                      ArrayRef<std::string> Args) = 0;
   

+  /// Run function with a int (*)(void) signature.
+  virtual Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) = 0;
+
+  /// Run function with a int (*)(int) signature.
+  virtual Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr,
+                                             int Arg) = 0;
+

  /// Run a wrapper function in the executor. The given WFRHandler will be
  /// called on the result when it is returned.
  ///
  /// The wrapper function should be callable as:
  ///
  /// \code{.cpp}
  ///   CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
  /// \endcode{.cpp}
  virtual void callWrapperAsync(ExecutorAddr WrapperFnAddr,
                                IncomingWFRHandler OnComplete,
                                ArrayRef<char> ArgBuffer) = 0;
   
  /// Run a wrapper function in the executor using the given Runner to dispatch
  /// OnComplete when the result is ready.
  template <typename RunPolicyT, typename FnT>
  void callWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
                        FnT &&OnComplete, ArrayRef<char> ArgBuffer) {
    callWrapperAsync(
        WrapperFnAddr, Runner(std::forward<FnT>(OnComplete)), ArgBuffer);
  }
   
  /// Run a wrapper function in the executor. OnComplete will be dispatched
  /// as a GenericNamedTask using this instance's TaskDispatch object.
  template <typename FnT>
  void callWrapperAsync(ExecutorAddr WrapperFnAddr, FnT &&OnComplete,
                        ArrayRef<char> ArgBuffer) {
    callWrapperAsync(RunAsTask(*D), WrapperFnAddr,
                     std::forward<FnT>(OnComplete), ArgBuffer);
  }
   
  /// Run a wrapper function in the executor. The wrapper function should be
  /// callable as:
  ///
  /// \code{.cpp}
  ///   CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
  /// \endcode{.cpp}
  shared::WrapperFunctionResult callWrapper(ExecutorAddr WrapperFnAddr,
                                            ArrayRef<char> ArgBuffer) {
    std::promise<shared::WrapperFunctionResult> RP;
    auto RF = RP.get_future();
    callWrapperAsync(
        RunInPlace(), WrapperFnAddr,
        [&](shared::WrapperFunctionResult R) {
          RP.set_value(std::move(R));
        }, ArgBuffer);
    return RF.get();
  }
   
  /// Run a wrapper function using SPS to serialize the arguments and
  /// deserialize the results.
  template <typename SPSSignature, typename RunPolicyT, typename SendResultT,
            typename... ArgTs>
  void callSPSWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
                           SendResultT &&SendResult, const ArgTs &...Args) {
    shared::WrapperFunction<SPSSignature>::callAsync(
        [this, WrapperFnAddr, Runner = std::move(Runner)]
        (auto &&SendResult, const char *ArgData, size_t ArgSize) mutable {
          this->callWrapperAsync(std::move(Runner), WrapperFnAddr,
                                 std::move(SendResult),
                                 ArrayRef<char>(ArgData, ArgSize));
        },
        std::forward<SendResultT>(SendResult), Args...);
  }
   
  /// Run a wrapper function using SPS to serialize the arguments and
  /// deserialize the results.
  template <typename SPSSignature, typename SendResultT, typename... ArgTs>
  void callSPSWrapperAsync(ExecutorAddr WrapperFnAddr, SendResultT &&SendResult,
                           const ArgTs &...Args) {
    callSPSWrapperAsync<SPSSignature>(RunAsTask(*D), WrapperFnAddr,
                                      std::forward<SendResultT>(SendResult),
                                      Args...);
  }
   
  /// Run a wrapper function using SPS to serialize the arguments and
  /// deserialize the results.
  ///
  /// If SPSSignature is a non-void function signature then the second argument
  /// (the first in the Args list) should be a reference to a return value.
  template <typename SPSSignature, typename... WrapperCallArgTs>
  Error callSPSWrapper(ExecutorAddr WrapperFnAddr,
                       WrapperCallArgTs &&...WrapperCallArgs) {
    return shared::WrapperFunction<SPSSignature>::call(
        [this, WrapperFnAddr](const char *ArgData, size_t ArgSize) {
          return callWrapper(WrapperFnAddr, ArrayRef<char>(ArgData, ArgSize));
        },
        std::forward<WrapperCallArgTs>(WrapperCallArgs)...);
  }
   
  /// Disconnect from the target process.
  ///
  /// This should be called after the JIT session is shut down.
  virtual Error disconnect() = 0;
   

protected:

  std::shared_ptr<SymbolStringPool> SSP;
  std::unique_ptr<TaskDispatcher> D;
  ExecutionSession *ES = nullptr;
  Triple TargetTriple;
  unsigned PageSize = 0;
  JITDispatchInfo JDI;
  MemoryAccess *MemAccess = nullptr;
  jitlink::JITLinkMemoryManager *MemMgr = nullptr;
  StringMap<ExecutorAddr> BootstrapSymbols;

};

/// A ExecutorProcessControl instance that asserts if any of its methods are
 /// used. Suitable for use is unit tests, and by ORC clients who haven't moved
 /// to ExecutorProcessControl-based APIs yet.
 class UnsupportedExecutorProcessControl : public ExecutorProcessControl {
public:

  UnsupportedExecutorProcessControl(
      std::shared_ptr<SymbolStringPool> SSP = nullptr,
      std::unique_ptr<TaskDispatcher> D = nullptr,
      const std::string &TT = "", unsigned PageSize = 0)
      : ExecutorProcessControl(SSP ? std::move(SSP)
                               : std::make_shared<SymbolStringPool>(),
                               D ? std::move(D)
                               : std::make_unique<InPlaceTaskDispatcher>()) {
    this->TargetTriple = Triple(TT);
    this->PageSize = PageSize;
  }
   
  Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override {
    llvm_unreachable("Unsupported");
  }
   
  Expected<std::vector<tpctypes::LookupResult>>
  lookupSymbols(ArrayRef<LookupRequest> Request) override {
    llvm_unreachable("Unsupported");
  }
   
  Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
                              ArrayRef<std::string> Args) override {
    llvm_unreachable("Unsupported");
  }
   

+  Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) override {
+    llvm_unreachable("Unsupported");
+  }
+
+  Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override {
+    llvm_unreachable("Unsupported");
+  }
+

  void callWrapperAsync(ExecutorAddr WrapperFnAddr,
                        IncomingWFRHandler OnComplete,
                        ArrayRef<char> ArgBuffer) override {
    llvm_unreachable("Unsupported");
  }
   
  Error disconnect() override { return Error::success(); }

};

/// A ExecutorProcessControl implementation targeting the current process.
 class SelfExecutorProcessControl

  : public ExecutorProcessControl,
    private ExecutorProcessControl::MemoryAccess {

public:

  SelfExecutorProcessControl(
      std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D,
      Triple TargetTriple, unsigned PageSize,
      std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
   
  /// Create a SelfExecutorProcessControl with the given symbol string pool and
  /// memory manager.
  /// If no symbol string pool is given then one will be created.
  /// If no memory manager is given a jitlink::InProcessMemoryManager will
  /// be created and used by default.
  static Expected<std::unique_ptr<SelfExecutorProcessControl>>
  Create(std::shared_ptr<SymbolStringPool> SSP = nullptr,
         std::unique_ptr<TaskDispatcher> D = nullptr,
         std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr);
   
  Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;
   
  Expected<std::vector<tpctypes::LookupResult>>
  lookupSymbols(ArrayRef<LookupRequest> Request) override;
   
  Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
                              ArrayRef<std::string> Args) override;
   

+  Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) override;
+
+  Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override;
+

  void callWrapperAsync(ExecutorAddr WrapperFnAddr,
                        IncomingWFRHandler OnComplete,
                        ArrayRef<char> ArgBuffer) override;
   
  Error disconnect() override;
   

private:

  void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
                        WriteResultFn OnWriteComplete) override;
   
  void writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws,
                         WriteResultFn OnWriteComplete) override;
   
  void writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws,
                         WriteResultFn OnWriteComplete) override;
   
  void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,
                         WriteResultFn OnWriteComplete) override;
   
  void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,
                         WriteResultFn OnWriteComplete) override;
   
  static shared::CWrapperFunctionResult
  jitDispatchViaWrapperFunctionManager(void *Ctx, const void *FnTag,
                                       const char *Data, size_t Size);
   
  std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
  char GlobalManglingPrefix = 0;
  std::vector<std::unique_ptr<sys::DynamicLibrary>> DynamicLibraries;

};

} // end namespace orc
 } // end namespace llvm

#endif // LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H
diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
index 1c9b9e8a1b31..06d0401fff11 100644

- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt

+++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
@@ -1,74 +1,76 @@
 add_llvm_component_library(LLVMOrcJIT
+  COFFVCRuntimeSupport.cpp

  CompileOnDemandLayer.cpp
  CompileUtils.cpp
  Core.cpp
  DebugObjectManagerPlugin.cpp
  DebuggerSupportPlugin.cpp
  DebugUtils.cpp
  EPCDynamicLibrarySearchGenerator.cpp
  EPCDebugObjectRegistrar.cpp
  EPCEHFrameRegistrar.cpp
  EPCGenericDylibManager.cpp
  EPCGenericJITLinkMemoryManager.cpp
  EPCGenericRTDyldMemoryManager.cpp
  EPCIndirectionUtils.cpp
  ExecutionUtils.cpp
  ObjectFileInterface.cpp
  IndirectionUtils.cpp
  IRCompileLayer.cpp
  IRTransformLayer.cpp
  JITTargetMachineBuilder.cpp
  LazyReexports.cpp
  Layer.cpp
  LookupAndRecordAddrs.cpp
  LLJIT.cpp
  MachOPlatform.cpp
  MemoryMapper.cpp
  ELFNixPlatform.cpp
  Mangling.cpp
  ObjectLinkingLayer.cpp
  ObjectTransformLayer.cpp
  OrcABISupport.cpp
  OrcV2CBindings.cpp
  RTDyldObjectLinkingLayer.cpp
  SimpleRemoteEPC.cpp
  Speculation.cpp
  SpeculateAnalyses.cpp
  ExecutorProcessControl.cpp
  TaskDispatch.cpp
  ThreadSafeModule.cpp
  ADDITIONAL_HEADER_DIRS
  ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
   
  DEPENDS
  intrinsics_gen
   
  LINK_LIBS
  ${LLVM_PTHREAD_LIB}
   
  LINK_COMPONENTS
  Core
  ExecutionEngine
  JITLink
  Object
  OrcShared
  OrcTargetProcess

+  WindowsDriver

  MC
  MCDisassembler
  Passes
  RuntimeDyld
  Support
  Target
  TransformUtils
  )
   

add_subdirectory(Shared)
 add_subdirectory(TargetProcess)

target_link_libraries(LLVMOrcJIT

  PRIVATE
  LLVMAnalysis
  LLVMBitReader
  LLVMBitWriter
  LLVMPasses
  )

diff --git a/llvm/lib/ExecutionEngine/Orc/COFFVCRuntimeSupport.cpp b/llvm/lib/ExecutionEngine/Orc/COFFVCRuntimeSupport.cpp
new file mode 100644
index 000000000000..a8b65fa3b4a8

- /dev/null

+++ b/llvm/lib/ExecutionEngine/Orc/COFFVCRuntimeSupport.cpp
@@ -0,0 +1,178 @@
+#include "llvm/ExecutionEngine/Orc/COFFVCRuntimeSupport.h"
+
+#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
+#include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/WindowsDriver/MSVCPaths.h"
+
+#define DEBUG_TYPE "orc"
+
+using namespace llvm;
+using namespace llvm::orc;
+using namespace llvm::orc::shared;
+
+Expected<std::unique_ptr<COFFVCRuntimeBootstrapper>>
+COFFVCRuntimeBootstrapper::Create(ExecutionSession &ES,
+                                  ObjectLinkingLayer &ObjLinkingLayer,
+                                  LoadDynamicLibrary LoadDynLibrary,
+                                  const char *RuntimePath) {
+  return std::unique_ptr<COFFVCRuntimeBootstrapper>(
+      new COFFVCRuntimeBootstrapper(ES, ObjLinkingLayer,
+                                    std::move(LoadDynLibrary), RuntimePath));
+}
+
+COFFVCRuntimeBootstrapper::COFFVCRuntimeBootstrapper(
+    ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
+    LoadDynamicLibrary LoadDynLibrary, const char *RuntimePath)
+    : ES(ES), ObjLinkingLayer(ObjLinkingLayer),
+      LoadDynLibrary(std::move(LoadDynLibrary)) {
+  if (RuntimePath)
+    this->RuntimePath = RuntimePath;
+}
+
+Error COFFVCRuntimeBootstrapper::loadStaticVCRuntime(JITDylib &JD,
+                                                     bool DebugVersion) {
+  StringRef VCLibs[] = {"libvcruntime.lib", "libcmt.lib", "libcpmt.lib"};
+  StringRef UCRTLibs[] = {"libucrt.lib"};
+  if (auto Err =
+          lLoadVCRuntime(JD, makeArrayRef(VCLibs), makeArrayRef(UCRTLibs)))
+    return Err;
+
+  return Error::success();
+}
+
+Error COFFVCRuntimeBootstrapper::loadDynamicVCRuntime(JITDylib &JD,
+                                                      bool DebugVersion) {
+  StringRef VCLibs[] = {"vcruntime.lib", "msvcrt.lib", "msvcprt.lib"};
+  StringRef UCRTLibs[] = {"ucrt.lib"};
+  return lLoadVCRuntime(JD, makeArrayRef(VCLibs), makeArrayRef(UCRTLibs));
+}
+
+Error COFFVCRuntimeBootstrapper::lLoadVCRuntime(JITDylib &JD,
+                                                ArrayRef<StringRef> VCLibs,
+                                                ArrayRef<StringRef> UCRTLibs) {
+  MSVCToolchainPath Path;
+  if (!RuntimePath.empty()) {
+    Path.UCRTSdkLib = RuntimePath;
+    Path.VCToolchainLib = RuntimePath;
+  } else {
+    auto ToolchainPath = getMSVCToolchainPath();
+    if (!ToolchainPath)
+      return ToolchainPath.takeError();
+    Path = *ToolchainPath;
+  }
+  LLVM_DEBUG({
+    dbgs() << "Using VC toolchain pathes\n";
+    dbgs() << "  VC toolchain path: " << Path.VCToolchainLib << "\n";
+    dbgs() << "  UCRT path: " << Path.UCRTSdkLib << "\n";
+  });
+
+  std::vector<std::string> ImportedLibraries;
+  auto LoadLibrary = [&](SmallString<256> LibPath, StringRef LibName) -> Error {
+    sys::path::append(LibPath, LibName);
+
+    auto G = StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer,
+                                                    LibPath.c_str());
+    if (!G)
+      return G.takeError();
+
+    for (auto &Lib : (*G)->getImportedDynamicLibraries())
+      ImportedLibraries.push_back(Lib);
+
+    JD.addGenerator(std::move(*G));
+
+    return Error::success();
+  };
+  for (auto &Lib : UCRTLibs)
+    if (auto Err = LoadLibrary(Path.UCRTSdkLib, Lib))
+      return Err;
+
+  for (auto &Lib : VCLibs)
+    if (auto Err = LoadLibrary(Path.VCToolchainLib, Lib))
+      return Err;
+  ImportedLibraries.push_back("ntdll.dll");
+  ImportedLibraries.push_back("Kernel32.dll");
+
+  for (auto &Lib : ImportedLibraries)
+    if (auto Err = LoadDynLibrary(JD, Lib))
+      return Err;
+
+  return Error::success();
+}
+
+Error COFFVCRuntimeBootstrapper::initializeStaticVCRuntime(JITDylib &JD) {
+  ExecutorAddr jit_scrt_initialize, jit_scrt_dllmain_before_initialize_c,
+      jit_scrt_initialize_type_info,
+      jit_scrt_initialize_default_local_stdio_options;
+  if (auto Err = lookupAndRecordAddrs(
+          ES, LookupKind::Static, makeJITDylibSearchOrder(&JD),
+          {{ES.intern("__scrt_initialize_crt"), &jit_scrt_initialize},
+           {ES.intern("__scrt_dllmain_before_initialize_c"),
+            &jit_scrt_dllmain_before_initialize_c},
+           {ES.intern("?__scrt_initialize_type_info@@YAXXZ"),
+            &jit_scrt_initialize_type_info},
+           {ES.intern("__scrt_initialize_default_local_stdio_options"),
+            &jit_scrt_initialize_default_local_stdio_options}}))
+    return Err;
+
+  auto RunVoidInitFunc = [&](ExecutorAddr Addr) -> Error {
+    if (auto Res = ES.getExecutorProcessControl().runAsVoidFunction(Addr))
+      return Error::success();
+    else
+      return Res.takeError();
+  };
+
+  auto R =
+      ES.getExecutorProcessControl().runAsIntFunction(jit_scrt_initialize, 0);
+  if (!R)
+    return R.takeError();
+
+  if (auto Err = RunVoidInitFunc(jit_scrt_dllmain_before_initialize_c))
+    return Err;
+
+  if (auto Err = RunVoidInitFunc(jit_scrt_initialize_type_info))
+    return Err;
+
+  if (auto Err =
+          RunVoidInitFunc(jit_scrt_initialize_default_local_stdio_options))
+    return Err;
+
+  SymbolAliasMap Alias;
+  Alias[ES.intern("__run_after_c_init")] = {
+      ES.intern("__scrt_dllmain_after_initialize_c"), JITSymbolFlags::Exported};
+  if (auto Err = JD.define(symbolAliases(Alias)))
+    return Err;
+
+  return Error::success();
+}
+
+Expected<COFFVCRuntimeBootstrapper::MSVCToolchainPath>
+COFFVCRuntimeBootstrapper::getMSVCToolchainPath() {
+  std::string VCToolChainPath;
+  ToolsetLayout VSLayout;
+  IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem();
+  if (!findVCToolChainViaCommandLine(*VFS, None, None, None, VCToolChainPath,
+                                     VSLayout) &&
+      !findVCToolChainViaEnvironment(*VFS, VCToolChainPath, VSLayout) &&
+      !findVCToolChainViaSetupConfig(*VFS, VCToolChainPath, VSLayout) &&
+      !findVCToolChainViaRegistry(VCToolChainPath, VSLayout))
+    return make_error<StringError>("Couldn't find msvc toolchain.",
+                                   inconvertibleErrorCode());
+
+  std::string UniversalCRTSdkPath;
+  std::string UCRTVersion;
+  if (!getUniversalCRTSdkDir(*VFS, None, None, None, UniversalCRTSdkPath,
+                             UCRTVersion))
+    return make_error<StringError>("Couldn't find universal sdk.",
+                                   inconvertibleErrorCode());
+
+  MSVCToolchainPath ToolchainPath;
+  SmallString<256> VCToolchainLib(VCToolChainPath);
+  sys::path::append(VCToolchainLib, "lib", "x64");
+  ToolchainPath.VCToolchainLib = VCToolchainLib;
+
+  SmallString<256> UCRTSdkLib(UniversalCRTSdkPath);
+  sys::path::append(UCRTSdkLib, "Lib", UCRTVersion, "ucrt", "x64");
+  ToolchainPath.UCRTSdkLib = UCRTSdkLib;
+  return ToolchainPath;
+}
diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
index 412b9f95ea62..ea78c15b02e6 100644

- a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp

+++ b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
@@ -1,197 +1,209 @@
 //===---- ExecutorProcessControl.cpp -- Executor process control APIs -----===//
 //
 // 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/ExecutorProcessControl.h"

#include "llvm/ExecutionEngine/Orc/Core.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"

namespace llvm {
 namespace orc {

ExecutorProcessControl::MemoryAccess::~MemoryAccess() = default;

ExecutorProcessControl::~ExecutorProcessControl() = default;

SelfExecutorProcessControl::SelfExecutorProcessControl(

    std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D,
    Triple TargetTriple, unsigned PageSize,
    std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr)
    : ExecutorProcessControl(std::move(SSP), std::move(D)) {
   
  OwnedMemMgr = std::move(MemMgr);
  if (!OwnedMemMgr)
    OwnedMemMgr = std::make_unique<jitlink::InProcessMemoryManager>(
        sys::Process::getPageSizeEstimate());
   
  this->TargetTriple = std::move(TargetTriple);
  this->PageSize = PageSize;
  this->MemMgr = OwnedMemMgr.get();
  this->MemAccess = this;
  this->JDI = {ExecutorAddr::fromPtr(jitDispatchViaWrapperFunctionManager),
               ExecutorAddr::fromPtr(this)};
  if (this->TargetTriple.isOSBinFormatMachO())
    GlobalManglingPrefix = '_';

}

Expected<std::unique_ptr<SelfExecutorProcessControl>>
 SelfExecutorProcessControl::Create(

    std::shared_ptr<SymbolStringPool> SSP,
    std::unique_ptr<TaskDispatcher> D,
    std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
   
  if (!SSP)
    SSP = std::make_shared<SymbolStringPool>();
   
  if (!D) {

#if LLVM_ENABLE_THREADS

  D = std::make_unique<DynamicThreadPoolTaskDispatcher>();

#else

  D = std::make_unique<InPlaceTaskDispatcher>();

#endif

  }
   
  auto PageSize = sys::Process::getPageSize();
  if (!PageSize)
    return PageSize.takeError();
   
  Triple TT(sys::getProcessTriple());
   
  return std::make_unique<SelfExecutorProcessControl>(
      std::move(SSP), std::move(D), std::move(TT), *PageSize,
      std::move(MemMgr));

}

Expected<tpctypes::DylibHandle>
 SelfExecutorProcessControl::loadDylib(const char *DylibPath) {

  std::string ErrMsg;
  auto Dylib = std::make_unique<sys::DynamicLibrary>(
      sys::DynamicLibrary::getPermanentLibrary(DylibPath, &ErrMsg));
  if (!Dylib->isValid())
    return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
  DynamicLibraries.push_back(std::move(Dylib));
  return pointerToJITTargetAddress(DynamicLibraries.back().get());

}

Expected<std::vector<tpctypes::LookupResult>>
 SelfExecutorProcessControl::lookupSymbols(ArrayRef<LookupRequest> Request) {

  std::vector<tpctypes::LookupResult> R;
   
  for (auto &Elem : Request) {
    auto *Dylib = jitTargetAddressToPointer<sys::DynamicLibrary *>(Elem.Handle);
    assert(llvm::any_of(DynamicLibraries,
                        [=](const std::unique_ptr<sys::DynamicLibrary> &DL) {
                          return DL.get() == Dylib;
                        }) &&
           "Invalid handle");
   
    R.push_back(std::vector<JITTargetAddress>());
    for (auto &KV : Elem.Symbols) {
      auto &Sym = KV.first;
      std::string Tmp((*Sym).data() + !!GlobalManglingPrefix,
                      (*Sym).size() - !!GlobalManglingPrefix);
      void *Addr = Dylib->getAddressOfSymbol(Tmp.c_str());
      if (!Addr && KV.second == SymbolLookupFlags::RequiredSymbol) {
        // FIXME: Collect all failing symbols before erroring out.
        SymbolNameVector MissingSymbols;
        MissingSymbols.push_back(Sym);
        return make_error<SymbolsNotFound>(SSP, std::move(MissingSymbols));
      }
      R.back().push_back(pointerToJITTargetAddress(Addr));
    }
  }
   
  return R;

}

Expected<int32_t>
 SelfExecutorProcessControl::runAsMain(ExecutorAddr MainFnAddr,

                                      ArrayRef<std::string> Args) {
  using MainTy = int (*)(int, char *[]);
  return orc::runAsMain(MainFnAddr.toPtr<MainTy>(), Args);

}

+Expected<int32_t>
+SelfExecutorProcessControl::runAsVoidFunction(ExecutorAddr VoidFnAddr) {
+  using VoidTy = int (*)();
+  return VoidFnAddr.toPtr<VoidTy>()();
+}
+
+Expected<int32_t>
+SelfExecutorProcessControl::runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) {
+  using IntTy = int (*)(int);
+  return IntFnAddr.toPtr<IntTy>()(Arg);
+}
+
 void SelfExecutorProcessControl::callWrapperAsync(ExecutorAddr WrapperFnAddr,

                                                  IncomingWFRHandler SendResult,
                                                  ArrayRef<char> ArgBuffer) {
  using WrapperFnTy =
      shared::CWrapperFunctionResult (*)(const char *Data, size_t Size);
  auto *WrapperFn = WrapperFnAddr.toPtr<WrapperFnTy>();
  SendResult(WrapperFn(ArgBuffer.data(), ArgBuffer.size()));

}

Error SelfExecutorProcessControl::disconnect() {

  D->shutdown();
  return Error::success();

}

void SelfExecutorProcessControl::writeUInt8sAsync(

    ArrayRef<tpctypes::UInt8Write> Ws, WriteResultFn OnWriteComplete) {
  for (auto &W : Ws)
    *W.Addr.toPtr<uint8_t *>() = W.Value;
  OnWriteComplete(Error::success());

}

void SelfExecutorProcessControl::writeUInt16sAsync(

    ArrayRef<tpctypes::UInt16Write> Ws, WriteResultFn OnWriteComplete) {
  for (auto &W : Ws)
    *W.Addr.toPtr<uint16_t *>() = W.Value;
  OnWriteComplete(Error::success());

}

void SelfExecutorProcessControl::writeUInt32sAsync(

    ArrayRef<tpctypes::UInt32Write> Ws, WriteResultFn OnWriteComplete) {
  for (auto &W : Ws)
    *W.Addr.toPtr<uint32_t *>() = W.Value;
  OnWriteComplete(Error::success());

}

void SelfExecutorProcessControl::writeUInt64sAsync(

    ArrayRef<tpctypes::UInt64Write> Ws, WriteResultFn OnWriteComplete) {
  for (auto &W : Ws)
    *W.Addr.toPtr<uint64_t *>() = W.Value;
  OnWriteComplete(Error::success());

}

void SelfExecutorProcessControl::writeBuffersAsync(

    ArrayRef<tpctypes::BufferWrite> Ws, WriteResultFn OnWriteComplete) {
  for (auto &W : Ws)
    memcpy(W.Addr.toPtr<char *>(), W.Buffer.data(), W.Buffer.size());
  OnWriteComplete(Error::success());

}

shared::CWrapperFunctionResult
 SelfExecutorProcessControl::jitDispatchViaWrapperFunctionManager(

    void *Ctx, const void *FnTag, const char *Data, size_t Size) {
   
  LLVM_DEBUG({
    dbgs() << "jit-dispatch call with tag " << FnTag << " and " << Size
           << " byte payload.\n";
  });
   
  std::promise<shared::WrapperFunctionResult> ResultP;
  auto ResultF = ResultP.get_future();
  static_cast<SelfExecutorProcessControl *>(Ctx)
      ->getExecutionSession()
      .runJITDispatchHandler(
          [ResultP = std::move(ResultP)](
              shared::WrapperFunctionResult Result) mutable {
            ResultP.set_value(std::move(Result));
          },
          pointerToJITTargetAddress(FnTag), {Data, Size});
   
  return ResultF.get().release();

}

} // end namespace orc
 } // end namespace llvm


https://reviews.llvm.org/D130455

Files:
  llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
  llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp


Index: llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
===================================================================
--- llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
+++ llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
@@ -121,6 +121,18 @@
   return orc::runAsMain(MainFnAddr.toPtr<MainTy>(), Args);
 }
 
+Expected<int32_t>
+SelfExecutorProcessControl::runAsVoidFunction(ExecutorAddr VoidFnAddr) {
+  using VoidTy = int (*)();
+  return VoidFnAddr.toPtr<VoidTy>()();
+}
+
+Expected<int32_t>
+SelfExecutorProcessControl::runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) {
+  using IntTy = int (*)(int);
+  return IntFnAddr.toPtr<IntTy>()(Arg);
+}
+
 void SelfExecutorProcessControl::callWrapperAsync(ExecutorAddr WrapperFnAddr,
                                                   IncomingWFRHandler SendResult,
                                                   ArrayRef<char> ArgBuffer) {
Index: llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
===================================================================
--- llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
+++ llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
@@ -259,6 +259,13 @@
   virtual Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
                                       ArrayRef<std::string> Args) = 0;
 
+  /// Run function with a int (*)(void) signature.
+  virtual Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) = 0;
+
+  /// Run function with a int (*)(int) signature.
+  virtual Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr,
+                                             int Arg) = 0;
+
   /// Run a wrapper function in the executor. The given WFRHandler will be
   /// called on the result when it is returned.
   ///
@@ -397,6 +404,14 @@
     llvm_unreachable("Unsupported");
   }
 
+  Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) override {
+    llvm_unreachable("Unsupported");
+  }
+
+  Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override {
+    llvm_unreachable("Unsupported");
+  }
+
   void callWrapperAsync(ExecutorAddr WrapperFnAddr,
                         IncomingWFRHandler OnComplete,
                         ArrayRef<char> ArgBuffer) override {
@@ -434,6 +449,10 @@
   Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
                               ArrayRef<std::string> Args) override;
 
+  Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) override;
+
+  Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override;
+
   void callWrapperAsync(ExecutorAddr WrapperFnAddr,
                         IncomingWFRHandler OnComplete,
                         ArrayRef<char> ArgBuffer) override;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D130455.447179.patch
Type: text/x-patch
Size: 2759 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20220725/51c0f2cc/attachment.bin>


More information about the llvm-commits mailing list