xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp (revision bb5f97e3ad10a0f8a62560890e5a87b4bc2c00bd)
1 //===---- ExecutorProcessControl.cpp -- Executor process control APIs -----===//
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/ExecutorProcessControl.h"
10 
11 #include "llvm/ExecutionEngine/Orc/Core.h"
12 #include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
13 #include "llvm/Support/FormatVariadic.h"
14 #include "llvm/Support/Host.h"
15 #include "llvm/Support/Process.h"
16 
17 #define DEBUG_TYPE "orc"
18 
19 namespace llvm {
20 namespace orc {
21 
22 ExecutorProcessControl::MemoryAccess::~MemoryAccess() {}
23 
24 ExecutorProcessControl::~ExecutorProcessControl() {}
25 
26 Error ExecutorProcessControl::associateJITSideWrapperFunctions(
27     JITDylib &JD, WrapperFunctionAssociationMap WFs) {
28 
29   // Look up tag addresses.
30   auto &ES = JD.getExecutionSession();
31   auto TagAddrs =
32       ES.lookup({{&JD, JITDylibLookupFlags::MatchAllSymbols}},
33                 SymbolLookupSet::fromMapKeys(
34                     WFs, SymbolLookupFlags::WeaklyReferencedSymbol));
35   if (!TagAddrs)
36     return TagAddrs.takeError();
37 
38   // Associate tag addresses with implementations.
39   std::lock_guard<std::mutex> Lock(TagToFuncMapMutex);
40   for (auto &KV : *TagAddrs) {
41     auto TagAddr = KV.second.getAddress();
42     if (TagToFunc.count(TagAddr))
43       return make_error<StringError>("Tag " + formatv("{0:x16}", TagAddr) +
44                                          " (for " + *KV.first +
45                                          ") already registered",
46                                      inconvertibleErrorCode());
47     auto I = WFs.find(KV.first);
48     assert(I != WFs.end() && I->second &&
49            "AsyncWrapperFunction implementation missing");
50     TagToFunc[KV.second.getAddress()] =
51         std::make_shared<AsyncWrapperFunction>(std::move(I->second));
52     LLVM_DEBUG({
53       dbgs() << "Associated function tag \"" << *KV.first << "\" ("
54              << formatv("{0:x}", KV.second.getAddress()) << ") with handler\n";
55     });
56   }
57   return Error::success();
58 }
59 
60 void ExecutorProcessControl::runJITSideWrapperFunction(
61     SendResultFunction SendResult, JITTargetAddress TagAddr,
62     ArrayRef<char> ArgBuffer) {
63 
64   std::shared_ptr<AsyncWrapperFunction> F;
65   {
66     std::lock_guard<std::mutex> Lock(TagToFuncMapMutex);
67     auto I = TagToFunc.find(TagAddr);
68     if (I != TagToFunc.end())
69       F = I->second;
70   }
71 
72   if (F)
73     (*F)(std::move(SendResult), ArgBuffer.data(), ArgBuffer.size());
74   else
75     SendResult(shared::WrapperFunctionResult::createOutOfBandError(
76         ("No function registered for tag " + formatv("{0:x16}", TagAddr))
77             .str()));
78 }
79 
80 SelfExecutorProcessControl::SelfExecutorProcessControl(
81     std::shared_ptr<SymbolStringPool> SSP, Triple TargetTriple,
82     unsigned PageSize, std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr)
83     : ExecutorProcessControl(std::move(SSP)) {
84 
85   OwnedMemMgr = std::move(MemMgr);
86   if (!OwnedMemMgr)
87     OwnedMemMgr = std::make_unique<jitlink::InProcessMemoryManager>();
88 
89   this->TargetTriple = std::move(TargetTriple);
90   this->PageSize = PageSize;
91   this->MemMgr = OwnedMemMgr.get();
92   this->MemAccess = this;
93   this->JDI = {ExecutorAddress::fromPtr(jitDispatchViaWrapperFunctionManager),
94                ExecutorAddress::fromPtr(this)};
95   if (this->TargetTriple.isOSBinFormatMachO())
96     GlobalManglingPrefix = '_';
97 }
98 
99 Expected<std::unique_ptr<SelfExecutorProcessControl>>
100 SelfExecutorProcessControl::Create(
101     std::shared_ptr<SymbolStringPool> SSP,
102     std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
103   auto PageSize = sys::Process::getPageSize();
104   if (!PageSize)
105     return PageSize.takeError();
106 
107   Triple TT(sys::getProcessTriple());
108 
109   return std::make_unique<SelfExecutorProcessControl>(
110       std::move(SSP), std::move(TT), *PageSize, std::move(MemMgr));
111 }
112 
113 Expected<tpctypes::DylibHandle>
114 SelfExecutorProcessControl::loadDylib(const char *DylibPath) {
115   std::string ErrMsg;
116   auto Dylib = std::make_unique<sys::DynamicLibrary>(
117       sys::DynamicLibrary::getPermanentLibrary(DylibPath, &ErrMsg));
118   if (!Dylib->isValid())
119     return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
120   DynamicLibraries.push_back(std::move(Dylib));
121   return pointerToJITTargetAddress(DynamicLibraries.back().get());
122 }
123 
124 Expected<std::vector<tpctypes::LookupResult>>
125 SelfExecutorProcessControl::lookupSymbols(ArrayRef<LookupRequest> Request) {
126   std::vector<tpctypes::LookupResult> R;
127 
128   for (auto &Elem : Request) {
129     auto *Dylib = jitTargetAddressToPointer<sys::DynamicLibrary *>(Elem.Handle);
130     assert(llvm::any_of(DynamicLibraries,
131                         [=](const std::unique_ptr<sys::DynamicLibrary> &DL) {
132                           return DL.get() == Dylib;
133                         }) &&
134            "Invalid handle");
135 
136     R.push_back(std::vector<JITTargetAddress>());
137     for (auto &KV : Elem.Symbols) {
138       auto &Sym = KV.first;
139       std::string Tmp((*Sym).data() + !!GlobalManglingPrefix,
140                       (*Sym).size() - !!GlobalManglingPrefix);
141       void *Addr = Dylib->getAddressOfSymbol(Tmp.c_str());
142       if (!Addr && KV.second == SymbolLookupFlags::RequiredSymbol) {
143         // FIXME: Collect all failing symbols before erroring out.
144         SymbolNameVector MissingSymbols;
145         MissingSymbols.push_back(Sym);
146         return make_error<SymbolsNotFound>(std::move(MissingSymbols));
147       }
148       R.back().push_back(pointerToJITTargetAddress(Addr));
149     }
150   }
151 
152   return R;
153 }
154 
155 Expected<int32_t>
156 SelfExecutorProcessControl::runAsMain(JITTargetAddress MainFnAddr,
157                                       ArrayRef<std::string> Args) {
158   using MainTy = int (*)(int, char *[]);
159   return orc::runAsMain(jitTargetAddressToFunction<MainTy>(MainFnAddr), Args);
160 }
161 
162 void SelfExecutorProcessControl::runWrapperAsync(SendResultFunction SendResult,
163                                                  JITTargetAddress WrapperFnAddr,
164                                                  ArrayRef<char> ArgBuffer) {
165   using WrapperFnTy =
166       shared::detail::CWrapperFunctionResult (*)(const char *Data, size_t Size);
167   auto *WrapperFn = jitTargetAddressToFunction<WrapperFnTy>(WrapperFnAddr);
168   SendResult(WrapperFn(ArgBuffer.data(), ArgBuffer.size()));
169 }
170 
171 Error SelfExecutorProcessControl::disconnect() { return Error::success(); }
172 
173 void SelfExecutorProcessControl::writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws,
174                                              WriteResultFn OnWriteComplete) {
175   for (auto &W : Ws)
176     *jitTargetAddressToPointer<uint8_t *>(W.Address) = W.Value;
177   OnWriteComplete(Error::success());
178 }
179 
180 void SelfExecutorProcessControl::writeUInt16s(
181     ArrayRef<tpctypes::UInt16Write> Ws, WriteResultFn OnWriteComplete) {
182   for (auto &W : Ws)
183     *jitTargetAddressToPointer<uint16_t *>(W.Address) = W.Value;
184   OnWriteComplete(Error::success());
185 }
186 
187 void SelfExecutorProcessControl::writeUInt32s(
188     ArrayRef<tpctypes::UInt32Write> Ws, WriteResultFn OnWriteComplete) {
189   for (auto &W : Ws)
190     *jitTargetAddressToPointer<uint32_t *>(W.Address) = W.Value;
191   OnWriteComplete(Error::success());
192 }
193 
194 void SelfExecutorProcessControl::writeUInt64s(
195     ArrayRef<tpctypes::UInt64Write> Ws, WriteResultFn OnWriteComplete) {
196   for (auto &W : Ws)
197     *jitTargetAddressToPointer<uint64_t *>(W.Address) = W.Value;
198   OnWriteComplete(Error::success());
199 }
200 
201 void SelfExecutorProcessControl::writeBuffers(
202     ArrayRef<tpctypes::BufferWrite> Ws, WriteResultFn OnWriteComplete) {
203   for (auto &W : Ws)
204     memcpy(jitTargetAddressToPointer<char *>(W.Address), W.Buffer.data(),
205            W.Buffer.size());
206   OnWriteComplete(Error::success());
207 }
208 
209 shared::detail::CWrapperFunctionResult
210 SelfExecutorProcessControl::jitDispatchViaWrapperFunctionManager(
211     void *Ctx, const void *FnTag, const char *Data, size_t Size) {
212 
213   LLVM_DEBUG({
214     dbgs() << "jit-dispatch call with tag " << FnTag << " and " << Size
215            << " byte payload.\n";
216   });
217 
218   std::promise<shared::WrapperFunctionResult> ResultP;
219   auto ResultF = ResultP.get_future();
220   static_cast<SelfExecutorProcessControl *>(Ctx)->runJITSideWrapperFunction(
221       [ResultP =
222            std::move(ResultP)](shared::WrapperFunctionResult Result) mutable {
223         ResultP.set_value(std::move(Result));
224       },
225       pointerToJITTargetAddress(FnTag), {Data, Size});
226 
227   return ResultF.get().release();
228 }
229 
230 } // end namespace orc
231 } // end namespace llvm
232