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/Orc/Core.h" |
12 | #include "llvm/ExecutionEngine/Orc/TargetProcess/DefaultHostBootstrapValues.h" |
13 | #include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h" |
14 | #include "llvm/Support/DynamicLibrary.h" |
15 | #include "llvm/Support/Process.h" |
16 | #include "llvm/TargetParser/Host.h" |
17 | |
18 | #define DEBUG_TYPE "orc" |
19 | |
20 | namespace llvm::orc { |
21 | |
22 | SelfExecutorProcessControl::SelfExecutorProcessControl( |
23 | std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D, |
24 | Triple TargetTriple, unsigned PageSize, |
25 | std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) |
26 | : ExecutorProcessControl(std::move(SSP), std::move(D)), |
27 | IPMA(TargetTriple.isArch64Bit()) { |
28 | |
29 | OwnedMemMgr = std::move(MemMgr); |
30 | if (!OwnedMemMgr) |
31 | OwnedMemMgr = std::make_unique<jitlink::InProcessMemoryManager>( |
32 | args: sys::Process::getPageSizeEstimate()); |
33 | |
34 | this->TargetTriple = std::move(TargetTriple); |
35 | this->PageSize = PageSize; |
36 | this->MemMgr = OwnedMemMgr.get(); |
37 | this->MemAccess = &IPMA; |
38 | this->DylibMgr = this; |
39 | this->JDI = {.JITDispatchFunction: ExecutorAddr::fromPtr(Ptr: jitDispatchViaWrapperFunctionManager), |
40 | .JITDispatchContext: ExecutorAddr::fromPtr(Ptr: this)}; |
41 | |
42 | if (this->TargetTriple.isOSBinFormatMachO()) |
43 | GlobalManglingPrefix = '_'; |
44 | |
45 | addDefaultBootstrapValuesForHostProcess(BootstrapMap, BootstrapSymbols); |
46 | |
47 | #ifdef __APPLE__ |
48 | // FIXME: Don't add an UnwindInfoManager by default -- it's redundant when |
49 | // the ORC runtime is loaded. We'll need a way to document this and |
50 | // allow clients to choose. |
51 | if (UnwindInfoManager::TryEnable()) |
52 | UnwindInfoManager::addBootstrapSymbols(this->BootstrapSymbols); |
53 | #endif // __APPLE__ |
54 | } |
55 | |
56 | Expected<std::unique_ptr<SelfExecutorProcessControl>> |
57 | SelfExecutorProcessControl::Create( |
58 | std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D, |
59 | std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) { |
60 | |
61 | if (!SSP) |
62 | SSP = std::make_shared<SymbolStringPool>(); |
63 | |
64 | if (!D) |
65 | D = std::make_unique<InPlaceTaskDispatcher>(); |
66 | |
67 | auto PageSize = sys::Process::getPageSize(); |
68 | if (!PageSize) |
69 | return PageSize.takeError(); |
70 | |
71 | Triple TT(sys::getProcessTriple()); |
72 | |
73 | return std::make_unique<SelfExecutorProcessControl>( |
74 | args: std::move(SSP), args: std::move(D), args: std::move(TT), args&: *PageSize, |
75 | args: std::move(MemMgr)); |
76 | } |
77 | |
78 | Expected<tpctypes::DylibHandle> |
79 | SelfExecutorProcessControl::loadDylib(const char *DylibPath) { |
80 | std::string ErrMsg; |
81 | auto Dylib = sys::DynamicLibrary::getPermanentLibrary(filename: DylibPath, errMsg: &ErrMsg); |
82 | if (!Dylib.isValid()) |
83 | return make_error<StringError>(Args: std::move(ErrMsg), Args: inconvertibleErrorCode()); |
84 | return ExecutorAddr::fromPtr(Ptr: Dylib.getOSSpecificHandle()); |
85 | } |
86 | |
87 | void SelfExecutorProcessControl::lookupSymbolsAsync( |
88 | ArrayRef<LookupRequest> Request, |
89 | DylibManager::SymbolLookupCompleteFn Complete) { |
90 | std::vector<tpctypes::LookupResult> R; |
91 | |
92 | for (auto &Elem : Request) { |
93 | sys::DynamicLibrary Dylib(Elem.Handle.toPtr<void *>()); |
94 | R.push_back(x: std::vector<ExecutorSymbolDef>()); |
95 | for (auto &KV : Elem.Symbols) { |
96 | auto &Sym = KV.first; |
97 | std::string Tmp((*Sym).data() + !!GlobalManglingPrefix, |
98 | (*Sym).size() - !!GlobalManglingPrefix); |
99 | void *Addr = Dylib.getAddressOfSymbol(symbolName: Tmp.c_str()); |
100 | if (!Addr && KV.second == SymbolLookupFlags::RequiredSymbol) { |
101 | // FIXME: Collect all failing symbols before erroring out. |
102 | SymbolNameVector MissingSymbols; |
103 | MissingSymbols.push_back(x: Sym); |
104 | return Complete( |
105 | make_error<SymbolsNotFound>(Args&: SSP, Args: std::move(MissingSymbols))); |
106 | } |
107 | // FIXME: determine accurate JITSymbolFlags. |
108 | R.back().push_back( |
109 | x: {ExecutorAddr::fromPtr(Ptr: Addr), JITSymbolFlags::Exported}); |
110 | } |
111 | } |
112 | |
113 | Complete(std::move(R)); |
114 | } |
115 | |
116 | Expected<int32_t> |
117 | SelfExecutorProcessControl::runAsMain(ExecutorAddr MainFnAddr, |
118 | ArrayRef<std::string> Args) { |
119 | using MainTy = int (*)(int, char *[]); |
120 | return orc::runAsMain(Main: MainFnAddr.toPtr<MainTy>(), Args); |
121 | } |
122 | |
123 | Expected<int32_t> |
124 | SelfExecutorProcessControl::runAsVoidFunction(ExecutorAddr VoidFnAddr) { |
125 | using VoidTy = int (*)(); |
126 | return orc::runAsVoidFunction(Func: VoidFnAddr.toPtr<VoidTy>()); |
127 | } |
128 | |
129 | Expected<int32_t> |
130 | SelfExecutorProcessControl::runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) { |
131 | using IntTy = int (*)(int); |
132 | return orc::runAsIntFunction(Func: IntFnAddr.toPtr<IntTy>(), Arg); |
133 | } |
134 | |
135 | void SelfExecutorProcessControl::callWrapperAsync(ExecutorAddr WrapperFnAddr, |
136 | IncomingWFRHandler SendResult, |
137 | ArrayRef<char> ArgBuffer) { |
138 | using WrapperFnTy = |
139 | shared::CWrapperFunctionResult (*)(const char *Data, size_t Size); |
140 | auto *WrapperFn = WrapperFnAddr.toPtr<WrapperFnTy>(); |
141 | SendResult(WrapperFn(ArgBuffer.data(), ArgBuffer.size())); |
142 | } |
143 | |
144 | Error SelfExecutorProcessControl::disconnect() { |
145 | D->shutdown(); |
146 | return Error::success(); |
147 | } |
148 | |
149 | shared::CWrapperFunctionResult |
150 | SelfExecutorProcessControl::jitDispatchViaWrapperFunctionManager( |
151 | void *Ctx, const void *FnTag, const char *Data, size_t Size) { |
152 | |
153 | LLVM_DEBUG({ |
154 | dbgs() << "jit-dispatch call with tag " << FnTag << " and " << Size |
155 | << " byte payload.\n" ; |
156 | }); |
157 | |
158 | std::promise<shared::WrapperFunctionResult> ResultP; |
159 | auto ResultF = ResultP.get_future(); |
160 | static_cast<SelfExecutorProcessControl *>(Ctx) |
161 | ->getExecutionSession() |
162 | .runJITDispatchHandler( |
163 | SendResult: [ResultP = std::move(ResultP)]( |
164 | shared::WrapperFunctionResult Result) mutable { |
165 | ResultP.set_value(std::move(Result)); |
166 | }, |
167 | HandlerFnTagAddr: ExecutorAddr::fromPtr(Ptr: FnTag), ArgBuffer: {Data, Size}); |
168 | |
169 | return ResultF.get().release(); |
170 | } |
171 | |
172 | } // namespace llvm::orc |
173 | |