1//===------ SelfExecutorProcessControl.cpp -- EPC for in-process JITs -----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/ExecutionEngine/Orc/SelfExecutorProcessControl.h"
10
11#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
12#include "llvm/ExecutionEngine/Orc/Core.h"
13#include "llvm/ExecutionEngine/Orc/DylibManager.h"
14#include "llvm/ExecutionEngine/Orc/InProcessMemoryAccess.h"
15#include "llvm/ExecutionEngine/Orc/TargetProcess/DefaultHostBootstrapValues.h"
16#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
17#include "llvm/Support/DynamicLibrary.h"
18#include "llvm/Support/Process.h"
19#include "llvm/TargetParser/Host.h"
20
21#define DEBUG_TYPE "orc"
22
23namespace llvm::orc {
24
25class SelfExecutorProcessControl::InProcessDylibManager : public DylibManager {
26public:
27 InProcessDylibManager(char GlobalManglingPrefix);
28 Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;
29 void
30 lookupSymbolsAsync(tpctypes::DylibHandle H, const SymbolLookupSet &Symbols,
31 DylibManager::SymbolLookupCompleteFn Complete) override;
32
33private:
34 char GlobalManglingPrefix;
35};
36
37SelfExecutorProcessControl::SelfExecutorProcessControl(
38 std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D,
39 Triple TargetTriple, unsigned PageSize)
40 : ExecutorProcessControl(std::move(SSP), std::move(D)) {
41
42 this->TargetTriple = std::move(TargetTriple);
43 this->PageSize = PageSize;
44 this->JDI = {.JITDispatchFunction: ExecutorAddr::fromPtr(Ptr: jitDispatchViaWrapperFunctionManager),
45 .JITDispatchContext: ExecutorAddr::fromPtr(Ptr: this)};
46
47 addDefaultBootstrapValuesForHostProcess(BootstrapMap, BootstrapSymbols);
48
49#ifdef __APPLE__
50 // FIXME: Don't add an UnwindInfoManager by default -- it's redundant when
51 // the ORC runtime is loaded. We'll need a way to document this and
52 // allow clients to choose.
53 if (UnwindInfoManager::TryEnable())
54 UnwindInfoManager::addBootstrapSymbols(this->BootstrapSymbols);
55#endif // __APPLE__
56}
57
58Expected<std::unique_ptr<SelfExecutorProcessControl>>
59SelfExecutorProcessControl::Create(std::shared_ptr<SymbolStringPool> SSP,
60 std::unique_ptr<TaskDispatcher> D) {
61
62 if (!SSP)
63 SSP = std::make_shared<SymbolStringPool>();
64
65 if (!D)
66 D = std::make_unique<InPlaceTaskDispatcher>();
67
68 auto PageSize = sys::Process::getPageSize();
69 if (!PageSize)
70 return PageSize.takeError();
71
72 Triple TT(sys::getProcessTriple());
73
74 return std::make_unique<SelfExecutorProcessControl>(
75 args: std::move(SSP), args: std::move(D), args: std::move(TT), args&: *PageSize);
76}
77
78Expected<int32_t>
79SelfExecutorProcessControl::runAsMain(ExecutorAddr MainFnAddr,
80 ArrayRef<std::string> Args) {
81 using MainTy = int (*)(int, char *[]);
82 return orc::runAsMain(Main: MainFnAddr.toPtr<MainTy>(), Args);
83}
84
85Expected<int32_t>
86SelfExecutorProcessControl::runAsVoidFunction(ExecutorAddr VoidFnAddr) {
87 using VoidTy = int (*)();
88 return orc::runAsVoidFunction(Func: VoidFnAddr.toPtr<VoidTy>());
89}
90
91Expected<int32_t>
92SelfExecutorProcessControl::runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) {
93 using IntTy = int (*)(int);
94 return orc::runAsIntFunction(Func: IntFnAddr.toPtr<IntTy>(), Arg);
95}
96
97void SelfExecutorProcessControl::callWrapperAsync(ExecutorAddr WrapperFnAddr,
98 IncomingWFRHandler SendResult,
99 ArrayRef<char> ArgBuffer) {
100 using WrapperFnTy =
101 shared::CWrapperFunctionBuffer (*)(const char *Data, size_t Size);
102 auto *WrapperFn = WrapperFnAddr.toPtr<WrapperFnTy>();
103 SendResult(shared::WrapperFunctionBuffer(
104 WrapperFn(ArgBuffer.data(), ArgBuffer.size())));
105}
106
107Error SelfExecutorProcessControl::disconnect() {
108 D->shutdown();
109 return Error::success();
110}
111
112Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>
113SelfExecutorProcessControl::createDefaultMemoryManager() {
114 return std::make_unique<jitlink::InProcessMemoryManager>(
115 args: sys::Process::getPageSizeEstimate());
116}
117
118Expected<std::unique_ptr<DylibManager>>
119SelfExecutorProcessControl::createDefaultDylibMgr() {
120 char Prefix = TargetTriple.isOSBinFormatMachO() ? '_' : '\0';
121 return std::make_unique<InProcessDylibManager>(args&: Prefix);
122}
123
124Expected<std::unique_ptr<MemoryAccess>>
125SelfExecutorProcessControl::createDefaultMemoryAccess() {
126 return std::make_unique<InProcessMemoryAccess>(args: TargetTriple.isArch64Bit());
127}
128
129shared::CWrapperFunctionBuffer
130SelfExecutorProcessControl::jitDispatchViaWrapperFunctionManager(
131 void *Ctx, const void *FnTag, const char *Data, size_t Size) {
132
133 LLVM_DEBUG({
134 dbgs() << "jit-dispatch call with tag " << FnTag << " and " << Size
135 << " byte payload.\n";
136 });
137
138 std::promise<shared::WrapperFunctionBuffer> ResultP;
139 auto ResultF = ResultP.get_future();
140 static_cast<SelfExecutorProcessControl *>(Ctx)
141 ->getExecutionSession()
142 .runJITDispatchHandler(
143 SendResult: [ResultP = std::move(ResultP)](
144 shared::WrapperFunctionBuffer Result) mutable {
145 ResultP.set_value(std::move(Result));
146 },
147 HandlerFnTagAddr: ExecutorAddr::fromPtr(Ptr: FnTag),
148 ArgBytes: shared::WrapperFunctionBuffer::copyFrom(Source: Data, Size));
149
150 return ResultF.get().release();
151}
152
153SelfExecutorProcessControl::InProcessDylibManager::InProcessDylibManager(
154 char GlobalManglingPrefix)
155 : GlobalManglingPrefix(GlobalManglingPrefix) {}
156
157Expected<tpctypes::DylibHandle>
158SelfExecutorProcessControl::InProcessDylibManager::loadDylib(
159 const char *DylibPath) {
160 std::string ErrMsg;
161 auto Dylib = sys::DynamicLibrary::getPermanentLibrary(filename: DylibPath, errMsg: &ErrMsg);
162 if (!Dylib.isValid())
163 return make_error<StringError>(Args: std::move(ErrMsg), Args: inconvertibleErrorCode());
164 return ExecutorAddr::fromPtr(Ptr: Dylib.getOSSpecificHandle());
165}
166
167void SelfExecutorProcessControl::InProcessDylibManager::lookupSymbolsAsync(
168 tpctypes::DylibHandle H, const SymbolLookupSet &Symbols,
169 DylibManager::SymbolLookupCompleteFn Complete) {
170 tpctypes::LookupResult R;
171
172 sys::DynamicLibrary Dylib(H.toPtr<void *>());
173 for (auto &KV : Symbols) {
174 auto &Sym = KV.first;
175 std::string Tmp((*Sym).data() + !!GlobalManglingPrefix,
176 (*Sym).size() - !!GlobalManglingPrefix);
177 void *Addr = Dylib.getAddressOfSymbol(symbolName: Tmp.c_str());
178 if (!Addr && KV.second == SymbolLookupFlags::RequiredSymbol)
179 R.emplace_back();
180 else
181 R.emplace_back(args: ExecutorAddr::fromPtr(Ptr: Addr));
182 }
183 Complete(std::move(R));
184}
185
186} // namespace llvm::orc
187