File: | build/source/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp |
Warning: | line 567, column 10 Moved-from object 'ErrResult' is moved |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===------ ELFNixPlatform.cpp - Utilities for executing MachO in Orc -----===// | ||||||||||
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/ELFNixPlatform.h" | ||||||||||
10 | |||||||||||
11 | #include "llvm/BinaryFormat/ELF.h" | ||||||||||
12 | #include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h" | ||||||||||
13 | #include "llvm/ExecutionEngine/JITLink/aarch64.h" | ||||||||||
14 | #include "llvm/ExecutionEngine/JITLink/x86_64.h" | ||||||||||
15 | #include "llvm/ExecutionEngine/Orc/DebugUtils.h" | ||||||||||
16 | #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" | ||||||||||
17 | #include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h" | ||||||||||
18 | #include "llvm/Support/BinaryByteStream.h" | ||||||||||
19 | #include "llvm/Support/Debug.h" | ||||||||||
20 | #include <optional> | ||||||||||
21 | |||||||||||
22 | #define DEBUG_TYPE"orc" "orc" | ||||||||||
23 | |||||||||||
24 | using namespace llvm; | ||||||||||
25 | using namespace llvm::orc; | ||||||||||
26 | using namespace llvm::orc::shared; | ||||||||||
27 | |||||||||||
28 | namespace { | ||||||||||
29 | |||||||||||
30 | class DSOHandleMaterializationUnit : public MaterializationUnit { | ||||||||||
31 | public: | ||||||||||
32 | DSOHandleMaterializationUnit(ELFNixPlatform &ENP, | ||||||||||
33 | const SymbolStringPtr &DSOHandleSymbol) | ||||||||||
34 | : MaterializationUnit( | ||||||||||
35 | createDSOHandleSectionInterface(ENP, DSOHandleSymbol)), | ||||||||||
36 | ENP(ENP) {} | ||||||||||
37 | |||||||||||
38 | StringRef getName() const override { return "DSOHandleMU"; } | ||||||||||
39 | |||||||||||
40 | void materialize(std::unique_ptr<MaterializationResponsibility> R) override { | ||||||||||
41 | unsigned PointerSize; | ||||||||||
42 | support::endianness Endianness; | ||||||||||
43 | jitlink::Edge::Kind EdgeKind; | ||||||||||
44 | const auto &TT = ENP.getExecutionSession().getTargetTriple(); | ||||||||||
45 | |||||||||||
46 | switch (TT.getArch()) { | ||||||||||
47 | case Triple::x86_64: | ||||||||||
48 | PointerSize = 8; | ||||||||||
49 | Endianness = support::endianness::little; | ||||||||||
50 | EdgeKind = jitlink::x86_64::Pointer64; | ||||||||||
51 | break; | ||||||||||
52 | case Triple::aarch64: | ||||||||||
53 | PointerSize = 8; | ||||||||||
54 | Endianness = support::endianness::little; | ||||||||||
55 | EdgeKind = jitlink::aarch64::Pointer64; | ||||||||||
56 | break; | ||||||||||
57 | default: | ||||||||||
58 | llvm_unreachable("Unrecognized architecture")::llvm::llvm_unreachable_internal("Unrecognized architecture" , "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp", 58); | ||||||||||
59 | } | ||||||||||
60 | |||||||||||
61 | // void *__dso_handle = &__dso_handle; | ||||||||||
62 | auto G = std::make_unique<jitlink::LinkGraph>( | ||||||||||
63 | "<DSOHandleMU>", TT, PointerSize, Endianness, | ||||||||||
64 | jitlink::getGenericEdgeKindName); | ||||||||||
65 | auto &DSOHandleSection = | ||||||||||
66 | G->createSection(".data.__dso_handle", MemProt::Read); | ||||||||||
67 | auto &DSOHandleBlock = G->createContentBlock( | ||||||||||
68 | DSOHandleSection, getDSOHandleContent(PointerSize), orc::ExecutorAddr(), | ||||||||||
69 | 8, 0); | ||||||||||
70 | auto &DSOHandleSymbol = G->addDefinedSymbol( | ||||||||||
71 | DSOHandleBlock, 0, *R->getInitializerSymbol(), DSOHandleBlock.getSize(), | ||||||||||
72 | jitlink::Linkage::Strong, jitlink::Scope::Default, false, true); | ||||||||||
73 | DSOHandleBlock.addEdge(EdgeKind, 0, DSOHandleSymbol, 0); | ||||||||||
74 | |||||||||||
75 | ENP.getObjectLinkingLayer().emit(std::move(R), std::move(G)); | ||||||||||
76 | } | ||||||||||
77 | |||||||||||
78 | void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {} | ||||||||||
79 | |||||||||||
80 | private: | ||||||||||
81 | static MaterializationUnit::Interface | ||||||||||
82 | createDSOHandleSectionInterface(ELFNixPlatform &ENP, | ||||||||||
83 | const SymbolStringPtr &DSOHandleSymbol) { | ||||||||||
84 | SymbolFlagsMap SymbolFlags; | ||||||||||
85 | SymbolFlags[DSOHandleSymbol] = JITSymbolFlags::Exported; | ||||||||||
86 | return MaterializationUnit::Interface(std::move(SymbolFlags), | ||||||||||
87 | DSOHandleSymbol); | ||||||||||
88 | } | ||||||||||
89 | |||||||||||
90 | ArrayRef<char> getDSOHandleContent(size_t PointerSize) { | ||||||||||
91 | static const char Content[8] = {0}; | ||||||||||
92 | assert(PointerSize <= sizeof Content)(static_cast <bool> (PointerSize <= sizeof Content) ? void (0) : __assert_fail ("PointerSize <= sizeof Content" , "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp", 92, __extension__ __PRETTY_FUNCTION__)); | ||||||||||
93 | return {Content, PointerSize}; | ||||||||||
94 | } | ||||||||||
95 | |||||||||||
96 | ELFNixPlatform &ENP; | ||||||||||
97 | }; | ||||||||||
98 | |||||||||||
99 | } // end anonymous namespace | ||||||||||
100 | |||||||||||
101 | namespace llvm { | ||||||||||
102 | namespace orc { | ||||||||||
103 | |||||||||||
104 | Expected<std::unique_ptr<ELFNixPlatform>> ELFNixPlatform::Create( | ||||||||||
105 | ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, | ||||||||||
106 | JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime, | ||||||||||
107 | std::optional<SymbolAliasMap> RuntimeAliases) { | ||||||||||
108 | |||||||||||
109 | // If the target is not supported then bail out immediately. | ||||||||||
110 | if (!supportedTarget(ES.getTargetTriple())) | ||||||||||
111 | return make_error<StringError>("Unsupported ELFNixPlatform triple: " + | ||||||||||
112 | ES.getTargetTriple().str(), | ||||||||||
113 | inconvertibleErrorCode()); | ||||||||||
114 | |||||||||||
115 | auto &EPC = ES.getExecutorProcessControl(); | ||||||||||
116 | |||||||||||
117 | // Create default aliases if the caller didn't supply any. | ||||||||||
118 | if (!RuntimeAliases) { | ||||||||||
119 | auto StandardRuntimeAliases = standardPlatformAliases(ES, PlatformJD); | ||||||||||
120 | if (!StandardRuntimeAliases) | ||||||||||
121 | return StandardRuntimeAliases.takeError(); | ||||||||||
122 | RuntimeAliases = std::move(*StandardRuntimeAliases); | ||||||||||
123 | } | ||||||||||
124 | |||||||||||
125 | // Define the aliases. | ||||||||||
126 | if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases)))) | ||||||||||
127 | return std::move(Err); | ||||||||||
128 | |||||||||||
129 | // Add JIT-dispatch function support symbols. | ||||||||||
130 | if (auto Err = PlatformJD.define( | ||||||||||
131 | absoluteSymbols({{ES.intern("__orc_rt_jit_dispatch"), | ||||||||||
132 | {EPC.getJITDispatchInfo().JITDispatchFunction, | ||||||||||
133 | JITSymbolFlags::Exported}}, | ||||||||||
134 | {ES.intern("__orc_rt_jit_dispatch_ctx"), | ||||||||||
135 | {EPC.getJITDispatchInfo().JITDispatchContext, | ||||||||||
136 | JITSymbolFlags::Exported}}}))) | ||||||||||
137 | return std::move(Err); | ||||||||||
138 | |||||||||||
139 | // Create the instance. | ||||||||||
140 | Error Err = Error::success(); | ||||||||||
141 | auto P = std::unique_ptr<ELFNixPlatform>(new ELFNixPlatform( | ||||||||||
142 | ES, ObjLinkingLayer, PlatformJD, std::move(OrcRuntime), Err)); | ||||||||||
143 | if (Err) | ||||||||||
144 | return std::move(Err); | ||||||||||
145 | return std::move(P); | ||||||||||
146 | } | ||||||||||
147 | |||||||||||
148 | Expected<std::unique_ptr<ELFNixPlatform>> | ||||||||||
149 | ELFNixPlatform::Create(ExecutionSession &ES, | ||||||||||
150 | ObjectLinkingLayer &ObjLinkingLayer, | ||||||||||
151 | JITDylib &PlatformJD, const char *OrcRuntimePath, | ||||||||||
152 | std::optional<SymbolAliasMap> RuntimeAliases) { | ||||||||||
153 | |||||||||||
154 | // Create a generator for the ORC runtime archive. | ||||||||||
155 | auto OrcRuntimeArchiveGenerator = | ||||||||||
156 | StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath); | ||||||||||
157 | if (!OrcRuntimeArchiveGenerator) | ||||||||||
158 | return OrcRuntimeArchiveGenerator.takeError(); | ||||||||||
159 | |||||||||||
160 | return Create(ES, ObjLinkingLayer, PlatformJD, | ||||||||||
161 | std::move(*OrcRuntimeArchiveGenerator), | ||||||||||
162 | std::move(RuntimeAliases)); | ||||||||||
163 | } | ||||||||||
164 | |||||||||||
165 | Error ELFNixPlatform::setupJITDylib(JITDylib &JD) { | ||||||||||
166 | return JD.define( | ||||||||||
167 | std::make_unique<DSOHandleMaterializationUnit>(*this, DSOHandleSymbol)); | ||||||||||
168 | } | ||||||||||
169 | |||||||||||
170 | Error ELFNixPlatform::teardownJITDylib(JITDylib &JD) { | ||||||||||
171 | return Error::success(); | ||||||||||
172 | } | ||||||||||
173 | |||||||||||
174 | Error ELFNixPlatform::notifyAdding(ResourceTracker &RT, | ||||||||||
175 | const MaterializationUnit &MU) { | ||||||||||
176 | auto &JD = RT.getJITDylib(); | ||||||||||
177 | const auto &InitSym = MU.getInitializerSymbol(); | ||||||||||
178 | if (!InitSym) | ||||||||||
179 | return Error::success(); | ||||||||||
180 | |||||||||||
181 | RegisteredInitSymbols[&JD].add(InitSym, | ||||||||||
182 | SymbolLookupFlags::WeaklyReferencedSymbol); | ||||||||||
183 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Registered init symbol " << *InitSym << " for MU " << MU.getName() << "\n"; }; } } while (false) | ||||||||||
184 | dbgs() << "ELFNixPlatform: Registered init symbol " << *InitSymdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Registered init symbol " << *InitSym << " for MU " << MU.getName() << "\n"; }; } } while (false) | ||||||||||
185 | << " for MU " << MU.getName() << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Registered init symbol " << *InitSym << " for MU " << MU.getName() << "\n"; }; } } while (false) | ||||||||||
186 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Registered init symbol " << *InitSym << " for MU " << MU.getName() << "\n"; }; } } while (false); | ||||||||||
187 | return Error::success(); | ||||||||||
188 | } | ||||||||||
189 | |||||||||||
190 | Error ELFNixPlatform::notifyRemoving(ResourceTracker &RT) { | ||||||||||
191 | llvm_unreachable("Not supported yet")::llvm::llvm_unreachable_internal("Not supported yet", "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp" , 191); | ||||||||||
192 | } | ||||||||||
193 | |||||||||||
194 | static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases, | ||||||||||
195 | ArrayRef<std::pair<const char *, const char *>> AL) { | ||||||||||
196 | for (auto &KV : AL) { | ||||||||||
197 | auto AliasName = ES.intern(KV.first); | ||||||||||
198 | assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map")(static_cast <bool> (!Aliases.count(AliasName) && "Duplicate symbol name in alias map") ? void (0) : __assert_fail ("!Aliases.count(AliasName) && \"Duplicate symbol name in alias map\"" , "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp", 198, __extension__ __PRETTY_FUNCTION__)); | ||||||||||
199 | Aliases[std::move(AliasName)] = {ES.intern(KV.second), | ||||||||||
200 | JITSymbolFlags::Exported}; | ||||||||||
201 | } | ||||||||||
202 | } | ||||||||||
203 | |||||||||||
204 | Expected<SymbolAliasMap> | ||||||||||
205 | ELFNixPlatform::standardPlatformAliases(ExecutionSession &ES, | ||||||||||
206 | JITDylib &PlatformJD) { | ||||||||||
207 | SymbolAliasMap Aliases; | ||||||||||
208 | addAliases(ES, Aliases, requiredCXXAliases()); | ||||||||||
209 | addAliases(ES, Aliases, standardRuntimeUtilityAliases()); | ||||||||||
210 | return Aliases; | ||||||||||
211 | } | ||||||||||
212 | |||||||||||
213 | ArrayRef<std::pair<const char *, const char *>> | ||||||||||
214 | ELFNixPlatform::requiredCXXAliases() { | ||||||||||
215 | static const std::pair<const char *, const char *> RequiredCXXAliases[] = { | ||||||||||
216 | {"__cxa_atexit", "__orc_rt_elfnix_cxa_atexit"}, | ||||||||||
217 | {"atexit", "__orc_rt_elfnix_atexit"}}; | ||||||||||
218 | |||||||||||
219 | return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases); | ||||||||||
220 | } | ||||||||||
221 | |||||||||||
222 | ArrayRef<std::pair<const char *, const char *>> | ||||||||||
223 | ELFNixPlatform::standardRuntimeUtilityAliases() { | ||||||||||
224 | static const std::pair<const char *, const char *> | ||||||||||
225 | StandardRuntimeUtilityAliases[] = { | ||||||||||
226 | {"__orc_rt_run_program", "__orc_rt_elfnix_run_program"}, | ||||||||||
227 | {"__orc_rt_jit_dlerror", "__orc_rt_elfnix_jit_dlerror"}, | ||||||||||
228 | {"__orc_rt_jit_dlopen", "__orc_rt_elfnix_jit_dlopen"}, | ||||||||||
229 | {"__orc_rt_jit_dlclose", "__orc_rt_elfnix_jit_dlclose"}, | ||||||||||
230 | {"__orc_rt_jit_dlsym", "__orc_rt_elfnix_jit_dlsym"}, | ||||||||||
231 | {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}}; | ||||||||||
232 | |||||||||||
233 | return ArrayRef<std::pair<const char *, const char *>>( | ||||||||||
234 | StandardRuntimeUtilityAliases); | ||||||||||
235 | } | ||||||||||
236 | |||||||||||
237 | bool ELFNixPlatform::supportedTarget(const Triple &TT) { | ||||||||||
238 | switch (TT.getArch()) { | ||||||||||
239 | case Triple::x86_64: | ||||||||||
240 | case Triple::aarch64: | ||||||||||
241 | return true; | ||||||||||
242 | default: | ||||||||||
243 | return false; | ||||||||||
244 | } | ||||||||||
245 | } | ||||||||||
246 | |||||||||||
247 | ELFNixPlatform::ELFNixPlatform( | ||||||||||
248 | ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, | ||||||||||
249 | JITDylib &PlatformJD, | ||||||||||
250 | std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err) | ||||||||||
251 | : ES(ES), ObjLinkingLayer(ObjLinkingLayer), | ||||||||||
252 | DSOHandleSymbol(ES.intern("__dso_handle")) { | ||||||||||
253 | ErrorAsOutParameter _(&Err); | ||||||||||
254 | |||||||||||
255 | ObjLinkingLayer.addPlugin(std::make_unique<ELFNixPlatformPlugin>(*this)); | ||||||||||
256 | |||||||||||
257 | PlatformJD.addGenerator(std::move(OrcRuntimeGenerator)); | ||||||||||
258 | |||||||||||
259 | // PlatformJD hasn't been 'set-up' by the platform yet (since we're creating | ||||||||||
260 | // the platform now), so set it up. | ||||||||||
261 | if (auto E2 = setupJITDylib(PlatformJD)) { | ||||||||||
262 | Err = std::move(E2); | ||||||||||
263 | return; | ||||||||||
264 | } | ||||||||||
265 | |||||||||||
266 | RegisteredInitSymbols[&PlatformJD].add( | ||||||||||
267 | DSOHandleSymbol, SymbolLookupFlags::WeaklyReferencedSymbol); | ||||||||||
268 | |||||||||||
269 | // Associate wrapper function tags with JIT-side function implementations. | ||||||||||
270 | if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) { | ||||||||||
271 | Err = std::move(E2); | ||||||||||
272 | return; | ||||||||||
273 | } | ||||||||||
274 | |||||||||||
275 | // Lookup addresses of runtime functions callable by the platform, | ||||||||||
276 | // call the platform bootstrap function to initialize the platform-state | ||||||||||
277 | // object in the executor. | ||||||||||
278 | if (auto E2 = bootstrapELFNixRuntime(PlatformJD)) { | ||||||||||
279 | Err = std::move(E2); | ||||||||||
280 | return; | ||||||||||
281 | } | ||||||||||
282 | } | ||||||||||
283 | |||||||||||
284 | Error ELFNixPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) { | ||||||||||
285 | ExecutionSession::JITDispatchHandlerAssociationMap WFs; | ||||||||||
286 | |||||||||||
287 | using GetInitializersSPSSig = | ||||||||||
288 | SPSExpected<SPSELFNixJITDylibInitializerSequence>(SPSString); | ||||||||||
289 | WFs[ES.intern("__orc_rt_elfnix_get_initializers_tag")] = | ||||||||||
290 | ES.wrapAsyncWithSPS<GetInitializersSPSSig>( | ||||||||||
291 | this, &ELFNixPlatform::rt_getInitializers); | ||||||||||
292 | |||||||||||
293 | using GetDeinitializersSPSSig = | ||||||||||
294 | SPSExpected<SPSELFJITDylibDeinitializerSequence>(SPSExecutorAddr); | ||||||||||
295 | WFs[ES.intern("__orc_rt_elfnix_get_deinitializers_tag")] = | ||||||||||
296 | ES.wrapAsyncWithSPS<GetDeinitializersSPSSig>( | ||||||||||
297 | this, &ELFNixPlatform::rt_getDeinitializers); | ||||||||||
298 | |||||||||||
299 | using LookupSymbolSPSSig = | ||||||||||
300 | SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString); | ||||||||||
301 | WFs[ES.intern("__orc_rt_elfnix_symbol_lookup_tag")] = | ||||||||||
302 | ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this, | ||||||||||
303 | &ELFNixPlatform::rt_lookupSymbol); | ||||||||||
304 | |||||||||||
305 | return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs)); | ||||||||||
306 | } | ||||||||||
307 | |||||||||||
308 | void ELFNixPlatform::getInitializersBuildSequencePhase( | ||||||||||
309 | SendInitializerSequenceFn SendResult, JITDylib &JD, | ||||||||||
310 | std::vector<JITDylibSP> DFSLinkOrder) { | ||||||||||
311 | ELFNixJITDylibInitializerSequence FullInitSeq; | ||||||||||
312 | { | ||||||||||
313 | std::lock_guard<std::mutex> Lock(PlatformMutex); | ||||||||||
314 | for (auto &InitJD : reverse(DFSLinkOrder)) { | ||||||||||
315 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Appending inits for \"" << InitJD->getName() << "\" to sequence\n"; } ; } } while (false) | ||||||||||
316 | dbgs() << "ELFNixPlatform: Appending inits for \"" << InitJD->getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Appending inits for \"" << InitJD->getName() << "\" to sequence\n"; } ; } } while (false) | ||||||||||
317 | << "\" to sequence\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Appending inits for \"" << InitJD->getName() << "\" to sequence\n"; } ; } } while (false) | ||||||||||
318 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Appending inits for \"" << InitJD->getName() << "\" to sequence\n"; } ; } } while (false); | ||||||||||
319 | auto ISItr = InitSeqs.find(InitJD.get()); | ||||||||||
320 | if (ISItr != InitSeqs.end()) { | ||||||||||
321 | FullInitSeq.emplace_back(std::move(ISItr->second)); | ||||||||||
322 | InitSeqs.erase(ISItr); | ||||||||||
323 | } | ||||||||||
324 | } | ||||||||||
325 | } | ||||||||||
326 | |||||||||||
327 | SendResult(std::move(FullInitSeq)); | ||||||||||
328 | } | ||||||||||
329 | |||||||||||
330 | void ELFNixPlatform::getInitializersLookupPhase( | ||||||||||
331 | SendInitializerSequenceFn SendResult, JITDylib &JD) { | ||||||||||
332 | |||||||||||
333 | auto DFSLinkOrder = JD.getDFSLinkOrder(); | ||||||||||
334 | if (!DFSLinkOrder) { | ||||||||||
335 | SendResult(DFSLinkOrder.takeError()); | ||||||||||
336 | return; | ||||||||||
337 | } | ||||||||||
338 | |||||||||||
339 | DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols; | ||||||||||
340 | ES.runSessionLocked([&]() { | ||||||||||
341 | for (auto &InitJD : *DFSLinkOrder) { | ||||||||||
342 | auto RISItr = RegisteredInitSymbols.find(InitJD.get()); | ||||||||||
343 | if (RISItr != RegisteredInitSymbols.end()) { | ||||||||||
344 | NewInitSymbols[InitJD.get()] = std::move(RISItr->second); | ||||||||||
345 | RegisteredInitSymbols.erase(RISItr); | ||||||||||
346 | } | ||||||||||
347 | } | ||||||||||
348 | }); | ||||||||||
349 | |||||||||||
350 | // If there are no further init symbols to look up then move on to the next | ||||||||||
351 | // phase. | ||||||||||
352 | if (NewInitSymbols.empty()) { | ||||||||||
353 | getInitializersBuildSequencePhase(std::move(SendResult), JD, | ||||||||||
354 | std::move(*DFSLinkOrder)); | ||||||||||
355 | return; | ||||||||||
356 | } | ||||||||||
357 | |||||||||||
358 | // Otherwise issue a lookup and re-run this phase when it completes. | ||||||||||
359 | lookupInitSymbolsAsync( | ||||||||||
360 | [this, SendResult = std::move(SendResult), &JD](Error Err) mutable { | ||||||||||
361 | if (Err) | ||||||||||
362 | SendResult(std::move(Err)); | ||||||||||
363 | else | ||||||||||
364 | getInitializersLookupPhase(std::move(SendResult), JD); | ||||||||||
365 | }, | ||||||||||
366 | ES, std::move(NewInitSymbols)); | ||||||||||
367 | } | ||||||||||
368 | |||||||||||
369 | void ELFNixPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult, | ||||||||||
370 | StringRef JDName) { | ||||||||||
371 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform::rt_getInitializers(\"" << JDName << "\")\n"; }; } } while (false) | ||||||||||
372 | dbgs() << "ELFNixPlatform::rt_getInitializers(\"" << JDName << "\")\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform::rt_getInitializers(\"" << JDName << "\")\n"; }; } } while (false) | ||||||||||
373 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform::rt_getInitializers(\"" << JDName << "\")\n"; }; } } while (false); | ||||||||||
374 | |||||||||||
375 | JITDylib *JD = ES.getJITDylibByName(JDName); | ||||||||||
376 | if (!JD) { | ||||||||||
377 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << " No such JITDylib \"" << JDName << "\". Sending error.\n"; }; } } while (false) | ||||||||||
378 | dbgs() << " No such JITDylib \"" << JDName << "\". Sending error.\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << " No such JITDylib \"" << JDName << "\". Sending error.\n"; }; } } while (false) | ||||||||||
379 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << " No such JITDylib \"" << JDName << "\". Sending error.\n"; }; } } while (false); | ||||||||||
380 | SendResult(make_error<StringError>("No JITDylib named " + JDName, | ||||||||||
381 | inconvertibleErrorCode())); | ||||||||||
382 | return; | ||||||||||
383 | } | ||||||||||
384 | |||||||||||
385 | getInitializersLookupPhase(std::move(SendResult), *JD); | ||||||||||
386 | } | ||||||||||
387 | |||||||||||
388 | void ELFNixPlatform::rt_getDeinitializers( | ||||||||||
389 | SendDeinitializerSequenceFn SendResult, ExecutorAddr Handle) { | ||||||||||
390 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform::rt_getDeinitializers(\"" << Handle << "\")\n"; }; } } while (false) | ||||||||||
391 | dbgs() << "ELFNixPlatform::rt_getDeinitializers(\"" << Handle << "\")\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform::rt_getDeinitializers(\"" << Handle << "\")\n"; }; } } while (false) | ||||||||||
392 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform::rt_getDeinitializers(\"" << Handle << "\")\n"; }; } } while (false); | ||||||||||
393 | |||||||||||
394 | JITDylib *JD = nullptr; | ||||||||||
395 | |||||||||||
396 | { | ||||||||||
397 | std::lock_guard<std::mutex> Lock(PlatformMutex); | ||||||||||
398 | auto I = HandleAddrToJITDylib.find(Handle); | ||||||||||
399 | if (I != HandleAddrToJITDylib.end()) | ||||||||||
400 | JD = I->second; | ||||||||||
401 | } | ||||||||||
402 | |||||||||||
403 | if (!JD) { | ||||||||||
404 | LLVM_DEBUG(dbgs() << " No JITDylib for handle " << Handle << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { dbgs() << " No JITDylib for handle " << Handle << "\n"; } } while (false); | ||||||||||
405 | SendResult(make_error<StringError>("No JITDylib associated with handle " + | ||||||||||
406 | formatv("{0:x}", Handle), | ||||||||||
407 | inconvertibleErrorCode())); | ||||||||||
408 | return; | ||||||||||
409 | } | ||||||||||
410 | |||||||||||
411 | SendResult(ELFNixJITDylibDeinitializerSequence()); | ||||||||||
412 | } | ||||||||||
413 | |||||||||||
414 | void ELFNixPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult, | ||||||||||
415 | ExecutorAddr Handle, | ||||||||||
416 | StringRef SymbolName) { | ||||||||||
417 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform::rt_lookupSymbol(\"" << Handle << "\")\n"; }; } } while (false) | ||||||||||
418 | dbgs() << "ELFNixPlatform::rt_lookupSymbol(\"" << Handle << "\")\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform::rt_lookupSymbol(\"" << Handle << "\")\n"; }; } } while (false) | ||||||||||
419 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform::rt_lookupSymbol(\"" << Handle << "\")\n"; }; } } while (false); | ||||||||||
420 | |||||||||||
421 | JITDylib *JD = nullptr; | ||||||||||
422 | |||||||||||
423 | { | ||||||||||
424 | std::lock_guard<std::mutex> Lock(PlatformMutex); | ||||||||||
425 | auto I = HandleAddrToJITDylib.find(Handle); | ||||||||||
426 | if (I != HandleAddrToJITDylib.end()) | ||||||||||
427 | JD = I->second; | ||||||||||
428 | } | ||||||||||
429 | |||||||||||
430 | if (!JD) { | ||||||||||
431 | LLVM_DEBUG(dbgs() << " No JITDylib for handle " << Handle << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { dbgs() << " No JITDylib for handle " << Handle << "\n"; } } while (false); | ||||||||||
432 | SendResult(make_error<StringError>("No JITDylib associated with handle " + | ||||||||||
433 | formatv("{0:x}", Handle), | ||||||||||
434 | inconvertibleErrorCode())); | ||||||||||
435 | return; | ||||||||||
436 | } | ||||||||||
437 | |||||||||||
438 | // Use functor class to work around XL build compiler issue on AIX. | ||||||||||
439 | class RtLookupNotifyComplete { | ||||||||||
440 | public: | ||||||||||
441 | RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult) | ||||||||||
442 | : SendResult(std::move(SendResult)) {} | ||||||||||
443 | void operator()(Expected<SymbolMap> Result) { | ||||||||||
444 | if (Result) { | ||||||||||
445 | assert(Result->size() == 1 && "Unexpected result map count")(static_cast <bool> (Result->size() == 1 && "Unexpected result map count" ) ? void (0) : __assert_fail ("Result->size() == 1 && \"Unexpected result map count\"" , "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp", 445, __extension__ __PRETTY_FUNCTION__)); | ||||||||||
446 | SendResult(Result->begin()->second.getAddress()); | ||||||||||
447 | } else { | ||||||||||
448 | SendResult(Result.takeError()); | ||||||||||
449 | } | ||||||||||
450 | } | ||||||||||
451 | |||||||||||
452 | private: | ||||||||||
453 | SendSymbolAddressFn SendResult; | ||||||||||
454 | }; | ||||||||||
455 | |||||||||||
456 | ES.lookup( | ||||||||||
457 | LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}}, | ||||||||||
458 | SymbolLookupSet(ES.intern(SymbolName)), SymbolState::Ready, | ||||||||||
459 | RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister); | ||||||||||
460 | } | ||||||||||
461 | |||||||||||
462 | Error ELFNixPlatform::bootstrapELFNixRuntime(JITDylib &PlatformJD) { | ||||||||||
463 | |||||||||||
464 | std::pair<const char *, ExecutorAddr *> Symbols[] = { | ||||||||||
465 | {"__orc_rt_elfnix_platform_bootstrap", &orc_rt_elfnix_platform_bootstrap}, | ||||||||||
466 | {"__orc_rt_elfnix_platform_shutdown", &orc_rt_elfnix_platform_shutdown}, | ||||||||||
467 | {"__orc_rt_elfnix_register_object_sections", | ||||||||||
468 | &orc_rt_elfnix_register_object_sections}, | ||||||||||
469 | {"__orc_rt_elfnix_create_pthread_key", | ||||||||||
470 | &orc_rt_elfnix_create_pthread_key}}; | ||||||||||
471 | |||||||||||
472 | SymbolLookupSet RuntimeSymbols; | ||||||||||
473 | std::vector<std::pair<SymbolStringPtr, ExecutorAddr *>> AddrsToRecord; | ||||||||||
474 | for (const auto &KV : Symbols) { | ||||||||||
475 | auto Name = ES.intern(KV.first); | ||||||||||
476 | RuntimeSymbols.add(Name); | ||||||||||
477 | AddrsToRecord.push_back({std::move(Name), KV.second}); | ||||||||||
478 | } | ||||||||||
479 | |||||||||||
480 | auto RuntimeSymbolAddrs = ES.lookup( | ||||||||||
481 | {{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, RuntimeSymbols); | ||||||||||
482 | if (!RuntimeSymbolAddrs) | ||||||||||
483 | return RuntimeSymbolAddrs.takeError(); | ||||||||||
484 | |||||||||||
485 | for (const auto &KV : AddrsToRecord) { | ||||||||||
486 | auto &Name = KV.first; | ||||||||||
487 | assert(RuntimeSymbolAddrs->count(Name) && "Missing runtime symbol?")(static_cast <bool> (RuntimeSymbolAddrs->count(Name) && "Missing runtime symbol?") ? void (0) : __assert_fail ("RuntimeSymbolAddrs->count(Name) && \"Missing runtime symbol?\"" , "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp", 487, __extension__ __PRETTY_FUNCTION__)); | ||||||||||
488 | *KV.second = (*RuntimeSymbolAddrs)[Name].getAddress(); | ||||||||||
489 | } | ||||||||||
490 | |||||||||||
491 | auto PJDDSOHandle = ES.lookup( | ||||||||||
492 | {{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, DSOHandleSymbol); | ||||||||||
493 | if (!PJDDSOHandle) | ||||||||||
494 | return PJDDSOHandle.takeError(); | ||||||||||
495 | |||||||||||
496 | if (auto Err = ES.callSPSWrapper<void(uint64_t)>( | ||||||||||
497 | orc_rt_elfnix_platform_bootstrap, | ||||||||||
498 | PJDDSOHandle->getAddress().getValue())) | ||||||||||
499 | return Err; | ||||||||||
500 | |||||||||||
501 | // FIXME: Ordering is fuzzy here. We're probably best off saying | ||||||||||
502 | // "behavior is undefined if code that uses the runtime is added before | ||||||||||
503 | // the platform constructor returns", then move all this to the constructor. | ||||||||||
504 | RuntimeBootstrapped = true; | ||||||||||
505 | std::vector<ELFPerObjectSectionsToRegister> DeferredPOSRs; | ||||||||||
506 | { | ||||||||||
507 | std::lock_guard<std::mutex> Lock(PlatformMutex); | ||||||||||
508 | DeferredPOSRs = std::move(BootstrapPOSRs); | ||||||||||
509 | } | ||||||||||
510 | |||||||||||
511 | for (auto &D : DeferredPOSRs) | ||||||||||
512 | if (auto Err = registerPerObjectSections(D)) | ||||||||||
513 | return Err; | ||||||||||
514 | |||||||||||
515 | return Error::success(); | ||||||||||
516 | } | ||||||||||
517 | |||||||||||
518 | Error ELFNixPlatform::registerInitInfo( | ||||||||||
519 | JITDylib &JD, ArrayRef<jitlink::Section *> InitSections) { | ||||||||||
520 | |||||||||||
521 | std::unique_lock<std::mutex> Lock(PlatformMutex); | ||||||||||
522 | |||||||||||
523 | ELFNixJITDylibInitializers *InitSeq = nullptr; | ||||||||||
524 | { | ||||||||||
525 | auto I = InitSeqs.find(&JD); | ||||||||||
526 | if (I == InitSeqs.end()) { | ||||||||||
527 | // If there's no init sequence entry yet then we need to look up the | ||||||||||
528 | // header symbol to force creation of one. | ||||||||||
529 | Lock.unlock(); | ||||||||||
530 | |||||||||||
531 | auto SearchOrder = | ||||||||||
532 | JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; }); | ||||||||||
533 | if (auto Err = ES.lookup(SearchOrder, DSOHandleSymbol).takeError()) | ||||||||||
534 | return Err; | ||||||||||
535 | |||||||||||
536 | Lock.lock(); | ||||||||||
537 | I = InitSeqs.find(&JD); | ||||||||||
538 | assert(I != InitSeqs.end() &&(static_cast <bool> (I != InitSeqs.end() && "Entry missing after header symbol lookup?" ) ? void (0) : __assert_fail ("I != InitSeqs.end() && \"Entry missing after header symbol lookup?\"" , "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp", 539, __extension__ __PRETTY_FUNCTION__)) | ||||||||||
539 | "Entry missing after header symbol lookup?")(static_cast <bool> (I != InitSeqs.end() && "Entry missing after header symbol lookup?" ) ? void (0) : __assert_fail ("I != InitSeqs.end() && \"Entry missing after header symbol lookup?\"" , "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp", 539, __extension__ __PRETTY_FUNCTION__)); | ||||||||||
540 | } | ||||||||||
541 | InitSeq = &I->second; | ||||||||||
542 | } | ||||||||||
543 | |||||||||||
544 | for (auto *Sec : InitSections) { | ||||||||||
545 | // FIXME: Avoid copy here. | ||||||||||
546 | jitlink::SectionRange R(*Sec); | ||||||||||
547 | InitSeq->InitSections[Sec->getName()].push_back(R.getRange()); | ||||||||||
548 | } | ||||||||||
549 | |||||||||||
550 | return Error::success(); | ||||||||||
551 | } | ||||||||||
552 | |||||||||||
553 | Error ELFNixPlatform::registerPerObjectSections( | ||||||||||
554 | const ELFPerObjectSectionsToRegister &POSR) { | ||||||||||
555 | |||||||||||
556 | if (!orc_rt_elfnix_register_object_sections) | ||||||||||
557 | return make_error<StringError>("Attempting to register per-object " | ||||||||||
558 | "sections, but runtime support has not " | ||||||||||
559 | "been loaded yet", | ||||||||||
560 | inconvertibleErrorCode()); | ||||||||||
561 | |||||||||||
562 | Error ErrResult = Error::success(); | ||||||||||
563 | if (auto Err = ES.callSPSWrapper<shared::SPSError( | ||||||||||
564 | SPSELFPerObjectSectionsToRegister)>( | ||||||||||
565 | orc_rt_elfnix_register_object_sections, ErrResult, POSR)) | ||||||||||
566 | return Err; | ||||||||||
567 | return ErrResult; | ||||||||||
| |||||||||||
568 | } | ||||||||||
569 | |||||||||||
570 | Expected<uint64_t> ELFNixPlatform::createPThreadKey() { | ||||||||||
571 | if (!orc_rt_elfnix_create_pthread_key) | ||||||||||
572 | return make_error<StringError>( | ||||||||||
573 | "Attempting to create pthread key in target, but runtime support has " | ||||||||||
574 | "not been loaded yet", | ||||||||||
575 | inconvertibleErrorCode()); | ||||||||||
576 | |||||||||||
577 | Expected<uint64_t> Result(0); | ||||||||||
578 | if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>( | ||||||||||
579 | orc_rt_elfnix_create_pthread_key, Result)) | ||||||||||
580 | return std::move(Err); | ||||||||||
581 | return Result; | ||||||||||
582 | } | ||||||||||
583 | |||||||||||
584 | void ELFNixPlatform::ELFNixPlatformPlugin::modifyPassConfig( | ||||||||||
585 | MaterializationResponsibility &MR, jitlink::LinkGraph &LG, | ||||||||||
586 | jitlink::PassConfiguration &Config) { | ||||||||||
587 | |||||||||||
588 | // If the initializer symbol is the __dso_handle symbol then just add | ||||||||||
589 | // the DSO handle support passes. | ||||||||||
590 | if (MR.getInitializerSymbol() == MP.DSOHandleSymbol) { | ||||||||||
591 | addDSOHandleSupportPasses(MR, Config); | ||||||||||
592 | // The DSOHandle materialization unit doesn't require any other | ||||||||||
593 | // support, so we can bail out early. | ||||||||||
594 | return; | ||||||||||
595 | } | ||||||||||
596 | |||||||||||
597 | // If the object contains initializers then add passes to record them. | ||||||||||
598 | if (MR.getInitializerSymbol()) | ||||||||||
599 | addInitializerSupportPasses(MR, Config); | ||||||||||
600 | |||||||||||
601 | // Add passes for eh-frame and TLV support. | ||||||||||
602 | addEHAndTLVSupportPasses(MR, Config); | ||||||||||
603 | } | ||||||||||
604 | |||||||||||
605 | ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap | ||||||||||
606 | ELFNixPlatform::ELFNixPlatformPlugin::getSyntheticSymbolDependencies( | ||||||||||
607 | MaterializationResponsibility &MR) { | ||||||||||
608 | std::lock_guard<std::mutex> Lock(PluginMutex); | ||||||||||
609 | auto I = InitSymbolDeps.find(&MR); | ||||||||||
610 | if (I != InitSymbolDeps.end()) { | ||||||||||
611 | SyntheticSymbolDependenciesMap Result; | ||||||||||
612 | Result[MR.getInitializerSymbol()] = std::move(I->second); | ||||||||||
613 | InitSymbolDeps.erase(&MR); | ||||||||||
614 | return Result; | ||||||||||
615 | } | ||||||||||
616 | return SyntheticSymbolDependenciesMap(); | ||||||||||
617 | } | ||||||||||
618 | |||||||||||
619 | void ELFNixPlatform::ELFNixPlatformPlugin::addInitializerSupportPasses( | ||||||||||
620 | MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) { | ||||||||||
621 | |||||||||||
622 | /// Preserve init sections. | ||||||||||
623 | Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) -> Error { | ||||||||||
624 | if (auto Err = preserveInitSections(G, MR)) | ||||||||||
625 | return Err; | ||||||||||
626 | return Error::success(); | ||||||||||
627 | }); | ||||||||||
628 | |||||||||||
629 | Config.PostFixupPasses.push_back( | ||||||||||
630 | [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { | ||||||||||
631 | return registerInitSections(G, JD); | ||||||||||
632 | }); | ||||||||||
633 | } | ||||||||||
634 | |||||||||||
635 | void ELFNixPlatform::ELFNixPlatformPlugin::addDSOHandleSupportPasses( | ||||||||||
636 | MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) { | ||||||||||
637 | |||||||||||
638 | Config.PostAllocationPasses.push_back([this, &JD = MR.getTargetJITDylib()]( | ||||||||||
639 | jitlink::LinkGraph &G) -> Error { | ||||||||||
640 | auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) { | ||||||||||
641 | return Sym->getName() == *MP.DSOHandleSymbol; | ||||||||||
642 | }); | ||||||||||
643 | assert(I != G.defined_symbols().end() && "Missing DSO handle symbol")(static_cast <bool> (I != G.defined_symbols().end() && "Missing DSO handle symbol") ? void (0) : __assert_fail ("I != G.defined_symbols().end() && \"Missing DSO handle symbol\"" , "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp", 643, __extension__ __PRETTY_FUNCTION__)); | ||||||||||
644 | { | ||||||||||
645 | std::lock_guard<std::mutex> Lock(MP.PlatformMutex); | ||||||||||
646 | auto HandleAddr = (*I)->getAddress(); | ||||||||||
647 | MP.HandleAddrToJITDylib[HandleAddr] = &JD; | ||||||||||
648 | assert(!MP.InitSeqs.count(&JD) && "InitSeq entry for JD already exists")(static_cast <bool> (!MP.InitSeqs.count(&JD) && "InitSeq entry for JD already exists") ? void (0) : __assert_fail ("!MP.InitSeqs.count(&JD) && \"InitSeq entry for JD already exists\"" , "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp", 648, __extension__ __PRETTY_FUNCTION__)); | ||||||||||
649 | MP.InitSeqs.insert(std::make_pair( | ||||||||||
650 | &JD, ELFNixJITDylibInitializers(JD.getName(), HandleAddr))); | ||||||||||
651 | } | ||||||||||
652 | return Error::success(); | ||||||||||
653 | }); | ||||||||||
654 | } | ||||||||||
655 | |||||||||||
656 | void ELFNixPlatform::ELFNixPlatformPlugin::addEHAndTLVSupportPasses( | ||||||||||
657 | MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) { | ||||||||||
658 | |||||||||||
659 | // Insert TLV lowering at the start of the PostPrunePasses, since we want | ||||||||||
660 | // it to run before GOT/PLT lowering. | ||||||||||
661 | |||||||||||
662 | // TODO: Check that before the fixTLVSectionsAndEdges pass, the GOT/PLT build | ||||||||||
663 | // pass has done. Because the TLS descriptor need to be allocate in GOT. | ||||||||||
664 | Config.PostPrunePasses.push_back( | ||||||||||
665 | [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { | ||||||||||
666 | return fixTLVSectionsAndEdges(G, JD); | ||||||||||
667 | }); | ||||||||||
668 | |||||||||||
669 | // Add a pass to register the final addresses of the eh-frame and TLV sections | ||||||||||
670 | // with the runtime. | ||||||||||
671 | Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error { | ||||||||||
672 | ELFPerObjectSectionsToRegister POSR; | ||||||||||
673 | |||||||||||
674 | if (auto *EHFrameSection = G.findSectionByName(ELFEHFrameSectionName)) { | ||||||||||
| |||||||||||
675 | jitlink::SectionRange R(*EHFrameSection); | ||||||||||
676 | if (!R.empty()) | ||||||||||
677 | POSR.EHFrameSection = R.getRange(); | ||||||||||
678 | } | ||||||||||
679 | |||||||||||
680 | // Get a pointer to the thread data section if there is one. It will be used | ||||||||||
681 | // below. | ||||||||||
682 | jitlink::Section *ThreadDataSection = | ||||||||||
683 | G.findSectionByName(ELFThreadDataSectionName); | ||||||||||
684 | |||||||||||
685 | // Handle thread BSS section if there is one. | ||||||||||
686 | if (auto *ThreadBSSSection
| ||||||||||
687 | // If there's already a thread data section in this graph then merge the | ||||||||||
688 | // thread BSS section content into it, otherwise just treat the thread | ||||||||||
689 | // BSS section as the thread data section. | ||||||||||
690 | if (ThreadDataSection) | ||||||||||
691 | G.mergeSections(*ThreadDataSection, *ThreadBSSSection); | ||||||||||
692 | else | ||||||||||
693 | ThreadDataSection = ThreadBSSSection; | ||||||||||
694 | } | ||||||||||
695 | |||||||||||
696 | // Having merged thread BSS (if present) and thread data (if present), | ||||||||||
697 | // record the resulting section range. | ||||||||||
698 | if (ThreadDataSection) { | ||||||||||
699 | jitlink::SectionRange R(*ThreadDataSection); | ||||||||||
700 | if (!R.empty()) | ||||||||||
701 | POSR.ThreadDataSection = R.getRange(); | ||||||||||
702 | } | ||||||||||
703 | |||||||||||
704 | if (POSR.EHFrameSection.Start || POSR.ThreadDataSection.Start) { | ||||||||||
705 | |||||||||||
706 | // If we're still bootstrapping the runtime then just record this | ||||||||||
707 | // frame for now. | ||||||||||
708 | if (!MP.RuntimeBootstrapped) { | ||||||||||
709 | std::lock_guard<std::mutex> Lock(MP.PlatformMutex); | ||||||||||
710 | MP.BootstrapPOSRs.push_back(POSR); | ||||||||||
711 | return Error::success(); | ||||||||||
712 | } | ||||||||||
713 | |||||||||||
714 | // Otherwise register it immediately. | ||||||||||
715 | if (auto Err = MP.registerPerObjectSections(POSR)) | ||||||||||
716 | return Err; | ||||||||||
717 | } | ||||||||||
718 | |||||||||||
719 | return Error::success(); | ||||||||||
720 | }); | ||||||||||
721 | } | ||||||||||
722 | |||||||||||
723 | Error ELFNixPlatform::ELFNixPlatformPlugin::preserveInitSections( | ||||||||||
724 | jitlink::LinkGraph &G, MaterializationResponsibility &MR) { | ||||||||||
725 | |||||||||||
726 | JITLinkSymbolSet InitSectionSymbols; | ||||||||||
727 | for (auto &InitSection : G.sections()) { | ||||||||||
728 | // Skip non-init sections. | ||||||||||
729 | if (!isELFInitializerSection(InitSection.getName())) | ||||||||||
730 | continue; | ||||||||||
731 | |||||||||||
732 | // Make a pass over live symbols in the section: those blocks are already | ||||||||||
733 | // preserved. | ||||||||||
734 | DenseSet<jitlink::Block *> AlreadyLiveBlocks; | ||||||||||
735 | for (auto &Sym : InitSection.symbols()) { | ||||||||||
736 | auto &B = Sym->getBlock(); | ||||||||||
737 | if (Sym->isLive() && Sym->getOffset() == 0 && | ||||||||||
738 | Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) { | ||||||||||
739 | InitSectionSymbols.insert(Sym); | ||||||||||
740 | AlreadyLiveBlocks.insert(&B); | ||||||||||
741 | } | ||||||||||
742 | } | ||||||||||
743 | |||||||||||
744 | // Add anonymous symbols to preserve any not-already-preserved blocks. | ||||||||||
745 | for (auto *B : InitSection.blocks()) | ||||||||||
746 | if (!AlreadyLiveBlocks.count(B)) | ||||||||||
747 | InitSectionSymbols.insert( | ||||||||||
748 | &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true)); | ||||||||||
749 | } | ||||||||||
750 | |||||||||||
751 | if (!InitSectionSymbols.empty()) { | ||||||||||
752 | std::lock_guard<std::mutex> Lock(PluginMutex); | ||||||||||
753 | InitSymbolDeps[&MR] = std::move(InitSectionSymbols); | ||||||||||
754 | } | ||||||||||
755 | |||||||||||
756 | return Error::success(); | ||||||||||
757 | } | ||||||||||
758 | |||||||||||
759 | Error ELFNixPlatform::ELFNixPlatformPlugin::registerInitSections( | ||||||||||
760 | jitlink::LinkGraph &G, JITDylib &JD) { | ||||||||||
761 | |||||||||||
762 | SmallVector<jitlink::Section *> InitSections; | ||||||||||
763 | |||||||||||
764 | LLVM_DEBUG(dbgs() << "ELFNixPlatform::registerInitSections\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { dbgs() << "ELFNixPlatform::registerInitSections\n" ; } } while (false); | ||||||||||
765 | |||||||||||
766 | for (auto &Sec : G.sections()) { | ||||||||||
767 | if (isELFInitializerSection(Sec.getName())) { | ||||||||||
768 | InitSections.push_back(&Sec); | ||||||||||
769 | } | ||||||||||
770 | } | ||||||||||
771 | |||||||||||
772 | // Dump the scraped inits. | ||||||||||
773 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n"; for (auto *Sec : InitSections ) { jitlink::SectionRange R(*Sec); dbgs() << " " << Sec->getName() << ": " << R.getRange() << "\n"; } }; } } while (false) | ||||||||||
774 | dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n"; for (auto *Sec : InitSections ) { jitlink::SectionRange R(*Sec); dbgs() << " " << Sec->getName() << ": " << R.getRange() << "\n"; } }; } } while (false) | ||||||||||
775 | for (auto *Sec : InitSections) {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n"; for (auto *Sec : InitSections ) { jitlink::SectionRange R(*Sec); dbgs() << " " << Sec->getName() << ": " << R.getRange() << "\n"; } }; } } while (false) | ||||||||||
776 | jitlink::SectionRange R(*Sec);do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n"; for (auto *Sec : InitSections ) { jitlink::SectionRange R(*Sec); dbgs() << " " << Sec->getName() << ": " << R.getRange() << "\n"; } }; } } while (false) | ||||||||||
777 | dbgs() << " " << Sec->getName() << ": " << R.getRange() << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n"; for (auto *Sec : InitSections ) { jitlink::SectionRange R(*Sec); dbgs() << " " << Sec->getName() << ": " << R.getRange() << "\n"; } }; } } while (false) | ||||||||||
778 | }do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n"; for (auto *Sec : InitSections ) { jitlink::SectionRange R(*Sec); dbgs() << " " << Sec->getName() << ": " << R.getRange() << "\n"; } }; } } while (false) | ||||||||||
779 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n"; for (auto *Sec : InitSections ) { jitlink::SectionRange R(*Sec); dbgs() << " " << Sec->getName() << ": " << R.getRange() << "\n"; } }; } } while (false); | ||||||||||
780 | |||||||||||
781 | return MP.registerInitInfo(JD, InitSections); | ||||||||||
782 | } | ||||||||||
783 | |||||||||||
784 | Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges( | ||||||||||
785 | jitlink::LinkGraph &G, JITDylib &JD) { | ||||||||||
786 | |||||||||||
787 | for (auto *Sym : G.external_symbols()) { | ||||||||||
788 | if (Sym->getName() == "__tls_get_addr") { | ||||||||||
789 | Sym->setName("___orc_rt_elfnix_tls_get_addr"); | ||||||||||
790 | } else if (Sym->getName() == "__tlsdesc_resolver") { | ||||||||||
791 | Sym->setName("___orc_rt_elfnix_tlsdesc_resolver"); | ||||||||||
792 | } | ||||||||||
793 | } | ||||||||||
794 | |||||||||||
795 | auto *TLSInfoEntrySection = G.findSectionByName("$__TLSINFO"); | ||||||||||
796 | |||||||||||
797 | if (TLSInfoEntrySection) { | ||||||||||
798 | std::optional<uint64_t> Key; | ||||||||||
799 | { | ||||||||||
800 | std::lock_guard<std::mutex> Lock(MP.PlatformMutex); | ||||||||||
801 | auto I = MP.JITDylibToPThreadKey.find(&JD); | ||||||||||
802 | if (I != MP.JITDylibToPThreadKey.end()) | ||||||||||
803 | Key = I->second; | ||||||||||
804 | } | ||||||||||
805 | if (!Key) { | ||||||||||
806 | if (auto KeyOrErr = MP.createPThreadKey()) | ||||||||||
807 | Key = *KeyOrErr; | ||||||||||
808 | else | ||||||||||
809 | return KeyOrErr.takeError(); | ||||||||||
810 | } | ||||||||||
811 | |||||||||||
812 | uint64_t PlatformKeyBits = | ||||||||||
813 | support::endian::byte_swap(*Key, G.getEndianness()); | ||||||||||
814 | |||||||||||
815 | for (auto *B : TLSInfoEntrySection->blocks()) { | ||||||||||
816 | // FIXME: The TLS descriptor byte length may different with different | ||||||||||
817 | // ISA | ||||||||||
818 | assert(B->getSize() == (G.getPointerSize() * 2) &&(static_cast <bool> (B->getSize() == (G.getPointerSize () * 2) && "TLS descriptor must be 2 words length") ? void (0) : __assert_fail ("B->getSize() == (G.getPointerSize() * 2) && \"TLS descriptor must be 2 words length\"" , "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp", 819, __extension__ __PRETTY_FUNCTION__)) | ||||||||||
819 | "TLS descriptor must be 2 words length")(static_cast <bool> (B->getSize() == (G.getPointerSize () * 2) && "TLS descriptor must be 2 words length") ? void (0) : __assert_fail ("B->getSize() == (G.getPointerSize() * 2) && \"TLS descriptor must be 2 words length\"" , "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp", 819, __extension__ __PRETTY_FUNCTION__)); | ||||||||||
820 | auto TLSInfoEntryContent = B->getMutableContent(G); | ||||||||||
821 | memcpy(TLSInfoEntryContent.data(), &PlatformKeyBits, G.getPointerSize()); | ||||||||||
822 | } | ||||||||||
823 | } | ||||||||||
824 | |||||||||||
825 | return Error::success(); | ||||||||||
826 | } | ||||||||||
827 | |||||||||||
828 | } // End namespace orc. | ||||||||||
829 | } // End namespace llvm. |
1 | //===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- C++ -*-===// |
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 | // Contains core ORC APIs. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_EXECUTIONENGINE_ORC_CORE_H |
14 | #define LLVM_EXECUTIONENGINE_ORC_CORE_H |
15 | |
16 | #include "llvm/ADT/BitmaskEnum.h" |
17 | #include "llvm/ADT/DenseSet.h" |
18 | #include "llvm/ADT/FunctionExtras.h" |
19 | #include "llvm/ADT/IntrusiveRefCntPtr.h" |
20 | #include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h" |
21 | #include "llvm/ExecutionEngine/JITSymbol.h" |
22 | #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" |
23 | #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" |
24 | #include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h" |
25 | #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" |
26 | #include "llvm/ExecutionEngine/Orc/TaskDispatch.h" |
27 | #include "llvm/Support/Debug.h" |
28 | #include "llvm/Support/ExtensibleRTTI.h" |
29 | |
30 | #include <atomic> |
31 | #include <future> |
32 | #include <memory> |
33 | #include <vector> |
34 | |
35 | namespace llvm { |
36 | namespace orc { |
37 | |
38 | // Forward declare some classes. |
39 | class AsynchronousSymbolQuery; |
40 | class ExecutionSession; |
41 | class MaterializationUnit; |
42 | class MaterializationResponsibility; |
43 | class JITDylib; |
44 | class ResourceTracker; |
45 | class InProgressLookupState; |
46 | |
47 | enum class SymbolState : uint8_t; |
48 | |
49 | using ResourceTrackerSP = IntrusiveRefCntPtr<ResourceTracker>; |
50 | using JITDylibSP = IntrusiveRefCntPtr<JITDylib>; |
51 | |
52 | using ResourceKey = uintptr_t; |
53 | |
54 | /// API to remove / transfer ownership of JIT resources. |
55 | class ResourceTracker : public ThreadSafeRefCountedBase<ResourceTracker> { |
56 | private: |
57 | friend class ExecutionSession; |
58 | friend class JITDylib; |
59 | friend class MaterializationResponsibility; |
60 | |
61 | public: |
62 | ResourceTracker(const ResourceTracker &) = delete; |
63 | ResourceTracker &operator=(const ResourceTracker &) = delete; |
64 | ResourceTracker(ResourceTracker &&) = delete; |
65 | ResourceTracker &operator=(ResourceTracker &&) = delete; |
66 | |
67 | ~ResourceTracker(); |
68 | |
69 | /// Return the JITDylib targeted by this tracker. |
70 | JITDylib &getJITDylib() const { |
71 | return *reinterpret_cast<JITDylib *>(JDAndFlag.load() & |
72 | ~static_cast<uintptr_t>(1)); |
73 | } |
74 | |
75 | /// Runs the given callback under the session lock, passing in the associated |
76 | /// ResourceKey. This is the safe way to associate resources with trackers. |
77 | template <typename Func> Error withResourceKeyDo(Func &&F); |
78 | |
79 | /// Remove all resources associated with this key. |
80 | Error remove(); |
81 | |
82 | /// Transfer all resources associated with this key to the given |
83 | /// tracker, which must target the same JITDylib as this one. |
84 | void transferTo(ResourceTracker &DstRT); |
85 | |
86 | /// Return true if this tracker has become defunct. |
87 | bool isDefunct() const { return JDAndFlag.load() & 0x1; } |
88 | |
89 | /// Returns the key associated with this tracker. |
90 | /// This method should not be used except for debug logging: there is no |
91 | /// guarantee that the returned value will remain valid. |
92 | ResourceKey getKeyUnsafe() const { return reinterpret_cast<uintptr_t>(this); } |
93 | |
94 | private: |
95 | ResourceTracker(JITDylibSP JD); |
96 | |
97 | void makeDefunct(); |
98 | |
99 | std::atomic_uintptr_t JDAndFlag; |
100 | }; |
101 | |
102 | /// Listens for ResourceTracker operations. |
103 | class ResourceManager { |
104 | public: |
105 | virtual ~ResourceManager(); |
106 | virtual Error handleRemoveResources(JITDylib &JD, ResourceKey K) = 0; |
107 | virtual void handleTransferResources(JITDylib &JD, ResourceKey DstK, |
108 | ResourceKey SrcK) = 0; |
109 | }; |
110 | |
111 | /// A set of symbol names (represented by SymbolStringPtrs for |
112 | // efficiency). |
113 | using SymbolNameSet = DenseSet<SymbolStringPtr>; |
114 | |
115 | /// A vector of symbol names. |
116 | using SymbolNameVector = std::vector<SymbolStringPtr>; |
117 | |
118 | /// A map from symbol names (as SymbolStringPtrs) to JITSymbols |
119 | /// (address/flags pairs). |
120 | using SymbolMap = DenseMap<SymbolStringPtr, ExecutorSymbolDef>; |
121 | |
122 | /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags. |
123 | using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>; |
124 | |
125 | /// A map from JITDylibs to sets of symbols. |
126 | using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>; |
127 | |
128 | /// Lookup flags that apply to each dylib in the search order for a lookup. |
129 | /// |
130 | /// If MatchHiddenSymbolsOnly is used (the default) for a given dylib, then |
131 | /// only symbols in that Dylib's interface will be searched. If |
132 | /// MatchHiddenSymbols is used then symbols with hidden visibility will match |
133 | /// as well. |
134 | enum class JITDylibLookupFlags { MatchExportedSymbolsOnly, MatchAllSymbols }; |
135 | |
136 | /// Lookup flags that apply to each symbol in a lookup. |
137 | /// |
138 | /// If RequiredSymbol is used (the default) for a given symbol then that symbol |
139 | /// must be found during the lookup or the lookup will fail returning a |
140 | /// SymbolNotFound error. If WeaklyReferencedSymbol is used and the given |
141 | /// symbol is not found then the query will continue, and no result for the |
142 | /// missing symbol will be present in the result (assuming the rest of the |
143 | /// lookup succeeds). |
144 | enum class SymbolLookupFlags { RequiredSymbol, WeaklyReferencedSymbol }; |
145 | |
146 | /// Describes the kind of lookup being performed. The lookup kind is passed to |
147 | /// symbol generators (if they're invoked) to help them determine what |
148 | /// definitions to generate. |
149 | /// |
150 | /// Static -- Lookup is being performed as-if at static link time (e.g. |
151 | /// generators representing static archives should pull in new |
152 | /// definitions). |
153 | /// |
154 | /// DLSym -- Lookup is being performed as-if at runtime (e.g. generators |
155 | /// representing static archives should not pull in new definitions). |
156 | enum class LookupKind { Static, DLSym }; |
157 | |
158 | /// A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search |
159 | /// order during symbol lookup. |
160 | using JITDylibSearchOrder = |
161 | std::vector<std::pair<JITDylib *, JITDylibLookupFlags>>; |
162 | |
163 | /// Convenience function for creating a search order from an ArrayRef of |
164 | /// JITDylib*, all with the same flags. |
165 | inline JITDylibSearchOrder makeJITDylibSearchOrder( |
166 | ArrayRef<JITDylib *> JDs, |
167 | JITDylibLookupFlags Flags = JITDylibLookupFlags::MatchExportedSymbolsOnly) { |
168 | JITDylibSearchOrder O; |
169 | O.reserve(JDs.size()); |
170 | for (auto *JD : JDs) |
171 | O.push_back(std::make_pair(JD, Flags)); |
172 | return O; |
173 | } |
174 | |
175 | /// A set of symbols to look up, each associated with a SymbolLookupFlags |
176 | /// value. |
177 | /// |
178 | /// This class is backed by a vector and optimized for fast insertion, |
179 | /// deletion and iteration. It does not guarantee a stable order between |
180 | /// operations, and will not automatically detect duplicate elements (they |
181 | /// can be manually checked by calling the validate method). |
182 | class SymbolLookupSet { |
183 | public: |
184 | using value_type = std::pair<SymbolStringPtr, SymbolLookupFlags>; |
185 | using UnderlyingVector = std::vector<value_type>; |
186 | using iterator = UnderlyingVector::iterator; |
187 | using const_iterator = UnderlyingVector::const_iterator; |
188 | |
189 | SymbolLookupSet() = default; |
190 | |
191 | explicit SymbolLookupSet( |
192 | SymbolStringPtr Name, |
193 | SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { |
194 | add(std::move(Name), Flags); |
195 | } |
196 | |
197 | /// Construct a SymbolLookupSet from an initializer list of SymbolStringPtrs. |
198 | explicit SymbolLookupSet( |
199 | std::initializer_list<SymbolStringPtr> Names, |
200 | SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { |
201 | Symbols.reserve(Names.size()); |
202 | for (const auto &Name : Names) |
203 | add(std::move(Name), Flags); |
204 | } |
205 | |
206 | /// Construct a SymbolLookupSet from a SymbolNameSet with the given |
207 | /// Flags used for each value. |
208 | explicit SymbolLookupSet( |
209 | const SymbolNameSet &Names, |
210 | SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { |
211 | Symbols.reserve(Names.size()); |
212 | for (const auto &Name : Names) |
213 | add(Name, Flags); |
214 | } |
215 | |
216 | /// Construct a SymbolLookupSet from a vector of symbols with the given Flags |
217 | /// used for each value. |
218 | /// If the ArrayRef contains duplicates it is up to the client to remove these |
219 | /// before using this instance for lookup. |
220 | explicit SymbolLookupSet( |
221 | ArrayRef<SymbolStringPtr> Names, |
222 | SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { |
223 | Symbols.reserve(Names.size()); |
224 | for (const auto &Name : Names) |
225 | add(Name, Flags); |
226 | } |
227 | |
228 | /// Construct a SymbolLookupSet from DenseMap keys. |
229 | template <typename KeyT> |
230 | static SymbolLookupSet |
231 | fromMapKeys(const DenseMap<SymbolStringPtr, KeyT> &M, |
232 | SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { |
233 | SymbolLookupSet Result; |
234 | Result.Symbols.reserve(M.size()); |
235 | for (const auto &KV : M) |
236 | Result.add(KV.first, Flags); |
237 | return Result; |
238 | } |
239 | |
240 | /// Add an element to the set. The client is responsible for checking that |
241 | /// duplicates are not added. |
242 | SymbolLookupSet & |
243 | add(SymbolStringPtr Name, |
244 | SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { |
245 | Symbols.push_back(std::make_pair(std::move(Name), Flags)); |
246 | return *this; |
247 | } |
248 | |
249 | /// Quickly append one lookup set to another. |
250 | SymbolLookupSet &append(SymbolLookupSet Other) { |
251 | Symbols.reserve(Symbols.size() + Other.size()); |
252 | for (auto &KV : Other) |
253 | Symbols.push_back(std::move(KV)); |
254 | return *this; |
255 | } |
256 | |
257 | bool empty() const { return Symbols.empty(); } |
258 | UnderlyingVector::size_type size() const { return Symbols.size(); } |
259 | iterator begin() { return Symbols.begin(); } |
260 | iterator end() { return Symbols.end(); } |
261 | const_iterator begin() const { return Symbols.begin(); } |
262 | const_iterator end() const { return Symbols.end(); } |
263 | |
264 | /// Removes the Ith element of the vector, replacing it with the last element. |
265 | void remove(UnderlyingVector::size_type I) { |
266 | std::swap(Symbols[I], Symbols.back()); |
267 | Symbols.pop_back(); |
268 | } |
269 | |
270 | /// Removes the element pointed to by the given iterator. This iterator and |
271 | /// all subsequent ones (including end()) are invalidated. |
272 | void remove(iterator I) { remove(I - begin()); } |
273 | |
274 | /// Removes all elements matching the given predicate, which must be callable |
275 | /// as bool(const SymbolStringPtr &, SymbolLookupFlags Flags). |
276 | template <typename PredFn> void remove_if(PredFn &&Pred) { |
277 | UnderlyingVector::size_type I = 0; |
278 | while (I != Symbols.size()) { |
279 | const auto &Name = Symbols[I].first; |
280 | auto Flags = Symbols[I].second; |
281 | if (Pred(Name, Flags)) |
282 | remove(I); |
283 | else |
284 | ++I; |
285 | } |
286 | } |
287 | |
288 | /// Loop over the elements of this SymbolLookupSet, applying the Body function |
289 | /// to each one. Body must be callable as |
290 | /// bool(const SymbolStringPtr &, SymbolLookupFlags). |
291 | /// If Body returns true then the element just passed in is removed from the |
292 | /// set. If Body returns false then the element is retained. |
293 | template <typename BodyFn> |
294 | auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t< |
295 | std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(), |
296 | std::declval<SymbolLookupFlags>())), |
297 | bool>::value> { |
298 | UnderlyingVector::size_type I = 0; |
299 | while (I != Symbols.size()) { |
300 | const auto &Name = Symbols[I].first; |
301 | auto Flags = Symbols[I].second; |
302 | if (Body(Name, Flags)) |
303 | remove(I); |
304 | else |
305 | ++I; |
306 | } |
307 | } |
308 | |
309 | /// Loop over the elements of this SymbolLookupSet, applying the Body function |
310 | /// to each one. Body must be callable as |
311 | /// Expected<bool>(const SymbolStringPtr &, SymbolLookupFlags). |
312 | /// If Body returns a failure value, the loop exits immediately. If Body |
313 | /// returns true then the element just passed in is removed from the set. If |
314 | /// Body returns false then the element is retained. |
315 | template <typename BodyFn> |
316 | auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t< |
317 | std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(), |
318 | std::declval<SymbolLookupFlags>())), |
319 | Expected<bool>>::value, |
320 | Error> { |
321 | UnderlyingVector::size_type I = 0; |
322 | while (I != Symbols.size()) { |
323 | const auto &Name = Symbols[I].first; |
324 | auto Flags = Symbols[I].second; |
325 | auto Remove = Body(Name, Flags); |
326 | if (!Remove) |
327 | return Remove.takeError(); |
328 | if (*Remove) |
329 | remove(I); |
330 | else |
331 | ++I; |
332 | } |
333 | return Error::success(); |
334 | } |
335 | |
336 | /// Construct a SymbolNameVector from this instance by dropping the Flags |
337 | /// values. |
338 | SymbolNameVector getSymbolNames() const { |
339 | SymbolNameVector Names; |
340 | Names.reserve(Symbols.size()); |
341 | for (const auto &KV : Symbols) |
342 | Names.push_back(KV.first); |
343 | return Names; |
344 | } |
345 | |
346 | /// Sort the lookup set by pointer value. This sort is fast but sensitive to |
347 | /// allocation order and so should not be used where a consistent order is |
348 | /// required. |
349 | void sortByAddress() { llvm::sort(Symbols, llvm::less_first()); } |
350 | |
351 | /// Sort the lookup set lexicographically. This sort is slow but the order |
352 | /// is unaffected by allocation order. |
353 | void sortByName() { |
354 | llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) { |
355 | return *LHS.first < *RHS.first; |
356 | }); |
357 | } |
358 | |
359 | /// Remove any duplicate elements. If a SymbolLookupSet is not duplicate-free |
360 | /// by construction, this method can be used to turn it into a proper set. |
361 | void removeDuplicates() { |
362 | sortByAddress(); |
363 | auto LastI = std::unique(Symbols.begin(), Symbols.end()); |
364 | Symbols.erase(LastI, Symbols.end()); |
365 | } |
366 | |
367 | #ifndef NDEBUG |
368 | /// Returns true if this set contains any duplicates. This should only be used |
369 | /// in assertions. |
370 | bool containsDuplicates() { |
371 | if (Symbols.size() < 2) |
372 | return false; |
373 | sortByAddress(); |
374 | for (UnderlyingVector::size_type I = 1; I != Symbols.size(); ++I) |
375 | if (Symbols[I].first == Symbols[I - 1].first) |
376 | return true; |
377 | return false; |
378 | } |
379 | #endif |
380 | |
381 | private: |
382 | UnderlyingVector Symbols; |
383 | }; |
384 | |
385 | struct SymbolAliasMapEntry { |
386 | SymbolAliasMapEntry() = default; |
387 | SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags) |
388 | : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {} |
389 | |
390 | SymbolStringPtr Aliasee; |
391 | JITSymbolFlags AliasFlags; |
392 | }; |
393 | |
394 | /// A map of Symbols to (Symbol, Flags) pairs. |
395 | using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>; |
396 | |
397 | /// Callback to notify client that symbols have been resolved. |
398 | using SymbolsResolvedCallback = unique_function<void(Expected<SymbolMap>)>; |
399 | |
400 | /// Callback to register the dependencies for a given query. |
401 | using RegisterDependenciesFunction = |
402 | std::function<void(const SymbolDependenceMap &)>; |
403 | |
404 | /// This can be used as the value for a RegisterDependenciesFunction if there |
405 | /// are no dependants to register with. |
406 | extern RegisterDependenciesFunction NoDependenciesToRegister; |
407 | |
408 | class ResourceTrackerDefunct : public ErrorInfo<ResourceTrackerDefunct> { |
409 | public: |
410 | static char ID; |
411 | |
412 | ResourceTrackerDefunct(ResourceTrackerSP RT); |
413 | std::error_code convertToErrorCode() const override; |
414 | void log(raw_ostream &OS) const override; |
415 | |
416 | private: |
417 | ResourceTrackerSP RT; |
418 | }; |
419 | |
420 | /// Used to notify a JITDylib that the given set of symbols failed to |
421 | /// materialize. |
422 | class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> { |
423 | public: |
424 | static char ID; |
425 | |
426 | FailedToMaterialize(std::shared_ptr<SymbolStringPool> SSP, |
427 | std::shared_ptr<SymbolDependenceMap> Symbols); |
428 | ~FailedToMaterialize(); |
429 | std::error_code convertToErrorCode() const override; |
430 | void log(raw_ostream &OS) const override; |
431 | const SymbolDependenceMap &getSymbols() const { return *Symbols; } |
432 | |
433 | private: |
434 | std::shared_ptr<SymbolStringPool> SSP; |
435 | std::shared_ptr<SymbolDependenceMap> Symbols; |
436 | }; |
437 | |
438 | /// Used to notify clients when symbols can not be found during a lookup. |
439 | class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> { |
440 | public: |
441 | static char ID; |
442 | |
443 | SymbolsNotFound(std::shared_ptr<SymbolStringPool> SSP, SymbolNameSet Symbols); |
444 | SymbolsNotFound(std::shared_ptr<SymbolStringPool> SSP, |
445 | SymbolNameVector Symbols); |
446 | std::error_code convertToErrorCode() const override; |
447 | void log(raw_ostream &OS) const override; |
448 | std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; } |
449 | const SymbolNameVector &getSymbols() const { return Symbols; } |
450 | |
451 | private: |
452 | std::shared_ptr<SymbolStringPool> SSP; |
453 | SymbolNameVector Symbols; |
454 | }; |
455 | |
456 | /// Used to notify clients that a set of symbols could not be removed. |
457 | class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> { |
458 | public: |
459 | static char ID; |
460 | |
461 | SymbolsCouldNotBeRemoved(std::shared_ptr<SymbolStringPool> SSP, |
462 | SymbolNameSet Symbols); |
463 | std::error_code convertToErrorCode() const override; |
464 | void log(raw_ostream &OS) const override; |
465 | std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; } |
466 | const SymbolNameSet &getSymbols() const { return Symbols; } |
467 | |
468 | private: |
469 | std::shared_ptr<SymbolStringPool> SSP; |
470 | SymbolNameSet Symbols; |
471 | }; |
472 | |
473 | /// Errors of this type should be returned if a module fails to include |
474 | /// definitions that are claimed by the module's associated |
475 | /// MaterializationResponsibility. If this error is returned it is indicative of |
476 | /// a broken transformation / compiler / object cache. |
477 | class MissingSymbolDefinitions : public ErrorInfo<MissingSymbolDefinitions> { |
478 | public: |
479 | static char ID; |
480 | |
481 | MissingSymbolDefinitions(std::shared_ptr<SymbolStringPool> SSP, |
482 | std::string ModuleName, SymbolNameVector Symbols) |
483 | : SSP(std::move(SSP)), ModuleName(std::move(ModuleName)), |
484 | Symbols(std::move(Symbols)) {} |
485 | std::error_code convertToErrorCode() const override; |
486 | void log(raw_ostream &OS) const override; |
487 | std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; } |
488 | const std::string &getModuleName() const { return ModuleName; } |
489 | const SymbolNameVector &getSymbols() const { return Symbols; } |
490 | private: |
491 | std::shared_ptr<SymbolStringPool> SSP; |
492 | std::string ModuleName; |
493 | SymbolNameVector Symbols; |
494 | }; |
495 | |
496 | /// Errors of this type should be returned if a module contains definitions for |
497 | /// symbols that are not claimed by the module's associated |
498 | /// MaterializationResponsibility. If this error is returned it is indicative of |
499 | /// a broken transformation / compiler / object cache. |
500 | class UnexpectedSymbolDefinitions : public ErrorInfo<UnexpectedSymbolDefinitions> { |
501 | public: |
502 | static char ID; |
503 | |
504 | UnexpectedSymbolDefinitions(std::shared_ptr<SymbolStringPool> SSP, |
505 | std::string ModuleName, SymbolNameVector Symbols) |
506 | : SSP(std::move(SSP)), ModuleName(std::move(ModuleName)), |
507 | Symbols(std::move(Symbols)) {} |
508 | std::error_code convertToErrorCode() const override; |
509 | void log(raw_ostream &OS) const override; |
510 | std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; } |
511 | const std::string &getModuleName() const { return ModuleName; } |
512 | const SymbolNameVector &getSymbols() const { return Symbols; } |
513 | private: |
514 | std::shared_ptr<SymbolStringPool> SSP; |
515 | std::string ModuleName; |
516 | SymbolNameVector Symbols; |
517 | }; |
518 | |
519 | /// Tracks responsibility for materialization, and mediates interactions between |
520 | /// MaterializationUnits and JDs. |
521 | /// |
522 | /// An instance of this class is passed to MaterializationUnits when their |
523 | /// materialize method is called. It allows MaterializationUnits to resolve and |
524 | /// emit symbols, or abandon materialization by notifying any unmaterialized |
525 | /// symbols of an error. |
526 | class MaterializationResponsibility { |
527 | friend class ExecutionSession; |
528 | friend class JITDylib; |
529 | |
530 | public: |
531 | MaterializationResponsibility(MaterializationResponsibility &&) = delete; |
532 | MaterializationResponsibility & |
533 | operator=(MaterializationResponsibility &&) = delete; |
534 | |
535 | /// Destruct a MaterializationResponsibility instance. In debug mode |
536 | /// this asserts that all symbols being tracked have been either |
537 | /// emitted or notified of an error. |
538 | ~MaterializationResponsibility(); |
539 | |
540 | /// Runs the given callback under the session lock, passing in the associated |
541 | /// ResourceKey. This is the safe way to associate resources with trackers. |
542 | template <typename Func> Error withResourceKeyDo(Func &&F) const { |
543 | return RT->withResourceKeyDo(std::forward<Func>(F)); |
544 | } |
545 | |
546 | /// Returns the target JITDylib that these symbols are being materialized |
547 | /// into. |
548 | JITDylib &getTargetJITDylib() const { return JD; } |
549 | |
550 | /// Returns the ExecutionSession for this instance. |
551 | ExecutionSession &getExecutionSession() const; |
552 | |
553 | /// Returns the symbol flags map for this responsibility instance. |
554 | /// Note: The returned flags may have transient flags (Lazy, Materializing) |
555 | /// set. These should be stripped with JITSymbolFlags::stripTransientFlags |
556 | /// before using. |
557 | const SymbolFlagsMap &getSymbols() const { return SymbolFlags; } |
558 | |
559 | /// Returns the initialization pseudo-symbol, if any. This symbol will also |
560 | /// be present in the SymbolFlagsMap for this MaterializationResponsibility |
561 | /// object. |
562 | const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; } |
563 | |
564 | /// Returns the names of any symbols covered by this |
565 | /// MaterializationResponsibility object that have queries pending. This |
566 | /// information can be used to return responsibility for unrequested symbols |
567 | /// back to the JITDylib via the delegate method. |
568 | SymbolNameSet getRequestedSymbols() const; |
569 | |
570 | /// Notifies the target JITDylib that the given symbols have been resolved. |
571 | /// This will update the given symbols' addresses in the JITDylib, and notify |
572 | /// any pending queries on the given symbols of their resolution. The given |
573 | /// symbols must be ones covered by this MaterializationResponsibility |
574 | /// instance. Individual calls to this method may resolve a subset of the |
575 | /// symbols, but all symbols must have been resolved prior to calling emit. |
576 | /// |
577 | /// This method will return an error if any symbols being resolved have been |
578 | /// moved to the error state due to the failure of a dependency. If this |
579 | /// method returns an error then clients should log it and call |
580 | /// failMaterialize. If no dependencies have been registered for the |
581 | /// symbols covered by this MaterializationResponsibiility then this method |
582 | /// is guaranteed to return Error::success() and can be wrapped with cantFail. |
583 | Error notifyResolved(const SymbolMap &Symbols); |
584 | |
585 | /// Notifies the target JITDylib (and any pending queries on that JITDylib) |
586 | /// that all symbols covered by this MaterializationResponsibility instance |
587 | /// have been emitted. |
588 | /// |
589 | /// This method will return an error if any symbols being resolved have been |
590 | /// moved to the error state due to the failure of a dependency. If this |
591 | /// method returns an error then clients should log it and call |
592 | /// failMaterialize. If no dependencies have been registered for the |
593 | /// symbols covered by this MaterializationResponsibiility then this method |
594 | /// is guaranteed to return Error::success() and can be wrapped with cantFail. |
595 | Error notifyEmitted(); |
596 | |
597 | /// Attempt to claim responsibility for new definitions. This method can be |
598 | /// used to claim responsibility for symbols that are added to a |
599 | /// materialization unit during the compilation process (e.g. literal pool |
600 | /// symbols). Symbol linkage rules are the same as for symbols that are |
601 | /// defined up front: duplicate strong definitions will result in errors. |
602 | /// Duplicate weak definitions will be discarded (in which case they will |
603 | /// not be added to this responsibility instance). |
604 | /// |
605 | /// This method can be used by materialization units that want to add |
606 | /// additional symbols at materialization time (e.g. stubs, compile |
607 | /// callbacks, metadata). |
608 | Error defineMaterializing(SymbolFlagsMap SymbolFlags); |
609 | |
610 | /// Define the given symbols as non-existent, removing it from the symbol |
611 | /// table and notifying any pending queries. Queries that lookup up the |
612 | /// symbol using the SymbolLookupFlags::WeaklyReferencedSymbol flag will |
613 | /// behave as if the symbol had not been matched in the first place. Queries |
614 | /// that required this symbol will fail with a missing symbol definition |
615 | /// error. |
616 | /// |
617 | /// This method is intended to support cleanup of special symbols like |
618 | /// initializer symbols: Queries using |
619 | /// SymbolLookupFlags::WeaklyReferencedSymbol can be used to trigger their |
620 | /// emission, and this method can be used to remove them from the JITDylib |
621 | /// once materialization is complete. |
622 | void defineNonExistent(ArrayRef<SymbolStringPtr> Symbols); |
623 | |
624 | /// Notify all not-yet-emitted covered by this MaterializationResponsibility |
625 | /// instance that an error has occurred. |
626 | /// This will remove all symbols covered by this MaterializationResponsibilty |
627 | /// from the target JITDylib, and send an error to any queries waiting on |
628 | /// these symbols. |
629 | void failMaterialization(); |
630 | |
631 | /// Transfers responsibility to the given MaterializationUnit for all |
632 | /// symbols defined by that MaterializationUnit. This allows |
633 | /// materializers to break up work based on run-time information (e.g. |
634 | /// by introspecting which symbols have actually been looked up and |
635 | /// materializing only those). |
636 | Error replace(std::unique_ptr<MaterializationUnit> MU); |
637 | |
638 | /// Delegates responsibility for the given symbols to the returned |
639 | /// materialization responsibility. Useful for breaking up work between |
640 | /// threads, or different kinds of materialization processes. |
641 | Expected<std::unique_ptr<MaterializationResponsibility>> |
642 | delegate(const SymbolNameSet &Symbols); |
643 | |
644 | void addDependencies(const SymbolStringPtr &Name, |
645 | const SymbolDependenceMap &Dependencies); |
646 | |
647 | /// Add dependencies that apply to all symbols covered by this instance. |
648 | void addDependenciesForAll(const SymbolDependenceMap &Dependencies); |
649 | |
650 | private: |
651 | /// Create a MaterializationResponsibility for the given JITDylib and |
652 | /// initial symbols. |
653 | MaterializationResponsibility(ResourceTrackerSP RT, |
654 | SymbolFlagsMap SymbolFlags, |
655 | SymbolStringPtr InitSymbol) |
656 | : JD(RT->getJITDylib()), RT(std::move(RT)), |
657 | SymbolFlags(std::move(SymbolFlags)), InitSymbol(std::move(InitSymbol)) { |
658 | assert(!this->SymbolFlags.empty() && "Materializing nothing?")(static_cast <bool> (!this->SymbolFlags.empty() && "Materializing nothing?") ? void (0) : __assert_fail ("!this->SymbolFlags.empty() && \"Materializing nothing?\"" , "llvm/include/llvm/ExecutionEngine/Orc/Core.h", 658, __extension__ __PRETTY_FUNCTION__)); |
659 | } |
660 | |
661 | JITDylib &JD; |
662 | ResourceTrackerSP RT; |
663 | SymbolFlagsMap SymbolFlags; |
664 | SymbolStringPtr InitSymbol; |
665 | }; |
666 | |
667 | /// A MaterializationUnit represents a set of symbol definitions that can |
668 | /// be materialized as a group, or individually discarded (when |
669 | /// overriding definitions are encountered). |
670 | /// |
671 | /// MaterializationUnits are used when providing lazy definitions of symbols to |
672 | /// JITDylibs. The JITDylib will call materialize when the address of a symbol |
673 | /// is requested via the lookup method. The JITDylib will call discard if a |
674 | /// stronger definition is added or already present. |
675 | class MaterializationUnit { |
676 | friend class ExecutionSession; |
677 | friend class JITDylib; |
678 | |
679 | public: |
680 | static char ID; |
681 | |
682 | struct Interface { |
683 | Interface() = default; |
684 | Interface(SymbolFlagsMap InitalSymbolFlags, SymbolStringPtr InitSymbol) |
685 | : SymbolFlags(std::move(InitalSymbolFlags)), |
686 | InitSymbol(std::move(InitSymbol)) { |
687 | assert((!this->InitSymbol || this->SymbolFlags.count(this->InitSymbol)) &&(static_cast <bool> ((!this->InitSymbol || this-> SymbolFlags.count(this->InitSymbol)) && "If set, InitSymbol should appear in InitialSymbolFlags map" ) ? void (0) : __assert_fail ("(!this->InitSymbol || this->SymbolFlags.count(this->InitSymbol)) && \"If set, InitSymbol should appear in InitialSymbolFlags map\"" , "llvm/include/llvm/ExecutionEngine/Orc/Core.h", 688, __extension__ __PRETTY_FUNCTION__)) |
688 | "If set, InitSymbol should appear in InitialSymbolFlags map")(static_cast <bool> ((!this->InitSymbol || this-> SymbolFlags.count(this->InitSymbol)) && "If set, InitSymbol should appear in InitialSymbolFlags map" ) ? void (0) : __assert_fail ("(!this->InitSymbol || this->SymbolFlags.count(this->InitSymbol)) && \"If set, InitSymbol should appear in InitialSymbolFlags map\"" , "llvm/include/llvm/ExecutionEngine/Orc/Core.h", 688, __extension__ __PRETTY_FUNCTION__)); |
689 | } |
690 | |
691 | SymbolFlagsMap SymbolFlags; |
692 | SymbolStringPtr InitSymbol; |
693 | }; |
694 | |
695 | MaterializationUnit(Interface I) |
696 | : SymbolFlags(std::move(I.SymbolFlags)), |
697 | InitSymbol(std::move(I.InitSymbol)) {} |
698 | virtual ~MaterializationUnit() = default; |
699 | |
700 | /// Return the name of this materialization unit. Useful for debugging |
701 | /// output. |
702 | virtual StringRef getName() const = 0; |
703 | |
704 | /// Return the set of symbols that this source provides. |
705 | const SymbolFlagsMap &getSymbols() const { return SymbolFlags; } |
706 | |
707 | /// Returns the initialization symbol for this MaterializationUnit (if any). |
708 | const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; } |
709 | |
710 | /// Implementations of this method should materialize all symbols |
711 | /// in the materialzation unit, except for those that have been |
712 | /// previously discarded. |
713 | virtual void |
714 | materialize(std::unique_ptr<MaterializationResponsibility> R) = 0; |
715 | |
716 | /// Called by JITDylibs to notify MaterializationUnits that the given symbol |
717 | /// has been overridden. |
718 | void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) { |
719 | SymbolFlags.erase(Name); |
720 | if (InitSymbol == Name) { |
721 | DEBUG_WITH_TYPE("orc", {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "In " << getName() << ": discarding init symbol \"" << *Name << "\"\n" ; }; } } while (false) |
722 | dbgs() << "In " << getName() << ": discarding init symbol \""do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "In " << getName() << ": discarding init symbol \"" << *Name << "\"\n" ; }; } } while (false) |
723 | << *Name << "\"\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "In " << getName() << ": discarding init symbol \"" << *Name << "\"\n" ; }; } } while (false) |
724 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "In " << getName() << ": discarding init symbol \"" << *Name << "\"\n" ; }; } } while (false); |
725 | InitSymbol = nullptr; |
726 | } |
727 | discard(JD, std::move(Name)); |
728 | } |
729 | |
730 | protected: |
731 | SymbolFlagsMap SymbolFlags; |
732 | SymbolStringPtr InitSymbol; |
733 | |
734 | private: |
735 | virtual void anchor(); |
736 | |
737 | /// Implementations of this method should discard the given symbol |
738 | /// from the source (e.g. if the source is an LLVM IR Module and the |
739 | /// symbol is a function, delete the function body or mark it available |
740 | /// externally). |
741 | virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0; |
742 | }; |
743 | |
744 | /// A MaterializationUnit implementation for pre-existing absolute symbols. |
745 | /// |
746 | /// All symbols will be resolved and marked ready as soon as the unit is |
747 | /// materialized. |
748 | class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit { |
749 | public: |
750 | AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols); |
751 | |
752 | StringRef getName() const override; |
753 | |
754 | private: |
755 | void materialize(std::unique_ptr<MaterializationResponsibility> R) override; |
756 | void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; |
757 | static MaterializationUnit::Interface extractFlags(const SymbolMap &Symbols); |
758 | |
759 | SymbolMap Symbols; |
760 | }; |
761 | |
762 | /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols. |
763 | /// Useful for inserting absolute symbols into a JITDylib. E.g.: |
764 | /// \code{.cpp} |
765 | /// JITDylib &JD = ...; |
766 | /// SymbolStringPtr Foo = ...; |
767 | /// ExecutorSymbolDef FooSym = ...; |
768 | /// if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}}))) |
769 | /// return Err; |
770 | /// \endcode |
771 | /// |
772 | inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit> |
773 | absoluteSymbols(SymbolMap Symbols) { |
774 | return std::make_unique<AbsoluteSymbolsMaterializationUnit>( |
775 | std::move(Symbols)); |
776 | } |
777 | |
778 | /// A materialization unit for symbol aliases. Allows existing symbols to be |
779 | /// aliased with alternate flags. |
780 | class ReExportsMaterializationUnit : public MaterializationUnit { |
781 | public: |
782 | /// SourceJD is allowed to be nullptr, in which case the source JITDylib is |
783 | /// taken to be whatever JITDylib these definitions are materialized in (and |
784 | /// MatchNonExported has no effect). This is useful for defining aliases |
785 | /// within a JITDylib. |
786 | /// |
787 | /// Note: Care must be taken that no sets of aliases form a cycle, as such |
788 | /// a cycle will result in a deadlock when any symbol in the cycle is |
789 | /// resolved. |
790 | ReExportsMaterializationUnit(JITDylib *SourceJD, |
791 | JITDylibLookupFlags SourceJDLookupFlags, |
792 | SymbolAliasMap Aliases); |
793 | |
794 | StringRef getName() const override; |
795 | |
796 | private: |
797 | void materialize(std::unique_ptr<MaterializationResponsibility> R) override; |
798 | void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; |
799 | static MaterializationUnit::Interface |
800 | extractFlags(const SymbolAliasMap &Aliases); |
801 | |
802 | JITDylib *SourceJD = nullptr; |
803 | JITDylibLookupFlags SourceJDLookupFlags; |
804 | SymbolAliasMap Aliases; |
805 | }; |
806 | |
807 | /// Create a ReExportsMaterializationUnit with the given aliases. |
808 | /// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing |
809 | /// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux" |
810 | /// (for "bar") with: \code{.cpp} |
811 | /// SymbolStringPtr Baz = ...; |
812 | /// SymbolStringPtr Qux = ...; |
813 | /// if (auto Err = JD.define(symbolAliases({ |
814 | /// {Baz, { Foo, JITSymbolFlags::Exported }}, |
815 | /// {Qux, { Bar, JITSymbolFlags::Weak }}})) |
816 | /// return Err; |
817 | /// \endcode |
818 | inline std::unique_ptr<ReExportsMaterializationUnit> |
819 | symbolAliases(SymbolAliasMap Aliases) { |
820 | return std::make_unique<ReExportsMaterializationUnit>( |
821 | nullptr, JITDylibLookupFlags::MatchAllSymbols, std::move(Aliases)); |
822 | } |
823 | |
824 | /// Create a materialization unit for re-exporting symbols from another JITDylib |
825 | /// with alternative names/flags. |
826 | /// SourceJD will be searched using the given JITDylibLookupFlags. |
827 | inline std::unique_ptr<ReExportsMaterializationUnit> |
828 | reexports(JITDylib &SourceJD, SymbolAliasMap Aliases, |
829 | JITDylibLookupFlags SourceJDLookupFlags = |
830 | JITDylibLookupFlags::MatchExportedSymbolsOnly) { |
831 | return std::make_unique<ReExportsMaterializationUnit>( |
832 | &SourceJD, SourceJDLookupFlags, std::move(Aliases)); |
833 | } |
834 | |
835 | /// Build a SymbolAliasMap for the common case where you want to re-export |
836 | /// symbols from another JITDylib with the same linkage/flags. |
837 | Expected<SymbolAliasMap> |
838 | buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols); |
839 | |
840 | /// Represents the state that a symbol has reached during materialization. |
841 | enum class SymbolState : uint8_t { |
842 | Invalid, /// No symbol should be in this state. |
843 | NeverSearched, /// Added to the symbol table, never queried. |
844 | Materializing, /// Queried, materialization begun. |
845 | Resolved, /// Assigned address, still materializing. |
846 | Emitted, /// Emitted to memory, but waiting on transitive dependencies. |
847 | Ready = 0x3f /// Ready and safe for clients to access. |
848 | }; |
849 | |
850 | /// A symbol query that returns results via a callback when results are |
851 | /// ready. |
852 | /// |
853 | /// makes a callback when all symbols are available. |
854 | class AsynchronousSymbolQuery { |
855 | friend class ExecutionSession; |
856 | friend class InProgressFullLookupState; |
857 | friend class JITDylib; |
858 | friend class JITSymbolResolverAdapter; |
859 | friend class MaterializationResponsibility; |
860 | |
861 | public: |
862 | /// Create a query for the given symbols. The NotifyComplete |
863 | /// callback will be called once all queried symbols reach the given |
864 | /// minimum state. |
865 | AsynchronousSymbolQuery(const SymbolLookupSet &Symbols, |
866 | SymbolState RequiredState, |
867 | SymbolsResolvedCallback NotifyComplete); |
868 | |
869 | /// Notify the query that a requested symbol has reached the required state. |
870 | void notifySymbolMetRequiredState(const SymbolStringPtr &Name, |
871 | ExecutorSymbolDef Sym); |
872 | |
873 | /// Returns true if all symbols covered by this query have been |
874 | /// resolved. |
875 | bool isComplete() const { return OutstandingSymbolsCount == 0; } |
876 | |
877 | |
878 | private: |
879 | void handleComplete(ExecutionSession &ES); |
880 | |
881 | SymbolState getRequiredState() { return RequiredState; } |
882 | |
883 | void addQueryDependence(JITDylib &JD, SymbolStringPtr Name); |
884 | |
885 | void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name); |
886 | |
887 | void dropSymbol(const SymbolStringPtr &Name); |
888 | |
889 | void handleFailed(Error Err); |
890 | |
891 | void detach(); |
892 | |
893 | SymbolsResolvedCallback NotifyComplete; |
894 | SymbolDependenceMap QueryRegistrations; |
895 | SymbolMap ResolvedSymbols; |
896 | size_t OutstandingSymbolsCount; |
897 | SymbolState RequiredState; |
898 | }; |
899 | |
900 | /// Wraps state for a lookup-in-progress. |
901 | /// DefinitionGenerators can optionally take ownership of a LookupState object |
902 | /// to suspend a lookup-in-progress while they search for definitions. |
903 | class LookupState { |
904 | friend class OrcV2CAPIHelper; |
905 | friend class ExecutionSession; |
906 | |
907 | public: |
908 | LookupState(); |
909 | LookupState(LookupState &&); |
910 | LookupState &operator=(LookupState &&); |
911 | ~LookupState(); |
912 | |
913 | /// Continue the lookup. This can be called by DefinitionGenerators |
914 | /// to re-start a captured query-application operation. |
915 | void continueLookup(Error Err); |
916 | |
917 | private: |
918 | LookupState(std::unique_ptr<InProgressLookupState> IPLS); |
919 | |
920 | // For C API. |
921 | void reset(InProgressLookupState *IPLS); |
922 | |
923 | std::unique_ptr<InProgressLookupState> IPLS; |
924 | }; |
925 | |
926 | /// Definition generators can be attached to JITDylibs to generate new |
927 | /// definitions for otherwise unresolved symbols during lookup. |
928 | class DefinitionGenerator { |
929 | public: |
930 | virtual ~DefinitionGenerator(); |
931 | |
932 | /// DefinitionGenerators should override this method to insert new |
933 | /// definitions into the parent JITDylib. K specifies the kind of this |
934 | /// lookup. JD specifies the target JITDylib being searched, and |
935 | /// JDLookupFlags specifies whether the search should match against |
936 | /// hidden symbols. Finally, Symbols describes the set of unresolved |
937 | /// symbols and their associated lookup flags. |
938 | virtual Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, |
939 | JITDylibLookupFlags JDLookupFlags, |
940 | const SymbolLookupSet &LookupSet) = 0; |
941 | }; |
942 | |
943 | /// Represents a JIT'd dynamic library. |
944 | /// |
945 | /// This class aims to mimic the behavior of a regular dylib or shared object, |
946 | /// but without requiring the contained program representations to be compiled |
947 | /// up-front. The JITDylib's content is defined by adding MaterializationUnits, |
948 | /// and contained MaterializationUnits will typically rely on the JITDylib's |
949 | /// links-against order to resolve external references (similar to a regular |
950 | /// dylib). |
951 | /// |
952 | /// The JITDylib object is a thin wrapper that references state held by the |
953 | /// ExecutionSession. JITDylibs can be removed, clearing this underlying state |
954 | /// and leaving the JITDylib object in a defunct state. In this state the |
955 | /// JITDylib's name is guaranteed to remain accessible. If the ExecutionSession |
956 | /// is still alive then other operations are callable but will return an Error |
957 | /// or null result (depending on the API). It is illegal to call any operation |
958 | /// other than getName on a JITDylib after the ExecutionSession has been torn |
959 | /// down. |
960 | /// |
961 | /// JITDylibs cannot be moved or copied. Their address is stable, and useful as |
962 | /// a key in some JIT data structures. |
963 | class JITDylib : public ThreadSafeRefCountedBase<JITDylib>, |
964 | public jitlink::JITLinkDylib { |
965 | friend class AsynchronousSymbolQuery; |
966 | friend class ExecutionSession; |
967 | friend class Platform; |
968 | friend class MaterializationResponsibility; |
969 | public: |
970 | |
971 | JITDylib(const JITDylib &) = delete; |
972 | JITDylib &operator=(const JITDylib &) = delete; |
973 | JITDylib(JITDylib &&) = delete; |
974 | JITDylib &operator=(JITDylib &&) = delete; |
975 | ~JITDylib(); |
976 | |
977 | /// Get a reference to the ExecutionSession for this JITDylib. |
978 | /// |
979 | /// It is legal to call this method on a defunct JITDylib, however the result |
980 | /// will only usable if the ExecutionSession is still alive. If this JITDylib |
981 | /// is held by an error that may have torn down the JIT then the result |
982 | /// should not be used. |
983 | ExecutionSession &getExecutionSession() const { return ES; } |
984 | |
985 | /// Dump current JITDylib state to OS. |
986 | /// |
987 | /// It is legal to call this method on a defunct JITDylib. |
988 | void dump(raw_ostream &OS); |
989 | |
990 | /// Calls remove on all trackers currently associated with this JITDylib. |
991 | /// Does not run static deinits. |
992 | /// |
993 | /// Note that removal happens outside the session lock, so new code may be |
994 | /// added concurrently while the clear is underway, and the newly added |
995 | /// code will *not* be cleared. Adding new code concurrently with a clear |
996 | /// is usually a bug and should be avoided. |
997 | /// |
998 | /// It is illegal to call this method on a defunct JITDylib and the client |
999 | /// is responsible for ensuring that they do not do so. |
1000 | Error clear(); |
1001 | |
1002 | /// Get the default resource tracker for this JITDylib. |
1003 | /// |
1004 | /// It is illegal to call this method on a defunct JITDylib and the client |
1005 | /// is responsible for ensuring that they do not do so. |
1006 | ResourceTrackerSP getDefaultResourceTracker(); |
1007 | |
1008 | /// Create a resource tracker for this JITDylib. |
1009 | /// |
1010 | /// It is illegal to call this method on a defunct JITDylib and the client |
1011 | /// is responsible for ensuring that they do not do so. |
1012 | ResourceTrackerSP createResourceTracker(); |
1013 | |
1014 | /// Adds a definition generator to this JITDylib and returns a referenece to |
1015 | /// it. |
1016 | /// |
1017 | /// When JITDylibs are searched during lookup, if no existing definition of |
1018 | /// a symbol is found, then any generators that have been added are run (in |
1019 | /// the order that they were added) to potentially generate a definition. |
1020 | /// |
1021 | /// It is illegal to call this method on a defunct JITDylib and the client |
1022 | /// is responsible for ensuring that they do not do so. |
1023 | template <typename GeneratorT> |
1024 | GeneratorT &addGenerator(std::unique_ptr<GeneratorT> DefGenerator); |
1025 | |
1026 | /// Remove a definition generator from this JITDylib. |
1027 | /// |
1028 | /// The given generator must exist in this JITDylib's generators list (i.e. |
1029 | /// have been added and not yet removed). |
1030 | /// |
1031 | /// It is illegal to call this method on a defunct JITDylib and the client |
1032 | /// is responsible for ensuring that they do not do so. |
1033 | void removeGenerator(DefinitionGenerator &G); |
1034 | |
1035 | /// Set the link order to be used when fixing up definitions in JITDylib. |
1036 | /// This will replace the previous link order, and apply to any symbol |
1037 | /// resolutions made for definitions in this JITDylib after the call to |
1038 | /// setLinkOrder (even if the definition itself was added before the |
1039 | /// call). |
1040 | /// |
1041 | /// If LinkAgainstThisJITDylibFirst is true (the default) then this JITDylib |
1042 | /// will add itself to the beginning of the LinkOrder (Clients should not |
1043 | /// put this JITDylib in the list in this case, to avoid redundant lookups). |
1044 | /// |
1045 | /// If LinkAgainstThisJITDylibFirst is false then the link order will be used |
1046 | /// as-is. The primary motivation for this feature is to support deliberate |
1047 | /// shadowing of symbols in this JITDylib by a facade JITDylib. For example, |
1048 | /// the facade may resolve function names to stubs, and the stubs may compile |
1049 | /// lazily by looking up symbols in this dylib. Adding the facade dylib |
1050 | /// as the first in the link order (instead of this dylib) ensures that |
1051 | /// definitions within this dylib resolve to the lazy-compiling stubs, |
1052 | /// rather than immediately materializing the definitions in this dylib. |
1053 | /// |
1054 | /// It is illegal to call this method on a defunct JITDylib and the client |
1055 | /// is responsible for ensuring that they do not do so. |
1056 | void setLinkOrder(JITDylibSearchOrder NewSearchOrder, |
1057 | bool LinkAgainstThisJITDylibFirst = true); |
1058 | |
1059 | /// Append the given JITDylibSearchOrder to the link order for this |
1060 | /// JITDylib (discarding any elements already present in this JITDylib's |
1061 | /// link order). |
1062 | void addToLinkOrder(const JITDylibSearchOrder &NewLinks); |
1063 | |
1064 | /// Add the given JITDylib to the link order for definitions in this |
1065 | /// JITDylib. |
1066 | /// |
1067 | /// It is illegal to call this method on a defunct JITDylib and the client |
1068 | /// is responsible for ensuring that they do not do so. |
1069 | void addToLinkOrder(JITDylib &JD, |
1070 | JITDylibLookupFlags JDLookupFlags = |
1071 | JITDylibLookupFlags::MatchExportedSymbolsOnly); |
1072 | |
1073 | /// Replace OldJD with NewJD in the link order if OldJD is present. |
1074 | /// Otherwise this operation is a no-op. |
1075 | /// |
1076 | /// It is illegal to call this method on a defunct JITDylib and the client |
1077 | /// is responsible for ensuring that they do not do so. |
1078 | void replaceInLinkOrder(JITDylib &OldJD, JITDylib &NewJD, |
1079 | JITDylibLookupFlags JDLookupFlags = |
1080 | JITDylibLookupFlags::MatchExportedSymbolsOnly); |
1081 | |
1082 | /// Remove the given JITDylib from the link order for this JITDylib if it is |
1083 | /// present. Otherwise this operation is a no-op. |
1084 | /// |
1085 | /// It is illegal to call this method on a defunct JITDylib and the client |
1086 | /// is responsible for ensuring that they do not do so. |
1087 | void removeFromLinkOrder(JITDylib &JD); |
1088 | |
1089 | /// Do something with the link order (run under the session lock). |
1090 | /// |
1091 | /// It is illegal to call this method on a defunct JITDylib and the client |
1092 | /// is responsible for ensuring that they do not do so. |
1093 | template <typename Func> |
1094 | auto withLinkOrderDo(Func &&F) |
1095 | -> decltype(F(std::declval<const JITDylibSearchOrder &>())); |
1096 | |
1097 | /// Define all symbols provided by the materialization unit to be part of this |
1098 | /// JITDylib. |
1099 | /// |
1100 | /// If RT is not specified then the default resource tracker will be used. |
1101 | /// |
1102 | /// This overload always takes ownership of the MaterializationUnit. If any |
1103 | /// errors occur, the MaterializationUnit consumed. |
1104 | /// |
1105 | /// It is illegal to call this method on a defunct JITDylib and the client |
1106 | /// is responsible for ensuring that they do not do so. |
1107 | template <typename MaterializationUnitType> |
1108 | Error define(std::unique_ptr<MaterializationUnitType> &&MU, |
1109 | ResourceTrackerSP RT = nullptr); |
1110 | |
1111 | /// Define all symbols provided by the materialization unit to be part of this |
1112 | /// JITDylib. |
1113 | /// |
1114 | /// This overload only takes ownership of the MaterializationUnit no error is |
1115 | /// generated. If an error occurs, ownership remains with the caller. This |
1116 | /// may allow the caller to modify the MaterializationUnit to correct the |
1117 | /// issue, then re-call define. |
1118 | /// |
1119 | /// It is illegal to call this method on a defunct JITDylib and the client |
1120 | /// is responsible for ensuring that they do not do so. |
1121 | template <typename MaterializationUnitType> |
1122 | Error define(std::unique_ptr<MaterializationUnitType> &MU, |
1123 | ResourceTrackerSP RT = nullptr); |
1124 | |
1125 | /// Tries to remove the given symbols. |
1126 | /// |
1127 | /// If any symbols are not defined in this JITDylib this method will return |
1128 | /// a SymbolsNotFound error covering the missing symbols. |
1129 | /// |
1130 | /// If all symbols are found but some symbols are in the process of being |
1131 | /// materialized this method will return a SymbolsCouldNotBeRemoved error. |
1132 | /// |
1133 | /// On success, all symbols are removed. On failure, the JITDylib state is |
1134 | /// left unmodified (no symbols are removed). |
1135 | /// |
1136 | /// It is illegal to call this method on a defunct JITDylib and the client |
1137 | /// is responsible for ensuring that they do not do so. |
1138 | Error remove(const SymbolNameSet &Names); |
1139 | |
1140 | /// Returns the given JITDylibs and all of their transitive dependencies in |
1141 | /// DFS order (based on linkage relationships). Each JITDylib will appear |
1142 | /// only once. |
1143 | /// |
1144 | /// If any JITDylib in the order is defunct then this method will return an |
1145 | /// error, otherwise returns the order. |
1146 | static Expected<std::vector<JITDylibSP>> |
1147 | getDFSLinkOrder(ArrayRef<JITDylibSP> JDs); |
1148 | |
1149 | /// Returns the given JITDylibs and all of their transitive dependencies in |
1150 | /// reverse DFS order (based on linkage relationships). Each JITDylib will |
1151 | /// appear only once. |
1152 | /// |
1153 | /// If any JITDylib in the order is defunct then this method will return an |
1154 | /// error, otherwise returns the order. |
1155 | static Expected<std::vector<JITDylibSP>> |
1156 | getReverseDFSLinkOrder(ArrayRef<JITDylibSP> JDs); |
1157 | |
1158 | /// Return this JITDylib and its transitive dependencies in DFS order |
1159 | /// based on linkage relationships. |
1160 | /// |
1161 | /// If any JITDylib in the order is defunct then this method will return an |
1162 | /// error, otherwise returns the order. |
1163 | Expected<std::vector<JITDylibSP>> getDFSLinkOrder(); |
1164 | |
1165 | /// Rteurn this JITDylib and its transitive dependencies in reverse DFS order |
1166 | /// based on linkage relationships. |
1167 | /// |
1168 | /// If any JITDylib in the order is defunct then this method will return an |
1169 | /// error, otherwise returns the order. |
1170 | Expected<std::vector<JITDylibSP>> getReverseDFSLinkOrder(); |
1171 | |
1172 | private: |
1173 | using AsynchronousSymbolQuerySet = |
1174 | std::set<std::shared_ptr<AsynchronousSymbolQuery>>; |
1175 | |
1176 | using AsynchronousSymbolQueryList = |
1177 | std::vector<std::shared_ptr<AsynchronousSymbolQuery>>; |
1178 | |
1179 | struct UnmaterializedInfo { |
1180 | UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU, |
1181 | ResourceTracker *RT) |
1182 | : MU(std::move(MU)), RT(RT) {} |
1183 | |
1184 | std::unique_ptr<MaterializationUnit> MU; |
1185 | ResourceTracker *RT; |
1186 | }; |
1187 | |
1188 | using UnmaterializedInfosMap = |
1189 | DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>; |
1190 | |
1191 | using UnmaterializedInfosList = |
1192 | std::vector<std::shared_ptr<UnmaterializedInfo>>; |
1193 | |
1194 | struct MaterializingInfo { |
1195 | SymbolDependenceMap Dependants; |
1196 | SymbolDependenceMap UnemittedDependencies; |
1197 | |
1198 | void addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q); |
1199 | void removeQuery(const AsynchronousSymbolQuery &Q); |
1200 | AsynchronousSymbolQueryList takeQueriesMeeting(SymbolState RequiredState); |
1201 | AsynchronousSymbolQueryList takeAllPendingQueries() { |
1202 | return std::move(PendingQueries); |
1203 | } |
1204 | bool hasQueriesPending() const { return !PendingQueries.empty(); } |
1205 | const AsynchronousSymbolQueryList &pendingQueries() const { |
1206 | return PendingQueries; |
1207 | } |
1208 | private: |
1209 | AsynchronousSymbolQueryList PendingQueries; |
1210 | }; |
1211 | |
1212 | using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>; |
1213 | |
1214 | class SymbolTableEntry { |
1215 | public: |
1216 | SymbolTableEntry() = default; |
1217 | SymbolTableEntry(JITSymbolFlags Flags) |
1218 | : Flags(Flags), State(static_cast<uint8_t>(SymbolState::NeverSearched)), |
1219 | MaterializerAttached(false), PendingRemoval(false) {} |
1220 | |
1221 | ExecutorAddr getAddress() const { return Addr; } |
1222 | JITSymbolFlags getFlags() const { return Flags; } |
1223 | SymbolState getState() const { return static_cast<SymbolState>(State); } |
1224 | |
1225 | bool hasMaterializerAttached() const { return MaterializerAttached; } |
1226 | bool isPendingRemoval() const { return PendingRemoval; } |
1227 | |
1228 | void setAddress(ExecutorAddr Addr) { this->Addr = Addr; } |
1229 | void setFlags(JITSymbolFlags Flags) { this->Flags = Flags; } |
1230 | void setState(SymbolState State) { |
1231 | assert(static_cast<uint8_t>(State) < (1 << 6) &&(static_cast <bool> (static_cast<uint8_t>(State) < (1 << 6) && "State does not fit in bitfield") ? void (0) : __assert_fail ("static_cast<uint8_t>(State) < (1 << 6) && \"State does not fit in bitfield\"" , "llvm/include/llvm/ExecutionEngine/Orc/Core.h", 1232, __extension__ __PRETTY_FUNCTION__)) |
1232 | "State does not fit in bitfield")(static_cast <bool> (static_cast<uint8_t>(State) < (1 << 6) && "State does not fit in bitfield") ? void (0) : __assert_fail ("static_cast<uint8_t>(State) < (1 << 6) && \"State does not fit in bitfield\"" , "llvm/include/llvm/ExecutionEngine/Orc/Core.h", 1232, __extension__ __PRETTY_FUNCTION__)); |
1233 | this->State = static_cast<uint8_t>(State); |
1234 | } |
1235 | |
1236 | void setMaterializerAttached(bool MaterializerAttached) { |
1237 | this->MaterializerAttached = MaterializerAttached; |
1238 | } |
1239 | |
1240 | void setPendingRemoval(bool PendingRemoval) { |
1241 | this->PendingRemoval = PendingRemoval; |
1242 | } |
1243 | |
1244 | ExecutorSymbolDef getSymbol() const { return {Addr, Flags}; } |
1245 | |
1246 | private: |
1247 | ExecutorAddr Addr; |
1248 | JITSymbolFlags Flags; |
1249 | uint8_t State : 6; |
1250 | uint8_t MaterializerAttached : 1; |
1251 | uint8_t PendingRemoval : 1; |
1252 | }; |
1253 | |
1254 | using SymbolTable = DenseMap<SymbolStringPtr, SymbolTableEntry>; |
1255 | |
1256 | JITDylib(ExecutionSession &ES, std::string Name); |
1257 | |
1258 | std::pair<AsynchronousSymbolQuerySet, std::shared_ptr<SymbolDependenceMap>> |
1259 | removeTracker(ResourceTracker &RT); |
1260 | |
1261 | void transferTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT); |
1262 | |
1263 | Error defineImpl(MaterializationUnit &MU); |
1264 | |
1265 | void installMaterializationUnit(std::unique_ptr<MaterializationUnit> MU, |
1266 | ResourceTracker &RT); |
1267 | |
1268 | void detachQueryHelper(AsynchronousSymbolQuery &Q, |
1269 | const SymbolNameSet &QuerySymbols); |
1270 | |
1271 | void transferEmittedNodeDependencies(MaterializingInfo &DependantMI, |
1272 | const SymbolStringPtr &DependantName, |
1273 | MaterializingInfo &EmittedMI); |
1274 | |
1275 | Expected<SymbolFlagsMap> defineMaterializing(SymbolFlagsMap SymbolFlags); |
1276 | |
1277 | Error replace(MaterializationResponsibility &FromMR, |
1278 | std::unique_ptr<MaterializationUnit> MU); |
1279 | |
1280 | Expected<std::unique_ptr<MaterializationResponsibility>> |
1281 | delegate(MaterializationResponsibility &FromMR, SymbolFlagsMap SymbolFlags, |
1282 | SymbolStringPtr InitSymbol); |
1283 | |
1284 | SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const; |
1285 | |
1286 | void addDependencies(const SymbolStringPtr &Name, |
1287 | const SymbolDependenceMap &Dependants); |
1288 | |
1289 | Error resolve(MaterializationResponsibility &MR, const SymbolMap &Resolved); |
1290 | |
1291 | Error emit(MaterializationResponsibility &MR, const SymbolFlagsMap &Emitted); |
1292 | |
1293 | void unlinkMaterializationResponsibility(MaterializationResponsibility &MR); |
1294 | |
1295 | using FailedSymbolsWorklist = |
1296 | std::vector<std::pair<JITDylib *, SymbolStringPtr>>; |
1297 | |
1298 | static std::pair<AsynchronousSymbolQuerySet, |
1299 | std::shared_ptr<SymbolDependenceMap>> |
1300 | failSymbols(FailedSymbolsWorklist); |
1301 | |
1302 | ExecutionSession &ES; |
1303 | enum { Open, Closing, Closed } State = Open; |
1304 | std::mutex GeneratorsMutex; |
1305 | SymbolTable Symbols; |
1306 | UnmaterializedInfosMap UnmaterializedInfos; |
1307 | MaterializingInfosMap MaterializingInfos; |
1308 | std::vector<std::shared_ptr<DefinitionGenerator>> DefGenerators; |
1309 | JITDylibSearchOrder LinkOrder; |
1310 | ResourceTrackerSP DefaultTracker; |
1311 | |
1312 | // Map trackers to sets of symbols tracked. |
1313 | DenseMap<ResourceTracker *, SymbolNameVector> TrackerSymbols; |
1314 | DenseMap<ResourceTracker *, DenseSet<MaterializationResponsibility *>> |
1315 | TrackerMRs; |
1316 | }; |
1317 | |
1318 | /// Platforms set up standard symbols and mediate interactions between dynamic |
1319 | /// initializers (e.g. C++ static constructors) and ExecutionSession state. |
1320 | /// Note that Platforms do not automatically run initializers: clients are still |
1321 | /// responsible for doing this. |
1322 | class Platform { |
1323 | public: |
1324 | virtual ~Platform(); |
1325 | |
1326 | /// This method will be called outside the session lock each time a JITDylib |
1327 | /// is created (unless it is created with EmptyJITDylib set) to allow the |
1328 | /// Platform to install any JITDylib specific standard symbols (e.g |
1329 | /// __dso_handle). |
1330 | virtual Error setupJITDylib(JITDylib &JD) = 0; |
1331 | |
1332 | /// This method will be called outside the session lock each time a JITDylib |
1333 | /// is removed to allow the Platform to remove any JITDylib-specific data. |
1334 | virtual Error teardownJITDylib(JITDylib &JD) = 0; |
1335 | |
1336 | /// This method will be called under the ExecutionSession lock each time a |
1337 | /// MaterializationUnit is added to a JITDylib. |
1338 | virtual Error notifyAdding(ResourceTracker &RT, |
1339 | const MaterializationUnit &MU) = 0; |
1340 | |
1341 | /// This method will be called under the ExecutionSession lock when a |
1342 | /// ResourceTracker is removed. |
1343 | virtual Error notifyRemoving(ResourceTracker &RT) = 0; |
1344 | |
1345 | /// A utility function for looking up initializer symbols. Performs a blocking |
1346 | /// lookup for the given symbols in each of the given JITDylibs. |
1347 | /// |
1348 | /// Note: This function is deprecated and will be removed in the near future. |
1349 | static Expected<DenseMap<JITDylib *, SymbolMap>> |
1350 | lookupInitSymbols(ExecutionSession &ES, |
1351 | const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms); |
1352 | |
1353 | /// Performs an async lookup for the given symbols in each of the given |
1354 | /// JITDylibs, calling the given handler once all lookups have completed. |
1355 | static void |
1356 | lookupInitSymbolsAsync(unique_function<void(Error)> OnComplete, |
1357 | ExecutionSession &ES, |
1358 | const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms); |
1359 | }; |
1360 | |
1361 | /// A materialization task. |
1362 | class MaterializationTask : public RTTIExtends<MaterializationTask, Task> { |
1363 | public: |
1364 | static char ID; |
1365 | |
1366 | MaterializationTask(std::unique_ptr<MaterializationUnit> MU, |
1367 | std::unique_ptr<MaterializationResponsibility> MR) |
1368 | : MU(std::move(MU)), MR(std::move(MR)) {} |
1369 | void printDescription(raw_ostream &OS) override; |
1370 | void run() override; |
1371 | |
1372 | private: |
1373 | std::unique_ptr<MaterializationUnit> MU; |
1374 | std::unique_ptr<MaterializationResponsibility> MR; |
1375 | }; |
1376 | |
1377 | /// An ExecutionSession represents a running JIT program. |
1378 | class ExecutionSession { |
1379 | friend class InProgressLookupFlagsState; |
1380 | friend class InProgressFullLookupState; |
1381 | friend class JITDylib; |
1382 | friend class LookupState; |
1383 | friend class MaterializationResponsibility; |
1384 | friend class ResourceTracker; |
1385 | |
1386 | public: |
1387 | /// For reporting errors. |
1388 | using ErrorReporter = std::function<void(Error)>; |
1389 | |
1390 | /// Send a result to the remote. |
1391 | using SendResultFunction = unique_function<void(shared::WrapperFunctionResult)>; |
1392 | |
1393 | /// For dispatching ORC tasks (typically materialization tasks). |
1394 | using DispatchTaskFunction = unique_function<void(std::unique_ptr<Task> T)>; |
1395 | |
1396 | /// An asynchronous wrapper-function callable from the executor via |
1397 | /// jit-dispatch. |
1398 | using JITDispatchHandlerFunction = unique_function<void( |
1399 | SendResultFunction SendResult, |
1400 | const char *ArgData, size_t ArgSize)>; |
1401 | |
1402 | /// A map associating tag names with asynchronous wrapper function |
1403 | /// implementations in the JIT. |
1404 | using JITDispatchHandlerAssociationMap = |
1405 | DenseMap<SymbolStringPtr, JITDispatchHandlerFunction>; |
1406 | |
1407 | /// Construct an ExecutionSession with the given ExecutorProcessControl |
1408 | /// object. |
1409 | ExecutionSession(std::unique_ptr<ExecutorProcessControl> EPC); |
1410 | |
1411 | /// Destroy an ExecutionSession. Verifies that endSession was called prior to |
1412 | /// destruction. |
1413 | ~ExecutionSession(); |
1414 | |
1415 | /// End the session. Closes all JITDylibs and disconnects from the |
1416 | /// executor. Clients must call this method before destroying the session. |
1417 | Error endSession(); |
1418 | |
1419 | /// Get the ExecutorProcessControl object associated with this |
1420 | /// ExecutionSession. |
1421 | ExecutorProcessControl &getExecutorProcessControl() { return *EPC; } |
1422 | |
1423 | /// Return the triple for the executor. |
1424 | const Triple &getTargetTriple() const { return EPC->getTargetTriple(); } |
1425 | |
1426 | /// Get the SymbolStringPool for this instance. |
1427 | std::shared_ptr<SymbolStringPool> getSymbolStringPool() { |
1428 | return EPC->getSymbolStringPool(); |
1429 | } |
1430 | |
1431 | /// Add a symbol name to the SymbolStringPool and return a pointer to it. |
1432 | SymbolStringPtr intern(StringRef SymName) { return EPC->intern(SymName); } |
1433 | |
1434 | /// Set the Platform for this ExecutionSession. |
1435 | void setPlatform(std::unique_ptr<Platform> P) { this->P = std::move(P); } |
1436 | |
1437 | /// Get the Platform for this session. |
1438 | /// Will return null if no Platform has been set for this ExecutionSession. |
1439 | Platform *getPlatform() { return P.get(); } |
1440 | |
1441 | /// Run the given lambda with the session mutex locked. |
1442 | template <typename Func> decltype(auto) runSessionLocked(Func &&F) { |
1443 | std::lock_guard<std::recursive_mutex> Lock(SessionMutex); |
1444 | return F(); |
1445 | } |
1446 | |
1447 | /// Register the given ResourceManager with this ExecutionSession. |
1448 | /// Managers will be notified of events in reverse order of registration. |
1449 | void registerResourceManager(ResourceManager &RM); |
1450 | |
1451 | /// Deregister the given ResourceManager with this ExecutionSession. |
1452 | /// Manager must have been previously registered. |
1453 | void deregisterResourceManager(ResourceManager &RM); |
1454 | |
1455 | /// Return a pointer to the "name" JITDylib. |
1456 | /// Ownership of JITDylib remains within Execution Session |
1457 | JITDylib *getJITDylibByName(StringRef Name); |
1458 | |
1459 | /// Add a new bare JITDylib to this ExecutionSession. |
1460 | /// |
1461 | /// The JITDylib Name is required to be unique. Clients should verify that |
1462 | /// names are not being re-used (E.g. by calling getJITDylibByName) if names |
1463 | /// are based on user input. |
1464 | /// |
1465 | /// This call does not install any library code or symbols into the newly |
1466 | /// created JITDylib. The client is responsible for all configuration. |
1467 | JITDylib &createBareJITDylib(std::string Name); |
1468 | |
1469 | /// Add a new JITDylib to this ExecutionSession. |
1470 | /// |
1471 | /// The JITDylib Name is required to be unique. Clients should verify that |
1472 | /// names are not being re-used (e.g. by calling getJITDylibByName) if names |
1473 | /// are based on user input. |
1474 | /// |
1475 | /// If a Platform is attached then Platform::setupJITDylib will be called to |
1476 | /// install standard platform symbols (e.g. standard library interposes). |
1477 | /// If no Platform is attached this call is equivalent to createBareJITDylib. |
1478 | Expected<JITDylib &> createJITDylib(std::string Name); |
1479 | |
1480 | /// Closes the given JITDylib. |
1481 | /// |
1482 | /// This method clears all resources held for the JITDylib, puts it in the |
1483 | /// closed state, and clears all references held by the ExecutionSession and |
1484 | /// other JITDylibs. No further code can be added to the JITDylib, and the |
1485 | /// object will be freed once any remaining JITDylibSPs to it are destroyed. |
1486 | /// |
1487 | /// This method does *not* run static destructors. |
1488 | /// |
1489 | /// This method can only be called once for each JITDylib. |
1490 | Error removeJITDylib(JITDylib &JD); |
1491 | |
1492 | /// Set the error reporter function. |
1493 | ExecutionSession &setErrorReporter(ErrorReporter ReportError) { |
1494 | this->ReportError = std::move(ReportError); |
1495 | return *this; |
1496 | } |
1497 | |
1498 | /// Report a error for this execution session. |
1499 | /// |
1500 | /// Unhandled errors can be sent here to log them. |
1501 | void reportError(Error Err) { ReportError(std::move(Err)); } |
1502 | |
1503 | /// Set the task dispatch function. |
1504 | ExecutionSession &setDispatchTask(DispatchTaskFunction DispatchTask) { |
1505 | this->DispatchTask = std::move(DispatchTask); |
1506 | return *this; |
1507 | } |
1508 | |
1509 | /// Search the given JITDylibs to find the flags associated with each of the |
1510 | /// given symbols. |
1511 | void lookupFlags(LookupKind K, JITDylibSearchOrder SearchOrder, |
1512 | SymbolLookupSet Symbols, |
1513 | unique_function<void(Expected<SymbolFlagsMap>)> OnComplete); |
1514 | |
1515 | /// Blocking version of lookupFlags. |
1516 | Expected<SymbolFlagsMap> lookupFlags(LookupKind K, |
1517 | JITDylibSearchOrder SearchOrder, |
1518 | SymbolLookupSet Symbols); |
1519 | |
1520 | /// Search the given JITDylibs for the given symbols. |
1521 | /// |
1522 | /// SearchOrder lists the JITDylibs to search. For each dylib, the associated |
1523 | /// boolean indicates whether the search should match against non-exported |
1524 | /// (hidden visibility) symbols in that dylib (true means match against |
1525 | /// non-exported symbols, false means do not match). |
1526 | /// |
1527 | /// The NotifyComplete callback will be called once all requested symbols |
1528 | /// reach the required state. |
1529 | /// |
1530 | /// If all symbols are found, the RegisterDependencies function will be called |
1531 | /// while the session lock is held. This gives clients a chance to register |
1532 | /// dependencies for on the queried symbols for any symbols they are |
1533 | /// materializing (if a MaterializationResponsibility instance is present, |
1534 | /// this can be implemented by calling |
1535 | /// MaterializationResponsibility::addDependencies). If there are no |
1536 | /// dependenant symbols for this query (e.g. it is being made by a top level |
1537 | /// client to get an address to call) then the value NoDependenciesToRegister |
1538 | /// can be used. |
1539 | void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder, |
1540 | SymbolLookupSet Symbols, SymbolState RequiredState, |
1541 | SymbolsResolvedCallback NotifyComplete, |
1542 | RegisterDependenciesFunction RegisterDependencies); |
1543 | |
1544 | /// Blocking version of lookup above. Returns the resolved symbol map. |
1545 | /// If WaitUntilReady is true (the default), will not return until all |
1546 | /// requested symbols are ready (or an error occurs). If WaitUntilReady is |
1547 | /// false, will return as soon as all requested symbols are resolved, |
1548 | /// or an error occurs. If WaitUntilReady is false and an error occurs |
1549 | /// after resolution, the function will return a success value, but the |
1550 | /// error will be reported via reportErrors. |
1551 | Expected<SymbolMap> lookup(const JITDylibSearchOrder &SearchOrder, |
1552 | SymbolLookupSet Symbols, |
1553 | LookupKind K = LookupKind::Static, |
1554 | SymbolState RequiredState = SymbolState::Ready, |
1555 | RegisterDependenciesFunction RegisterDependencies = |
1556 | NoDependenciesToRegister); |
1557 | |
1558 | /// Convenience version of blocking lookup. |
1559 | /// Searches each of the JITDylibs in the search order in turn for the given |
1560 | /// symbol. |
1561 | Expected<ExecutorSymbolDef> |
1562 | lookup(const JITDylibSearchOrder &SearchOrder, SymbolStringPtr Symbol, |
1563 | SymbolState RequiredState = SymbolState::Ready); |
1564 | |
1565 | /// Convenience version of blocking lookup. |
1566 | /// Searches each of the JITDylibs in the search order in turn for the given |
1567 | /// symbol. The search will not find non-exported symbols. |
1568 | Expected<ExecutorSymbolDef> |
1569 | lookup(ArrayRef<JITDylib *> SearchOrder, SymbolStringPtr Symbol, |
1570 | SymbolState RequiredState = SymbolState::Ready); |
1571 | |
1572 | /// Convenience version of blocking lookup. |
1573 | /// Searches each of the JITDylibs in the search order in turn for the given |
1574 | /// symbol. The search will not find non-exported symbols. |
1575 | Expected<ExecutorSymbolDef> |
1576 | lookup(ArrayRef<JITDylib *> SearchOrder, StringRef Symbol, |
1577 | SymbolState RequiredState = SymbolState::Ready); |
1578 | |
1579 | /// Materialize the given unit. |
1580 | void dispatchTask(std::unique_ptr<Task> T) { |
1581 | assert(T && "T must be non-null")(static_cast <bool> (T && "T must be non-null") ? void (0) : __assert_fail ("T && \"T must be non-null\"" , "llvm/include/llvm/ExecutionEngine/Orc/Core.h", 1581, __extension__ __PRETTY_FUNCTION__)); |
1582 | DEBUG_WITH_TYPE("orc", dumpDispatchInfo(*T))do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { dumpDispatchInfo(*T); } } while (false); |
1583 | DispatchTask(std::move(T)); |
1584 | } |
1585 | |
1586 | /// Run a wrapper function in the executor. |
1587 | /// |
1588 | /// The wrapper function should be callable as: |
1589 | /// |
1590 | /// \code{.cpp} |
1591 | /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size); |
1592 | /// \endcode{.cpp} |
1593 | /// |
1594 | /// The given OnComplete function will be called to return the result. |
1595 | template <typename... ArgTs> |
1596 | void callWrapperAsync(ArgTs &&... Args) { |
1597 | EPC->callWrapperAsync(std::forward<ArgTs>(Args)...); |
1598 | } |
1599 | |
1600 | /// Run a wrapper function in the executor. The wrapper function should be |
1601 | /// callable as: |
1602 | /// |
1603 | /// \code{.cpp} |
1604 | /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size); |
1605 | /// \endcode{.cpp} |
1606 | shared::WrapperFunctionResult callWrapper(ExecutorAddr WrapperFnAddr, |
1607 | ArrayRef<char> ArgBuffer) { |
1608 | return EPC->callWrapper(WrapperFnAddr, ArgBuffer); |
1609 | } |
1610 | |
1611 | /// Run a wrapper function using SPS to serialize the arguments and |
1612 | /// deserialize the results. |
1613 | template <typename SPSSignature, typename SendResultT, typename... ArgTs> |
1614 | void callSPSWrapperAsync(ExecutorAddr WrapperFnAddr, SendResultT &&SendResult, |
1615 | const ArgTs &...Args) { |
1616 | EPC->callSPSWrapperAsync<SPSSignature, SendResultT, ArgTs...>( |
1617 | WrapperFnAddr, std::forward<SendResultT>(SendResult), Args...); |
1618 | } |
1619 | |
1620 | /// Run a wrapper function using SPS to serialize the arguments and |
1621 | /// deserialize the results. |
1622 | /// |
1623 | /// If SPSSignature is a non-void function signature then the second argument |
1624 | /// (the first in the Args list) should be a reference to a return value. |
1625 | template <typename SPSSignature, typename... WrapperCallArgTs> |
1626 | Error callSPSWrapper(ExecutorAddr WrapperFnAddr, |
1627 | WrapperCallArgTs &&...WrapperCallArgs) { |
1628 | return EPC->callSPSWrapper<SPSSignature, WrapperCallArgTs...>( |
1629 | WrapperFnAddr, std::forward<WrapperCallArgTs>(WrapperCallArgs)...); |
1630 | } |
1631 | |
1632 | /// Wrap a handler that takes concrete argument types (and a sender for a |
1633 | /// concrete return type) to produce an AsyncHandlerWrapperFunction. Uses SPS |
1634 | /// to unpack the arguments and pack the result. |
1635 | /// |
1636 | /// This function is intended to support easy construction of |
1637 | /// AsyncHandlerWrapperFunctions that can be associated with a tag |
1638 | /// (using registerJITDispatchHandler) and called from the executor. |
1639 | template <typename SPSSignature, typename HandlerT> |
1640 | static JITDispatchHandlerFunction wrapAsyncWithSPS(HandlerT &&H) { |
1641 | return [H = std::forward<HandlerT>(H)]( |
1642 | SendResultFunction SendResult, |
1643 | const char *ArgData, size_t ArgSize) mutable { |
1644 | shared::WrapperFunction<SPSSignature>::handleAsync(ArgData, ArgSize, H, |
1645 | std::move(SendResult)); |
1646 | }; |
1647 | } |
1648 | |
1649 | /// Wrap a class method that takes concrete argument types (and a sender for |
1650 | /// a concrete return type) to produce an AsyncHandlerWrapperFunction. Uses |
1651 | /// SPS to unpack teh arguments and pack the result. |
1652 | /// |
1653 | /// This function is intended to support easy construction of |
1654 | /// AsyncHandlerWrapperFunctions that can be associated with a tag |
1655 | /// (using registerJITDispatchHandler) and called from the executor. |
1656 | template <typename SPSSignature, typename ClassT, typename... MethodArgTs> |
1657 | static JITDispatchHandlerFunction |
1658 | wrapAsyncWithSPS(ClassT *Instance, void (ClassT::*Method)(MethodArgTs...)) { |
1659 | return wrapAsyncWithSPS<SPSSignature>( |
1660 | [Instance, Method](MethodArgTs &&...MethodArgs) { |
1661 | (Instance->*Method)(std::forward<MethodArgTs>(MethodArgs)...); |
1662 | }); |
1663 | } |
1664 | |
1665 | /// For each tag symbol name, associate the corresponding |
1666 | /// AsyncHandlerWrapperFunction with the address of that symbol. The |
1667 | /// handler becomes callable from the executor using the ORC runtime |
1668 | /// __orc_rt_jit_dispatch function and the given tag. |
1669 | /// |
1670 | /// Tag symbols will be looked up in JD using LookupKind::Static, |
1671 | /// JITDylibLookupFlags::MatchAllSymbols (hidden tags will be found), and |
1672 | /// LookupFlags::WeaklyReferencedSymbol. Missing tag definitions will not |
1673 | /// cause an error, the handler will simply be dropped. |
1674 | Error registerJITDispatchHandlers(JITDylib &JD, |
1675 | JITDispatchHandlerAssociationMap WFs); |
1676 | |
1677 | /// Run a registered jit-side wrapper function. |
1678 | /// This should be called by the ExecutorProcessControl instance in response |
1679 | /// to incoming jit-dispatch requests from the executor. |
1680 | void runJITDispatchHandler(SendResultFunction SendResult, |
1681 | ExecutorAddr HandlerFnTagAddr, |
1682 | ArrayRef<char> ArgBuffer); |
1683 | |
1684 | /// Dump the state of all the JITDylibs in this session. |
1685 | void dump(raw_ostream &OS); |
1686 | |
1687 | private: |
1688 | static void logErrorsToStdErr(Error Err) { |
1689 | logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: "); |
1690 | } |
1691 | |
1692 | static void runOnCurrentThread(std::unique_ptr<Task> T) { T->run(); } |
1693 | |
1694 | void dispatchOutstandingMUs(); |
1695 | |
1696 | static std::unique_ptr<MaterializationResponsibility> |
1697 | createMaterializationResponsibility(ResourceTracker &RT, |
1698 | SymbolFlagsMap Symbols, |
1699 | SymbolStringPtr InitSymbol) { |
1700 | auto &JD = RT.getJITDylib(); |
1701 | std::unique_ptr<MaterializationResponsibility> MR( |
1702 | new MaterializationResponsibility(&RT, std::move(Symbols), |
1703 | std::move(InitSymbol))); |
1704 | JD.TrackerMRs[&RT].insert(MR.get()); |
1705 | return MR; |
1706 | } |
1707 | |
1708 | Error removeResourceTracker(ResourceTracker &RT); |
1709 | void transferResourceTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT); |
1710 | void destroyResourceTracker(ResourceTracker &RT); |
1711 | |
1712 | // State machine functions for query application.. |
1713 | |
1714 | /// IL_updateCandidatesFor is called to remove already-defined symbols that |
1715 | /// match a given query from the set of candidate symbols to generate |
1716 | /// definitions for (no need to generate a definition if one already exists). |
1717 | Error IL_updateCandidatesFor(JITDylib &JD, JITDylibLookupFlags JDLookupFlags, |
1718 | SymbolLookupSet &Candidates, |
1719 | SymbolLookupSet *NonCandidates); |
1720 | |
1721 | /// OL_applyQueryPhase1 is an optionally re-startable loop for triggering |
1722 | /// definition generation. It is called when a lookup is performed, and again |
1723 | /// each time that LookupState::continueLookup is called. |
1724 | void OL_applyQueryPhase1(std::unique_ptr<InProgressLookupState> IPLS, |
1725 | Error Err); |
1726 | |
1727 | /// OL_completeLookup is run once phase 1 successfully completes for a lookup |
1728 | /// call. It attempts to attach the symbol to all symbol table entries and |
1729 | /// collect all MaterializationUnits to dispatch. If this method fails then |
1730 | /// all MaterializationUnits will be left un-materialized. |
1731 | void OL_completeLookup(std::unique_ptr<InProgressLookupState> IPLS, |
1732 | std::shared_ptr<AsynchronousSymbolQuery> Q, |
1733 | RegisterDependenciesFunction RegisterDependencies); |
1734 | |
1735 | /// OL_completeLookupFlags is run once phase 1 successfully completes for a |
1736 | /// lookupFlags call. |
1737 | void OL_completeLookupFlags( |
1738 | std::unique_ptr<InProgressLookupState> IPLS, |
1739 | unique_function<void(Expected<SymbolFlagsMap>)> OnComplete); |
1740 | |
1741 | // State machine functions for MaterializationResponsibility. |
1742 | void OL_destroyMaterializationResponsibility( |
1743 | MaterializationResponsibility &MR); |
1744 | SymbolNameSet OL_getRequestedSymbols(const MaterializationResponsibility &MR); |
1745 | Error OL_notifyResolved(MaterializationResponsibility &MR, |
1746 | const SymbolMap &Symbols); |
1747 | Error OL_notifyEmitted(MaterializationResponsibility &MR); |
1748 | Error OL_defineMaterializing(MaterializationResponsibility &MR, |
1749 | SymbolFlagsMap SymbolFlags); |
1750 | void OL_notifyFailed(MaterializationResponsibility &MR); |
1751 | Error OL_replace(MaterializationResponsibility &MR, |
1752 | std::unique_ptr<MaterializationUnit> MU); |
1753 | Expected<std::unique_ptr<MaterializationResponsibility>> |
1754 | OL_delegate(MaterializationResponsibility &MR, const SymbolNameSet &Symbols); |
1755 | void OL_addDependencies(MaterializationResponsibility &MR, |
1756 | const SymbolStringPtr &Name, |
1757 | const SymbolDependenceMap &Dependencies); |
1758 | void OL_addDependenciesForAll(MaterializationResponsibility &MR, |
1759 | const SymbolDependenceMap &Dependencies); |
1760 | |
1761 | #ifndef NDEBUG |
1762 | void dumpDispatchInfo(Task &T); |
1763 | #endif // NDEBUG |
1764 | |
1765 | mutable std::recursive_mutex SessionMutex; |
1766 | bool SessionOpen = true; |
1767 | std::unique_ptr<ExecutorProcessControl> EPC; |
1768 | std::unique_ptr<Platform> P; |
1769 | ErrorReporter ReportError = logErrorsToStdErr; |
1770 | DispatchTaskFunction DispatchTask = runOnCurrentThread; |
1771 | |
1772 | std::vector<ResourceManager *> ResourceManagers; |
1773 | |
1774 | std::vector<JITDylibSP> JDs; |
1775 | |
1776 | // FIXME: Remove this (and runOutstandingMUs) once the linking layer works |
1777 | // with callbacks from asynchronous queries. |
1778 | mutable std::recursive_mutex OutstandingMUsMutex; |
1779 | std::vector<std::pair<std::unique_ptr<MaterializationUnit>, |
1780 | std::unique_ptr<MaterializationResponsibility>>> |
1781 | OutstandingMUs; |
1782 | |
1783 | mutable std::mutex JITDispatchHandlersMutex; |
1784 | DenseMap<ExecutorAddr, std::shared_ptr<JITDispatchHandlerFunction>> |
1785 | JITDispatchHandlers; |
1786 | }; |
1787 | |
1788 | template <typename Func> Error ResourceTracker::withResourceKeyDo(Func &&F) { |
1789 | return getJITDylib().getExecutionSession().runSessionLocked([&]() -> Error { |
1790 | if (isDefunct()) |
1791 | return make_error<ResourceTrackerDefunct>(this); |
1792 | F(getKeyUnsafe()); |
1793 | return Error::success(); |
1794 | }); |
1795 | } |
1796 | |
1797 | inline ExecutionSession & |
1798 | MaterializationResponsibility::getExecutionSession() const { |
1799 | return JD.getExecutionSession(); |
1800 | } |
1801 | |
1802 | template <typename GeneratorT> |
1803 | GeneratorT &JITDylib::addGenerator(std::unique_ptr<GeneratorT> DefGenerator) { |
1804 | auto &G = *DefGenerator; |
1805 | ES.runSessionLocked([&] { |
1806 | assert(State == Open && "Cannot add generator to closed JITDylib")(static_cast <bool> (State == Open && "Cannot add generator to closed JITDylib" ) ? void (0) : __assert_fail ("State == Open && \"Cannot add generator to closed JITDylib\"" , "llvm/include/llvm/ExecutionEngine/Orc/Core.h", 1806, __extension__ __PRETTY_FUNCTION__)); |
1807 | DefGenerators.push_back(std::move(DefGenerator)); |
1808 | }); |
1809 | return G; |
1810 | } |
1811 | |
1812 | template <typename Func> |
1813 | auto JITDylib::withLinkOrderDo(Func &&F) |
1814 | -> decltype(F(std::declval<const JITDylibSearchOrder &>())) { |
1815 | assert(State == Open && "Cannot use link order of closed JITDylib")(static_cast <bool> (State == Open && "Cannot use link order of closed JITDylib" ) ? void (0) : __assert_fail ("State == Open && \"Cannot use link order of closed JITDylib\"" , "llvm/include/llvm/ExecutionEngine/Orc/Core.h", 1815, __extension__ __PRETTY_FUNCTION__)); |
1816 | return ES.runSessionLocked([&]() { return F(LinkOrder); }); |
1817 | } |
1818 | |
1819 | template <typename MaterializationUnitType> |
1820 | Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU, |
1821 | ResourceTrackerSP RT) { |
1822 | assert(MU && "Can not define with a null MU")(static_cast <bool> (MU && "Can not define with a null MU" ) ? void (0) : __assert_fail ("MU && \"Can not define with a null MU\"" , "llvm/include/llvm/ExecutionEngine/Orc/Core.h", 1822, __extension__ __PRETTY_FUNCTION__)); |
1823 | |
1824 | if (MU->getSymbols().empty()) { |
1825 | // Empty MUs are allowable but pathological, so issue a warning. |
1826 | DEBUG_WITH_TYPE("orc", {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Warning: Discarding empty MU " << MU->getName() << " for " << getName() << "\n"; }; } } while (false) |
1827 | dbgs() << "Warning: Discarding empty MU " << MU->getName() << " for "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Warning: Discarding empty MU " << MU->getName() << " for " << getName() << "\n"; }; } } while (false) |
1828 | << getName() << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Warning: Discarding empty MU " << MU->getName() << " for " << getName() << "\n"; }; } } while (false) |
1829 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Warning: Discarding empty MU " << MU->getName() << " for " << getName() << "\n"; }; } } while (false); |
1830 | return Error::success(); |
1831 | } else |
1832 | DEBUG_WITH_TYPE("orc", {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1833 | dbgs() << "Defining MU " << MU->getName() << " for " << getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1834 | << " (tracker: ";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1835 | if (RT == getDefaultResourceTracker())do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1836 | dbgs() << "default)";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1837 | else if (RT)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1838 | dbgs() << RT.get() << ")\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1839 | elsedo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1840 | dbgs() << "0x0, default will be used)\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1841 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ); |
1842 | |
1843 | return ES.runSessionLocked([&, this]() -> Error { |
1844 | assert(State == Open && "JD is defunct")(static_cast <bool> (State == Open && "JD is defunct" ) ? void (0) : __assert_fail ("State == Open && \"JD is defunct\"" , "llvm/include/llvm/ExecutionEngine/Orc/Core.h", 1844, __extension__ __PRETTY_FUNCTION__)); |
1845 | |
1846 | if (auto Err = defineImpl(*MU)) |
1847 | return Err; |
1848 | |
1849 | if (!RT) |
1850 | RT = getDefaultResourceTracker(); |
1851 | |
1852 | if (auto *P = ES.getPlatform()) { |
1853 | if (auto Err = P->notifyAdding(*RT, *MU)) |
1854 | return Err; |
1855 | } |
1856 | |
1857 | installMaterializationUnit(std::move(MU), *RT); |
1858 | return Error::success(); |
1859 | }); |
1860 | } |
1861 | |
1862 | template <typename MaterializationUnitType> |
1863 | Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU, |
1864 | ResourceTrackerSP RT) { |
1865 | assert(MU && "Can not define with a null MU")(static_cast <bool> (MU && "Can not define with a null MU" ) ? void (0) : __assert_fail ("MU && \"Can not define with a null MU\"" , "llvm/include/llvm/ExecutionEngine/Orc/Core.h", 1865, __extension__ __PRETTY_FUNCTION__)); |
1866 | |
1867 | if (MU->getSymbols().empty()) { |
1868 | // Empty MUs are allowable but pathological, so issue a warning. |
1869 | DEBUG_WITH_TYPE("orc", {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Warning: Discarding empty MU " << MU->getName() << getName() << "\n"; }; } } while (false) |
1870 | dbgs() << "Warning: Discarding empty MU " << MU->getName() << getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Warning: Discarding empty MU " << MU->getName() << getName() << "\n"; }; } } while (false) |
1871 | << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Warning: Discarding empty MU " << MU->getName() << getName() << "\n"; }; } } while (false) |
1872 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Warning: Discarding empty MU " << MU->getName() << getName() << "\n"; }; } } while (false); |
1873 | return Error::success(); |
1874 | } else |
1875 | DEBUG_WITH_TYPE("orc", {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1876 | dbgs() << "Defining MU " << MU->getName() << " for " << getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1877 | << " (tracker: ";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1878 | if (RT == getDefaultResourceTracker())do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1879 | dbgs() << "default)";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1880 | else if (RT)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1881 | dbgs() << RT.get() << ")\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1882 | elsedo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1883 | dbgs() << "0x0, default will be used)\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ) |
1884 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("orc")) { { dbgs() << "Defining MU " << MU->getName () << " for " << getName() << " (tracker: " ; if (RT == getDefaultResourceTracker()) dbgs() << "default)" ; else if (RT) dbgs() << RT.get() << ")\n"; else dbgs () << "0x0, default will be used)\n"; }; } } while (false ); |
1885 | |
1886 | return ES.runSessionLocked([&, this]() -> Error { |
1887 | assert(State == Open && "JD is defunct")(static_cast <bool> (State == Open && "JD is defunct" ) ? void (0) : __assert_fail ("State == Open && \"JD is defunct\"" , "llvm/include/llvm/ExecutionEngine/Orc/Core.h", 1887, __extension__ __PRETTY_FUNCTION__)); |
1888 | |
1889 | if (auto Err = defineImpl(*MU)) |
1890 | return Err; |
1891 | |
1892 | if (!RT) |
1893 | RT = getDefaultResourceTracker(); |
1894 | |
1895 | if (auto *P = ES.getPlatform()) { |
1896 | if (auto Err = P->notifyAdding(*RT, *MU)) |
1897 | return Err; |
1898 | } |
1899 | |
1900 | installMaterializationUnit(std::move(MU), *RT); |
1901 | return Error::success(); |
1902 | }); |
1903 | } |
1904 | |
1905 | /// ReexportsGenerator can be used with JITDylib::addGenerator to automatically |
1906 | /// re-export a subset of the source JITDylib's symbols in the target. |
1907 | class ReexportsGenerator : public DefinitionGenerator { |
1908 | public: |
1909 | using SymbolPredicate = std::function<bool(SymbolStringPtr)>; |
1910 | |
1911 | /// Create a reexports generator. If an Allow predicate is passed, only |
1912 | /// symbols for which the predicate returns true will be reexported. If no |
1913 | /// Allow predicate is passed, all symbols will be exported. |
1914 | ReexportsGenerator(JITDylib &SourceJD, |
1915 | JITDylibLookupFlags SourceJDLookupFlags, |
1916 | SymbolPredicate Allow = SymbolPredicate()); |
1917 | |
1918 | Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, |
1919 | JITDylibLookupFlags JDLookupFlags, |
1920 | const SymbolLookupSet &LookupSet) override; |
1921 | |
1922 | private: |
1923 | JITDylib &SourceJD; |
1924 | JITDylibLookupFlags SourceJDLookupFlags; |
1925 | SymbolPredicate Allow; |
1926 | }; |
1927 | |
1928 | // --------------- IMPLEMENTATION -------------- |
1929 | // Implementations for inline functions/methods. |
1930 | // --------------------------------------------- |
1931 | |
1932 | inline MaterializationResponsibility::~MaterializationResponsibility() { |
1933 | getExecutionSession().OL_destroyMaterializationResponsibility(*this); |
1934 | } |
1935 | |
1936 | inline SymbolNameSet MaterializationResponsibility::getRequestedSymbols() const { |
1937 | return getExecutionSession().OL_getRequestedSymbols(*this); |
1938 | } |
1939 | |
1940 | inline Error MaterializationResponsibility::notifyResolved( |
1941 | const SymbolMap &Symbols) { |
1942 | return getExecutionSession().OL_notifyResolved(*this, Symbols); |
1943 | } |
1944 | |
1945 | inline Error MaterializationResponsibility::notifyEmitted() { |
1946 | return getExecutionSession().OL_notifyEmitted(*this); |
1947 | } |
1948 | |
1949 | inline Error MaterializationResponsibility::defineMaterializing( |
1950 | SymbolFlagsMap SymbolFlags) { |
1951 | return getExecutionSession().OL_defineMaterializing(*this, |
1952 | std::move(SymbolFlags)); |
1953 | } |
1954 | |
1955 | inline void MaterializationResponsibility::failMaterialization() { |
1956 | getExecutionSession().OL_notifyFailed(*this); |
1957 | } |
1958 | |
1959 | inline Error MaterializationResponsibility::replace( |
1960 | std::unique_ptr<MaterializationUnit> MU) { |
1961 | return getExecutionSession().OL_replace(*this, std::move(MU)); |
1962 | } |
1963 | |
1964 | inline Expected<std::unique_ptr<MaterializationResponsibility>> |
1965 | MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) { |
1966 | return getExecutionSession().OL_delegate(*this, Symbols); |
1967 | } |
1968 | |
1969 | inline void MaterializationResponsibility::addDependencies( |
1970 | const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) { |
1971 | getExecutionSession().OL_addDependencies(*this, Name, Dependencies); |
1972 | } |
1973 | |
1974 | inline void MaterializationResponsibility::addDependenciesForAll( |
1975 | const SymbolDependenceMap &Dependencies) { |
1976 | getExecutionSession().OL_addDependenciesForAll(*this, Dependencies); |
1977 | } |
1978 | |
1979 | } // End namespace orc |
1980 | } // End namespace llvm |
1981 | |
1982 | #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H |
1 | //===- ExecutorProcessControl.h - Executor process control APIs -*- C++ -*-===// |
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 | // Utilities for interacting with the executor processes. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H |
14 | #define LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H |
15 | |
16 | #include "llvm/ADT/StringRef.h" |
17 | #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" |
18 | #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" |
19 | #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h" |
20 | #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" |
21 | #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" |
22 | #include "llvm/ExecutionEngine/Orc/TaskDispatch.h" |
23 | #include "llvm/Support/DynamicLibrary.h" |
24 | #include "llvm/Support/MSVCErrorWorkarounds.h" |
25 | #include "llvm/TargetParser/Triple.h" |
26 | |
27 | #include <future> |
28 | #include <mutex> |
29 | #include <vector> |
30 | |
31 | namespace llvm { |
32 | namespace orc { |
33 | |
34 | class ExecutionSession; |
35 | class SymbolLookupSet; |
36 | |
37 | /// ExecutorProcessControl supports interaction with a JIT target process. |
38 | class ExecutorProcessControl { |
39 | friend class ExecutionSession; |
40 | public: |
41 | |
42 | /// A handler or incoming WrapperFunctionResults -- either return values from |
43 | /// callWrapper* calls, or incoming JIT-dispatch requests. |
44 | /// |
45 | /// IncomingWFRHandlers are constructible from |
46 | /// unique_function<void(shared::WrapperFunctionResult)>s using the |
47 | /// runInPlace function or a RunWithDispatch object. |
48 | class IncomingWFRHandler { |
49 | friend class ExecutorProcessControl; |
50 | public: |
51 | IncomingWFRHandler() = default; |
52 | explicit operator bool() const { return !!H; } |
53 | void operator()(shared::WrapperFunctionResult WFR) { H(std::move(WFR)); } |
54 | private: |
55 | template <typename FnT> IncomingWFRHandler(FnT &&Fn) |
56 | : H(std::forward<FnT>(Fn)) {} |
57 | |
58 | unique_function<void(shared::WrapperFunctionResult)> H; |
59 | }; |
60 | |
61 | /// Constructs an IncomingWFRHandler from a function object that is callable |
62 | /// as void(shared::WrapperFunctionResult). The function object will be called |
63 | /// directly. This should be used with care as it may block listener threads |
64 | /// in remote EPCs. It is only suitable for simple tasks (e.g. setting a |
65 | /// future), or for performing some quick analysis before dispatching "real" |
66 | /// work as a Task. |
67 | class RunInPlace { |
68 | public: |
69 | template <typename FnT> |
70 | IncomingWFRHandler operator()(FnT &&Fn) { |
71 | return IncomingWFRHandler(std::forward<FnT>(Fn)); |
72 | } |
73 | }; |
74 | |
75 | /// Constructs an IncomingWFRHandler from a function object by creating a new |
76 | /// function object that dispatches the original using a TaskDispatcher, |
77 | /// wrapping the original as a GenericNamedTask. |
78 | /// |
79 | /// This is the default approach for running WFR handlers. |
80 | class RunAsTask { |
81 | public: |
82 | RunAsTask(TaskDispatcher &D) : D(D) {} |
83 | |
84 | template <typename FnT> |
85 | IncomingWFRHandler operator()(FnT &&Fn) { |
86 | return IncomingWFRHandler( |
87 | [&D = this->D, Fn = std::move(Fn)] |
88 | (shared::WrapperFunctionResult WFR) mutable { |
89 | D.dispatch( |
90 | makeGenericNamedTask( |
91 | [Fn = std::move(Fn), WFR = std::move(WFR)]() mutable { |
92 | Fn(std::move(WFR)); |
93 | }, "WFR handler task")); |
94 | }); |
95 | } |
96 | private: |
97 | TaskDispatcher &D; |
98 | }; |
99 | |
100 | /// APIs for manipulating memory in the target process. |
101 | class MemoryAccess { |
102 | public: |
103 | /// Callback function for asynchronous writes. |
104 | using WriteResultFn = unique_function<void(Error)>; |
105 | |
106 | virtual ~MemoryAccess(); |
107 | |
108 | virtual void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws, |
109 | WriteResultFn OnWriteComplete) = 0; |
110 | |
111 | virtual void writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws, |
112 | WriteResultFn OnWriteComplete) = 0; |
113 | |
114 | virtual void writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws, |
115 | WriteResultFn OnWriteComplete) = 0; |
116 | |
117 | virtual void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws, |
118 | WriteResultFn OnWriteComplete) = 0; |
119 | |
120 | virtual void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws, |
121 | WriteResultFn OnWriteComplete) = 0; |
122 | |
123 | Error writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws) { |
124 | std::promise<MSVCPError> ResultP; |
125 | auto ResultF = ResultP.get_future(); |
126 | writeUInt8sAsync(Ws, |
127 | [&](Error Err) { ResultP.set_value(std::move(Err)); }); |
128 | return ResultF.get(); |
129 | } |
130 | |
131 | Error writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws) { |
132 | std::promise<MSVCPError> ResultP; |
133 | auto ResultF = ResultP.get_future(); |
134 | writeUInt16sAsync(Ws, |
135 | [&](Error Err) { ResultP.set_value(std::move(Err)); }); |
136 | return ResultF.get(); |
137 | } |
138 | |
139 | Error writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws) { |
140 | std::promise<MSVCPError> ResultP; |
141 | auto ResultF = ResultP.get_future(); |
142 | writeUInt32sAsync(Ws, |
143 | [&](Error Err) { ResultP.set_value(std::move(Err)); }); |
144 | return ResultF.get(); |
145 | } |
146 | |
147 | Error writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws) { |
148 | std::promise<MSVCPError> ResultP; |
149 | auto ResultF = ResultP.get_future(); |
150 | writeUInt64sAsync(Ws, |
151 | [&](Error Err) { ResultP.set_value(std::move(Err)); }); |
152 | return ResultF.get(); |
153 | } |
154 | |
155 | Error writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws) { |
156 | std::promise<MSVCPError> ResultP; |
157 | auto ResultF = ResultP.get_future(); |
158 | writeBuffersAsync(Ws, |
159 | [&](Error Err) { ResultP.set_value(std::move(Err)); }); |
160 | return ResultF.get(); |
161 | } |
162 | }; |
163 | |
164 | /// A pair of a dylib and a set of symbols to be looked up. |
165 | struct LookupRequest { |
166 | LookupRequest(tpctypes::DylibHandle Handle, const SymbolLookupSet &Symbols) |
167 | : Handle(Handle), Symbols(Symbols) {} |
168 | tpctypes::DylibHandle Handle; |
169 | const SymbolLookupSet &Symbols; |
170 | }; |
171 | |
172 | /// Contains the address of the dispatch function and context that the ORC |
173 | /// runtime can use to call functions in the JIT. |
174 | struct JITDispatchInfo { |
175 | ExecutorAddr JITDispatchFunction; |
176 | ExecutorAddr JITDispatchContext; |
177 | }; |
178 | |
179 | ExecutorProcessControl(std::shared_ptr<SymbolStringPool> SSP, |
180 | std::unique_ptr<TaskDispatcher> D) |
181 | : SSP(std::move(SSP)), D(std::move(D)) {} |
182 | |
183 | virtual ~ExecutorProcessControl(); |
184 | |
185 | /// Return the ExecutionSession associated with this instance. |
186 | /// Not callable until the ExecutionSession has been associated. |
187 | ExecutionSession &getExecutionSession() { |
188 | assert(ES && "No ExecutionSession associated yet")(static_cast <bool> (ES && "No ExecutionSession associated yet" ) ? void (0) : __assert_fail ("ES && \"No ExecutionSession associated yet\"" , "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" , 188, __extension__ __PRETTY_FUNCTION__)); |
189 | return *ES; |
190 | } |
191 | |
192 | /// Intern a symbol name in the SymbolStringPool. |
193 | SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); } |
194 | |
195 | /// Return a shared pointer to the SymbolStringPool for this instance. |
196 | std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; } |
197 | |
198 | TaskDispatcher &getDispatcher() { return *D; } |
199 | |
200 | /// Return the Triple for the target process. |
201 | const Triple &getTargetTriple() const { return TargetTriple; } |
202 | |
203 | /// Get the page size for the target process. |
204 | unsigned getPageSize() const { return PageSize; } |
205 | |
206 | /// Get the JIT dispatch function and context address for the executor. |
207 | const JITDispatchInfo &getJITDispatchInfo() const { return JDI; } |
208 | |
209 | /// Return a MemoryAccess object for the target process. |
210 | MemoryAccess &getMemoryAccess() const { |
211 | assert(MemAccess && "No MemAccess object set.")(static_cast <bool> (MemAccess && "No MemAccess object set." ) ? void (0) : __assert_fail ("MemAccess && \"No MemAccess object set.\"" , "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" , 211, __extension__ __PRETTY_FUNCTION__)); |
212 | return *MemAccess; |
213 | } |
214 | |
215 | /// Return a JITLinkMemoryManager for the target process. |
216 | jitlink::JITLinkMemoryManager &getMemMgr() const { |
217 | assert(MemMgr && "No MemMgr object set")(static_cast <bool> (MemMgr && "No MemMgr object set" ) ? void (0) : __assert_fail ("MemMgr && \"No MemMgr object set\"" , "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" , 217, __extension__ __PRETTY_FUNCTION__)); |
218 | return *MemMgr; |
219 | } |
220 | |
221 | /// Returns the bootstrap map. |
222 | const StringMap<std::vector<char>> &getBootstrapMap() const { |
223 | return BootstrapMap; |
224 | } |
225 | |
226 | /// Look up and SPS-deserialize a bootstrap map value. |
227 | /// |
228 | /// |
229 | template <typename T, typename SPSTagT> |
230 | Error getBootstrapMapValue(StringRef Key, std::optional<T> &Val) const { |
231 | Val = std::nullopt; |
232 | |
233 | auto I = BootstrapMap.find(Key); |
234 | if (I == BootstrapMap.end()) |
235 | return Error::success(); |
236 | |
237 | T Tmp; |
238 | shared::SPSInputBuffer IB(I->second.data(), I->second.size()); |
239 | if (!shared::SPSArgList<SPSTagT>::deserialize(IB, Tmp)) |
240 | return make_error<StringError>("Could not deserialize value for key " + |
241 | Key, |
242 | inconvertibleErrorCode()); |
243 | |
244 | Val = std::move(Tmp); |
245 | return Error::success(); |
246 | } |
247 | |
248 | /// Returns the bootstrap symbol map. |
249 | const StringMap<ExecutorAddr> &getBootstrapSymbolsMap() const { |
250 | return BootstrapSymbols; |
251 | } |
252 | |
253 | /// For each (ExecutorAddr&, StringRef) pair, looks up the string in the |
254 | /// bootstrap symbols map and writes its address to the ExecutorAddr if |
255 | /// found. If any symbol is not found then the function returns an error. |
256 | Error getBootstrapSymbols( |
257 | ArrayRef<std::pair<ExecutorAddr &, StringRef>> Pairs) const { |
258 | for (const auto &KV : Pairs) { |
259 | auto I = BootstrapSymbols.find(KV.second); |
260 | if (I == BootstrapSymbols.end()) |
261 | return make_error<StringError>("Symbol \"" + KV.second + |
262 | "\" not found " |
263 | "in bootstrap symbols map", |
264 | inconvertibleErrorCode()); |
265 | |
266 | KV.first = I->second; |
267 | } |
268 | return Error::success(); |
269 | } |
270 | |
271 | /// Load the dynamic library at the given path and return a handle to it. |
272 | /// If LibraryPath is null this function will return the global handle for |
273 | /// the target process. |
274 | virtual Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) = 0; |
275 | |
276 | /// Search for symbols in the target process. |
277 | /// |
278 | /// The result of the lookup is a 2-dimentional array of target addresses |
279 | /// that correspond to the lookup order. If a required symbol is not |
280 | /// found then this method will return an error. If a weakly referenced |
281 | /// symbol is not found then it be assigned a '0' value. |
282 | virtual Expected<std::vector<tpctypes::LookupResult>> |
283 | lookupSymbols(ArrayRef<LookupRequest> Request) = 0; |
284 | |
285 | /// Run function with a main-like signature. |
286 | virtual Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr, |
287 | ArrayRef<std::string> Args) = 0; |
288 | |
289 | // TODO: move this to ORC runtime. |
290 | /// Run function with a int (*)(void) signature. |
291 | virtual Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) = 0; |
292 | |
293 | // TODO: move this to ORC runtime. |
294 | /// Run function with a int (*)(int) signature. |
295 | virtual Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, |
296 | int Arg) = 0; |
297 | |
298 | /// Run a wrapper function in the executor. The given WFRHandler will be |
299 | /// called on the result when it is returned. |
300 | /// |
301 | /// The wrapper function should be callable as: |
302 | /// |
303 | /// \code{.cpp} |
304 | /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size); |
305 | /// \endcode{.cpp} |
306 | virtual void callWrapperAsync(ExecutorAddr WrapperFnAddr, |
307 | IncomingWFRHandler OnComplete, |
308 | ArrayRef<char> ArgBuffer) = 0; |
309 | |
310 | /// Run a wrapper function in the executor using the given Runner to dispatch |
311 | /// OnComplete when the result is ready. |
312 | template <typename RunPolicyT, typename FnT> |
313 | void callWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr, |
314 | FnT &&OnComplete, ArrayRef<char> ArgBuffer) { |
315 | callWrapperAsync( |
316 | WrapperFnAddr, Runner(std::forward<FnT>(OnComplete)), ArgBuffer); |
317 | } |
318 | |
319 | /// Run a wrapper function in the executor. OnComplete will be dispatched |
320 | /// as a GenericNamedTask using this instance's TaskDispatch object. |
321 | template <typename FnT> |
322 | void callWrapperAsync(ExecutorAddr WrapperFnAddr, FnT &&OnComplete, |
323 | ArrayRef<char> ArgBuffer) { |
324 | callWrapperAsync(RunAsTask(*D), WrapperFnAddr, |
325 | std::forward<FnT>(OnComplete), ArgBuffer); |
326 | } |
327 | |
328 | /// Run a wrapper function in the executor. The wrapper function should be |
329 | /// callable as: |
330 | /// |
331 | /// \code{.cpp} |
332 | /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size); |
333 | /// \endcode{.cpp} |
334 | shared::WrapperFunctionResult callWrapper(ExecutorAddr WrapperFnAddr, |
335 | ArrayRef<char> ArgBuffer) { |
336 | std::promise<shared::WrapperFunctionResult> RP; |
337 | auto RF = RP.get_future(); |
338 | callWrapperAsync( |
339 | RunInPlace(), WrapperFnAddr, |
340 | [&](shared::WrapperFunctionResult R) { |
341 | RP.set_value(std::move(R)); |
342 | }, ArgBuffer); |
343 | return RF.get(); |
344 | } |
345 | |
346 | /// Run a wrapper function using SPS to serialize the arguments and |
347 | /// deserialize the results. |
348 | template <typename SPSSignature, typename RunPolicyT, typename SendResultT, |
349 | typename... ArgTs> |
350 | void callSPSWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr, |
351 | SendResultT &&SendResult, const ArgTs &...Args) { |
352 | shared::WrapperFunction<SPSSignature>::callAsync( |
353 | [this, WrapperFnAddr, Runner = std::move(Runner)] |
354 | (auto &&SendResult, const char *ArgData, size_t ArgSize) mutable { |
355 | this->callWrapperAsync(std::move(Runner), WrapperFnAddr, |
356 | std::move(SendResult), |
357 | ArrayRef<char>(ArgData, ArgSize)); |
358 | }, |
359 | std::forward<SendResultT>(SendResult), Args...); |
360 | } |
361 | |
362 | /// Run a wrapper function using SPS to serialize the arguments and |
363 | /// deserialize the results. |
364 | template <typename SPSSignature, typename SendResultT, typename... ArgTs> |
365 | void callSPSWrapperAsync(ExecutorAddr WrapperFnAddr, SendResultT &&SendResult, |
366 | const ArgTs &...Args) { |
367 | callSPSWrapperAsync<SPSSignature>(RunAsTask(*D), WrapperFnAddr, |
368 | std::forward<SendResultT>(SendResult), |
369 | Args...); |
370 | } |
371 | |
372 | /// Run a wrapper function using SPS to serialize the arguments and |
373 | /// deserialize the results. |
374 | /// |
375 | /// If SPSSignature is a non-void function signature then the second argument |
376 | /// (the first in the Args list) should be a reference to a return value. |
377 | template <typename SPSSignature, typename... WrapperCallArgTs> |
378 | Error callSPSWrapper(ExecutorAddr WrapperFnAddr, |
379 | WrapperCallArgTs &&...WrapperCallArgs) { |
380 | return shared::WrapperFunction<SPSSignature>::call( |
381 | [this, WrapperFnAddr](const char *ArgData, size_t ArgSize) { |
382 | return callWrapper(WrapperFnAddr, ArrayRef<char>(ArgData, ArgSize)); |
383 | }, |
384 | std::forward<WrapperCallArgTs>(WrapperCallArgs)...); |
385 | } |
386 | |
387 | /// Disconnect from the target process. |
388 | /// |
389 | /// This should be called after the JIT session is shut down. |
390 | virtual Error disconnect() = 0; |
391 | |
392 | protected: |
393 | |
394 | std::shared_ptr<SymbolStringPool> SSP; |
395 | std::unique_ptr<TaskDispatcher> D; |
396 | ExecutionSession *ES = nullptr; |
397 | Triple TargetTriple; |
398 | unsigned PageSize = 0; |
399 | JITDispatchInfo JDI; |
400 | MemoryAccess *MemAccess = nullptr; |
401 | jitlink::JITLinkMemoryManager *MemMgr = nullptr; |
402 | StringMap<std::vector<char>> BootstrapMap; |
403 | StringMap<ExecutorAddr> BootstrapSymbols; |
404 | }; |
405 | |
406 | /// A ExecutorProcessControl instance that asserts if any of its methods are |
407 | /// used. Suitable for use is unit tests, and by ORC clients who haven't moved |
408 | /// to ExecutorProcessControl-based APIs yet. |
409 | class UnsupportedExecutorProcessControl : public ExecutorProcessControl { |
410 | public: |
411 | UnsupportedExecutorProcessControl( |
412 | std::shared_ptr<SymbolStringPool> SSP = nullptr, |
413 | std::unique_ptr<TaskDispatcher> D = nullptr, |
414 | const std::string &TT = "", unsigned PageSize = 0) |
415 | : ExecutorProcessControl(SSP ? std::move(SSP) |
416 | : std::make_shared<SymbolStringPool>(), |
417 | D ? std::move(D) |
418 | : std::make_unique<InPlaceTaskDispatcher>()) { |
419 | this->TargetTriple = Triple(TT); |
420 | this->PageSize = PageSize; |
421 | } |
422 | |
423 | Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override { |
424 | llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" , 424); |
425 | } |
426 | |
427 | Expected<std::vector<tpctypes::LookupResult>> |
428 | lookupSymbols(ArrayRef<LookupRequest> Request) override { |
429 | llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" , 429); |
430 | } |
431 | |
432 | Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr, |
433 | ArrayRef<std::string> Args) override { |
434 | llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" , 434); |
435 | } |
436 | |
437 | Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) override { |
438 | llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" , 438); |
439 | } |
440 | |
441 | Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override { |
442 | llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" , 442); |
443 | } |
444 | |
445 | void callWrapperAsync(ExecutorAddr WrapperFnAddr, |
446 | IncomingWFRHandler OnComplete, |
447 | ArrayRef<char> ArgBuffer) override { |
448 | llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" , 448); |
449 | } |
450 | |
451 | Error disconnect() override { return Error::success(); } |
452 | }; |
453 | |
454 | /// A ExecutorProcessControl implementation targeting the current process. |
455 | class SelfExecutorProcessControl |
456 | : public ExecutorProcessControl, |
457 | private ExecutorProcessControl::MemoryAccess { |
458 | public: |
459 | SelfExecutorProcessControl( |
460 | std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D, |
461 | Triple TargetTriple, unsigned PageSize, |
462 | std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr); |
463 | |
464 | /// Create a SelfExecutorProcessControl with the given symbol string pool and |
465 | /// memory manager. |
466 | /// If no symbol string pool is given then one will be created. |
467 | /// If no memory manager is given a jitlink::InProcessMemoryManager will |
468 | /// be created and used by default. |
469 | static Expected<std::unique_ptr<SelfExecutorProcessControl>> |
470 | Create(std::shared_ptr<SymbolStringPool> SSP = nullptr, |
471 | std::unique_ptr<TaskDispatcher> D = nullptr, |
472 | std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr); |
473 | |
474 | Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override; |
475 | |
476 | Expected<std::vector<tpctypes::LookupResult>> |
477 | lookupSymbols(ArrayRef<LookupRequest> Request) override; |
478 | |
479 | Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr, |
480 | ArrayRef<std::string> Args) override; |
481 | |
482 | Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) override; |
483 | |
484 | Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override; |
485 | |
486 | void callWrapperAsync(ExecutorAddr WrapperFnAddr, |
487 | IncomingWFRHandler OnComplete, |
488 | ArrayRef<char> ArgBuffer) override; |
489 | |
490 | Error disconnect() override; |
491 | |
492 | private: |
493 | void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws, |
494 | WriteResultFn OnWriteComplete) override; |
495 | |
496 | void writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws, |
497 | WriteResultFn OnWriteComplete) override; |
498 | |
499 | void writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws, |
500 | WriteResultFn OnWriteComplete) override; |
501 | |
502 | void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws, |
503 | WriteResultFn OnWriteComplete) override; |
504 | |
505 | void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws, |
506 | WriteResultFn OnWriteComplete) override; |
507 | |
508 | static shared::CWrapperFunctionResult |
509 | jitDispatchViaWrapperFunctionManager(void *Ctx, const void *FnTag, |
510 | const char *Data, size_t Size); |
511 | |
512 | std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr; |
513 | char GlobalManglingPrefix = 0; |
514 | }; |
515 | |
516 | } // end namespace orc |
517 | } // end namespace llvm |
518 | |
519 | #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H |
1 | //===- WrapperFunctionUtils.h - Utilities for wrapper functions -*- C++ -*-===// | ||||||||||
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 | // A buffer for serialized results. | ||||||||||
10 | // | ||||||||||
11 | //===----------------------------------------------------------------------===// | ||||||||||
12 | |||||||||||
13 | #ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H | ||||||||||
14 | #define LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H | ||||||||||
15 | |||||||||||
16 | #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" | ||||||||||
17 | #include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h" | ||||||||||
18 | #include "llvm/Support/Error.h" | ||||||||||
19 | |||||||||||
20 | #include <type_traits> | ||||||||||
21 | |||||||||||
22 | namespace llvm { | ||||||||||
23 | namespace orc { | ||||||||||
24 | namespace shared { | ||||||||||
25 | |||||||||||
26 | // Must be kept in-sync with compiler-rt/lib/orc/c-api.h. | ||||||||||
27 | union CWrapperFunctionResultDataUnion { | ||||||||||
28 | char *ValuePtr; | ||||||||||
29 | char Value[sizeof(ValuePtr)]; | ||||||||||
30 | }; | ||||||||||
31 | |||||||||||
32 | // Must be kept in-sync with compiler-rt/lib/orc/c-api.h. | ||||||||||
33 | typedef struct { | ||||||||||
34 | CWrapperFunctionResultDataUnion Data; | ||||||||||
35 | size_t Size; | ||||||||||
36 | } CWrapperFunctionResult; | ||||||||||
37 | |||||||||||
38 | /// C++ wrapper function result: Same as CWrapperFunctionResult but | ||||||||||
39 | /// auto-releases memory. | ||||||||||
40 | class WrapperFunctionResult { | ||||||||||
41 | public: | ||||||||||
42 | /// Create a default WrapperFunctionResult. | ||||||||||
43 | WrapperFunctionResult() { init(R); } | ||||||||||
44 | |||||||||||
45 | /// Create a WrapperFunctionResult by taking ownership of a | ||||||||||
46 | /// CWrapperFunctionResult. | ||||||||||
47 | /// | ||||||||||
48 | /// Warning: This should only be used by clients writing wrapper-function | ||||||||||
49 | /// caller utilities (like TargetProcessControl). | ||||||||||
50 | WrapperFunctionResult(CWrapperFunctionResult R) : R(R) { | ||||||||||
51 | // Reset R. | ||||||||||
52 | init(R); | ||||||||||
53 | } | ||||||||||
54 | |||||||||||
55 | WrapperFunctionResult(const WrapperFunctionResult &) = delete; | ||||||||||
56 | WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete; | ||||||||||
57 | |||||||||||
58 | WrapperFunctionResult(WrapperFunctionResult &&Other) { | ||||||||||
59 | init(R); | ||||||||||
60 | std::swap(R, Other.R); | ||||||||||
61 | } | ||||||||||
62 | |||||||||||
63 | WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) { | ||||||||||
64 | WrapperFunctionResult Tmp(std::move(Other)); | ||||||||||
65 | std::swap(R, Tmp.R); | ||||||||||
66 | return *this; | ||||||||||
67 | } | ||||||||||
68 | |||||||||||
69 | ~WrapperFunctionResult() { | ||||||||||
70 | if ((R.Size > sizeof(R.Data.Value)) || | ||||||||||
71 | (R.Size == 0 && R.Data.ValuePtr != nullptr)) | ||||||||||
72 | free(R.Data.ValuePtr); | ||||||||||
73 | } | ||||||||||
74 | |||||||||||
75 | /// Release ownership of the contained CWrapperFunctionResult. | ||||||||||
76 | /// Warning: Do not use -- this method will be removed in the future. It only | ||||||||||
77 | /// exists to temporarily support some code that will eventually be moved to | ||||||||||
78 | /// the ORC runtime. | ||||||||||
79 | CWrapperFunctionResult release() { | ||||||||||
80 | CWrapperFunctionResult Tmp; | ||||||||||
81 | init(Tmp); | ||||||||||
82 | std::swap(R, Tmp); | ||||||||||
83 | return Tmp; | ||||||||||
84 | } | ||||||||||
85 | |||||||||||
86 | /// Get a pointer to the data contained in this instance. | ||||||||||
87 | char *data() { | ||||||||||
88 | assert((R.Size != 0 || R.Data.ValuePtr == nullptr) &&(static_cast <bool> ((R.Size != 0 || R.Data.ValuePtr == nullptr) && "Cannot get data for out-of-band error value" ) ? void (0) : __assert_fail ("(R.Size != 0 || R.Data.ValuePtr == nullptr) && \"Cannot get data for out-of-band error value\"" , "llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" , 89, __extension__ __PRETTY_FUNCTION__)) | ||||||||||
89 | "Cannot get data for out-of-band error value")(static_cast <bool> ((R.Size != 0 || R.Data.ValuePtr == nullptr) && "Cannot get data for out-of-band error value" ) ? void (0) : __assert_fail ("(R.Size != 0 || R.Data.ValuePtr == nullptr) && \"Cannot get data for out-of-band error value\"" , "llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" , 89, __extension__ __PRETTY_FUNCTION__)); | ||||||||||
90 | return R.Size > sizeof(R.Data.Value) ? R.Data.ValuePtr : R.Data.Value; | ||||||||||
91 | } | ||||||||||
92 | |||||||||||
93 | /// Get a const pointer to the data contained in this instance. | ||||||||||
94 | const char *data() const { | ||||||||||
95 | assert((R.Size != 0 || R.Data.ValuePtr == nullptr) &&(static_cast <bool> ((R.Size != 0 || R.Data.ValuePtr == nullptr) && "Cannot get data for out-of-band error value" ) ? void (0) : __assert_fail ("(R.Size != 0 || R.Data.ValuePtr == nullptr) && \"Cannot get data for out-of-band error value\"" , "llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" , 96, __extension__ __PRETTY_FUNCTION__)) | ||||||||||
96 | "Cannot get data for out-of-band error value")(static_cast <bool> ((R.Size != 0 || R.Data.ValuePtr == nullptr) && "Cannot get data for out-of-band error value" ) ? void (0) : __assert_fail ("(R.Size != 0 || R.Data.ValuePtr == nullptr) && \"Cannot get data for out-of-band error value\"" , "llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" , 96, __extension__ __PRETTY_FUNCTION__)); | ||||||||||
97 | return R.Size > sizeof(R.Data.Value) ? R.Data.ValuePtr : R.Data.Value; | ||||||||||
98 | } | ||||||||||
99 | |||||||||||
100 | /// Returns the size of the data contained in this instance. | ||||||||||
101 | size_t size() const { | ||||||||||
102 | assert((R.Size != 0 || R.Data.ValuePtr == nullptr) &&(static_cast <bool> ((R.Size != 0 || R.Data.ValuePtr == nullptr) && "Cannot get data for out-of-band error value" ) ? void (0) : __assert_fail ("(R.Size != 0 || R.Data.ValuePtr == nullptr) && \"Cannot get data for out-of-band error value\"" , "llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" , 103, __extension__ __PRETTY_FUNCTION__)) | ||||||||||
103 | "Cannot get data for out-of-band error value")(static_cast <bool> ((R.Size != 0 || R.Data.ValuePtr == nullptr) && "Cannot get data for out-of-band error value" ) ? void (0) : __assert_fail ("(R.Size != 0 || R.Data.ValuePtr == nullptr) && \"Cannot get data for out-of-band error value\"" , "llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" , 103, __extension__ __PRETTY_FUNCTION__)); | ||||||||||
104 | return R.Size; | ||||||||||
105 | } | ||||||||||
106 | |||||||||||
107 | /// Returns true if this value is equivalent to a default-constructed | ||||||||||
108 | /// WrapperFunctionResult. | ||||||||||
109 | bool empty() const { return R.Size == 0 && R.Data.ValuePtr == nullptr; } | ||||||||||
110 | |||||||||||
111 | /// Create a WrapperFunctionResult with the given size and return a pointer | ||||||||||
112 | /// to the underlying memory. | ||||||||||
113 | static WrapperFunctionResult allocate(size_t Size) { | ||||||||||
114 | // Reset. | ||||||||||
115 | WrapperFunctionResult WFR; | ||||||||||
116 | WFR.R.Size = Size; | ||||||||||
117 | if (WFR.R.Size > sizeof(WFR.R.Data.Value)) | ||||||||||
118 | WFR.R.Data.ValuePtr = (char *)malloc(WFR.R.Size); | ||||||||||
119 | return WFR; | ||||||||||
120 | } | ||||||||||
121 | |||||||||||
122 | /// Copy from the given char range. | ||||||||||
123 | static WrapperFunctionResult copyFrom(const char *Source, size_t Size) { | ||||||||||
124 | auto WFR = allocate(Size); | ||||||||||
125 | memcpy(WFR.data(), Source, Size); | ||||||||||
126 | return WFR; | ||||||||||
127 | } | ||||||||||
128 | |||||||||||
129 | /// Copy from the given null-terminated string (includes the null-terminator). | ||||||||||
130 | static WrapperFunctionResult copyFrom(const char *Source) { | ||||||||||
131 | return copyFrom(Source, strlen(Source) + 1); | ||||||||||
132 | } | ||||||||||
133 | |||||||||||
134 | /// Copy from the given std::string (includes the null terminator). | ||||||||||
135 | static WrapperFunctionResult copyFrom(const std::string &Source) { | ||||||||||
136 | return copyFrom(Source.c_str()); | ||||||||||
137 | } | ||||||||||
138 | |||||||||||
139 | /// Create an out-of-band error by copying the given string. | ||||||||||
140 | static WrapperFunctionResult createOutOfBandError(const char *Msg) { | ||||||||||
141 | // Reset. | ||||||||||
142 | WrapperFunctionResult WFR; | ||||||||||
143 | char *Tmp = (char *)malloc(strlen(Msg) + 1); | ||||||||||
144 | strcpy(Tmp, Msg); | ||||||||||
145 | WFR.R.Data.ValuePtr = Tmp; | ||||||||||
146 | return WFR; | ||||||||||
147 | } | ||||||||||
148 | |||||||||||
149 | /// Create an out-of-band error by copying the given string. | ||||||||||
150 | static WrapperFunctionResult createOutOfBandError(const std::string &Msg) { | ||||||||||
151 | return createOutOfBandError(Msg.c_str()); | ||||||||||
152 | } | ||||||||||
153 | |||||||||||
154 | /// If this value is an out-of-band error then this returns the error message, | ||||||||||
155 | /// otherwise returns nullptr. | ||||||||||
156 | const char *getOutOfBandError() const { | ||||||||||
157 | return R.Size == 0 ? R.Data.ValuePtr : nullptr; | ||||||||||
158 | } | ||||||||||
159 | |||||||||||
160 | private: | ||||||||||
161 | static void init(CWrapperFunctionResult &R) { | ||||||||||
162 | R.Data.ValuePtr = nullptr; | ||||||||||
163 | R.Size = 0; | ||||||||||
164 | } | ||||||||||
165 | |||||||||||
166 | CWrapperFunctionResult R; | ||||||||||
167 | }; | ||||||||||
168 | |||||||||||
169 | namespace detail { | ||||||||||
170 | |||||||||||
171 | template <typename SPSArgListT, typename... ArgTs> | ||||||||||
172 | WrapperFunctionResult | ||||||||||
173 | serializeViaSPSToWrapperFunctionResult(const ArgTs &...Args) { | ||||||||||
174 | auto Result = WrapperFunctionResult::allocate(SPSArgListT::size(Args...)); | ||||||||||
175 | SPSOutputBuffer OB(Result.data(), Result.size()); | ||||||||||
176 | if (!SPSArgListT::serialize(OB, Args...)) | ||||||||||
177 | return WrapperFunctionResult::createOutOfBandError( | ||||||||||
178 | "Error serializing arguments to blob in call"); | ||||||||||
179 | return Result; | ||||||||||
180 | } | ||||||||||
181 | |||||||||||
182 | template <typename RetT> class WrapperFunctionHandlerCaller { | ||||||||||
183 | public: | ||||||||||
184 | template <typename HandlerT, typename ArgTupleT, std::size_t... I> | ||||||||||
185 | static decltype(auto) call(HandlerT &&H, ArgTupleT &Args, | ||||||||||
186 | std::index_sequence<I...>) { | ||||||||||
187 | return std::forward<HandlerT>(H)(std::get<I>(Args)...); | ||||||||||
188 | } | ||||||||||
189 | }; | ||||||||||
190 | |||||||||||
191 | template <> class WrapperFunctionHandlerCaller<void> { | ||||||||||
192 | public: | ||||||||||
193 | template <typename HandlerT, typename ArgTupleT, std::size_t... I> | ||||||||||
194 | static SPSEmpty call(HandlerT &&H, ArgTupleT &Args, | ||||||||||
195 | std::index_sequence<I...>) { | ||||||||||
196 | std::forward<HandlerT>(H)(std::get<I>(Args)...); | ||||||||||
197 | return SPSEmpty(); | ||||||||||
198 | } | ||||||||||
199 | }; | ||||||||||
200 | |||||||||||
201 | template <typename WrapperFunctionImplT, | ||||||||||
202 | template <typename> class ResultSerializer, typename... SPSTagTs> | ||||||||||
203 | class WrapperFunctionHandlerHelper | ||||||||||
204 | : public WrapperFunctionHandlerHelper< | ||||||||||
205 | decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()), | ||||||||||
206 | ResultSerializer, SPSTagTs...> {}; | ||||||||||
207 | |||||||||||
208 | template <typename RetT, typename... ArgTs, | ||||||||||
209 | template <typename> class ResultSerializer, typename... SPSTagTs> | ||||||||||
210 | class WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer, | ||||||||||
211 | SPSTagTs...> { | ||||||||||
212 | public: | ||||||||||
213 | using ArgTuple = std::tuple<std::decay_t<ArgTs>...>; | ||||||||||
214 | using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>; | ||||||||||
215 | |||||||||||
216 | template <typename HandlerT> | ||||||||||
217 | static WrapperFunctionResult apply(HandlerT &&H, const char *ArgData, | ||||||||||
218 | size_t ArgSize) { | ||||||||||
219 | ArgTuple Args; | ||||||||||
220 | if (!deserialize(ArgData, ArgSize, Args, ArgIndices{})) | ||||||||||
221 | return WrapperFunctionResult::createOutOfBandError( | ||||||||||
222 | "Could not deserialize arguments for wrapper function call"); | ||||||||||
223 | |||||||||||
224 | auto HandlerResult = WrapperFunctionHandlerCaller<RetT>::call( | ||||||||||
225 | std::forward<HandlerT>(H), Args, ArgIndices{}); | ||||||||||
226 | |||||||||||
227 | return ResultSerializer<decltype(HandlerResult)>::serialize( | ||||||||||
228 | std::move(HandlerResult)); | ||||||||||
229 | } | ||||||||||
230 | |||||||||||
231 | private: | ||||||||||
232 | template <std::size_t... I> | ||||||||||
233 | static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args, | ||||||||||
234 | std::index_sequence<I...>) { | ||||||||||
235 | SPSInputBuffer IB(ArgData, ArgSize); | ||||||||||
236 | return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...); | ||||||||||
237 | } | ||||||||||
238 | }; | ||||||||||
239 | |||||||||||
240 | // Map function pointers to function types. | ||||||||||
241 | template <typename RetT, typename... ArgTs, | ||||||||||
242 | template <typename> class ResultSerializer, typename... SPSTagTs> | ||||||||||
243 | class WrapperFunctionHandlerHelper<RetT (*)(ArgTs...), ResultSerializer, | ||||||||||
244 | SPSTagTs...> | ||||||||||
245 | : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer, | ||||||||||
246 | SPSTagTs...> {}; | ||||||||||
247 | |||||||||||
248 | // Map non-const member function types to function types. | ||||||||||
249 | template <typename ClassT, typename RetT, typename... ArgTs, | ||||||||||
250 | template <typename> class ResultSerializer, typename... SPSTagTs> | ||||||||||
251 | class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...), ResultSerializer, | ||||||||||
252 | SPSTagTs...> | ||||||||||
253 | : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer, | ||||||||||
254 | SPSTagTs...> {}; | ||||||||||
255 | |||||||||||
256 | // Map const member function types to function types. | ||||||||||
257 | template <typename ClassT, typename RetT, typename... ArgTs, | ||||||||||
258 | template <typename> class ResultSerializer, typename... SPSTagTs> | ||||||||||
259 | class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...) const, | ||||||||||
260 | ResultSerializer, SPSTagTs...> | ||||||||||
261 | : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer, | ||||||||||
262 | SPSTagTs...> {}; | ||||||||||
263 | |||||||||||
264 | template <typename WrapperFunctionImplT, | ||||||||||
265 | template <typename> class ResultSerializer, typename... SPSTagTs> | ||||||||||
266 | class WrapperFunctionAsyncHandlerHelper | ||||||||||
267 | : public WrapperFunctionAsyncHandlerHelper< | ||||||||||
268 | decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()), | ||||||||||
269 | ResultSerializer, SPSTagTs...> {}; | ||||||||||
270 | |||||||||||
271 | template <typename RetT, typename SendResultT, typename... ArgTs, | ||||||||||
272 | template <typename> class ResultSerializer, typename... SPSTagTs> | ||||||||||
273 | class WrapperFunctionAsyncHandlerHelper<RetT(SendResultT, ArgTs...), | ||||||||||
274 | ResultSerializer, SPSTagTs...> { | ||||||||||
275 | public: | ||||||||||
276 | using ArgTuple = std::tuple<std::decay_t<ArgTs>...>; | ||||||||||
277 | using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>; | ||||||||||
278 | |||||||||||
279 | template <typename HandlerT, typename SendWrapperFunctionResultT> | ||||||||||
280 | static void applyAsync(HandlerT &&H, | ||||||||||
281 | SendWrapperFunctionResultT &&SendWrapperFunctionResult, | ||||||||||
282 | const char *ArgData, size_t ArgSize) { | ||||||||||
283 | ArgTuple Args; | ||||||||||
284 | if (!deserialize(ArgData, ArgSize, Args, ArgIndices{})) { | ||||||||||
285 | SendWrapperFunctionResult(WrapperFunctionResult::createOutOfBandError( | ||||||||||
286 | "Could not deserialize arguments for wrapper function call")); | ||||||||||
287 | return; | ||||||||||
288 | } | ||||||||||
289 | |||||||||||
290 | auto SendResult = | ||||||||||
291 | [SendWFR = std::move(SendWrapperFunctionResult)](auto Result) mutable { | ||||||||||
292 | using ResultT = decltype(Result); | ||||||||||
293 | SendWFR(ResultSerializer<ResultT>::serialize(std::move(Result))); | ||||||||||
294 | }; | ||||||||||
295 | |||||||||||
296 | callAsync(std::forward<HandlerT>(H), std::move(SendResult), std::move(Args), | ||||||||||
297 | ArgIndices{}); | ||||||||||
298 | } | ||||||||||
299 | |||||||||||
300 | private: | ||||||||||
301 | template <std::size_t... I> | ||||||||||
302 | static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args, | ||||||||||
303 | std::index_sequence<I...>) { | ||||||||||
304 | SPSInputBuffer IB(ArgData, ArgSize); | ||||||||||
305 | return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...); | ||||||||||
306 | } | ||||||||||
307 | |||||||||||
308 | template <typename HandlerT, typename SerializeAndSendResultT, | ||||||||||
309 | typename ArgTupleT, std::size_t... I> | ||||||||||
310 | static void callAsync(HandlerT &&H, | ||||||||||
311 | SerializeAndSendResultT &&SerializeAndSendResult, | ||||||||||
312 | ArgTupleT Args, std::index_sequence<I...>) { | ||||||||||
313 | (void)Args; // Silence a buggy GCC warning. | ||||||||||
314 | return std::forward<HandlerT>(H)(std::move(SerializeAndSendResult), | ||||||||||
315 | std::move(std::get<I>(Args))...); | ||||||||||
316 | } | ||||||||||
317 | }; | ||||||||||
318 | |||||||||||
319 | // Map function pointers to function types. | ||||||||||
320 | template <typename RetT, typename... ArgTs, | ||||||||||
321 | template <typename> class ResultSerializer, typename... SPSTagTs> | ||||||||||
322 | class WrapperFunctionAsyncHandlerHelper<RetT (*)(ArgTs...), ResultSerializer, | ||||||||||
323 | SPSTagTs...> | ||||||||||
324 | : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer, | ||||||||||
325 | SPSTagTs...> {}; | ||||||||||
326 | |||||||||||
327 | // Map non-const member function types to function types. | ||||||||||
328 | template <typename ClassT, typename RetT, typename... ArgTs, | ||||||||||
329 | template <typename> class ResultSerializer, typename... SPSTagTs> | ||||||||||
330 | class WrapperFunctionAsyncHandlerHelper<RetT (ClassT::*)(ArgTs...), | ||||||||||
331 | ResultSerializer, SPSTagTs...> | ||||||||||
332 | : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer, | ||||||||||
333 | SPSTagTs...> {}; | ||||||||||
334 | |||||||||||
335 | // Map const member function types to function types. | ||||||||||
336 | template <typename ClassT, typename RetT, typename... ArgTs, | ||||||||||
337 | template <typename> class ResultSerializer, typename... SPSTagTs> | ||||||||||
338 | class WrapperFunctionAsyncHandlerHelper<RetT (ClassT::*)(ArgTs...) const, | ||||||||||
339 | ResultSerializer, SPSTagTs...> | ||||||||||
340 | : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer, | ||||||||||
341 | SPSTagTs...> {}; | ||||||||||
342 | |||||||||||
343 | template <typename SPSRetTagT, typename RetT> class ResultSerializer { | ||||||||||
344 | public: | ||||||||||
345 | static WrapperFunctionResult serialize(RetT Result) { | ||||||||||
346 | return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>( | ||||||||||
347 | Result); | ||||||||||
348 | } | ||||||||||
349 | }; | ||||||||||
350 | |||||||||||
351 | template <typename SPSRetTagT> class ResultSerializer<SPSRetTagT, Error> { | ||||||||||
352 | public: | ||||||||||
353 | static WrapperFunctionResult serialize(Error Err) { | ||||||||||
354 | return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>( | ||||||||||
355 | toSPSSerializable(std::move(Err))); | ||||||||||
356 | } | ||||||||||
357 | }; | ||||||||||
358 | |||||||||||
359 | template <typename SPSRetTagT> | ||||||||||
360 | class ResultSerializer<SPSRetTagT, ErrorSuccess> { | ||||||||||
361 | public: | ||||||||||
362 | static WrapperFunctionResult serialize(ErrorSuccess Err) { | ||||||||||
363 | return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>( | ||||||||||
364 | toSPSSerializable(std::move(Err))); | ||||||||||
365 | } | ||||||||||
366 | }; | ||||||||||
367 | |||||||||||
368 | template <typename SPSRetTagT, typename T> | ||||||||||
369 | class ResultSerializer<SPSRetTagT, Expected<T>> { | ||||||||||
370 | public: | ||||||||||
371 | static WrapperFunctionResult serialize(Expected<T> E) { | ||||||||||
372 | return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>( | ||||||||||
373 | toSPSSerializable(std::move(E))); | ||||||||||
374 | } | ||||||||||
375 | }; | ||||||||||
376 | |||||||||||
377 | template <typename SPSRetTagT, typename RetT> class ResultDeserializer { | ||||||||||
378 | public: | ||||||||||
379 | static RetT makeValue() { return RetT(); } | ||||||||||
380 | static void makeSafe(RetT &Result) {} | ||||||||||
381 | |||||||||||
382 | static Error deserialize(RetT &Result, const char *ArgData, size_t ArgSize) { | ||||||||||
383 | SPSInputBuffer IB(ArgData, ArgSize); | ||||||||||
384 | if (!SPSArgList<SPSRetTagT>::deserialize(IB, Result)) | ||||||||||
385 | return make_error<StringError>( | ||||||||||
386 | "Error deserializing return value from blob in call", | ||||||||||
387 | inconvertibleErrorCode()); | ||||||||||
388 | return Error::success(); | ||||||||||
389 | } | ||||||||||
390 | }; | ||||||||||
391 | |||||||||||
392 | template <> class ResultDeserializer<SPSError, Error> { | ||||||||||
393 | public: | ||||||||||
394 | static Error makeValue() { return Error::success(); } | ||||||||||
395 | static void makeSafe(Error &Err) { cantFail(std::move(Err)); } | ||||||||||
396 | |||||||||||
397 | static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize) { | ||||||||||
398 | SPSInputBuffer IB(ArgData, ArgSize); | ||||||||||
399 | SPSSerializableError BSE; | ||||||||||
400 | if (!SPSArgList<SPSError>::deserialize(IB, BSE)) | ||||||||||
401 | return make_error<StringError>( | ||||||||||
402 | "Error deserializing return value from blob in call", | ||||||||||
403 | inconvertibleErrorCode()); | ||||||||||
404 | Err = fromSPSSerializable(std::move(BSE)); | ||||||||||
405 | return Error::success(); | ||||||||||
406 | } | ||||||||||
407 | }; | ||||||||||
408 | |||||||||||
409 | template <typename SPSTagT, typename T> | ||||||||||
410 | class ResultDeserializer<SPSExpected<SPSTagT>, Expected<T>> { | ||||||||||
411 | public: | ||||||||||
412 | static Expected<T> makeValue() { return T(); } | ||||||||||
413 | static void makeSafe(Expected<T> &E) { cantFail(E.takeError()); } | ||||||||||
414 | |||||||||||
415 | static Error deserialize(Expected<T> &E, const char *ArgData, | ||||||||||
416 | size_t ArgSize) { | ||||||||||
417 | SPSInputBuffer IB(ArgData, ArgSize); | ||||||||||
418 | SPSSerializableExpected<T> BSE; | ||||||||||
419 | if (!SPSArgList<SPSExpected<SPSTagT>>::deserialize(IB, BSE)) | ||||||||||
420 | return make_error<StringError>( | ||||||||||
421 | "Error deserializing return value from blob in call", | ||||||||||
422 | inconvertibleErrorCode()); | ||||||||||
423 | E = fromSPSSerializable(std::move(BSE)); | ||||||||||
424 | return Error::success(); | ||||||||||
425 | } | ||||||||||
426 | }; | ||||||||||
427 | |||||||||||
428 | template <typename SPSRetTagT, typename RetT> class AsyncCallResultHelper { | ||||||||||
429 | // Did you forget to use Error / Expected in your handler? | ||||||||||
430 | }; | ||||||||||
431 | |||||||||||
432 | } // end namespace detail | ||||||||||
433 | |||||||||||
434 | template <typename SPSSignature> class WrapperFunction; | ||||||||||
435 | |||||||||||
436 | template <typename SPSRetTagT, typename... SPSTagTs> | ||||||||||
437 | class WrapperFunction<SPSRetTagT(SPSTagTs...)> { | ||||||||||
438 | private: | ||||||||||
439 | template <typename RetT> | ||||||||||
440 | using ResultSerializer = detail::ResultSerializer<SPSRetTagT, RetT>; | ||||||||||
441 | |||||||||||
442 | public: | ||||||||||
443 | /// Call a wrapper function. Caller should be callable as | ||||||||||
444 | /// WrapperFunctionResult Fn(const char *ArgData, size_t ArgSize); | ||||||||||
445 | template <typename CallerFn, typename RetT, typename... ArgTs> | ||||||||||
446 | static Error call(const CallerFn &Caller, RetT &Result, | ||||||||||
447 | const ArgTs &...Args) { | ||||||||||
448 | |||||||||||
449 | // RetT might be an Error or Expected value. Set the checked flag now: | ||||||||||
450 | // we don't want the user to have to check the unused result if this | ||||||||||
451 | // operation fails. | ||||||||||
452 | detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(Result); | ||||||||||
453 | |||||||||||
454 | auto ArgBuffer = | ||||||||||
455 | detail::serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSTagTs...>>( | ||||||||||
456 | Args...); | ||||||||||
457 | if (const char *ErrMsg
| ||||||||||
458 | return make_error<StringError>(ErrMsg, inconvertibleErrorCode()); | ||||||||||
459 | |||||||||||
460 | WrapperFunctionResult ResultBuffer = | ||||||||||
461 | Caller(ArgBuffer.data(), ArgBuffer.size()); | ||||||||||
462 | if (auto ErrMsg = ResultBuffer.getOutOfBandError()) | ||||||||||
463 | return make_error<StringError>(ErrMsg, inconvertibleErrorCode()); | ||||||||||
464 | |||||||||||
465 | return detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize( | ||||||||||
466 | Result, ResultBuffer.data(), ResultBuffer.size()); | ||||||||||
467 | } | ||||||||||
468 | |||||||||||
469 | /// Call an async wrapper function. | ||||||||||
470 | /// Caller should be callable as | ||||||||||
471 | /// void Fn(unique_function<void(WrapperFunctionResult)> SendResult, | ||||||||||
472 | /// WrapperFunctionResult ArgBuffer); | ||||||||||
473 | template <typename AsyncCallerFn, typename SendDeserializedResultFn, | ||||||||||
474 | typename... ArgTs> | ||||||||||
475 | static void callAsync(AsyncCallerFn &&Caller, | ||||||||||
476 | SendDeserializedResultFn &&SendDeserializedResult, | ||||||||||
477 | const ArgTs &...Args) { | ||||||||||
478 | using RetT = typename std::tuple_element< | ||||||||||
479 | 1, typename detail::WrapperFunctionHandlerHelper< | ||||||||||
480 | std::remove_reference_t<SendDeserializedResultFn>, | ||||||||||
481 | ResultSerializer, SPSRetTagT>::ArgTuple>::type; | ||||||||||
482 | |||||||||||
483 | auto ArgBuffer = | ||||||||||
484 | detail::serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSTagTs...>>( | ||||||||||
485 | Args...); | ||||||||||
486 | if (auto *ErrMsg = ArgBuffer.getOutOfBandError()) { | ||||||||||
487 | SendDeserializedResult( | ||||||||||
488 | make_error<StringError>(ErrMsg, inconvertibleErrorCode()), | ||||||||||
489 | detail::ResultDeserializer<SPSRetTagT, RetT>::makeValue()); | ||||||||||
490 | return; | ||||||||||
491 | } | ||||||||||
492 | |||||||||||
493 | auto SendSerializedResult = [SDR = std::move(SendDeserializedResult)]( | ||||||||||
494 | WrapperFunctionResult R) mutable { | ||||||||||
495 | RetT RetVal = detail::ResultDeserializer<SPSRetTagT, RetT>::makeValue(); | ||||||||||
496 | detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(RetVal); | ||||||||||
497 | |||||||||||
498 | if (auto *ErrMsg = R.getOutOfBandError()) { | ||||||||||
499 | SDR(make_error<StringError>(ErrMsg, inconvertibleErrorCode()), | ||||||||||
500 | std::move(RetVal)); | ||||||||||
501 | return; | ||||||||||
502 | } | ||||||||||
503 | |||||||||||
504 | SPSInputBuffer IB(R.data(), R.size()); | ||||||||||
505 | if (auto Err = detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize( | ||||||||||
506 | RetVal, R.data(), R.size())) | ||||||||||
507 | SDR(std::move(Err), std::move(RetVal)); | ||||||||||
508 | |||||||||||
509 | SDR(Error::success(), std::move(RetVal)); | ||||||||||
510 | }; | ||||||||||
511 | |||||||||||
512 | Caller(std::move(SendSerializedResult), ArgBuffer.data(), ArgBuffer.size()); | ||||||||||
513 | } | ||||||||||
514 | |||||||||||
515 | /// Handle a call to a wrapper function. | ||||||||||
516 | template <typename HandlerT> | ||||||||||
517 | static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize, | ||||||||||
518 | HandlerT &&Handler) { | ||||||||||
519 | using WFHH = | ||||||||||
520 | detail::WrapperFunctionHandlerHelper<std::remove_reference_t<HandlerT>, | ||||||||||
521 | ResultSerializer, SPSTagTs...>; | ||||||||||
522 | return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize); | ||||||||||
523 | } | ||||||||||
524 | |||||||||||
525 | /// Handle a call to an async wrapper function. | ||||||||||
526 | template <typename HandlerT, typename SendResultT> | ||||||||||
527 | static void handleAsync(const char *ArgData, size_t ArgSize, | ||||||||||
528 | HandlerT &&Handler, SendResultT &&SendResult) { | ||||||||||
529 | using WFAHH = detail::WrapperFunctionAsyncHandlerHelper< | ||||||||||
530 | std::remove_reference_t<HandlerT>, ResultSerializer, SPSTagTs...>; | ||||||||||
531 | WFAHH::applyAsync(std::forward<HandlerT>(Handler), | ||||||||||
532 | std::forward<SendResultT>(SendResult), ArgData, ArgSize); | ||||||||||
533 | } | ||||||||||
534 | |||||||||||
535 | private: | ||||||||||
536 | template <typename T> static const T &makeSerializable(const T &Value) { | ||||||||||
537 | return Value; | ||||||||||
538 | } | ||||||||||
539 | |||||||||||
540 | static detail::SPSSerializableError makeSerializable(Error Err) { | ||||||||||
541 | return detail::toSPSSerializable(std::move(Err)); | ||||||||||
542 | } | ||||||||||
543 | |||||||||||
544 | template <typename T> | ||||||||||
545 | static detail::SPSSerializableExpected<T> makeSerializable(Expected<T> E) { | ||||||||||
546 | return detail::toSPSSerializable(std::move(E)); | ||||||||||
547 | } | ||||||||||
548 | }; | ||||||||||
549 | |||||||||||
550 | template <typename... SPSTagTs> | ||||||||||
551 | class WrapperFunction<void(SPSTagTs...)> | ||||||||||
552 | : private WrapperFunction<SPSEmpty(SPSTagTs...)> { | ||||||||||
553 | |||||||||||
554 | public: | ||||||||||
555 | template <typename CallerFn, typename... ArgTs> | ||||||||||
556 | static Error call(const CallerFn &Caller, const ArgTs &...Args) { | ||||||||||
557 | SPSEmpty BE; | ||||||||||
558 | return WrapperFunction<SPSEmpty(SPSTagTs...)>::call(Caller, BE, Args...); | ||||||||||
559 | } | ||||||||||
560 | |||||||||||
561 | template <typename AsyncCallerFn, typename SendDeserializedResultFn, | ||||||||||
562 | typename... ArgTs> | ||||||||||
563 | static void callAsync(AsyncCallerFn &&Caller, | ||||||||||
564 | SendDeserializedResultFn &&SendDeserializedResult, | ||||||||||
565 | const ArgTs &...Args) { | ||||||||||
566 | WrapperFunction<SPSEmpty(SPSTagTs...)>::callAsync( | ||||||||||
567 | std::forward<AsyncCallerFn>(Caller), | ||||||||||
568 | [SDR = std::move(SendDeserializedResult)](Error SerializeErr, | ||||||||||
569 | SPSEmpty E) mutable { | ||||||||||
570 | SDR(std::move(SerializeErr)); | ||||||||||
571 | }, | ||||||||||
572 | Args...); | ||||||||||
573 | } | ||||||||||
574 | |||||||||||
575 | using WrapperFunction<SPSEmpty(SPSTagTs...)>::handle; | ||||||||||
576 | using WrapperFunction<SPSEmpty(SPSTagTs...)>::handleAsync; | ||||||||||
577 | }; | ||||||||||
578 | |||||||||||
579 | /// A function object that takes an ExecutorAddr as its first argument, | ||||||||||
580 | /// casts that address to a ClassT*, then calls the given method on that | ||||||||||
581 | /// pointer passing in the remaining function arguments. This utility | ||||||||||
582 | /// removes some of the boilerplate from writing wrappers for method calls. | ||||||||||
583 | /// | ||||||||||
584 | /// @code{.cpp} | ||||||||||
585 | /// class MyClass { | ||||||||||
586 | /// public: | ||||||||||
587 | /// void myMethod(uint32_t, bool) { ... } | ||||||||||
588 | /// }; | ||||||||||
589 | /// | ||||||||||
590 | /// // SPS Method signature -- note MyClass object address as first argument. | ||||||||||
591 | /// using SPSMyMethodWrapperSignature = | ||||||||||
592 | /// SPSTuple<SPSExecutorAddr, uint32_t, bool>; | ||||||||||
593 | /// | ||||||||||
594 | /// WrapperFunctionResult | ||||||||||
595 | /// myMethodCallWrapper(const char *ArgData, size_t ArgSize) { | ||||||||||
596 | /// return WrapperFunction<SPSMyMethodWrapperSignature>::handle( | ||||||||||
597 | /// ArgData, ArgSize, makeMethodWrapperHandler(&MyClass::myMethod)); | ||||||||||
598 | /// } | ||||||||||
599 | /// @endcode | ||||||||||
600 | /// | ||||||||||
601 | template <typename RetT, typename ClassT, typename... ArgTs> | ||||||||||
602 | class MethodWrapperHandler { | ||||||||||
603 | public: | ||||||||||
604 | using MethodT = RetT (ClassT::*)(ArgTs...); | ||||||||||
605 | MethodWrapperHandler(MethodT M) : M(M) {} | ||||||||||
606 | RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args) { | ||||||||||
607 | return (ObjAddr.toPtr<ClassT*>()->*M)(std::forward<ArgTs>(Args)...); | ||||||||||
608 | } | ||||||||||
609 | |||||||||||
610 | private: | ||||||||||
611 | MethodT M; | ||||||||||
612 | }; | ||||||||||
613 | |||||||||||
614 | /// Create a MethodWrapperHandler object from the given method pointer. | ||||||||||
615 | template <typename RetT, typename ClassT, typename... ArgTs> | ||||||||||
616 | MethodWrapperHandler<RetT, ClassT, ArgTs...> | ||||||||||
617 | makeMethodWrapperHandler(RetT (ClassT::*Method)(ArgTs...)) { | ||||||||||
618 | return MethodWrapperHandler<RetT, ClassT, ArgTs...>(Method); | ||||||||||
619 | } | ||||||||||
620 | |||||||||||
621 | /// Represents a serialized wrapper function call. | ||||||||||
622 | /// Serializing calls themselves allows us to batch them: We can make one | ||||||||||
623 | /// "run-wrapper-functions" utility and send it a list of calls to run. | ||||||||||
624 | /// | ||||||||||
625 | /// The motivating use-case for this API is JITLink allocation actions, where | ||||||||||
626 | /// we want to run multiple functions to finalize linked memory without having | ||||||||||
627 | /// to make separate IPC calls for each one. | ||||||||||
628 | class WrapperFunctionCall { | ||||||||||
629 | public: | ||||||||||
630 | using ArgDataBufferType = SmallVector<char, 24>; | ||||||||||
631 | |||||||||||
632 | /// Create a WrapperFunctionCall using the given SPS serializer to serialize | ||||||||||
633 | /// the arguments. | ||||||||||
634 | template <typename SPSSerializer, typename... ArgTs> | ||||||||||
635 | static Expected<WrapperFunctionCall> Create(ExecutorAddr FnAddr, | ||||||||||
636 | const ArgTs &...Args) { | ||||||||||
637 | ArgDataBufferType ArgData; | ||||||||||
638 | ArgData.resize(SPSSerializer::size(Args...)); | ||||||||||
639 | SPSOutputBuffer OB(ArgData.empty() ? nullptr : ArgData.data(), | ||||||||||
640 | ArgData.size()); | ||||||||||
641 | if (SPSSerializer::serialize(OB, Args...)) | ||||||||||
642 | return WrapperFunctionCall(FnAddr, std::move(ArgData)); | ||||||||||
643 | return make_error<StringError>("Cannot serialize arguments for " | ||||||||||
644 | "AllocActionCall", | ||||||||||
645 | inconvertibleErrorCode()); | ||||||||||
646 | } | ||||||||||
647 | |||||||||||
648 | WrapperFunctionCall() = default; | ||||||||||
649 | |||||||||||
650 | /// Create a WrapperFunctionCall from a target function and arg buffer. | ||||||||||
651 | WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData) | ||||||||||
652 | : FnAddr(FnAddr), ArgData(std::move(ArgData)) {} | ||||||||||
653 | |||||||||||
654 | /// Returns the address to be called. | ||||||||||
655 | const ExecutorAddr &getCallee() const { return FnAddr; } | ||||||||||
656 | |||||||||||
657 | /// Returns the argument data. | ||||||||||
658 | const ArgDataBufferType &getArgData() const { return ArgData; } | ||||||||||
659 | |||||||||||
660 | /// WrapperFunctionCalls convert to true if the callee is non-null. | ||||||||||
661 | explicit operator bool() const { return !!FnAddr; } | ||||||||||
662 | |||||||||||
663 | /// Run call returning raw WrapperFunctionResult. | ||||||||||
664 | shared::WrapperFunctionResult run() const { | ||||||||||
665 | using FnTy = | ||||||||||
666 | shared::CWrapperFunctionResult(const char *ArgData, size_t ArgSize); | ||||||||||
667 | return shared::WrapperFunctionResult( | ||||||||||
668 | FnAddr.toPtr<FnTy *>()(ArgData.data(), ArgData.size())); | ||||||||||
669 | } | ||||||||||
670 | |||||||||||
671 | /// Run call and deserialize result using SPS. | ||||||||||
672 | template <typename SPSRetT, typename RetT> | ||||||||||
673 | std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error> | ||||||||||
674 | runWithSPSRet(RetT &RetVal) const { | ||||||||||
675 | auto WFR = run(); | ||||||||||
676 | if (const char *ErrMsg = WFR.getOutOfBandError()) | ||||||||||
677 | return make_error<StringError>(ErrMsg, inconvertibleErrorCode()); | ||||||||||
678 | shared::SPSInputBuffer IB(WFR.data(), WFR.size()); | ||||||||||
679 | if (!shared::SPSSerializationTraits<SPSRetT, RetT>::deserialize(IB, RetVal)) | ||||||||||
680 | return make_error<StringError>("Could not deserialize result from " | ||||||||||
681 | "serialized wrapper function call", | ||||||||||
682 | inconvertibleErrorCode()); | ||||||||||
683 | return Error::success(); | ||||||||||
684 | } | ||||||||||
685 | |||||||||||
686 | /// Overload for SPS functions returning void. | ||||||||||
687 | template <typename SPSRetT> | ||||||||||
688 | std::enable_if_t<std::is_same<SPSRetT, void>::value, Error> | ||||||||||
689 | runWithSPSRet() const { | ||||||||||
690 | shared::SPSEmpty E; | ||||||||||
691 | return runWithSPSRet<shared::SPSEmpty>(E); | ||||||||||
692 | } | ||||||||||
693 | |||||||||||
694 | /// Run call and deserialize an SPSError result. SPSError returns and | ||||||||||
695 | /// deserialization failures are merged into the returned error. | ||||||||||
696 | Error runWithSPSRetErrorMerged() const { | ||||||||||
697 | detail::SPSSerializableError RetErr; | ||||||||||
698 | if (auto Err = runWithSPSRet<SPSError>(RetErr)) | ||||||||||
699 | return Err; | ||||||||||
700 | return detail::fromSPSSerializable(std::move(RetErr)); | ||||||||||
701 | } | ||||||||||
702 | |||||||||||
703 | private: | ||||||||||
704 | orc::ExecutorAddr FnAddr; | ||||||||||
705 | ArgDataBufferType ArgData; | ||||||||||
706 | }; | ||||||||||
707 | |||||||||||
708 | using SPSWrapperFunctionCall = SPSTuple<SPSExecutorAddr, SPSSequence<char>>; | ||||||||||
709 | |||||||||||
710 | template <> | ||||||||||
711 | class SPSSerializationTraits<SPSWrapperFunctionCall, WrapperFunctionCall> { | ||||||||||
712 | public: | ||||||||||
713 | static size_t size(const WrapperFunctionCall &WFC) { | ||||||||||
714 | return SPSWrapperFunctionCall::AsArgList::size(WFC.getCallee(), | ||||||||||
715 | WFC.getArgData()); | ||||||||||
716 | } | ||||||||||
717 | |||||||||||
718 | static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC) { | ||||||||||
719 | return SPSWrapperFunctionCall::AsArgList::serialize(OB, WFC.getCallee(), | ||||||||||
720 | WFC.getArgData()); | ||||||||||
721 | } | ||||||||||
722 | |||||||||||
723 | static bool deserialize(SPSInputBuffer &IB, WrapperFunctionCall &WFC) { | ||||||||||
724 | ExecutorAddr FnAddr; | ||||||||||
725 | WrapperFunctionCall::ArgDataBufferType ArgData; | ||||||||||
726 | if (!SPSWrapperFunctionCall::AsArgList::deserialize(IB, FnAddr, ArgData)) | ||||||||||
727 | return false; | ||||||||||
728 | WFC = WrapperFunctionCall(FnAddr, std::move(ArgData)); | ||||||||||
729 | return true; | ||||||||||
730 | } | ||||||||||
731 | }; | ||||||||||
732 | |||||||||||
733 | } // end namespace shared | ||||||||||
734 | } // end namespace orc | ||||||||||
735 | } // end namespace llvm | ||||||||||
736 | |||||||||||
737 | #endif // LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H |
1 | //===- llvm/Support/Error.h - Recoverable error handling --------*- C++ -*-===// |
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 | // This file defines an API used to report recoverable errors. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_SUPPORT_ERROR_H |
14 | #define LLVM_SUPPORT_ERROR_H |
15 | |
16 | #include "llvm-c/Error.h" |
17 | #include "llvm/ADT/SmallVector.h" |
18 | #include "llvm/ADT/StringExtras.h" |
19 | #include "llvm/ADT/Twine.h" |
20 | #include "llvm/Config/abi-breaking.h" |
21 | #include "llvm/Support/AlignOf.h" |
22 | #include "llvm/Support/Compiler.h" |
23 | #include "llvm/Support/Debug.h" |
24 | #include "llvm/Support/ErrorHandling.h" |
25 | #include "llvm/Support/ErrorOr.h" |
26 | #include "llvm/Support/Format.h" |
27 | #include "llvm/Support/raw_ostream.h" |
28 | #include <cassert> |
29 | #include <cstdint> |
30 | #include <cstdlib> |
31 | #include <functional> |
32 | #include <memory> |
33 | #include <new> |
34 | #include <optional> |
35 | #include <string> |
36 | #include <system_error> |
37 | #include <type_traits> |
38 | #include <utility> |
39 | #include <vector> |
40 | |
41 | namespace llvm { |
42 | |
43 | class ErrorSuccess; |
44 | |
45 | /// Base class for error info classes. Do not extend this directly: Extend |
46 | /// the ErrorInfo template subclass instead. |
47 | class ErrorInfoBase { |
48 | public: |
49 | virtual ~ErrorInfoBase() = default; |
50 | |
51 | /// Print an error message to an output stream. |
52 | virtual void log(raw_ostream &OS) const = 0; |
53 | |
54 | /// Return the error message as a string. |
55 | virtual std::string message() const { |
56 | std::string Msg; |
57 | raw_string_ostream OS(Msg); |
58 | log(OS); |
59 | return OS.str(); |
60 | } |
61 | |
62 | /// Convert this error to a std::error_code. |
63 | /// |
64 | /// This is a temporary crutch to enable interaction with code still |
65 | /// using std::error_code. It will be removed in the future. |
66 | virtual std::error_code convertToErrorCode() const = 0; |
67 | |
68 | // Returns the class ID for this type. |
69 | static const void *classID() { return &ID; } |
70 | |
71 | // Returns the class ID for the dynamic type of this ErrorInfoBase instance. |
72 | virtual const void *dynamicClassID() const = 0; |
73 | |
74 | // Check whether this instance is a subclass of the class identified by |
75 | // ClassID. |
76 | virtual bool isA(const void *const ClassID) const { |
77 | return ClassID == classID(); |
78 | } |
79 | |
80 | // Check whether this instance is a subclass of ErrorInfoT. |
81 | template <typename ErrorInfoT> bool isA() const { |
82 | return isA(ErrorInfoT::classID()); |
83 | } |
84 | |
85 | private: |
86 | virtual void anchor(); |
87 | |
88 | static char ID; |
89 | }; |
90 | |
91 | /// Lightweight error class with error context and mandatory checking. |
92 | /// |
93 | /// Instances of this class wrap a ErrorInfoBase pointer. Failure states |
94 | /// are represented by setting the pointer to a ErrorInfoBase subclass |
95 | /// instance containing information describing the failure. Success is |
96 | /// represented by a null pointer value. |
97 | /// |
98 | /// Instances of Error also contains a 'Checked' flag, which must be set |
99 | /// before the destructor is called, otherwise the destructor will trigger a |
100 | /// runtime error. This enforces at runtime the requirement that all Error |
101 | /// instances be checked or returned to the caller. |
102 | /// |
103 | /// There are two ways to set the checked flag, depending on what state the |
104 | /// Error instance is in. For Error instances indicating success, it |
105 | /// is sufficient to invoke the boolean conversion operator. E.g.: |
106 | /// |
107 | /// @code{.cpp} |
108 | /// Error foo(<...>); |
109 | /// |
110 | /// if (auto E = foo(<...>)) |
111 | /// return E; // <- Return E if it is in the error state. |
112 | /// // We have verified that E was in the success state. It can now be safely |
113 | /// // destroyed. |
114 | /// @endcode |
115 | /// |
116 | /// A success value *can not* be dropped. For example, just calling 'foo(<...>)' |
117 | /// without testing the return value will raise a runtime error, even if foo |
118 | /// returns success. |
119 | /// |
120 | /// For Error instances representing failure, you must use either the |
121 | /// handleErrors or handleAllErrors function with a typed handler. E.g.: |
122 | /// |
123 | /// @code{.cpp} |
124 | /// class MyErrorInfo : public ErrorInfo<MyErrorInfo> { |
125 | /// // Custom error info. |
126 | /// }; |
127 | /// |
128 | /// Error foo(<...>) { return make_error<MyErrorInfo>(...); } |
129 | /// |
130 | /// auto E = foo(<...>); // <- foo returns failure with MyErrorInfo. |
131 | /// auto NewE = |
132 | /// handleErrors(E, |
133 | /// [](const MyErrorInfo &M) { |
134 | /// // Deal with the error. |
135 | /// }, |
136 | /// [](std::unique_ptr<OtherError> M) -> Error { |
137 | /// if (canHandle(*M)) { |
138 | /// // handle error. |
139 | /// return Error::success(); |
140 | /// } |
141 | /// // Couldn't handle this error instance. Pass it up the stack. |
142 | /// return Error(std::move(M)); |
143 | /// ); |
144 | /// // Note - we must check or return NewE in case any of the handlers |
145 | /// // returned a new error. |
146 | /// @endcode |
147 | /// |
148 | /// The handleAllErrors function is identical to handleErrors, except |
149 | /// that it has a void return type, and requires all errors to be handled and |
150 | /// no new errors be returned. It prevents errors (assuming they can all be |
151 | /// handled) from having to be bubbled all the way to the top-level. |
152 | /// |
153 | /// *All* Error instances must be checked before destruction, even if |
154 | /// they're moved-assigned or constructed from Success values that have already |
155 | /// been checked. This enforces checking through all levels of the call stack. |
156 | class [[nodiscard]] Error { |
157 | // ErrorList needs to be able to yank ErrorInfoBase pointers out of Errors |
158 | // to add to the error list. It can't rely on handleErrors for this, since |
159 | // handleErrors does not support ErrorList handlers. |
160 | friend class ErrorList; |
161 | |
162 | // handleErrors needs to be able to set the Checked flag. |
163 | template <typename... HandlerTs> |
164 | friend Error handleErrors(Error E, HandlerTs &&... Handlers); |
165 | |
166 | // Expected<T> needs to be able to steal the payload when constructed from an |
167 | // error. |
168 | template <typename T> friend class Expected; |
169 | |
170 | // wrap needs to be able to steal the payload. |
171 | friend LLVMErrorRef wrap(Error); |
172 | |
173 | protected: |
174 | /// Create a success value. Prefer using 'Error::success()' for readability |
175 | Error() { |
176 | setPtr(nullptr); |
177 | setChecked(false); |
178 | } |
179 | |
180 | public: |
181 | /// Create a success value. |
182 | static ErrorSuccess success(); |
183 | |
184 | // Errors are not copy-constructable. |
185 | Error(const Error &Other) = delete; |
186 | |
187 | /// Move-construct an error value. The newly constructed error is considered |
188 | /// unchecked, even if the source error had been checked. The original error |
189 | /// becomes a checked Success value, regardless of its original state. |
190 | Error(Error &&Other) { |
191 | setChecked(true); |
192 | *this = std::move(Other); |
193 | } |
194 | |
195 | /// Create an error value. Prefer using the 'make_error' function, but |
196 | /// this constructor can be useful when "re-throwing" errors from handlers. |
197 | Error(std::unique_ptr<ErrorInfoBase> Payload) { |
198 | setPtr(Payload.release()); |
199 | setChecked(false); |
200 | } |
201 | |
202 | // Errors are not copy-assignable. |
203 | Error &operator=(const Error &Other) = delete; |
204 | |
205 | /// Move-assign an error value. The current error must represent success, you |
206 | /// you cannot overwrite an unhandled error. The current error is then |
207 | /// considered unchecked. The source error becomes a checked success value, |
208 | /// regardless of its original state. |
209 | Error &operator=(Error &&Other) { |
210 | // Don't allow overwriting of unchecked values. |
211 | assertIsChecked(); |
212 | setPtr(Other.getPtr()); |
213 | |
214 | // This Error is unchecked, even if the source error was checked. |
215 | setChecked(false); |
216 | |
217 | // Null out Other's payload and set its checked bit. |
218 | Other.setPtr(nullptr); |
219 | Other.setChecked(true); |
220 | |
221 | return *this; |
222 | } |
223 | |
224 | /// Destroy a Error. Fails with a call to abort() if the error is |
225 | /// unchecked. |
226 | ~Error() { |
227 | assertIsChecked(); |
228 | delete getPtr(); |
229 | } |
230 | |
231 | /// Bool conversion. Returns true if this Error is in a failure state, |
232 | /// and false if it is in an accept state. If the error is in a Success state |
233 | /// it will be considered checked. |
234 | explicit operator bool() { |
235 | setChecked(getPtr() == nullptr); |
236 | return getPtr() != nullptr; |
237 | } |
238 | |
239 | /// Check whether one error is a subclass of another. |
240 | template <typename ErrT> bool isA() const { |
241 | return getPtr() && getPtr()->isA(ErrT::classID()); |
242 | } |
243 | |
244 | /// Returns the dynamic class id of this error, or null if this is a success |
245 | /// value. |
246 | const void* dynamicClassID() const { |
247 | if (!getPtr()) |
248 | return nullptr; |
249 | return getPtr()->dynamicClassID(); |
250 | } |
251 | |
252 | private: |
253 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
254 | // assertIsChecked() happens very frequently, but under normal circumstances |
255 | // is supposed to be a no-op. So we want it to be inlined, but having a bunch |
256 | // of debug prints can cause the function to be too large for inlining. So |
257 | // it's important that we define this function out of line so that it can't be |
258 | // inlined. |
259 | [[noreturn]] void fatalUncheckedError() const; |
260 | #endif |
261 | |
262 | void assertIsChecked() { |
263 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
264 | if (LLVM_UNLIKELY(!getChecked() || getPtr())__builtin_expect((bool)(!getChecked() || getPtr()), false)) |
265 | fatalUncheckedError(); |
266 | #endif |
267 | } |
268 | |
269 | ErrorInfoBase *getPtr() const { |
270 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
271 | return reinterpret_cast<ErrorInfoBase*>( |
272 | reinterpret_cast<uintptr_t>(Payload) & |
273 | ~static_cast<uintptr_t>(0x1)); |
274 | #else |
275 | return Payload; |
276 | #endif |
277 | } |
278 | |
279 | void setPtr(ErrorInfoBase *EI) { |
280 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
281 | Payload = reinterpret_cast<ErrorInfoBase*>( |
282 | (reinterpret_cast<uintptr_t>(EI) & |
283 | ~static_cast<uintptr_t>(0x1)) | |
284 | (reinterpret_cast<uintptr_t>(Payload) & 0x1)); |
285 | #else |
286 | Payload = EI; |
287 | #endif |
288 | } |
289 | |
290 | bool getChecked() const { |
291 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
292 | return (reinterpret_cast<uintptr_t>(Payload) & 0x1) == 0; |
293 | #else |
294 | return true; |
295 | #endif |
296 | } |
297 | |
298 | void setChecked(bool V) { |
299 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
300 | Payload = reinterpret_cast<ErrorInfoBase*>( |
301 | (reinterpret_cast<uintptr_t>(Payload) & |
302 | ~static_cast<uintptr_t>(0x1)) | |
303 | (V ? 0 : 1)); |
304 | #endif |
305 | } |
306 | |
307 | std::unique_ptr<ErrorInfoBase> takePayload() { |
308 | std::unique_ptr<ErrorInfoBase> Tmp(getPtr()); |
309 | setPtr(nullptr); |
310 | setChecked(true); |
311 | return Tmp; |
312 | } |
313 | |
314 | friend raw_ostream &operator<<(raw_ostream &OS, const Error &E) { |
315 | if (auto *P = E.getPtr()) |
316 | P->log(OS); |
317 | else |
318 | OS << "success"; |
319 | return OS; |
320 | } |
321 | |
322 | ErrorInfoBase *Payload = nullptr; |
323 | }; |
324 | |
325 | /// Subclass of Error for the sole purpose of identifying the success path in |
326 | /// the type system. This allows to catch invalid conversion to Expected<T> at |
327 | /// compile time. |
328 | class ErrorSuccess final : public Error {}; |
329 | |
330 | inline ErrorSuccess Error::success() { return ErrorSuccess(); } |
331 | |
332 | /// Make a Error instance representing failure using the given error info |
333 | /// type. |
334 | template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) { |
335 | return Error(std::make_unique<ErrT>(std::forward<ArgTs>(Args)...)); |
336 | } |
337 | |
338 | /// Base class for user error types. Users should declare their error types |
339 | /// like: |
340 | /// |
341 | /// class MyError : public ErrorInfo<MyError> { |
342 | /// .... |
343 | /// }; |
344 | /// |
345 | /// This class provides an implementation of the ErrorInfoBase::kind |
346 | /// method, which is used by the Error RTTI system. |
347 | template <typename ThisErrT, typename ParentErrT = ErrorInfoBase> |
348 | class ErrorInfo : public ParentErrT { |
349 | public: |
350 | using ParentErrT::ParentErrT; // inherit constructors |
351 | |
352 | static const void *classID() { return &ThisErrT::ID; } |
353 | |
354 | const void *dynamicClassID() const override { return &ThisErrT::ID; } |
355 | |
356 | bool isA(const void *const ClassID) const override { |
357 | return ClassID == classID() || ParentErrT::isA(ClassID); |
358 | } |
359 | }; |
360 | |
361 | /// Special ErrorInfo subclass representing a list of ErrorInfos. |
362 | /// Instances of this class are constructed by joinError. |
363 | class ErrorList final : public ErrorInfo<ErrorList> { |
364 | // handleErrors needs to be able to iterate the payload list of an |
365 | // ErrorList. |
366 | template <typename... HandlerTs> |
367 | friend Error handleErrors(Error E, HandlerTs &&... Handlers); |
368 | |
369 | // joinErrors is implemented in terms of join. |
370 | friend Error joinErrors(Error, Error); |
371 | |
372 | public: |
373 | void log(raw_ostream &OS) const override { |
374 | OS << "Multiple errors:\n"; |
375 | for (const auto &ErrPayload : Payloads) { |
376 | ErrPayload->log(OS); |
377 | OS << "\n"; |
378 | } |
379 | } |
380 | |
381 | std::error_code convertToErrorCode() const override; |
382 | |
383 | // Used by ErrorInfo::classID. |
384 | static char ID; |
385 | |
386 | private: |
387 | ErrorList(std::unique_ptr<ErrorInfoBase> Payload1, |
388 | std::unique_ptr<ErrorInfoBase> Payload2) { |
389 | assert(!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() &&(static_cast <bool> (!Payload1->isA<ErrorList> () && !Payload2->isA<ErrorList>() && "ErrorList constructor payloads should be singleton errors") ? void (0) : __assert_fail ("!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() && \"ErrorList constructor payloads should be singleton errors\"" , "llvm/include/llvm/Support/Error.h", 390, __extension__ __PRETTY_FUNCTION__ )) |
390 | "ErrorList constructor payloads should be singleton errors")(static_cast <bool> (!Payload1->isA<ErrorList> () && !Payload2->isA<ErrorList>() && "ErrorList constructor payloads should be singleton errors") ? void (0) : __assert_fail ("!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() && \"ErrorList constructor payloads should be singleton errors\"" , "llvm/include/llvm/Support/Error.h", 390, __extension__ __PRETTY_FUNCTION__ )); |
391 | Payloads.push_back(std::move(Payload1)); |
392 | Payloads.push_back(std::move(Payload2)); |
393 | } |
394 | |
395 | static Error join(Error E1, Error E2) { |
396 | if (!E1) |
397 | return E2; |
398 | if (!E2) |
399 | return E1; |
400 | if (E1.isA<ErrorList>()) { |
401 | auto &E1List = static_cast<ErrorList &>(*E1.getPtr()); |
402 | if (E2.isA<ErrorList>()) { |
403 | auto E2Payload = E2.takePayload(); |
404 | auto &E2List = static_cast<ErrorList &>(*E2Payload); |
405 | for (auto &Payload : E2List.Payloads) |
406 | E1List.Payloads.push_back(std::move(Payload)); |
407 | } else |
408 | E1List.Payloads.push_back(E2.takePayload()); |
409 | |
410 | return E1; |
411 | } |
412 | if (E2.isA<ErrorList>()) { |
413 | auto &E2List = static_cast<ErrorList &>(*E2.getPtr()); |
414 | E2List.Payloads.insert(E2List.Payloads.begin(), E1.takePayload()); |
415 | return E2; |
416 | } |
417 | return Error(std::unique_ptr<ErrorList>( |
418 | new ErrorList(E1.takePayload(), E2.takePayload()))); |
419 | } |
420 | |
421 | std::vector<std::unique_ptr<ErrorInfoBase>> Payloads; |
422 | }; |
423 | |
424 | /// Concatenate errors. The resulting Error is unchecked, and contains the |
425 | /// ErrorInfo(s), if any, contained in E1, followed by the |
426 | /// ErrorInfo(s), if any, contained in E2. |
427 | inline Error joinErrors(Error E1, Error E2) { |
428 | return ErrorList::join(std::move(E1), std::move(E2)); |
429 | } |
430 | |
431 | /// Tagged union holding either a T or a Error. |
432 | /// |
433 | /// This class parallels ErrorOr, but replaces error_code with Error. Since |
434 | /// Error cannot be copied, this class replaces getError() with |
435 | /// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the |
436 | /// error class type. |
437 | /// |
438 | /// Example usage of 'Expected<T>' as a function return type: |
439 | /// |
440 | /// @code{.cpp} |
441 | /// Expected<int> myDivide(int A, int B) { |
442 | /// if (B == 0) { |
443 | /// // return an Error |
444 | /// return createStringError(inconvertibleErrorCode(), |
445 | /// "B must not be zero!"); |
446 | /// } |
447 | /// // return an integer |
448 | /// return A / B; |
449 | /// } |
450 | /// @endcode |
451 | /// |
452 | /// Checking the results of to a function returning 'Expected<T>': |
453 | /// @code{.cpp} |
454 | /// if (auto E = Result.takeError()) { |
455 | /// // We must consume the error. Typically one of: |
456 | /// // - return the error to our caller |
457 | /// // - toString(), when logging |
458 | /// // - consumeError(), to silently swallow the error |
459 | /// // - handleErrors(), to distinguish error types |
460 | /// errs() << "Problem with division " << toString(std::move(E)) << "\n"; |
461 | /// return; |
462 | /// } |
463 | /// // use the result |
464 | /// outs() << "The answer is " << *Result << "\n"; |
465 | /// @endcode |
466 | /// |
467 | /// For unit-testing a function returning an 'Expected<T>', see the |
468 | /// 'EXPECT_THAT_EXPECTED' macros in llvm/Testing/Support/Error.h |
469 | |
470 | template <class T> class [[nodiscard]] Expected { |
471 | template <class T1> friend class ExpectedAsOutParameter; |
472 | template <class OtherT> friend class Expected; |
473 | |
474 | static constexpr bool isRef = std::is_reference_v<T>; |
475 | |
476 | using wrap = std::reference_wrapper<std::remove_reference_t<T>>; |
477 | |
478 | using error_type = std::unique_ptr<ErrorInfoBase>; |
479 | |
480 | public: |
481 | using storage_type = std::conditional_t<isRef, wrap, T>; |
482 | using value_type = T; |
483 | |
484 | private: |
485 | using reference = std::remove_reference_t<T> &; |
486 | using const_reference = const std::remove_reference_t<T> &; |
487 | using pointer = std::remove_reference_t<T> *; |
488 | using const_pointer = const std::remove_reference_t<T> *; |
489 | |
490 | public: |
491 | /// Create an Expected<T> error value from the given Error. |
492 | Expected(Error Err) |
493 | : HasError(true) |
494 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
495 | // Expected is unchecked upon construction in Debug builds. |
496 | , Unchecked(true) |
497 | #endif |
498 | { |
499 | assert(Err && "Cannot create Expected<T> from Error success value.")(static_cast <bool> (Err && "Cannot create Expected<T> from Error success value." ) ? void (0) : __assert_fail ("Err && \"Cannot create Expected<T> from Error success value.\"" , "llvm/include/llvm/Support/Error.h", 499, __extension__ __PRETTY_FUNCTION__ )); |
500 | new (getErrorStorage()) error_type(Err.takePayload()); |
501 | } |
502 | |
503 | /// Forbid to convert from Error::success() implicitly, this avoids having |
504 | /// Expected<T> foo() { return Error::success(); } which compiles otherwise |
505 | /// but triggers the assertion above. |
506 | Expected(ErrorSuccess) = delete; |
507 | |
508 | /// Create an Expected<T> success value from the given OtherT value, which |
509 | /// must be convertible to T. |
510 | template <typename OtherT> |
511 | Expected(OtherT &&Val, |
512 | std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr) |
513 | : HasError(false) |
514 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
515 | // Expected is unchecked upon construction in Debug builds. |
516 | , |
517 | Unchecked(true) |
518 | #endif |
519 | { |
520 | new (getStorage()) storage_type(std::forward<OtherT>(Val)); |
521 | } |
522 | |
523 | /// Move construct an Expected<T> value. |
524 | Expected(Expected &&Other) { moveConstruct(std::move(Other)); } |
525 | |
526 | /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT |
527 | /// must be convertible to T. |
528 | template <class OtherT> |
529 | Expected(Expected<OtherT> &&Other, |
530 | std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr) { |
531 | moveConstruct(std::move(Other)); |
532 | } |
533 | |
534 | /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT |
535 | /// isn't convertible to T. |
536 | template <class OtherT> |
537 | explicit Expected( |
538 | Expected<OtherT> &&Other, |
539 | std::enable_if_t<!std::is_convertible_v<OtherT, T>> * = nullptr) { |
540 | moveConstruct(std::move(Other)); |
541 | } |
542 | |
543 | /// Move-assign from another Expected<T>. |
544 | Expected &operator=(Expected &&Other) { |
545 | moveAssign(std::move(Other)); |
546 | return *this; |
547 | } |
548 | |
549 | /// Destroy an Expected<T>. |
550 | ~Expected() { |
551 | assertIsChecked(); |
552 | if (!HasError) |
553 | getStorage()->~storage_type(); |
554 | else |
555 | getErrorStorage()->~error_type(); |
556 | } |
557 | |
558 | /// Return false if there is an error. |
559 | explicit operator bool() { |
560 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
561 | Unchecked = HasError; |
562 | #endif |
563 | return !HasError; |
564 | } |
565 | |
566 | /// Returns a reference to the stored T value. |
567 | reference get() { |
568 | assertIsChecked(); |
569 | return *getStorage(); |
570 | } |
571 | |
572 | /// Returns a const reference to the stored T value. |
573 | const_reference get() const { |
574 | assertIsChecked(); |
575 | return const_cast<Expected<T> *>(this)->get(); |
576 | } |
577 | |
578 | /// Returns \a takeError() after moving the held T (if any) into \p V. |
579 | template <class OtherT> |
580 | Error moveInto( |
581 | OtherT &Value, |
582 | std::enable_if_t<std::is_assignable_v<OtherT &, T &&>> * = nullptr) && { |
583 | if (*this) |
584 | Value = std::move(get()); |
585 | return takeError(); |
586 | } |
587 | |
588 | /// Check that this Expected<T> is an error of type ErrT. |
589 | template <typename ErrT> bool errorIsA() const { |
590 | return HasError && (*getErrorStorage())->template isA<ErrT>(); |
591 | } |
592 | |
593 | /// Take ownership of the stored error. |
594 | /// After calling this the Expected<T> is in an indeterminate state that can |
595 | /// only be safely destructed. No further calls (beside the destructor) should |
596 | /// be made on the Expected<T> value. |
597 | Error takeError() { |
598 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
599 | Unchecked = false; |
600 | #endif |
601 | return HasError ? Error(std::move(*getErrorStorage())) : Error::success(); |
602 | } |
603 | |
604 | /// Returns a pointer to the stored T value. |
605 | pointer operator->() { |
606 | assertIsChecked(); |
607 | return toPointer(getStorage()); |
608 | } |
609 | |
610 | /// Returns a const pointer to the stored T value. |
611 | const_pointer operator->() const { |
612 | assertIsChecked(); |
613 | return toPointer(getStorage()); |
614 | } |
615 | |
616 | /// Returns a reference to the stored T value. |
617 | reference operator*() { |
618 | assertIsChecked(); |
619 | return *getStorage(); |
620 | } |
621 | |
622 | /// Returns a const reference to the stored T value. |
623 | const_reference operator*() const { |
624 | assertIsChecked(); |
625 | return *getStorage(); |
626 | } |
627 | |
628 | private: |
629 | template <class T1> |
630 | static bool compareThisIfSameType(const T1 &a, const T1 &b) { |
631 | return &a == &b; |
632 | } |
633 | |
634 | template <class T1, class T2> |
635 | static bool compareThisIfSameType(const T1 &, const T2 &) { |
636 | return false; |
637 | } |
638 | |
639 | template <class OtherT> void moveConstruct(Expected<OtherT> &&Other) { |
640 | HasError = Other.HasError; |
641 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
642 | Unchecked = true; |
643 | Other.Unchecked = false; |
644 | #endif |
645 | |
646 | if (!HasError) |
647 | new (getStorage()) storage_type(std::move(*Other.getStorage())); |
648 | else |
649 | new (getErrorStorage()) error_type(std::move(*Other.getErrorStorage())); |
650 | } |
651 | |
652 | template <class OtherT> void moveAssign(Expected<OtherT> &&Other) { |
653 | assertIsChecked(); |
654 | |
655 | if (compareThisIfSameType(*this, Other)) |
656 | return; |
657 | |
658 | this->~Expected(); |
659 | new (this) Expected(std::move(Other)); |
660 | } |
661 | |
662 | pointer toPointer(pointer Val) { return Val; } |
663 | |
664 | const_pointer toPointer(const_pointer Val) const { return Val; } |
665 | |
666 | pointer toPointer(wrap *Val) { return &Val->get(); } |
667 | |
668 | const_pointer toPointer(const wrap *Val) const { return &Val->get(); } |
669 | |
670 | storage_type *getStorage() { |
671 | assert(!HasError && "Cannot get value when an error exists!")(static_cast <bool> (!HasError && "Cannot get value when an error exists!" ) ? void (0) : __assert_fail ("!HasError && \"Cannot get value when an error exists!\"" , "llvm/include/llvm/Support/Error.h", 671, __extension__ __PRETTY_FUNCTION__ )); |
672 | return reinterpret_cast<storage_type *>(&TStorage); |
673 | } |
674 | |
675 | const storage_type *getStorage() const { |
676 | assert(!HasError && "Cannot get value when an error exists!")(static_cast <bool> (!HasError && "Cannot get value when an error exists!" ) ? void (0) : __assert_fail ("!HasError && \"Cannot get value when an error exists!\"" , "llvm/include/llvm/Support/Error.h", 676, __extension__ __PRETTY_FUNCTION__ )); |
677 | return reinterpret_cast<const storage_type *>(&TStorage); |
678 | } |
679 | |
680 | error_type *getErrorStorage() { |
681 | assert(HasError && "Cannot get error when a value exists!")(static_cast <bool> (HasError && "Cannot get error when a value exists!" ) ? void (0) : __assert_fail ("HasError && \"Cannot get error when a value exists!\"" , "llvm/include/llvm/Support/Error.h", 681, __extension__ __PRETTY_FUNCTION__ )); |
682 | return reinterpret_cast<error_type *>(&ErrorStorage); |
683 | } |
684 | |
685 | const error_type *getErrorStorage() const { |
686 | assert(HasError && "Cannot get error when a value exists!")(static_cast <bool> (HasError && "Cannot get error when a value exists!" ) ? void (0) : __assert_fail ("HasError && \"Cannot get error when a value exists!\"" , "llvm/include/llvm/Support/Error.h", 686, __extension__ __PRETTY_FUNCTION__ )); |
687 | return reinterpret_cast<const error_type *>(&ErrorStorage); |
688 | } |
689 | |
690 | // Used by ExpectedAsOutParameter to reset the checked flag. |
691 | void setUnchecked() { |
692 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
693 | Unchecked = true; |
694 | #endif |
695 | } |
696 | |
697 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
698 | [[noreturn]] LLVM_ATTRIBUTE_NOINLINE__attribute__((noinline)) void fatalUncheckedExpected() const { |
699 | dbgs() << "Expected<T> must be checked before access or destruction.\n"; |
700 | if (HasError) { |
701 | dbgs() << "Unchecked Expected<T> contained error:\n"; |
702 | (*getErrorStorage())->log(dbgs()); |
703 | } else |
704 | dbgs() << "Expected<T> value was in success state. (Note: Expected<T> " |
705 | "values in success mode must still be checked prior to being " |
706 | "destroyed).\n"; |
707 | abort(); |
708 | } |
709 | #endif |
710 | |
711 | void assertIsChecked() const { |
712 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
713 | if (LLVM_UNLIKELY(Unchecked)__builtin_expect((bool)(Unchecked), false)) |
714 | fatalUncheckedExpected(); |
715 | #endif |
716 | } |
717 | |
718 | union { |
719 | AlignedCharArrayUnion<storage_type> TStorage; |
720 | AlignedCharArrayUnion<error_type> ErrorStorage; |
721 | }; |
722 | bool HasError : 1; |
723 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 |
724 | bool Unchecked : 1; |
725 | #endif |
726 | }; |
727 | |
728 | /// Report a serious error, calling any installed error handler. See |
729 | /// ErrorHandling.h. |
730 | [[noreturn]] void report_fatal_error(Error Err, bool gen_crash_diag = true); |
731 | |
732 | /// Report a fatal error if Err is a failure value. |
733 | /// |
734 | /// This function can be used to wrap calls to fallible functions ONLY when it |
735 | /// is known that the Error will always be a success value. E.g. |
736 | /// |
737 | /// @code{.cpp} |
738 | /// // foo only attempts the fallible operation if DoFallibleOperation is |
739 | /// // true. If DoFallibleOperation is false then foo always returns |
740 | /// // Error::success(). |
741 | /// Error foo(bool DoFallibleOperation); |
742 | /// |
743 | /// cantFail(foo(false)); |
744 | /// @endcode |
745 | inline void cantFail(Error Err, const char *Msg = nullptr) { |
746 | if (Err) { |
747 | if (!Msg) |
748 | Msg = "Failure value returned from cantFail wrapped call"; |
749 | #ifndef NDEBUG |
750 | std::string Str; |
751 | raw_string_ostream OS(Str); |
752 | OS << Msg << "\n" << Err; |
753 | Msg = OS.str().c_str(); |
754 | #endif |
755 | llvm_unreachable(Msg)::llvm::llvm_unreachable_internal(Msg, "llvm/include/llvm/Support/Error.h" , 755); |
756 | } |
757 | } |
758 | |
759 | /// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and |
760 | /// returns the contained value. |
761 | /// |
762 | /// This function can be used to wrap calls to fallible functions ONLY when it |
763 | /// is known that the Error will always be a success value. E.g. |
764 | /// |
765 | /// @code{.cpp} |
766 | /// // foo only attempts the fallible operation if DoFallibleOperation is |
767 | /// // true. If DoFallibleOperation is false then foo always returns an int. |
768 | /// Expected<int> foo(bool DoFallibleOperation); |
769 | /// |
770 | /// int X = cantFail(foo(false)); |
771 | /// @endcode |
772 | template <typename T> |
773 | T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) { |
774 | if (ValOrErr) |
775 | return std::move(*ValOrErr); |
776 | else { |
777 | if (!Msg) |
778 | Msg = "Failure value returned from cantFail wrapped call"; |
779 | #ifndef NDEBUG |
780 | std::string Str; |
781 | raw_string_ostream OS(Str); |
782 | auto E = ValOrErr.takeError(); |
783 | OS << Msg << "\n" << E; |
784 | Msg = OS.str().c_str(); |
785 | #endif |
786 | llvm_unreachable(Msg)::llvm::llvm_unreachable_internal(Msg, "llvm/include/llvm/Support/Error.h" , 786); |
787 | } |
788 | } |
789 | |
790 | /// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and |
791 | /// returns the contained reference. |
792 | /// |
793 | /// This function can be used to wrap calls to fallible functions ONLY when it |
794 | /// is known that the Error will always be a success value. E.g. |
795 | /// |
796 | /// @code{.cpp} |
797 | /// // foo only attempts the fallible operation if DoFallibleOperation is |
798 | /// // true. If DoFallibleOperation is false then foo always returns a Bar&. |
799 | /// Expected<Bar&> foo(bool DoFallibleOperation); |
800 | /// |
801 | /// Bar &X = cantFail(foo(false)); |
802 | /// @endcode |
803 | template <typename T> |
804 | T& cantFail(Expected<T&> ValOrErr, const char *Msg = nullptr) { |
805 | if (ValOrErr) |
806 | return *ValOrErr; |
807 | else { |
808 | if (!Msg) |
809 | Msg = "Failure value returned from cantFail wrapped call"; |
810 | #ifndef NDEBUG |
811 | std::string Str; |
812 | raw_string_ostream OS(Str); |
813 | auto E = ValOrErr.takeError(); |
814 | OS << Msg << "\n" << E; |
815 | Msg = OS.str().c_str(); |
816 | #endif |
817 | llvm_unreachable(Msg)::llvm::llvm_unreachable_internal(Msg, "llvm/include/llvm/Support/Error.h" , 817); |
818 | } |
819 | } |
820 | |
821 | /// Helper for testing applicability of, and applying, handlers for |
822 | /// ErrorInfo types. |
823 | template <typename HandlerT> |
824 | class ErrorHandlerTraits |
825 | : public ErrorHandlerTraits< |
826 | decltype(&std::remove_reference_t<HandlerT>::operator())> {}; |
827 | |
828 | // Specialization functions of the form 'Error (const ErrT&)'. |
829 | template <typename ErrT> class ErrorHandlerTraits<Error (&)(ErrT &)> { |
830 | public: |
831 | static bool appliesTo(const ErrorInfoBase &E) { |
832 | return E.template isA<ErrT>(); |
833 | } |
834 | |
835 | template <typename HandlerT> |
836 | static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { |
837 | assert(appliesTo(*E) && "Applying incorrect handler")(static_cast <bool> (appliesTo(*E) && "Applying incorrect handler" ) ? void (0) : __assert_fail ("appliesTo(*E) && \"Applying incorrect handler\"" , "llvm/include/llvm/Support/Error.h", 837, __extension__ __PRETTY_FUNCTION__ )); |
838 | return H(static_cast<ErrT &>(*E)); |
839 | } |
840 | }; |
841 | |
842 | // Specialization functions of the form 'void (const ErrT&)'. |
843 | template <typename ErrT> class ErrorHandlerTraits<void (&)(ErrT &)> { |
844 | public: |
845 | static bool appliesTo(const ErrorInfoBase &E) { |
846 | return E.template isA<ErrT>(); |
847 | } |
848 | |
849 | template <typename HandlerT> |
850 | static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { |
851 | assert(appliesTo(*E) && "Applying incorrect handler")(static_cast <bool> (appliesTo(*E) && "Applying incorrect handler" ) ? void (0) : __assert_fail ("appliesTo(*E) && \"Applying incorrect handler\"" , "llvm/include/llvm/Support/Error.h", 851, __extension__ __PRETTY_FUNCTION__ )); |
852 | H(static_cast<ErrT &>(*E)); |
853 | return Error::success(); |
854 | } |
855 | }; |
856 | |
857 | /// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'. |
858 | template <typename ErrT> |
859 | class ErrorHandlerTraits<Error (&)(std::unique_ptr<ErrT>)> { |
860 | public: |
861 | static bool appliesTo(const ErrorInfoBase &E) { |
862 | return E.template isA<ErrT>(); |
863 | } |
864 | |
865 | template <typename HandlerT> |
866 | static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { |
867 | assert(appliesTo(*E) && "Applying incorrect handler")(static_cast <bool> (appliesTo(*E) && "Applying incorrect handler" ) ? void (0) : __assert_fail ("appliesTo(*E) && \"Applying incorrect handler\"" , "llvm/include/llvm/Support/Error.h", 867, __extension__ __PRETTY_FUNCTION__ )); |
868 | std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release())); |
869 | return H(std::move(SubE)); |
870 | } |
871 | }; |
872 | |
873 | /// Specialization for functions of the form 'void (std::unique_ptr<ErrT>)'. |
874 | template <typename ErrT> |
875 | class ErrorHandlerTraits<void (&)(std::unique_ptr<ErrT>)> { |
876 | public: |
877 | static bool appliesTo(const ErrorInfoBase &E) { |
878 | return E.template isA<ErrT>(); |
879 | } |
880 | |
881 | template <typename HandlerT> |
882 | static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { |
883 | assert(appliesTo(*E) && "Applying incorrect handler")(static_cast <bool> (appliesTo(*E) && "Applying incorrect handler" ) ? void (0) : __assert_fail ("appliesTo(*E) && \"Applying incorrect handler\"" , "llvm/include/llvm/Support/Error.h", 883, __extension__ __PRETTY_FUNCTION__ )); |
884 | std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release())); |
885 | H(std::move(SubE)); |
886 | return Error::success(); |
887 | } |
888 | }; |
889 | |
890 | // Specialization for member functions of the form 'RetT (const ErrT&)'. |
891 | template <typename C, typename RetT, typename ErrT> |
892 | class ErrorHandlerTraits<RetT (C::*)(ErrT &)> |
893 | : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; |
894 | |
895 | // Specialization for member functions of the form 'RetT (const ErrT&) const'. |
896 | template <typename C, typename RetT, typename ErrT> |
897 | class ErrorHandlerTraits<RetT (C::*)(ErrT &) const> |
898 | : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; |
899 | |
900 | // Specialization for member functions of the form 'RetT (const ErrT&)'. |
901 | template <typename C, typename RetT, typename ErrT> |
902 | class ErrorHandlerTraits<RetT (C::*)(const ErrT &)> |
903 | : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; |
904 | |
905 | // Specialization for member functions of the form 'RetT (const ErrT&) const'. |
906 | template <typename C, typename RetT, typename ErrT> |
907 | class ErrorHandlerTraits<RetT (C::*)(const ErrT &) const> |
908 | : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; |
909 | |
910 | /// Specialization for member functions of the form |
911 | /// 'RetT (std::unique_ptr<ErrT>)'. |
912 | template <typename C, typename RetT, typename ErrT> |
913 | class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>)> |
914 | : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {}; |
915 | |
916 | /// Specialization for member functions of the form |
917 | /// 'RetT (std::unique_ptr<ErrT>) const'. |
918 | template <typename C, typename RetT, typename ErrT> |
919 | class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>) const> |
920 | : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {}; |
921 | |
922 | inline Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload) { |
923 | return Error(std::move(Payload)); |
924 | } |
925 | |
926 | template <typename HandlerT, typename... HandlerTs> |
927 | Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload, |
928 | HandlerT &&Handler, HandlerTs &&... Handlers) { |
929 | if (ErrorHandlerTraits<HandlerT>::appliesTo(*Payload)) |
930 | return ErrorHandlerTraits<HandlerT>::apply(std::forward<HandlerT>(Handler), |
931 | std::move(Payload)); |
932 | return handleErrorImpl(std::move(Payload), |
933 | std::forward<HandlerTs>(Handlers)...); |
934 | } |
935 | |
936 | /// Pass the ErrorInfo(s) contained in E to their respective handlers. Any |
937 | /// unhandled errors (or Errors returned by handlers) are re-concatenated and |
938 | /// returned. |
939 | /// Because this function returns an error, its result must also be checked |
940 | /// or returned. If you intend to handle all errors use handleAllErrors |
941 | /// (which returns void, and will abort() on unhandled errors) instead. |
942 | template <typename... HandlerTs> |
943 | Error handleErrors(Error E, HandlerTs &&... Hs) { |
944 | if (!E) |
945 | return Error::success(); |
946 | |
947 | std::unique_ptr<ErrorInfoBase> Payload = E.takePayload(); |
948 | |
949 | if (Payload->isA<ErrorList>()) { |
950 | ErrorList &List = static_cast<ErrorList &>(*Payload); |
951 | Error R; |
952 | for (auto &P : List.Payloads) |
953 | R = ErrorList::join( |
954 | std::move(R), |
955 | handleErrorImpl(std::move(P), std::forward<HandlerTs>(Hs)...)); |
956 | return R; |
957 | } |
958 | |
959 | return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...); |
960 | } |
961 | |
962 | /// Behaves the same as handleErrors, except that by contract all errors |
963 | /// *must* be handled by the given handlers (i.e. there must be no remaining |
964 | /// errors after running the handlers, or llvm_unreachable is called). |
965 | template <typename... HandlerTs> |
966 | void handleAllErrors(Error E, HandlerTs &&... Handlers) { |
967 | cantFail(handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...)); |
968 | } |
969 | |
970 | /// Check that E is a non-error, then drop it. |
971 | /// If E is an error, llvm_unreachable will be called. |
972 | inline void handleAllErrors(Error E) { |
973 | cantFail(std::move(E)); |
974 | } |
975 | |
976 | /// Handle any errors (if present) in an Expected<T>, then try a recovery path. |
977 | /// |
978 | /// If the incoming value is a success value it is returned unmodified. If it |
979 | /// is a failure value then it the contained error is passed to handleErrors. |
980 | /// If handleErrors is able to handle the error then the RecoveryPath functor |
981 | /// is called to supply the final result. If handleErrors is not able to |
982 | /// handle all errors then the unhandled errors are returned. |
983 | /// |
984 | /// This utility enables the follow pattern: |
985 | /// |
986 | /// @code{.cpp} |
987 | /// enum FooStrategy { Aggressive, Conservative }; |
988 | /// Expected<Foo> foo(FooStrategy S); |
989 | /// |
990 | /// auto ResultOrErr = |
991 | /// handleExpected( |
992 | /// foo(Aggressive), |
993 | /// []() { return foo(Conservative); }, |
994 | /// [](AggressiveStrategyError&) { |
995 | /// // Implicitly conusme this - we'll recover by using a conservative |
996 | /// // strategy. |
997 | /// }); |
998 | /// |
999 | /// @endcode |
1000 | template <typename T, typename RecoveryFtor, typename... HandlerTs> |
1001 | Expected<T> handleExpected(Expected<T> ValOrErr, RecoveryFtor &&RecoveryPath, |
1002 | HandlerTs &&... Handlers) { |
1003 | if (ValOrErr) |
1004 | return ValOrErr; |
1005 | |
1006 | if (auto Err = handleErrors(ValOrErr.takeError(), |
1007 | std::forward<HandlerTs>(Handlers)...)) |
1008 | return std::move(Err); |
1009 | |
1010 | return RecoveryPath(); |
1011 | } |
1012 | |
1013 | /// Log all errors (if any) in E to OS. If there are any errors, ErrorBanner |
1014 | /// will be printed before the first one is logged. A newline will be printed |
1015 | /// after each error. |
1016 | /// |
1017 | /// This function is compatible with the helpers from Support/WithColor.h. You |
1018 | /// can pass any of them as the OS. Please consider using them instead of |
1019 | /// including 'error: ' in the ErrorBanner. |
1020 | /// |
1021 | /// This is useful in the base level of your program to allow clean termination |
1022 | /// (allowing clean deallocation of resources, etc.), while reporting error |
1023 | /// information to the user. |
1024 | void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner = {}); |
1025 | |
1026 | /// Write all error messages (if any) in E to a string. The newline character |
1027 | /// is used to separate error messages. |
1028 | inline std::string toString(Error E) { |
1029 | SmallVector<std::string, 2> Errors; |
1030 | handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) { |
1031 | Errors.push_back(EI.message()); |
1032 | }); |
1033 | return join(Errors.begin(), Errors.end(), "\n"); |
1034 | } |
1035 | |
1036 | /// Consume a Error without doing anything. This method should be used |
1037 | /// only where an error can be considered a reasonable and expected return |
1038 | /// value. |
1039 | /// |
1040 | /// Uses of this method are potentially indicative of design problems: If it's |
1041 | /// legitimate to do nothing while processing an "error", the error-producer |
1042 | /// might be more clearly refactored to return an std::optional<T>. |
1043 | inline void consumeError(Error Err) { |
1044 | handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {}); |
1045 | } |
1046 | |
1047 | /// Convert an Expected to an Optional without doing anything. This method |
1048 | /// should be used only where an error can be considered a reasonable and |
1049 | /// expected return value. |
1050 | /// |
1051 | /// Uses of this method are potentially indicative of problems: perhaps the |
1052 | /// error should be propagated further, or the error-producer should just |
1053 | /// return an Optional in the first place. |
1054 | template <typename T> std::optional<T> expectedToOptional(Expected<T> &&E) { |
1055 | if (E) |
1056 | return std::move(*E); |
1057 | consumeError(E.takeError()); |
1058 | return std::nullopt; |
1059 | } |
1060 | |
1061 | template <typename T> std::optional<T> expectedToStdOptional(Expected<T> &&E) { |
1062 | if (E) |
1063 | return std::move(*E); |
1064 | consumeError(E.takeError()); |
1065 | return std::nullopt; |
1066 | } |
1067 | |
1068 | /// Helper for converting an Error to a bool. |
1069 | /// |
1070 | /// This method returns true if Err is in an error state, or false if it is |
1071 | /// in a success state. Puts Err in a checked state in both cases (unlike |
1072 | /// Error::operator bool(), which only does this for success states). |
1073 | inline bool errorToBool(Error Err) { |
1074 | bool IsError = static_cast<bool>(Err); |
1075 | if (IsError) |
1076 | consumeError(std::move(Err)); |
1077 | return IsError; |
1078 | } |
1079 | |
1080 | /// Helper for Errors used as out-parameters. |
1081 | /// |
1082 | /// This helper is for use with the Error-as-out-parameter idiom, where an error |
1083 | /// is passed to a function or method by reference, rather than being returned. |
1084 | /// In such cases it is helpful to set the checked bit on entry to the function |
1085 | /// so that the error can be written to (unchecked Errors abort on assignment) |
1086 | /// and clear the checked bit on exit so that clients cannot accidentally forget |
1087 | /// to check the result. This helper performs these actions automatically using |
1088 | /// RAII: |
1089 | /// |
1090 | /// @code{.cpp} |
1091 | /// Result foo(Error &Err) { |
1092 | /// ErrorAsOutParameter ErrAsOutParam(&Err); // 'Checked' flag set |
1093 | /// // <body of foo> |
1094 | /// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed. |
1095 | /// } |
1096 | /// @endcode |
1097 | /// |
1098 | /// ErrorAsOutParameter takes an Error* rather than Error& so that it can be |
1099 | /// used with optional Errors (Error pointers that are allowed to be null). If |
1100 | /// ErrorAsOutParameter took an Error reference, an instance would have to be |
1101 | /// created inside every condition that verified that Error was non-null. By |
1102 | /// taking an Error pointer we can just create one instance at the top of the |
1103 | /// function. |
1104 | class ErrorAsOutParameter { |
1105 | public: |
1106 | ErrorAsOutParameter(Error *Err) : Err(Err) { |
1107 | // Raise the checked bit if Err is success. |
1108 | if (Err) |
1109 | (void)!!*Err; |
1110 | } |
1111 | |
1112 | ~ErrorAsOutParameter() { |
1113 | // Clear the checked bit. |
1114 | if (Err && !*Err) |
1115 | *Err = Error::success(); |
1116 | } |
1117 | |
1118 | private: |
1119 | Error *Err; |
1120 | }; |
1121 | |
1122 | /// Helper for Expected<T>s used as out-parameters. |
1123 | /// |
1124 | /// See ErrorAsOutParameter. |
1125 | template <typename T> |
1126 | class ExpectedAsOutParameter { |
1127 | public: |
1128 | ExpectedAsOutParameter(Expected<T> *ValOrErr) |
1129 | : ValOrErr(ValOrErr) { |
1130 | if (ValOrErr) |
1131 | (void)!!*ValOrErr; |
1132 | } |
1133 | |
1134 | ~ExpectedAsOutParameter() { |
1135 | if (ValOrErr) |
1136 | ValOrErr->setUnchecked(); |
1137 | } |
1138 | |
1139 | private: |
1140 | Expected<T> *ValOrErr; |
1141 | }; |
1142 | |
1143 | /// This class wraps a std::error_code in a Error. |
1144 | /// |
1145 | /// This is useful if you're writing an interface that returns a Error |
1146 | /// (or Expected) and you want to call code that still returns |
1147 | /// std::error_codes. |
1148 | class ECError : public ErrorInfo<ECError> { |
1149 | friend Error errorCodeToError(std::error_code); |
1150 | |
1151 | void anchor() override; |
1152 | |
1153 | public: |
1154 | void setErrorCode(std::error_code EC) { this->EC = EC; } |
1155 | std::error_code convertToErrorCode() const override { return EC; } |
1156 | void log(raw_ostream &OS) const override { OS << EC.message(); } |
1157 | |
1158 | // Used by ErrorInfo::classID. |
1159 | static char ID; |
1160 | |
1161 | protected: |
1162 | ECError() = default; |
1163 | ECError(std::error_code EC) : EC(EC) {} |
1164 | |
1165 | std::error_code EC; |
1166 | }; |
1167 | |
1168 | /// The value returned by this function can be returned from convertToErrorCode |
1169 | /// for Error values where no sensible translation to std::error_code exists. |
1170 | /// It should only be used in this situation, and should never be used where a |
1171 | /// sensible conversion to std::error_code is available, as attempts to convert |
1172 | /// to/from this error will result in a fatal error. (i.e. it is a programmatic |
1173 | /// error to try to convert such a value). |
1174 | std::error_code inconvertibleErrorCode(); |
1175 | |
1176 | /// Helper for converting an std::error_code to a Error. |
1177 | Error errorCodeToError(std::error_code EC); |
1178 | |
1179 | /// Helper for converting an ECError to a std::error_code. |
1180 | /// |
1181 | /// This method requires that Err be Error() or an ECError, otherwise it |
1182 | /// will trigger a call to abort(). |
1183 | std::error_code errorToErrorCode(Error Err); |
1184 | |
1185 | /// Convert an ErrorOr<T> to an Expected<T>. |
1186 | template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> &&EO) { |
1187 | if (auto EC = EO.getError()) |
1188 | return errorCodeToError(EC); |
1189 | return std::move(*EO); |
1190 | } |
1191 | |
1192 | /// Convert an Expected<T> to an ErrorOr<T>. |
1193 | template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> &&E) { |
1194 | if (auto Err = E.takeError()) |
1195 | return errorToErrorCode(std::move(Err)); |
1196 | return std::move(*E); |
1197 | } |
1198 | |
1199 | /// This class wraps a string in an Error. |
1200 | /// |
1201 | /// StringError is useful in cases where the client is not expected to be able |
1202 | /// to consume the specific error message programmatically (for example, if the |
1203 | /// error message is to be presented to the user). |
1204 | /// |
1205 | /// StringError can also be used when additional information is to be printed |
1206 | /// along with a error_code message. Depending on the constructor called, this |
1207 | /// class can either display: |
1208 | /// 1. the error_code message (ECError behavior) |
1209 | /// 2. a string |
1210 | /// 3. the error_code message and a string |
1211 | /// |
1212 | /// These behaviors are useful when subtyping is required; for example, when a |
1213 | /// specific library needs an explicit error type. In the example below, |
1214 | /// PDBError is derived from StringError: |
1215 | /// |
1216 | /// @code{.cpp} |
1217 | /// Expected<int> foo() { |
1218 | /// return llvm::make_error<PDBError>(pdb_error_code::dia_failed_loading, |
1219 | /// "Additional information"); |
1220 | /// } |
1221 | /// @endcode |
1222 | /// |
1223 | class StringError : public ErrorInfo<StringError> { |
1224 | public: |
1225 | static char ID; |
1226 | |
1227 | // Prints EC + S and converts to EC |
1228 | StringError(std::error_code EC, const Twine &S = Twine()); |
1229 | |
1230 | // Prints S and converts to EC |
1231 | StringError(const Twine &S, std::error_code EC); |
1232 | |
1233 | void log(raw_ostream &OS) const override; |
1234 | std::error_code convertToErrorCode() const override; |
1235 | |
1236 | const std::string &getMessage() const { return Msg; } |
1237 | |
1238 | private: |
1239 | std::string Msg; |
1240 | std::error_code EC; |
1241 | const bool PrintMsgOnly = false; |
1242 | }; |
1243 | |
1244 | /// Create formatted StringError object. |
1245 | template <typename... Ts> |
1246 | inline Error createStringError(std::error_code EC, char const *Fmt, |
1247 | const Ts &... Vals) { |
1248 | std::string Buffer; |
1249 | raw_string_ostream Stream(Buffer); |
1250 | Stream << format(Fmt, Vals...); |
1251 | return make_error<StringError>(Stream.str(), EC); |
1252 | } |
1253 | |
1254 | Error createStringError(std::error_code EC, char const *Msg); |
1255 | |
1256 | inline Error createStringError(std::error_code EC, const Twine &S) { |
1257 | return createStringError(EC, S.str().c_str()); |
1258 | } |
1259 | |
1260 | template <typename... Ts> |
1261 | inline Error createStringError(std::errc EC, char const *Fmt, |
1262 | const Ts &... Vals) { |
1263 | return createStringError(std::make_error_code(EC), Fmt, Vals...); |
1264 | } |
1265 | |
1266 | /// This class wraps a filename and another Error. |
1267 | /// |
1268 | /// In some cases, an error needs to live along a 'source' name, in order to |
1269 | /// show more detailed information to the user. |
1270 | class FileError final : public ErrorInfo<FileError> { |
1271 | |
1272 | friend Error createFileError(const Twine &, Error); |
1273 | friend Error createFileError(const Twine &, size_t, Error); |
1274 | |
1275 | public: |
1276 | void log(raw_ostream &OS) const override { |
1277 | assert(Err && "Trying to log after takeError().")(static_cast <bool> (Err && "Trying to log after takeError()." ) ? void (0) : __assert_fail ("Err && \"Trying to log after takeError().\"" , "llvm/include/llvm/Support/Error.h", 1277, __extension__ __PRETTY_FUNCTION__ )); |
1278 | OS << "'" << FileName << "': "; |
1279 | if (Line) |
1280 | OS << "line " << *Line << ": "; |
1281 | Err->log(OS); |
1282 | } |
1283 | |
1284 | std::string messageWithoutFileInfo() const { |
1285 | std::string Msg; |
1286 | raw_string_ostream OS(Msg); |
1287 | Err->log(OS); |
1288 | return OS.str(); |
1289 | } |
1290 | |
1291 | StringRef getFileName() const { return FileName; } |
1292 | |
1293 | Error takeError() { return Error(std::move(Err)); } |
1294 | |
1295 | std::error_code convertToErrorCode() const override; |
1296 | |
1297 | // Used by ErrorInfo::classID. |
1298 | static char ID; |
1299 | |
1300 | private: |
1301 | FileError(const Twine &F, std::optional<size_t> LineNum, |
1302 | std::unique_ptr<ErrorInfoBase> E) { |
1303 | assert(E && "Cannot create FileError from Error success value.")(static_cast <bool> (E && "Cannot create FileError from Error success value." ) ? void (0) : __assert_fail ("E && \"Cannot create FileError from Error success value.\"" , "llvm/include/llvm/Support/Error.h", 1303, __extension__ __PRETTY_FUNCTION__ )); |
1304 | FileName = F.str(); |
1305 | Err = std::move(E); |
1306 | Line = std::move(LineNum); |
1307 | } |
1308 | |
1309 | static Error build(const Twine &F, std::optional<size_t> Line, Error E) { |
1310 | std::unique_ptr<ErrorInfoBase> Payload; |
1311 | handleAllErrors(std::move(E), |
1312 | [&](std::unique_ptr<ErrorInfoBase> EIB) -> Error { |
1313 | Payload = std::move(EIB); |
1314 | return Error::success(); |
1315 | }); |
1316 | return Error( |
1317 | std::unique_ptr<FileError>(new FileError(F, Line, std::move(Payload)))); |
1318 | } |
1319 | |
1320 | std::string FileName; |
1321 | std::optional<size_t> Line; |
1322 | std::unique_ptr<ErrorInfoBase> Err; |
1323 | }; |
1324 | |
1325 | /// Concatenate a source file path and/or name with an Error. The resulting |
1326 | /// Error is unchecked. |
1327 | inline Error createFileError(const Twine &F, Error E) { |
1328 | return FileError::build(F, std::optional<size_t>(), std::move(E)); |
1329 | } |
1330 | |
1331 | /// Concatenate a source file path and/or name with line number and an Error. |
1332 | /// The resulting Error is unchecked. |
1333 | inline Error createFileError(const Twine &F, size_t Line, Error E) { |
1334 | return FileError::build(F, std::optional<size_t>(Line), std::move(E)); |
1335 | } |
1336 | |
1337 | /// Concatenate a source file path and/or name with a std::error_code |
1338 | /// to form an Error object. |
1339 | inline Error createFileError(const Twine &F, std::error_code EC) { |
1340 | return createFileError(F, errorCodeToError(EC)); |
1341 | } |
1342 | |
1343 | /// Concatenate a source file path and/or name with line number and |
1344 | /// std::error_code to form an Error object. |
1345 | inline Error createFileError(const Twine &F, size_t Line, std::error_code EC) { |
1346 | return createFileError(F, Line, errorCodeToError(EC)); |
1347 | } |
1348 | |
1349 | Error createFileError(const Twine &F, ErrorSuccess) = delete; |
1350 | |
1351 | /// Helper for check-and-exit error handling. |
1352 | /// |
1353 | /// For tool use only. NOT FOR USE IN LIBRARY CODE. |
1354 | /// |
1355 | class ExitOnError { |
1356 | public: |
1357 | /// Create an error on exit helper. |
1358 | ExitOnError(std::string Banner = "", int DefaultErrorExitCode = 1) |
1359 | : Banner(std::move(Banner)), |
1360 | GetExitCode([=](const Error &) { return DefaultErrorExitCode; }) {} |
1361 | |
1362 | /// Set the banner string for any errors caught by operator(). |
1363 | void setBanner(std::string Banner) { this->Banner = std::move(Banner); } |
1364 | |
1365 | /// Set the exit-code mapper function. |
1366 | void setExitCodeMapper(std::function<int(const Error &)> GetExitCode) { |
1367 | this->GetExitCode = std::move(GetExitCode); |
1368 | } |
1369 | |
1370 | /// Check Err. If it's in a failure state log the error(s) and exit. |
1371 | void operator()(Error Err) const { checkError(std::move(Err)); } |
1372 | |
1373 | /// Check E. If it's in a success state then return the contained value. If |
1374 | /// it's in a failure state log the error(s) and exit. |
1375 | template <typename T> T operator()(Expected<T> &&E) const { |
1376 | checkError(E.takeError()); |
1377 | return std::move(*E); |
1378 | } |
1379 | |
1380 | /// Check E. If it's in a success state then return the contained reference. If |
1381 | /// it's in a failure state log the error(s) and exit. |
1382 | template <typename T> T& operator()(Expected<T&> &&E) const { |
1383 | checkError(E.takeError()); |
1384 | return *E; |
1385 | } |
1386 | |
1387 | private: |
1388 | void checkError(Error Err) const { |
1389 | if (Err) { |
1390 | int ExitCode = GetExitCode(Err); |
1391 | logAllUnhandledErrors(std::move(Err), errs(), Banner); |
1392 | exit(ExitCode); |
1393 | } |
1394 | } |
1395 | |
1396 | std::string Banner; |
1397 | std::function<int(const Error &)> GetExitCode; |
1398 | }; |
1399 | |
1400 | /// Conversion from Error to LLVMErrorRef for C error bindings. |
1401 | inline LLVMErrorRef wrap(Error Err) { |
1402 | return reinterpret_cast<LLVMErrorRef>(Err.takePayload().release()); |
1403 | } |
1404 | |
1405 | /// Conversion from LLVMErrorRef to Error for C error bindings. |
1406 | inline Error unwrap(LLVMErrorRef ErrRef) { |
1407 | return Error(std::unique_ptr<ErrorInfoBase>( |
1408 | reinterpret_cast<ErrorInfoBase *>(ErrRef))); |
1409 | } |
1410 | |
1411 | } // end namespace llvm |
1412 | |
1413 | #endif // LLVM_SUPPORT_ERROR_H |