1fe6060f1SDimitry Andric //===---- ExecutorProcessControl.cpp -- Executor process control APIs -----===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric
9fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
10fe6060f1SDimitry Andric
11fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/Orc/Core.h"
12c9157d92SDimitry Andric #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
13c9157d92SDimitry Andric #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
14fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
15fe6060f1SDimitry Andric #include "llvm/Support/FormatVariadic.h"
16fe6060f1SDimitry Andric #include "llvm/Support/Process.h"
17fe013be4SDimitry Andric #include "llvm/TargetParser/Host.h"
18fe6060f1SDimitry Andric
19fe6060f1SDimitry Andric #define DEBUG_TYPE "orc"
20fe6060f1SDimitry Andric
21fe6060f1SDimitry Andric namespace llvm {
22fe6060f1SDimitry Andric namespace orc {
23fe6060f1SDimitry Andric
2481ad6265SDimitry Andric ExecutorProcessControl::MemoryAccess::~MemoryAccess() = default;
25fe6060f1SDimitry Andric
2681ad6265SDimitry Andric ExecutorProcessControl::~ExecutorProcessControl() = default;
27fe6060f1SDimitry Andric
SelfExecutorProcessControl(std::shared_ptr<SymbolStringPool> SSP,std::unique_ptr<TaskDispatcher> D,Triple TargetTriple,unsigned PageSize,std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr)28fe6060f1SDimitry Andric SelfExecutorProcessControl::SelfExecutorProcessControl(
29349cc55cSDimitry Andric std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D,
30349cc55cSDimitry Andric Triple TargetTriple, unsigned PageSize,
31349cc55cSDimitry Andric std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr)
32c9157d92SDimitry Andric : ExecutorProcessControl(std::move(SSP), std::move(D)),
33c9157d92SDimitry Andric InProcessMemoryAccess(TargetTriple.isArch64Bit()) {
34fe6060f1SDimitry Andric
35fe6060f1SDimitry Andric OwnedMemMgr = std::move(MemMgr);
36fe6060f1SDimitry Andric if (!OwnedMemMgr)
37349cc55cSDimitry Andric OwnedMemMgr = std::make_unique<jitlink::InProcessMemoryManager>(
38349cc55cSDimitry Andric sys::Process::getPageSizeEstimate());
39fe6060f1SDimitry Andric
40fe6060f1SDimitry Andric this->TargetTriple = std::move(TargetTriple);
41fe6060f1SDimitry Andric this->PageSize = PageSize;
42fe6060f1SDimitry Andric this->MemMgr = OwnedMemMgr.get();
43fe6060f1SDimitry Andric this->MemAccess = this;
44349cc55cSDimitry Andric this->JDI = {ExecutorAddr::fromPtr(jitDispatchViaWrapperFunctionManager),
45349cc55cSDimitry Andric ExecutorAddr::fromPtr(this)};
46fe6060f1SDimitry Andric if (this->TargetTriple.isOSBinFormatMachO())
47fe6060f1SDimitry Andric GlobalManglingPrefix = '_';
48c9157d92SDimitry Andric
49c9157d92SDimitry Andric this->BootstrapSymbols[rt::RegisterEHFrameSectionWrapperName] =
50c9157d92SDimitry Andric ExecutorAddr::fromPtr(&llvm_orc_registerEHFrameSectionWrapper);
51c9157d92SDimitry Andric this->BootstrapSymbols[rt::DeregisterEHFrameSectionWrapperName] =
52c9157d92SDimitry Andric ExecutorAddr::fromPtr(&llvm_orc_deregisterEHFrameSectionWrapper);
53fe6060f1SDimitry Andric }
54fe6060f1SDimitry Andric
55fe6060f1SDimitry Andric Expected<std::unique_ptr<SelfExecutorProcessControl>>
Create(std::shared_ptr<SymbolStringPool> SSP,std::unique_ptr<TaskDispatcher> D,std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr)56fe6060f1SDimitry Andric SelfExecutorProcessControl::Create(
57fe6060f1SDimitry Andric std::shared_ptr<SymbolStringPool> SSP,
58349cc55cSDimitry Andric std::unique_ptr<TaskDispatcher> D,
59fe6060f1SDimitry Andric std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
60fe6060f1SDimitry Andric
61fe6060f1SDimitry Andric if (!SSP)
62fe6060f1SDimitry Andric SSP = std::make_shared<SymbolStringPool>();
63fe6060f1SDimitry Andric
64349cc55cSDimitry Andric if (!D) {
65349cc55cSDimitry Andric #if LLVM_ENABLE_THREADS
66349cc55cSDimitry Andric D = std::make_unique<DynamicThreadPoolTaskDispatcher>();
67349cc55cSDimitry Andric #else
68349cc55cSDimitry Andric D = std::make_unique<InPlaceTaskDispatcher>();
69349cc55cSDimitry Andric #endif
70349cc55cSDimitry Andric }
71349cc55cSDimitry Andric
72fe6060f1SDimitry Andric auto PageSize = sys::Process::getPageSize();
73fe6060f1SDimitry Andric if (!PageSize)
74fe6060f1SDimitry Andric return PageSize.takeError();
75fe6060f1SDimitry Andric
76fe6060f1SDimitry Andric Triple TT(sys::getProcessTriple());
77fe6060f1SDimitry Andric
78fe6060f1SDimitry Andric return std::make_unique<SelfExecutorProcessControl>(
79349cc55cSDimitry Andric std::move(SSP), std::move(D), std::move(TT), *PageSize,
80349cc55cSDimitry Andric std::move(MemMgr));
81fe6060f1SDimitry Andric }
82fe6060f1SDimitry Andric
83fe6060f1SDimitry Andric Expected<tpctypes::DylibHandle>
loadDylib(const char * DylibPath)84fe6060f1SDimitry Andric SelfExecutorProcessControl::loadDylib(const char *DylibPath) {
85fe6060f1SDimitry Andric std::string ErrMsg;
86bdd1243dSDimitry Andric auto Dylib = sys::DynamicLibrary::getPermanentLibrary(DylibPath, &ErrMsg);
87bdd1243dSDimitry Andric if (!Dylib.isValid())
88fe6060f1SDimitry Andric return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
89bdd1243dSDimitry Andric return ExecutorAddr::fromPtr(Dylib.getOSSpecificHandle());
90fe6060f1SDimitry Andric }
91fe6060f1SDimitry Andric
92fe6060f1SDimitry Andric Expected<std::vector<tpctypes::LookupResult>>
lookupSymbols(ArrayRef<LookupRequest> Request)93fe6060f1SDimitry Andric SelfExecutorProcessControl::lookupSymbols(ArrayRef<LookupRequest> Request) {
94fe6060f1SDimitry Andric std::vector<tpctypes::LookupResult> R;
95fe6060f1SDimitry Andric
96fe6060f1SDimitry Andric for (auto &Elem : Request) {
97bdd1243dSDimitry Andric sys::DynamicLibrary Dylib(Elem.Handle.toPtr<void *>());
98*cdc20ff6SDimitry Andric R.push_back(std::vector<ExecutorSymbolDef>());
99fe6060f1SDimitry Andric for (auto &KV : Elem.Symbols) {
100fe6060f1SDimitry Andric auto &Sym = KV.first;
101fe6060f1SDimitry Andric std::string Tmp((*Sym).data() + !!GlobalManglingPrefix,
102fe6060f1SDimitry Andric (*Sym).size() - !!GlobalManglingPrefix);
103bdd1243dSDimitry Andric void *Addr = Dylib.getAddressOfSymbol(Tmp.c_str());
104fe6060f1SDimitry Andric if (!Addr && KV.second == SymbolLookupFlags::RequiredSymbol) {
105fe6060f1SDimitry Andric // FIXME: Collect all failing symbols before erroring out.
106fe6060f1SDimitry Andric SymbolNameVector MissingSymbols;
107fe6060f1SDimitry Andric MissingSymbols.push_back(Sym);
108349cc55cSDimitry Andric return make_error<SymbolsNotFound>(SSP, std::move(MissingSymbols));
109fe6060f1SDimitry Andric }
110*cdc20ff6SDimitry Andric // FIXME: determine accurate JITSymbolFlags.
111*cdc20ff6SDimitry Andric R.back().push_back(
112*cdc20ff6SDimitry Andric {ExecutorAddr::fromPtr(Addr), JITSymbolFlags::Exported});
113fe6060f1SDimitry Andric }
114fe6060f1SDimitry Andric }
115fe6060f1SDimitry Andric
116fe6060f1SDimitry Andric return R;
117fe6060f1SDimitry Andric }
118fe6060f1SDimitry Andric
119fe6060f1SDimitry Andric Expected<int32_t>
runAsMain(ExecutorAddr MainFnAddr,ArrayRef<std::string> Args)120349cc55cSDimitry Andric SelfExecutorProcessControl::runAsMain(ExecutorAddr MainFnAddr,
121fe6060f1SDimitry Andric ArrayRef<std::string> Args) {
122fe6060f1SDimitry Andric using MainTy = int (*)(int, char *[]);
123349cc55cSDimitry Andric return orc::runAsMain(MainFnAddr.toPtr<MainTy>(), Args);
124fe6060f1SDimitry Andric }
125fe6060f1SDimitry Andric
126bdd1243dSDimitry Andric Expected<int32_t>
runAsVoidFunction(ExecutorAddr VoidFnAddr)127bdd1243dSDimitry Andric SelfExecutorProcessControl::runAsVoidFunction(ExecutorAddr VoidFnAddr) {
128bdd1243dSDimitry Andric using VoidTy = int (*)();
129bdd1243dSDimitry Andric return orc::runAsVoidFunction(VoidFnAddr.toPtr<VoidTy>());
130bdd1243dSDimitry Andric }
131bdd1243dSDimitry Andric
132bdd1243dSDimitry Andric Expected<int32_t>
runAsIntFunction(ExecutorAddr IntFnAddr,int Arg)133bdd1243dSDimitry Andric SelfExecutorProcessControl::runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) {
134bdd1243dSDimitry Andric using IntTy = int (*)(int);
135bdd1243dSDimitry Andric return orc::runAsIntFunction(IntFnAddr.toPtr<IntTy>(), Arg);
136bdd1243dSDimitry Andric }
137bdd1243dSDimitry Andric
callWrapperAsync(ExecutorAddr WrapperFnAddr,IncomingWFRHandler SendResult,ArrayRef<char> ArgBuffer)138349cc55cSDimitry Andric void SelfExecutorProcessControl::callWrapperAsync(ExecutorAddr WrapperFnAddr,
139349cc55cSDimitry Andric IncomingWFRHandler SendResult,
140fe6060f1SDimitry Andric ArrayRef<char> ArgBuffer) {
141fe6060f1SDimitry Andric using WrapperFnTy =
142349cc55cSDimitry Andric shared::CWrapperFunctionResult (*)(const char *Data, size_t Size);
143349cc55cSDimitry Andric auto *WrapperFn = WrapperFnAddr.toPtr<WrapperFnTy>();
144fe6060f1SDimitry Andric SendResult(WrapperFn(ArgBuffer.data(), ArgBuffer.size()));
145fe6060f1SDimitry Andric }
146fe6060f1SDimitry Andric
disconnect()147349cc55cSDimitry Andric Error SelfExecutorProcessControl::disconnect() {
148349cc55cSDimitry Andric D->shutdown();
149349cc55cSDimitry Andric return Error::success();
150349cc55cSDimitry Andric }
151fe6060f1SDimitry Andric
writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,WriteResultFn OnWriteComplete)152c9157d92SDimitry Andric void InProcessMemoryAccess::writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
153c9157d92SDimitry Andric WriteResultFn OnWriteComplete) {
154fe6060f1SDimitry Andric for (auto &W : Ws)
155349cc55cSDimitry Andric *W.Addr.toPtr<uint8_t *>() = W.Value;
156fe6060f1SDimitry Andric OnWriteComplete(Error::success());
157fe6060f1SDimitry Andric }
158fe6060f1SDimitry Andric
writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws,WriteResultFn OnWriteComplete)159c9157d92SDimitry Andric void InProcessMemoryAccess::writeUInt16sAsync(
160fe6060f1SDimitry Andric ArrayRef<tpctypes::UInt16Write> Ws, WriteResultFn OnWriteComplete) {
161fe6060f1SDimitry Andric for (auto &W : Ws)
162349cc55cSDimitry Andric *W.Addr.toPtr<uint16_t *>() = W.Value;
163fe6060f1SDimitry Andric OnWriteComplete(Error::success());
164fe6060f1SDimitry Andric }
165fe6060f1SDimitry Andric
writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws,WriteResultFn OnWriteComplete)166c9157d92SDimitry Andric void InProcessMemoryAccess::writeUInt32sAsync(
167fe6060f1SDimitry Andric ArrayRef<tpctypes::UInt32Write> Ws, WriteResultFn OnWriteComplete) {
168fe6060f1SDimitry Andric for (auto &W : Ws)
169349cc55cSDimitry Andric *W.Addr.toPtr<uint32_t *>() = W.Value;
170fe6060f1SDimitry Andric OnWriteComplete(Error::success());
171fe6060f1SDimitry Andric }
172fe6060f1SDimitry Andric
writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,WriteResultFn OnWriteComplete)173c9157d92SDimitry Andric void InProcessMemoryAccess::writeUInt64sAsync(
174fe6060f1SDimitry Andric ArrayRef<tpctypes::UInt64Write> Ws, WriteResultFn OnWriteComplete) {
175fe6060f1SDimitry Andric for (auto &W : Ws)
176349cc55cSDimitry Andric *W.Addr.toPtr<uint64_t *>() = W.Value;
177fe6060f1SDimitry Andric OnWriteComplete(Error::success());
178fe6060f1SDimitry Andric }
179fe6060f1SDimitry Andric
writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,WriteResultFn OnWriteComplete)180c9157d92SDimitry Andric void InProcessMemoryAccess::writeBuffersAsync(
181fe6060f1SDimitry Andric ArrayRef<tpctypes::BufferWrite> Ws, WriteResultFn OnWriteComplete) {
182fe6060f1SDimitry Andric for (auto &W : Ws)
183349cc55cSDimitry Andric memcpy(W.Addr.toPtr<char *>(), W.Buffer.data(), W.Buffer.size());
184fe6060f1SDimitry Andric OnWriteComplete(Error::success());
185fe6060f1SDimitry Andric }
186fe6060f1SDimitry Andric
writePointersAsync(ArrayRef<tpctypes::PointerWrite> Ws,WriteResultFn OnWriteComplete)187c9157d92SDimitry Andric void InProcessMemoryAccess::writePointersAsync(
188c9157d92SDimitry Andric ArrayRef<tpctypes::PointerWrite> Ws, WriteResultFn OnWriteComplete) {
189c9157d92SDimitry Andric if (IsArch64Bit) {
190c9157d92SDimitry Andric for (auto &W : Ws)
191c9157d92SDimitry Andric *W.Addr.toPtr<uint64_t *>() = W.Value.getValue();
192c9157d92SDimitry Andric } else {
193c9157d92SDimitry Andric for (auto &W : Ws)
194c9157d92SDimitry Andric *W.Addr.toPtr<uint32_t *>() = static_cast<uint32_t>(W.Value.getValue());
195c9157d92SDimitry Andric }
196c9157d92SDimitry Andric
197c9157d92SDimitry Andric OnWriteComplete(Error::success());
198c9157d92SDimitry Andric }
199c9157d92SDimitry Andric
200349cc55cSDimitry Andric shared::CWrapperFunctionResult
jitDispatchViaWrapperFunctionManager(void * Ctx,const void * FnTag,const char * Data,size_t Size)201fe6060f1SDimitry Andric SelfExecutorProcessControl::jitDispatchViaWrapperFunctionManager(
202fe6060f1SDimitry Andric void *Ctx, const void *FnTag, const char *Data, size_t Size) {
203fe6060f1SDimitry Andric
204fe6060f1SDimitry Andric LLVM_DEBUG({
205fe6060f1SDimitry Andric dbgs() << "jit-dispatch call with tag " << FnTag << " and " << Size
206fe6060f1SDimitry Andric << " byte payload.\n";
207fe6060f1SDimitry Andric });
208fe6060f1SDimitry Andric
209fe6060f1SDimitry Andric std::promise<shared::WrapperFunctionResult> ResultP;
210fe6060f1SDimitry Andric auto ResultF = ResultP.get_future();
211fe6060f1SDimitry Andric static_cast<SelfExecutorProcessControl *>(Ctx)
212fe6060f1SDimitry Andric ->getExecutionSession()
213fe6060f1SDimitry Andric .runJITDispatchHandler(
214fe6060f1SDimitry Andric [ResultP = std::move(ResultP)](
215fe6060f1SDimitry Andric shared::WrapperFunctionResult Result) mutable {
216fe6060f1SDimitry Andric ResultP.set_value(std::move(Result));
217fe6060f1SDimitry Andric },
218fe013be4SDimitry Andric ExecutorAddr::fromPtr(FnTag), {Data, Size});
219fe6060f1SDimitry Andric
220fe6060f1SDimitry Andric return ResultF.get().release();
221fe6060f1SDimitry Andric }
222fe6060f1SDimitry Andric
223fe6060f1SDimitry Andric } // end namespace orc
224fe6060f1SDimitry Andric } // end namespace llvm
225