Bug Summary

File:build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
Warning:line 564, column 10
Moved-from object 'ErrResult' is moved

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ELFNixPlatform.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-15/lib/clang/15.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I lib/ExecutionEngine/Orc -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/lib/ExecutionEngine/Orc -I include -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-15/lib/clang/15.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -O3 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-04-20-140412-16051-1 -x c++ /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp

/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp

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/x86_64.h"
14#include "llvm/ExecutionEngine/Orc/DebugUtils.h"
15#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
16#include "llvm/Support/BinaryByteStream.h"
17#include "llvm/Support/Debug.h"
18
19#define DEBUG_TYPE"orc" "orc"
20
21using namespace llvm;
22using namespace llvm::orc;
23using namespace llvm::orc::shared;
24
25namespace {
26
27class DSOHandleMaterializationUnit : public MaterializationUnit {
28public:
29 DSOHandleMaterializationUnit(ELFNixPlatform &ENP,
30 const SymbolStringPtr &DSOHandleSymbol)
31 : MaterializationUnit(
32 createDSOHandleSectionInterface(ENP, DSOHandleSymbol)),
33 ENP(ENP) {}
34
35 StringRef getName() const override { return "DSOHandleMU"; }
36
37 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
38 unsigned PointerSize;
39 support::endianness Endianness;
40 jitlink::Edge::Kind EdgeKind;
41 const auto &TT =
42 ENP.getExecutionSession().getExecutorProcessControl().getTargetTriple();
43
44 switch (TT.getArch()) {
45 case Triple::x86_64:
46 PointerSize = 8;
47 Endianness = support::endianness::little;
48 EdgeKind = jitlink::x86_64::Pointer64;
49 break;
50 default:
51 llvm_unreachable("Unrecognized architecture")::llvm::llvm_unreachable_internal("Unrecognized architecture"
, "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp", 51)
;
52 }
53
54 // void *__dso_handle = &__dso_handle;
55 auto G = std::make_unique<jitlink::LinkGraph>(
56 "<DSOHandleMU>", TT, PointerSize, Endianness,
57 jitlink::getGenericEdgeKindName);
58 auto &DSOHandleSection =
59 G->createSection(".data.__dso_handle", jitlink::MemProt::Read);
60 auto &DSOHandleBlock = G->createContentBlock(
61 DSOHandleSection, getDSOHandleContent(PointerSize), orc::ExecutorAddr(),
62 8, 0);
63 auto &DSOHandleSymbol = G->addDefinedSymbol(
64 DSOHandleBlock, 0, *R->getInitializerSymbol(), DSOHandleBlock.getSize(),
65 jitlink::Linkage::Strong, jitlink::Scope::Default, false, true);
66 DSOHandleBlock.addEdge(EdgeKind, 0, DSOHandleSymbol, 0);
67
68 ENP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
69 }
70
71 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
72
73private:
74 static MaterializationUnit::Interface
75 createDSOHandleSectionInterface(ELFNixPlatform &ENP,
76 const SymbolStringPtr &DSOHandleSymbol) {
77 SymbolFlagsMap SymbolFlags;
78 SymbolFlags[DSOHandleSymbol] = JITSymbolFlags::Exported;
79 return MaterializationUnit::Interface(std::move(SymbolFlags),
80 DSOHandleSymbol);
81 }
82
83 ArrayRef<char> getDSOHandleContent(size_t PointerSize) {
84 static const char Content[8] = {0};
85 assert(PointerSize <= sizeof Content)(static_cast <bool> (PointerSize <= sizeof Content) ?
void (0) : __assert_fail ("PointerSize <= sizeof Content"
, "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp", 85, __extension__
__PRETTY_FUNCTION__))
;
86 return {Content, PointerSize};
87 }
88
89 ELFNixPlatform &ENP;
90};
91
92StringRef EHFrameSectionName = ".eh_frame";
93StringRef InitArrayFuncSectionName = ".init_array";
94
95StringRef ThreadBSSSectionName = ".tbss";
96StringRef ThreadDataSectionName = ".tdata";
97
98StringRef InitSectionNames[] = {InitArrayFuncSectionName};
99
100} // end anonymous namespace
101
102namespace llvm {
103namespace orc {
104
105Expected<std::unique_ptr<ELFNixPlatform>>
106ELFNixPlatform::Create(ExecutionSession &ES,
107 ObjectLinkingLayer &ObjLinkingLayer,
108 JITDylib &PlatformJD, const char *OrcRuntimePath,
109 Optional<SymbolAliasMap> RuntimeAliases) {
110
111 auto &EPC = ES.getExecutorProcessControl();
112
113 // If the target is not supported then bail out immediately.
114 if (!supportedTarget(EPC.getTargetTriple()))
115 return make_error<StringError>("Unsupported ELFNixPlatform triple: " +
116 EPC.getTargetTriple().str(),
117 inconvertibleErrorCode());
118
119 // Create default aliases if the caller didn't supply any.
120 if (!RuntimeAliases)
121 RuntimeAliases = standardPlatformAliases(ES);
122
123 // Define the aliases.
124 if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
125 return std::move(Err);
126
127 // Add JIT-dispatch function support symbols.
128 if (auto Err = PlatformJD.define(absoluteSymbols(
129 {{ES.intern("__orc_rt_jit_dispatch"),
130 {EPC.getJITDispatchInfo().JITDispatchFunction.getValue(),
131 JITSymbolFlags::Exported}},
132 {ES.intern("__orc_rt_jit_dispatch_ctx"),
133 {EPC.getJITDispatchInfo().JITDispatchContext.getValue(),
134 JITSymbolFlags::Exported}}})))
135 return std::move(Err);
136
137 // Create a generator for the ORC runtime archive.
138 auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Load(
139 ObjLinkingLayer, OrcRuntimePath, EPC.getTargetTriple());
140 if (!OrcRuntimeArchiveGenerator)
141 return OrcRuntimeArchiveGenerator.takeError();
142
143 // Create the instance.
144 Error Err = Error::success();
145 auto P = std::unique_ptr<ELFNixPlatform>(
146 new ELFNixPlatform(ES, ObjLinkingLayer, PlatformJD,
147 std::move(*OrcRuntimeArchiveGenerator), Err));
148 if (Err)
149 return std::move(Err);
150 return std::move(P);
151}
152
153Error ELFNixPlatform::setupJITDylib(JITDylib &JD) {
154 return JD.define(
155 std::make_unique<DSOHandleMaterializationUnit>(*this, DSOHandleSymbol));
156}
157
158Error ELFNixPlatform::teardownJITDylib(JITDylib &JD) {
159 return Error::success();
160}
161
162Error ELFNixPlatform::notifyAdding(ResourceTracker &RT,
163 const MaterializationUnit &MU) {
164 auto &JD = RT.getJITDylib();
165 const auto &InitSym = MU.getInitializerSymbol();
166 if (!InitSym)
167 return Error::success();
168
169 RegisteredInitSymbols[&JD].add(InitSym,
170 SymbolLookupFlags::WeaklyReferencedSymbol);
171 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform: Registered init symbol "
<< *InitSym << " for MU " << MU.getName() <<
"\n"; }; } } while (false)
172 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)
173 << " 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)
174 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform: Registered init symbol "
<< *InitSym << " for MU " << MU.getName() <<
"\n"; }; } } while (false)
;
175 return Error::success();
176}
177
178Error ELFNixPlatform::notifyRemoving(ResourceTracker &RT) {
179 llvm_unreachable("Not supported yet")::llvm::llvm_unreachable_internal("Not supported yet", "llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp"
, 179)
;
180}
181
182static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
183 ArrayRef<std::pair<const char *, const char *>> AL) {
184 for (auto &KV : AL) {
185 auto AliasName = ES.intern(KV.first);
186 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", 186, __extension__
__PRETTY_FUNCTION__))
;
187 Aliases[std::move(AliasName)] = {ES.intern(KV.second),
188 JITSymbolFlags::Exported};
189 }
190}
191
192SymbolAliasMap ELFNixPlatform::standardPlatformAliases(ExecutionSession &ES) {
193 SymbolAliasMap Aliases;
194 addAliases(ES, Aliases, requiredCXXAliases());
195 addAliases(ES, Aliases, standardRuntimeUtilityAliases());
196 return Aliases;
197}
198
199ArrayRef<std::pair<const char *, const char *>>
200ELFNixPlatform::requiredCXXAliases() {
201 static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
202 {"__cxa_atexit", "__orc_rt_elfnix_cxa_atexit"},
203 {"atexit", "__orc_rt_elfnix_atexit"}};
204
205 return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
206}
207
208ArrayRef<std::pair<const char *, const char *>>
209ELFNixPlatform::standardRuntimeUtilityAliases() {
210 static const std::pair<const char *, const char *>
211 StandardRuntimeUtilityAliases[] = {
212 {"__orc_rt_run_program", "__orc_rt_elfnix_run_program"},
213 {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}};
214
215 return ArrayRef<std::pair<const char *, const char *>>(
216 StandardRuntimeUtilityAliases);
217}
218
219bool ELFNixPlatform::isInitializerSection(StringRef SecName) {
220 for (auto &Name : InitSectionNames) {
221 if (Name.equals(SecName))
222 return true;
223 }
224 return false;
225}
226
227bool ELFNixPlatform::supportedTarget(const Triple &TT) {
228 switch (TT.getArch()) {
229 case Triple::x86_64:
230 return true;
231 default:
232 return false;
233 }
234}
235
236ELFNixPlatform::ELFNixPlatform(
237 ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
238 JITDylib &PlatformJD,
239 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
240 : ES(ES), ObjLinkingLayer(ObjLinkingLayer),
241 DSOHandleSymbol(ES.intern("__dso_handle")) {
242 ErrorAsOutParameter _(&Err);
243
244 ObjLinkingLayer.addPlugin(std::make_unique<ELFNixPlatformPlugin>(*this));
245
246 PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
247
248 // PlatformJD hasn't been 'set-up' by the platform yet (since we're creating
249 // the platform now), so set it up.
250 if (auto E2 = setupJITDylib(PlatformJD)) {
251 Err = std::move(E2);
252 return;
253 }
254
255 RegisteredInitSymbols[&PlatformJD].add(
256 DSOHandleSymbol, SymbolLookupFlags::WeaklyReferencedSymbol);
257
258 // Associate wrapper function tags with JIT-side function implementations.
259 if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) {
260 Err = std::move(E2);
261 return;
262 }
263
264 // Lookup addresses of runtime functions callable by the platform,
265 // call the platform bootstrap function to initialize the platform-state
266 // object in the executor.
267 if (auto E2 = bootstrapELFNixRuntime(PlatformJD)) {
268 Err = std::move(E2);
269 return;
270 }
271}
272
273Error ELFNixPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) {
274 ExecutionSession::JITDispatchHandlerAssociationMap WFs;
275
276 using GetInitializersSPSSig =
277 SPSExpected<SPSELFNixJITDylibInitializerSequence>(SPSString);
278 WFs[ES.intern("__orc_rt_elfnix_get_initializers_tag")] =
279 ES.wrapAsyncWithSPS<GetInitializersSPSSig>(
280 this, &ELFNixPlatform::rt_getInitializers);
281
282 using GetDeinitializersSPSSig =
283 SPSExpected<SPSELFJITDylibDeinitializerSequence>(SPSExecutorAddr);
284 WFs[ES.intern("__orc_rt_elfnix_get_deinitializers_tag")] =
285 ES.wrapAsyncWithSPS<GetDeinitializersSPSSig>(
286 this, &ELFNixPlatform::rt_getDeinitializers);
287
288 using LookupSymbolSPSSig =
289 SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString);
290 WFs[ES.intern("__orc_rt_elfnix_symbol_lookup_tag")] =
291 ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
292 &ELFNixPlatform::rt_lookupSymbol);
293
294 return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
295}
296
297void ELFNixPlatform::getInitializersBuildSequencePhase(
298 SendInitializerSequenceFn SendResult, JITDylib &JD,
299 std::vector<JITDylibSP> DFSLinkOrder) {
300 ELFNixJITDylibInitializerSequence FullInitSeq;
301 {
302 std::lock_guard<std::mutex> Lock(PlatformMutex);
303 for (auto &InitJD : reverse(DFSLinkOrder)) {
304 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform: Appending inits for \""
<< InitJD->getName() << "\" to sequence\n"; }
; } } while (false)
305 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)
306 << "\" to sequence\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform: Appending inits for \""
<< InitJD->getName() << "\" to sequence\n"; }
; } } while (false)
307 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform: Appending inits for \""
<< InitJD->getName() << "\" to sequence\n"; }
; } } while (false)
;
308 auto ISItr = InitSeqs.find(InitJD.get());
309 if (ISItr != InitSeqs.end()) {
310 FullInitSeq.emplace_back(std::move(ISItr->second));
311 InitSeqs.erase(ISItr);
312 }
313 }
314 }
315
316 SendResult(std::move(FullInitSeq));
317}
318
319void ELFNixPlatform::getInitializersLookupPhase(
320 SendInitializerSequenceFn SendResult, JITDylib &JD) {
321
322 auto DFSLinkOrder = JD.getDFSLinkOrder();
323 if (!DFSLinkOrder) {
324 SendResult(DFSLinkOrder.takeError());
325 return;
326 }
327
328 DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
329 ES.runSessionLocked([&]() {
330 for (auto &InitJD : *DFSLinkOrder) {
331 auto RISItr = RegisteredInitSymbols.find(InitJD.get());
332 if (RISItr != RegisteredInitSymbols.end()) {
333 NewInitSymbols[InitJD.get()] = std::move(RISItr->second);
334 RegisteredInitSymbols.erase(RISItr);
335 }
336 }
337 });
338
339 // If there are no further init symbols to look up then move on to the next
340 // phase.
341 if (NewInitSymbols.empty()) {
342 getInitializersBuildSequencePhase(std::move(SendResult), JD,
343 std::move(*DFSLinkOrder));
344 return;
345 }
346
347 // Otherwise issue a lookup and re-run this phase when it completes.
348 lookupInitSymbolsAsync(
349 [this, SendResult = std::move(SendResult), &JD](Error Err) mutable {
350 if (Err)
351 SendResult(std::move(Err));
352 else
353 getInitializersLookupPhase(std::move(SendResult), JD);
354 },
355 ES, std::move(NewInitSymbols));
356}
357
358void ELFNixPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult,
359 StringRef JDName) {
360 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform::rt_getInitializers(\""
<< JDName << "\")\n"; }; } } while (false)
361 dbgs() << "ELFNixPlatform::rt_getInitializers(\"" << JDName << "\")\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform::rt_getInitializers(\""
<< JDName << "\")\n"; }; } } while (false)
362 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform::rt_getInitializers(\""
<< JDName << "\")\n"; }; } } while (false)
;
363
364 JITDylib *JD = ES.getJITDylibByName(JDName);
365 if (!JD) {
366 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No such JITDylib \"" <<
JDName << "\". Sending error.\n"; }; } } while (false)
367 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)
368 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No such JITDylib \"" <<
JDName << "\". Sending error.\n"; }; } } while (false)
;
369 SendResult(make_error<StringError>("No JITDylib named " + JDName,
370 inconvertibleErrorCode()));
371 return;
372 }
373
374 getInitializersLookupPhase(std::move(SendResult), *JD);
375}
376
377void ELFNixPlatform::rt_getDeinitializers(
378 SendDeinitializerSequenceFn SendResult, ExecutorAddr Handle) {
379 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform::rt_getDeinitializers(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
380 dbgs() << "ELFNixPlatform::rt_getDeinitializers(\""do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform::rt_getDeinitializers(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
381 << formatv("{0:x}", Handle.getValue()) << "\")\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform::rt_getDeinitializers(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
382 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform::rt_getDeinitializers(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
;
383
384 JITDylib *JD = nullptr;
385
386 {
387 std::lock_guard<std::mutex> Lock(PlatformMutex);
388 auto I = HandleAddrToJITDylib.find(Handle);
389 if (I != HandleAddrToJITDylib.end())
390 JD = I->second;
391 }
392
393 if (!JD) {
394 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No JITDylib for handle " <<
formatv("{0:x}", Handle.getValue()) << "\n"; }; } } while
(false)
395 dbgs() << " No JITDylib for handle "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No JITDylib for handle " <<
formatv("{0:x}", Handle.getValue()) << "\n"; }; } } while
(false)
396 << formatv("{0:x}", Handle.getValue()) << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No JITDylib for handle " <<
formatv("{0:x}", Handle.getValue()) << "\n"; }; } } while
(false)
397 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No JITDylib for handle " <<
formatv("{0:x}", Handle.getValue()) << "\n"; }; } } while
(false)
;
398 SendResult(make_error<StringError>("No JITDylib associated with handle " +
399 formatv("{0:x}", Handle.getValue()),
400 inconvertibleErrorCode()));
401 return;
402 }
403
404 SendResult(ELFNixJITDylibDeinitializerSequence());
405}
406
407void ELFNixPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
408 ExecutorAddr Handle,
409 StringRef SymbolName) {
410 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform::rt_lookupSymbol(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
411 dbgs() << "ELFNixPlatform::rt_lookupSymbol(\""do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform::rt_lookupSymbol(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
412 << formatv("{0:x}", Handle.getValue()) << "\")\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform::rt_lookupSymbol(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
413 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "ELFNixPlatform::rt_lookupSymbol(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
;
414
415 JITDylib *JD = nullptr;
416
417 {
418 std::lock_guard<std::mutex> Lock(PlatformMutex);
419 auto I = HandleAddrToJITDylib.find(Handle);
420 if (I != HandleAddrToJITDylib.end())
421 JD = I->second;
422 }
423
424 if (!JD) {
425 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No JITDylib for handle " <<
formatv("{0:x}", Handle.getValue()) << "\n"; }; } } while
(false)
426 dbgs() << " No JITDylib for handle "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No JITDylib for handle " <<
formatv("{0:x}", Handle.getValue()) << "\n"; }; } } while
(false)
427 << formatv("{0:x}", Handle.getValue()) << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No JITDylib for handle " <<
formatv("{0:x}", Handle.getValue()) << "\n"; }; } } while
(false)
428 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No JITDylib for handle " <<
formatv("{0:x}", Handle.getValue()) << "\n"; }; } } while
(false)
;
429 SendResult(make_error<StringError>("No JITDylib associated with handle " +
430 formatv("{0:x}", Handle.getValue()),
431 inconvertibleErrorCode()));
432 return;
433 }
434
435 // Use functor class to work around XL build compiler issue on AIX.
436 class RtLookupNotifyComplete {
437 public:
438 RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)
439 : SendResult(std::move(SendResult)) {}
440 void operator()(Expected<SymbolMap> Result) {
441 if (Result) {
442 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", 442, __extension__
__PRETTY_FUNCTION__))
;
443 SendResult(ExecutorAddr(Result->begin()->second.getAddress()));
444 } else {
445 SendResult(Result.takeError());
446 }
447 }
448
449 private:
450 SendSymbolAddressFn SendResult;
451 };
452
453 ES.lookup(
454 LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
455 SymbolLookupSet(ES.intern(SymbolName)), SymbolState::Ready,
456 RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
457}
458
459Error ELFNixPlatform::bootstrapELFNixRuntime(JITDylib &PlatformJD) {
460
461 std::pair<const char *, ExecutorAddr *> Symbols[] = {
462 {"__orc_rt_elfnix_platform_bootstrap", &orc_rt_elfnix_platform_bootstrap},
463 {"__orc_rt_elfnix_platform_shutdown", &orc_rt_elfnix_platform_shutdown},
464 {"__orc_rt_elfnix_register_object_sections",
465 &orc_rt_elfnix_register_object_sections},
466 {"__orc_rt_elfnix_create_pthread_key",
467 &orc_rt_elfnix_create_pthread_key}};
468
469 SymbolLookupSet RuntimeSymbols;
470 std::vector<std::pair<SymbolStringPtr, ExecutorAddr *>> AddrsToRecord;
471 for (const auto &KV : Symbols) {
472 auto Name = ES.intern(KV.first);
473 RuntimeSymbols.add(Name);
474 AddrsToRecord.push_back({std::move(Name), KV.second});
475 }
476
477 auto RuntimeSymbolAddrs = ES.lookup(
478 {{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, RuntimeSymbols);
479 if (!RuntimeSymbolAddrs)
480 return RuntimeSymbolAddrs.takeError();
481
482 for (const auto &KV : AddrsToRecord) {
483 auto &Name = KV.first;
484 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", 484, __extension__
__PRETTY_FUNCTION__))
;
485 KV.second->setValue((*RuntimeSymbolAddrs)[Name].getAddress());
486 }
487
488 auto PJDDSOHandle = ES.lookup(
489 {{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, DSOHandleSymbol);
490 if (!PJDDSOHandle)
491 return PJDDSOHandle.takeError();
492
493 if (auto Err = ES.callSPSWrapper<void(uint64_t)>(
494 orc_rt_elfnix_platform_bootstrap, PJDDSOHandle->getAddress()))
495 return Err;
496
497 // FIXME: Ordering is fuzzy here. We're probably best off saying
498 // "behavior is undefined if code that uses the runtime is added before
499 // the platform constructor returns", then move all this to the constructor.
500 RuntimeBootstrapped = true;
501 std::vector<ELFPerObjectSectionsToRegister> DeferredPOSRs;
502 {
503 std::lock_guard<std::mutex> Lock(PlatformMutex);
504 DeferredPOSRs = std::move(BootstrapPOSRs);
505 }
506
507 for (auto &D : DeferredPOSRs)
508 if (auto Err = registerPerObjectSections(D))
509 return Err;
510
511 return Error::success();
512}
513
514Error ELFNixPlatform::registerInitInfo(
515 JITDylib &JD, ArrayRef<jitlink::Section *> InitSections) {
516
517 std::unique_lock<std::mutex> Lock(PlatformMutex);
518
519 ELFNixJITDylibInitializers *InitSeq = nullptr;
520 {
521 auto I = InitSeqs.find(&JD);
522 if (I == InitSeqs.end()) {
523 // If there's no init sequence entry yet then we need to look up the
524 // header symbol to force creation of one.
525 Lock.unlock();
526
527 auto SearchOrder =
528 JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; });
529 if (auto Err = ES.lookup(SearchOrder, DSOHandleSymbol).takeError())
530 return Err;
531
532 Lock.lock();
533 I = InitSeqs.find(&JD);
534 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", 535, __extension__
__PRETTY_FUNCTION__))
535 "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", 535, __extension__
__PRETTY_FUNCTION__))
;
536 }
537 InitSeq = &I->second;
538 }
539
540 for (auto *Sec : InitSections) {
541 // FIXME: Avoid copy here.
542 jitlink::SectionRange R(*Sec);
543 InitSeq->InitSections[Sec->getName()].push_back(
544 {ExecutorAddr(R.getStart()), ExecutorAddr(R.getEnd())});
545 }
546
547 return Error::success();
548}
549
550Error ELFNixPlatform::registerPerObjectSections(
551 const ELFPerObjectSectionsToRegister &POSR) {
552
553 if (!orc_rt_elfnix_register_object_sections)
10
Taking false branch
554 return make_error<StringError>("Attempting to register per-object "
555 "sections, but runtime support has not "
556 "been loaded yet",
557 inconvertibleErrorCode());
558
559 Error ErrResult = Error::success();
560 if (auto Err = ES.callSPSWrapper<shared::SPSError(
11
Calling 'ExecutionSession::callSPSWrapper'
24
Returning from 'ExecutionSession::callSPSWrapper'
25
Assuming the condition is false
26
Taking false branch
561 SPSELFPerObjectSectionsToRegister)>(
562 orc_rt_elfnix_register_object_sections, ErrResult, POSR))
563 return Err;
564 return ErrResult;
27
Moved-from object 'ErrResult' is moved
565}
566
567Expected<uint64_t> ELFNixPlatform::createPThreadKey() {
568 if (!orc_rt_elfnix_create_pthread_key)
569 return make_error<StringError>(
570 "Attempting to create pthread key in target, but runtime support has "
571 "not been loaded yet",
572 inconvertibleErrorCode());
573
574 Expected<uint64_t> Result(0);
575 if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(
576 orc_rt_elfnix_create_pthread_key, Result))
577 return std::move(Err);
578 return Result;
579}
580
581void ELFNixPlatform::ELFNixPlatformPlugin::modifyPassConfig(
582 MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
583 jitlink::PassConfiguration &Config) {
584
585 // If the initializer symbol is the __dso_handle symbol then just add
586 // the DSO handle support passes.
587 if (MR.getInitializerSymbol() == MP.DSOHandleSymbol) {
588 addDSOHandleSupportPasses(MR, Config);
589 // The DSOHandle materialization unit doesn't require any other
590 // support, so we can bail out early.
591 return;
592 }
593
594 // If the object contains initializers then add passes to record them.
595 if (MR.getInitializerSymbol())
596 addInitializerSupportPasses(MR, Config);
597
598 // Add passes for eh-frame and TLV support.
599 addEHAndTLVSupportPasses(MR, Config);
600}
601
602ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
603ELFNixPlatform::ELFNixPlatformPlugin::getSyntheticSymbolDependencies(
604 MaterializationResponsibility &MR) {
605 std::lock_guard<std::mutex> Lock(PluginMutex);
606 auto I = InitSymbolDeps.find(&MR);
607 if (I != InitSymbolDeps.end()) {
608 SyntheticSymbolDependenciesMap Result;
609 Result[MR.getInitializerSymbol()] = std::move(I->second);
610 InitSymbolDeps.erase(&MR);
611 return Result;
612 }
613 return SyntheticSymbolDependenciesMap();
614}
615
616void ELFNixPlatform::ELFNixPlatformPlugin::addInitializerSupportPasses(
617 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {
618
619 /// Preserve init sections.
620 Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) -> Error {
621 if (auto Err = preserveInitSections(G, MR))
622 return Err;
623 return Error::success();
624 });
625
626 Config.PostFixupPasses.push_back(
627 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
628 return registerInitSections(G, JD);
629 });
630}
631
632void ELFNixPlatform::ELFNixPlatformPlugin::addDSOHandleSupportPasses(
633 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {
634
635 Config.PostAllocationPasses.push_back([this, &JD = MR.getTargetJITDylib()](
636 jitlink::LinkGraph &G) -> Error {
637 auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
638 return Sym->getName() == *MP.DSOHandleSymbol;
639 });
640 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", 640, __extension__
__PRETTY_FUNCTION__))
;
641 {
642 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
643 auto HandleAddr = (*I)->getAddress();
644 MP.HandleAddrToJITDylib[HandleAddr] = &JD;
645 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", 645, __extension__
__PRETTY_FUNCTION__))
;
646 MP.InitSeqs.insert(std::make_pair(
647 &JD, ELFNixJITDylibInitializers(JD.getName(), HandleAddr)));
648 }
649 return Error::success();
650 });
651}
652
653void ELFNixPlatform::ELFNixPlatformPlugin::addEHAndTLVSupportPasses(
654 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {
655
656 // Insert TLV lowering at the start of the PostPrunePasses, since we want
657 // it to run before GOT/PLT lowering.
658
659 // TODO: Check that before the fixTLVSectionsAndEdges pass, the GOT/PLT build
660 // pass has done. Because the TLS descriptor need to be allocate in GOT.
661 Config.PostPrunePasses.push_back(
662 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
663 return fixTLVSectionsAndEdges(G, JD);
664 });
665
666 // Add a pass to register the final addresses of the eh-frame and TLV sections
667 // with the runtime.
668 Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error {
669 ELFPerObjectSectionsToRegister POSR;
670
671 if (auto *EHFrameSection
0.1
'EHFrameSection' is null
0.1
'EHFrameSection' is null
0.1
'EHFrameSection' is null
0.1
'EHFrameSection' is null
0.1
'EHFrameSection' is null
= G.findSectionByName(EHFrameSectionName)) {
1
Taking false branch
672 jitlink::SectionRange R(*EHFrameSection);
673 if (!R.empty())
674 POSR.EHFrameSection = {ExecutorAddr(R.getStart()),
675 ExecutorAddr(R.getEnd())};
676 }
677
678 // Get a pointer to the thread data section if there is one. It will be used
679 // below.
680 jitlink::Section *ThreadDataSection =
681 G.findSectionByName(ThreadDataSectionName);
682
683 // Handle thread BSS section if there is one.
684 if (auto *ThreadBSSSection
1.1
'ThreadBSSSection' is non-null
1.1
'ThreadBSSSection' is non-null
1.1
'ThreadBSSSection' is non-null
1.1
'ThreadBSSSection' is non-null
1.1
'ThreadBSSSection' is non-null
= G.findSectionByName(ThreadBSSSectionName)) {
2
Taking true branch
685 // If there's already a thread data section in this graph then merge the
686 // thread BSS section content into it, otherwise just treat the thread
687 // BSS section as the thread data section.
688 if (ThreadDataSection
2.1
'ThreadDataSection' is null
2.1
'ThreadDataSection' is null
2.1
'ThreadDataSection' is null
2.1
'ThreadDataSection' is null
2.1
'ThreadDataSection' is null
)
3
Taking false branch
689 G.mergeSections(*ThreadDataSection, *ThreadBSSSection);
690 else
691 ThreadDataSection = ThreadBSSSection;
692 }
693
694 // Having merged thread BSS (if present) and thread data (if present),
695 // record the resulting section range.
696 if (ThreadDataSection
3.1
'ThreadDataSection' is non-null
3.1
'ThreadDataSection' is non-null
3.1
'ThreadDataSection' is non-null
3.1
'ThreadDataSection' is non-null
3.1
'ThreadDataSection' is non-null
) {
4
Taking true branch
697 jitlink::SectionRange R(*ThreadDataSection);
698 if (!R.empty())
5
Taking true branch
699 POSR.ThreadDataSection = {ExecutorAddr(R.getStart()),
700 ExecutorAddr(R.getEnd())};
701 }
702
703 if (POSR.EHFrameSection.Start || POSR.ThreadDataSection.Start) {
6
Taking true branch
704
705 // If we're still bootstrapping the runtime then just record this
706 // frame for now.
707 if (!MP.RuntimeBootstrapped) {
7
Assuming the condition is false
8
Taking false branch
708 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
709 MP.BootstrapPOSRs.push_back(POSR);
710 return Error::success();
711 }
712
713 // Otherwise register it immediately.
714 if (auto Err = MP.registerPerObjectSections(POSR))
9
Calling 'ELFNixPlatform::registerPerObjectSections'
715 return Err;
716 }
717
718 return Error::success();
719 });
720}
721
722Error ELFNixPlatform::ELFNixPlatformPlugin::preserveInitSections(
723 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
724
725 JITLinkSymbolSet InitSectionSymbols;
726 for (auto &InitSectionName : InitSectionNames) {
727 // Skip non-init sections.
728 auto *InitSection = G.findSectionByName(InitSectionName);
729 if (!InitSection)
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
759Error 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 InitSectionName : InitSectionNames) {
767 if (auto *Sec = G.findSectionByName(InitSectionName)) {
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() << ": " << formatv("[ {0:x} -- {1:x} ]"
, R.getStart(), R.getEnd()) << "\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() << ": " << formatv("[ {0:x} -- {1:x} ]"
, R.getStart(), R.getEnd()) << "\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() << ": " << formatv("[ {0:x} -- {1:x} ]"
, R.getStart(), R.getEnd()) << "\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() << ": " << formatv("[ {0:x} -- {1:x} ]"
, R.getStart(), R.getEnd()) << "\n"; } }; } } while (false
)
777 dbgs() << " " << Sec->getName() << ": "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() << ": " << formatv("[ {0:x} -- {1:x} ]"
, R.getStart(), R.getEnd()) << "\n"; } }; } } while (false
)
778 << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.getEnd()) << "\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() << ": " << formatv("[ {0:x} -- {1:x} ]"
, R.getStart(), R.getEnd()) << "\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() << ": " << formatv("[ {0:x} -- {1:x} ]"
, R.getStart(), R.getEnd()) << "\n"; } }; } } while (false
)
780 })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() << ": " << formatv("[ {0:x} -- {1:x} ]"
, R.getStart(), R.getEnd()) << "\n"; } }; } } while (false
)
;
781
782 return MP.registerInitInfo(JD, InitSections);
783}
784
785Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges(
786 jitlink::LinkGraph &G, JITDylib &JD) {
787
788 // TODO implement TLV support
789 for (auto *Sym : G.external_symbols())
790 if (Sym->getName() == "__tls_get_addr") {
791 Sym->setName("___orc_rt_elfnix_tls_get_addr");
792 }
793
794 auto *TLSInfoEntrySection = G.findSectionByName("$__TLSINFO");
795
796 if (TLSInfoEntrySection) {
797 Optional<uint64_t> Key;
798 {
799 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
800 auto I = MP.JITDylibToPThreadKey.find(&JD);
801 if (I != MP.JITDylibToPThreadKey.end())
802 Key = I->second;
803 }
804 if (!Key) {
805 if (auto KeyOrErr = MP.createPThreadKey())
806 Key = *KeyOrErr;
807 else
808 return KeyOrErr.takeError();
809 }
810
811 uint64_t PlatformKeyBits =
812 support::endian::byte_swap(*Key, G.getEndianness());
813
814 for (auto *B : TLSInfoEntrySection->blocks()) {
815 // FIXME: The TLS descriptor byte length may different with different
816 // ISA
817 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", 818, __extension__
__PRETTY_FUNCTION__))
818 "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", 818, __extension__
__PRETTY_FUNCTION__))
;
819 auto TLSInfoEntryContent = B->getMutableContent(G);
820 memcpy(TLSInfoEntryContent.data(), &PlatformKeyBits, G.getPointerSize());
821 }
822 }
823
824 return Error::success();
825}
826
827} // End namespace orc.
828} // End namespace llvm.

/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/include/llvm/ExecutionEngine/Orc/Core.h

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/WrapperFunctionUtils.h"
24#include "llvm/ExecutionEngine/Orc/TaskDispatch.h"
25#include "llvm/Support/Debug.h"
26#include "llvm/Support/ExtensibleRTTI.h"
27
28#include <atomic>
29#include <future>
30#include <memory>
31#include <vector>
32
33namespace llvm {
34namespace orc {
35
36// Forward declare some classes.
37class AsynchronousSymbolQuery;
38class ExecutionSession;
39class MaterializationUnit;
40class MaterializationResponsibility;
41class JITDylib;
42class ResourceTracker;
43class InProgressLookupState;
44
45enum class SymbolState : uint8_t;
46
47using ResourceTrackerSP = IntrusiveRefCntPtr<ResourceTracker>;
48using JITDylibSP = IntrusiveRefCntPtr<JITDylib>;
49
50using ResourceKey = uintptr_t;
51
52/// API to remove / transfer ownership of JIT resources.
53class ResourceTracker : public ThreadSafeRefCountedBase<ResourceTracker> {
54private:
55 friend class ExecutionSession;
56 friend class JITDylib;
57 friend class MaterializationResponsibility;
58
59public:
60 ResourceTracker(const ResourceTracker &) = delete;
61 ResourceTracker &operator=(const ResourceTracker &) = delete;
62 ResourceTracker(ResourceTracker &&) = delete;
63 ResourceTracker &operator=(ResourceTracker &&) = delete;
64
65 ~ResourceTracker();
66
67 /// Return the JITDylib targeted by this tracker.
68 JITDylib &getJITDylib() const {
69 return *reinterpret_cast<JITDylib *>(JDAndFlag.load() &
70 ~static_cast<uintptr_t>(1));
71 }
72
73 /// Remove all resources associated with this key.
74 Error remove();
75
76 /// Transfer all resources associated with this key to the given
77 /// tracker, which must target the same JITDylib as this one.
78 void transferTo(ResourceTracker &DstRT);
79
80 /// Return true if this tracker has become defunct.
81 bool isDefunct() const { return JDAndFlag.load() & 0x1; }
82
83 /// Returns the key associated with this tracker.
84 /// This method should not be used except for debug logging: there is no
85 /// guarantee that the returned value will remain valid.
86 ResourceKey getKeyUnsafe() const { return reinterpret_cast<uintptr_t>(this); }
87
88private:
89 ResourceTracker(JITDylibSP JD);
90
91 void makeDefunct();
92
93 std::atomic_uintptr_t JDAndFlag;
94};
95
96/// Listens for ResourceTracker operations.
97class ResourceManager {
98public:
99 virtual ~ResourceManager();
100 virtual Error handleRemoveResources(ResourceKey K) = 0;
101 virtual void handleTransferResources(ResourceKey DstK, ResourceKey SrcK) = 0;
102};
103
104/// A set of symbol names (represented by SymbolStringPtrs for
105// efficiency).
106using SymbolNameSet = DenseSet<SymbolStringPtr>;
107
108/// A vector of symbol names.
109using SymbolNameVector = std::vector<SymbolStringPtr>;
110
111/// A map from symbol names (as SymbolStringPtrs) to JITSymbols
112/// (address/flags pairs).
113using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>;
114
115/// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
116using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>;
117
118/// A map from JITDylibs to sets of symbols.
119using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>;
120
121/// Lookup flags that apply to each dylib in the search order for a lookup.
122///
123/// If MatchHiddenSymbolsOnly is used (the default) for a given dylib, then
124/// only symbols in that Dylib's interface will be searched. If
125/// MatchHiddenSymbols is used then symbols with hidden visibility will match
126/// as well.
127enum class JITDylibLookupFlags { MatchExportedSymbolsOnly, MatchAllSymbols };
128
129/// Lookup flags that apply to each symbol in a lookup.
130///
131/// If RequiredSymbol is used (the default) for a given symbol then that symbol
132/// must be found during the lookup or the lookup will fail returning a
133/// SymbolNotFound error. If WeaklyReferencedSymbol is used and the given
134/// symbol is not found then the query will continue, and no result for the
135/// missing symbol will be present in the result (assuming the rest of the
136/// lookup succeeds).
137enum class SymbolLookupFlags { RequiredSymbol, WeaklyReferencedSymbol };
138
139/// Describes the kind of lookup being performed. The lookup kind is passed to
140/// symbol generators (if they're invoked) to help them determine what
141/// definitions to generate.
142///
143/// Static -- Lookup is being performed as-if at static link time (e.g.
144/// generators representing static archives should pull in new
145/// definitions).
146///
147/// DLSym -- Lookup is being performed as-if at runtime (e.g. generators
148/// representing static archives should not pull in new definitions).
149enum class LookupKind { Static, DLSym };
150
151/// A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search
152/// order during symbol lookup.
153using JITDylibSearchOrder =
154 std::vector<std::pair<JITDylib *, JITDylibLookupFlags>>;
155
156/// Convenience function for creating a search order from an ArrayRef of
157/// JITDylib*, all with the same flags.
158inline JITDylibSearchOrder makeJITDylibSearchOrder(
159 ArrayRef<JITDylib *> JDs,
160 JITDylibLookupFlags Flags = JITDylibLookupFlags::MatchExportedSymbolsOnly) {
161 JITDylibSearchOrder O;
162 O.reserve(JDs.size());
163 for (auto *JD : JDs)
164 O.push_back(std::make_pair(JD, Flags));
165 return O;
166}
167
168/// A set of symbols to look up, each associated with a SymbolLookupFlags
169/// value.
170///
171/// This class is backed by a vector and optimized for fast insertion,
172/// deletion and iteration. It does not guarantee a stable order between
173/// operations, and will not automatically detect duplicate elements (they
174/// can be manually checked by calling the validate method).
175class SymbolLookupSet {
176public:
177 using value_type = std::pair<SymbolStringPtr, SymbolLookupFlags>;
178 using UnderlyingVector = std::vector<value_type>;
179 using iterator = UnderlyingVector::iterator;
180 using const_iterator = UnderlyingVector::const_iterator;
181
182 SymbolLookupSet() = default;
183
184 explicit SymbolLookupSet(
185 SymbolStringPtr Name,
186 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
187 add(std::move(Name), Flags);
188 }
189
190 /// Construct a SymbolLookupSet from an initializer list of SymbolStringPtrs.
191 explicit SymbolLookupSet(
192 std::initializer_list<SymbolStringPtr> Names,
193 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
194 Symbols.reserve(Names.size());
195 for (auto &Name : Names)
196 add(std::move(Name), Flags);
197 }
198
199 /// Construct a SymbolLookupSet from a SymbolNameSet with the given
200 /// Flags used for each value.
201 explicit SymbolLookupSet(
202 const SymbolNameSet &Names,
203 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
204 Symbols.reserve(Names.size());
205 for (const auto &Name : Names)
206 add(Name, Flags);
207 }
208
209 /// Construct a SymbolLookupSet from a vector of symbols with the given Flags
210 /// used for each value.
211 /// If the ArrayRef contains duplicates it is up to the client to remove these
212 /// before using this instance for lookup.
213 explicit SymbolLookupSet(
214 ArrayRef<SymbolStringPtr> Names,
215 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
216 Symbols.reserve(Names.size());
217 for (const auto &Name : Names)
218 add(Name, Flags);
219 }
220
221 /// Construct a SymbolLookupSet from DenseMap keys.
222 template <typename KeyT>
223 static SymbolLookupSet
224 fromMapKeys(const DenseMap<SymbolStringPtr, KeyT> &M,
225 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
226 SymbolLookupSet Result;
227 Result.Symbols.reserve(M.size());
228 for (const auto &KV : M)
229 Result.add(KV.first, Flags);
230 return Result;
231 }
232
233 /// Add an element to the set. The client is responsible for checking that
234 /// duplicates are not added.
235 SymbolLookupSet &
236 add(SymbolStringPtr Name,
237 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
238 Symbols.push_back(std::make_pair(std::move(Name), Flags));
239 return *this;
240 }
241
242 /// Quickly append one lookup set to another.
243 SymbolLookupSet &append(SymbolLookupSet Other) {
244 Symbols.reserve(Symbols.size() + Other.size());
245 for (auto &KV : Other)
246 Symbols.push_back(std::move(KV));
247 return *this;
248 }
249
250 bool empty() const { return Symbols.empty(); }
251 UnderlyingVector::size_type size() const { return Symbols.size(); }
252 iterator begin() { return Symbols.begin(); }
253 iterator end() { return Symbols.end(); }
254 const_iterator begin() const { return Symbols.begin(); }
255 const_iterator end() const { return Symbols.end(); }
256
257 /// Removes the Ith element of the vector, replacing it with the last element.
258 void remove(UnderlyingVector::size_type I) {
259 std::swap(Symbols[I], Symbols.back());
260 Symbols.pop_back();
261 }
262
263 /// Removes the element pointed to by the given iterator. This iterator and
264 /// all subsequent ones (including end()) are invalidated.
265 void remove(iterator I) { remove(I - begin()); }
266
267 /// Removes all elements matching the given predicate, which must be callable
268 /// as bool(const SymbolStringPtr &, SymbolLookupFlags Flags).
269 template <typename PredFn> void remove_if(PredFn &&Pred) {
270 UnderlyingVector::size_type I = 0;
271 while (I != Symbols.size()) {
272 const auto &Name = Symbols[I].first;
273 auto Flags = Symbols[I].second;
274 if (Pred(Name, Flags))
275 remove(I);
276 else
277 ++I;
278 }
279 }
280
281 /// Loop over the elements of this SymbolLookupSet, applying the Body function
282 /// to each one. Body must be callable as
283 /// bool(const SymbolStringPtr &, SymbolLookupFlags).
284 /// If Body returns true then the element just passed in is removed from the
285 /// set. If Body returns false then the element is retained.
286 template <typename BodyFn>
287 auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t<
288 std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(),
289 std::declval<SymbolLookupFlags>())),
290 bool>::value> {
291 UnderlyingVector::size_type I = 0;
292 while (I != Symbols.size()) {
293 const auto &Name = Symbols[I].first;
294 auto Flags = Symbols[I].second;
295 if (Body(Name, Flags))
296 remove(I);
297 else
298 ++I;
299 }
300 }
301
302 /// Loop over the elements of this SymbolLookupSet, applying the Body function
303 /// to each one. Body must be callable as
304 /// Expected<bool>(const SymbolStringPtr &, SymbolLookupFlags).
305 /// If Body returns a failure value, the loop exits immediately. If Body
306 /// returns true then the element just passed in is removed from the set. If
307 /// Body returns false then the element is retained.
308 template <typename BodyFn>
309 auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t<
310 std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(),
311 std::declval<SymbolLookupFlags>())),
312 Expected<bool>>::value,
313 Error> {
314 UnderlyingVector::size_type I = 0;
315 while (I != Symbols.size()) {
316 const auto &Name = Symbols[I].first;
317 auto Flags = Symbols[I].second;
318 auto Remove = Body(Name, Flags);
319 if (!Remove)
320 return Remove.takeError();
321 if (*Remove)
322 remove(I);
323 else
324 ++I;
325 }
326 return Error::success();
327 }
328
329 /// Construct a SymbolNameVector from this instance by dropping the Flags
330 /// values.
331 SymbolNameVector getSymbolNames() const {
332 SymbolNameVector Names;
333 Names.reserve(Symbols.size());
334 for (auto &KV : Symbols)
335 Names.push_back(KV.first);
336 return Names;
337 }
338
339 /// Sort the lookup set by pointer value. This sort is fast but sensitive to
340 /// allocation order and so should not be used where a consistent order is
341 /// required.
342 void sortByAddress() {
343 llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) {
344 return LHS.first < RHS.first;
345 });
346 }
347
348 /// Sort the lookup set lexicographically. This sort is slow but the order
349 /// is unaffected by allocation order.
350 void sortByName() {
351 llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) {
352 return *LHS.first < *RHS.first;
353 });
354 }
355
356 /// Remove any duplicate elements. If a SymbolLookupSet is not duplicate-free
357 /// by construction, this method can be used to turn it into a proper set.
358 void removeDuplicates() {
359 sortByAddress();
360 auto LastI = std::unique(Symbols.begin(), Symbols.end());
361 Symbols.erase(LastI, Symbols.end());
362 }
363
364#ifndef NDEBUG
365 /// Returns true if this set contains any duplicates. This should only be used
366 /// in assertions.
367 bool containsDuplicates() {
368 if (Symbols.size() < 2)
369 return false;
370 sortByAddress();
371 for (UnderlyingVector::size_type I = 1; I != Symbols.size(); ++I)
372 if (Symbols[I].first == Symbols[I - 1].first)
373 return true;
374 return false;
375 }
376#endif
377
378private:
379 UnderlyingVector Symbols;
380};
381
382struct SymbolAliasMapEntry {
383 SymbolAliasMapEntry() = default;
384 SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
385 : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {}
386
387 SymbolStringPtr Aliasee;
388 JITSymbolFlags AliasFlags;
389};
390
391/// A map of Symbols to (Symbol, Flags) pairs.
392using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>;
393
394/// Callback to notify client that symbols have been resolved.
395using SymbolsResolvedCallback = unique_function<void(Expected<SymbolMap>)>;
396
397/// Callback to register the dependencies for a given query.
398using RegisterDependenciesFunction =
399 std::function<void(const SymbolDependenceMap &)>;
400
401/// This can be used as the value for a RegisterDependenciesFunction if there
402/// are no dependants to register with.
403extern RegisterDependenciesFunction NoDependenciesToRegister;
404
405class ResourceTrackerDefunct : public ErrorInfo<ResourceTrackerDefunct> {
406public:
407 static char ID;
408
409 ResourceTrackerDefunct(ResourceTrackerSP RT);
410 std::error_code convertToErrorCode() const override;
411 void log(raw_ostream &OS) const override;
412
413private:
414 ResourceTrackerSP RT;
415};
416
417/// Used to notify a JITDylib that the given set of symbols failed to
418/// materialize.
419class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
420public:
421 static char ID;
422
423 FailedToMaterialize(std::shared_ptr<SymbolDependenceMap> Symbols);
424 std::error_code convertToErrorCode() const override;
425 void log(raw_ostream &OS) const override;
426 const SymbolDependenceMap &getSymbols() const { return *Symbols; }
427
428private:
429 std::shared_ptr<SymbolDependenceMap> Symbols;
430};
431
432/// Used to notify clients when symbols can not be found during a lookup.
433class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
434public:
435 static char ID;
436
437 SymbolsNotFound(std::shared_ptr<SymbolStringPool> SSP, SymbolNameSet Symbols);
438 SymbolsNotFound(std::shared_ptr<SymbolStringPool> SSP,
439 SymbolNameVector Symbols);
440 std::error_code convertToErrorCode() const override;
441 void log(raw_ostream &OS) const override;
442 std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; }
443 const SymbolNameVector &getSymbols() const { return Symbols; }
444
445private:
446 std::shared_ptr<SymbolStringPool> SSP;
447 SymbolNameVector Symbols;
448};
449
450/// Used to notify clients that a set of symbols could not be removed.
451class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> {
452public:
453 static char ID;
454
455 SymbolsCouldNotBeRemoved(std::shared_ptr<SymbolStringPool> SSP,
456 SymbolNameSet Symbols);
457 std::error_code convertToErrorCode() const override;
458 void log(raw_ostream &OS) const override;
459 std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; }
460 const SymbolNameSet &getSymbols() const { return Symbols; }
461
462private:
463 std::shared_ptr<SymbolStringPool> SSP;
464 SymbolNameSet Symbols;
465};
466
467/// Errors of this type should be returned if a module fails to include
468/// definitions that are claimed by the module's associated
469/// MaterializationResponsibility. If this error is returned it is indicative of
470/// a broken transformation / compiler / object cache.
471class MissingSymbolDefinitions : public ErrorInfo<MissingSymbolDefinitions> {
472public:
473 static char ID;
474
475 MissingSymbolDefinitions(std::shared_ptr<SymbolStringPool> SSP,
476 std::string ModuleName, SymbolNameVector Symbols)
477 : SSP(std::move(SSP)), ModuleName(std::move(ModuleName)),
478 Symbols(std::move(Symbols)) {}
479 std::error_code convertToErrorCode() const override;
480 void log(raw_ostream &OS) const override;
481 std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; }
482 const std::string &getModuleName() const { return ModuleName; }
483 const SymbolNameVector &getSymbols() const { return Symbols; }
484private:
485 std::shared_ptr<SymbolStringPool> SSP;
486 std::string ModuleName;
487 SymbolNameVector Symbols;
488};
489
490/// Errors of this type should be returned if a module contains definitions for
491/// symbols that are not claimed by the module's associated
492/// MaterializationResponsibility. If this error is returned it is indicative of
493/// a broken transformation / compiler / object cache.
494class UnexpectedSymbolDefinitions : public ErrorInfo<UnexpectedSymbolDefinitions> {
495public:
496 static char ID;
497
498 UnexpectedSymbolDefinitions(std::shared_ptr<SymbolStringPool> SSP,
499 std::string ModuleName, SymbolNameVector Symbols)
500 : SSP(std::move(SSP)), ModuleName(std::move(ModuleName)),
501 Symbols(std::move(Symbols)) {}
502 std::error_code convertToErrorCode() const override;
503 void log(raw_ostream &OS) const override;
504 std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; }
505 const std::string &getModuleName() const { return ModuleName; }
506 const SymbolNameVector &getSymbols() const { return Symbols; }
507private:
508 std::shared_ptr<SymbolStringPool> SSP;
509 std::string ModuleName;
510 SymbolNameVector Symbols;
511};
512
513/// Tracks responsibility for materialization, and mediates interactions between
514/// MaterializationUnits and JDs.
515///
516/// An instance of this class is passed to MaterializationUnits when their
517/// materialize method is called. It allows MaterializationUnits to resolve and
518/// emit symbols, or abandon materialization by notifying any unmaterialized
519/// symbols of an error.
520class MaterializationResponsibility {
521 friend class ExecutionSession;
522 friend class JITDylib;
523
524public:
525 MaterializationResponsibility(MaterializationResponsibility &&) = delete;
526 MaterializationResponsibility &
527 operator=(MaterializationResponsibility &&) = delete;
528
529 /// Destruct a MaterializationResponsibility instance. In debug mode
530 /// this asserts that all symbols being tracked have been either
531 /// emitted or notified of an error.
532 ~MaterializationResponsibility();
533
534 /// Returns the ResourceTracker for this instance.
535 template <typename Func> Error withResourceKeyDo(Func &&F) const;
536
537 /// Returns the target JITDylib that these symbols are being materialized
538 /// into.
539 JITDylib &getTargetJITDylib() const { return JD; }
540
541 /// Returns the ExecutionSession for this instance.
542 ExecutionSession &getExecutionSession() const;
543
544 /// Returns the symbol flags map for this responsibility instance.
545 /// Note: The returned flags may have transient flags (Lazy, Materializing)
546 /// set. These should be stripped with JITSymbolFlags::stripTransientFlags
547 /// before using.
548 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
549
550 /// Returns the initialization pseudo-symbol, if any. This symbol will also
551 /// be present in the SymbolFlagsMap for this MaterializationResponsibility
552 /// object.
553 const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; }
554
555 /// Returns the names of any symbols covered by this
556 /// MaterializationResponsibility object that have queries pending. This
557 /// information can be used to return responsibility for unrequested symbols
558 /// back to the JITDylib via the delegate method.
559 SymbolNameSet getRequestedSymbols() const;
560
561 /// Notifies the target JITDylib that the given symbols have been resolved.
562 /// This will update the given symbols' addresses in the JITDylib, and notify
563 /// any pending queries on the given symbols of their resolution. The given
564 /// symbols must be ones covered by this MaterializationResponsibility
565 /// instance. Individual calls to this method may resolve a subset of the
566 /// symbols, but all symbols must have been resolved prior to calling emit.
567 ///
568 /// This method will return an error if any symbols being resolved have been
569 /// moved to the error state due to the failure of a dependency. If this
570 /// method returns an error then clients should log it and call
571 /// failMaterialize. If no dependencies have been registered for the
572 /// symbols covered by this MaterializationResponsibiility then this method
573 /// is guaranteed to return Error::success() and can be wrapped with cantFail.
574 Error notifyResolved(const SymbolMap &Symbols);
575
576 /// Notifies the target JITDylib (and any pending queries on that JITDylib)
577 /// that all symbols covered by this MaterializationResponsibility instance
578 /// have been emitted.
579 ///
580 /// This method will return an error if any symbols being resolved have been
581 /// moved to the error state due to the failure of a dependency. If this
582 /// method returns an error then clients should log it and call
583 /// failMaterialize. If no dependencies have been registered for the
584 /// symbols covered by this MaterializationResponsibiility then this method
585 /// is guaranteed to return Error::success() and can be wrapped with cantFail.
586 Error notifyEmitted();
587
588 /// Attempt to claim responsibility for new definitions. This method can be
589 /// used to claim responsibility for symbols that are added to a
590 /// materialization unit during the compilation process (e.g. literal pool
591 /// symbols). Symbol linkage rules are the same as for symbols that are
592 /// defined up front: duplicate strong definitions will result in errors.
593 /// Duplicate weak definitions will be discarded (in which case they will
594 /// not be added to this responsibility instance).
595 ///
596 /// This method can be used by materialization units that want to add
597 /// additional symbols at materialization time (e.g. stubs, compile
598 /// callbacks, metadata).
599 Error defineMaterializing(SymbolFlagsMap SymbolFlags);
600
601 /// Define the given symbols as non-existent, removing it from the symbol
602 /// table and notifying any pending queries. Queries that lookup up the
603 /// symbol using the SymbolLookupFlags::WeaklyReferencedSymbol flag will
604 /// behave as if the symbol had not been matched in the first place. Queries
605 /// that required this symbol will fail with a missing symbol definition
606 /// error.
607 ///
608 /// This method is intended to support cleanup of special symbols like
609 /// initializer symbols: Queries using
610 /// SymbolLookupFlags::WeaklyReferencedSymbol can be used to trigger their
611 /// emission, and this method can be used to remove them from the JITDylib
612 /// once materialization is complete.
613 void defineNonExistent(ArrayRef<SymbolStringPtr> Symbols);
614
615 /// Notify all not-yet-emitted covered by this MaterializationResponsibility
616 /// instance that an error has occurred.
617 /// This will remove all symbols covered by this MaterializationResponsibilty
618 /// from the target JITDylib, and send an error to any queries waiting on
619 /// these symbols.
620 void failMaterialization();
621
622 /// Transfers responsibility to the given MaterializationUnit for all
623 /// symbols defined by that MaterializationUnit. This allows
624 /// materializers to break up work based on run-time information (e.g.
625 /// by introspecting which symbols have actually been looked up and
626 /// materializing only those).
627 Error replace(std::unique_ptr<MaterializationUnit> MU);
628
629 /// Delegates responsibility for the given symbols to the returned
630 /// materialization responsibility. Useful for breaking up work between
631 /// threads, or different kinds of materialization processes.
632 Expected<std::unique_ptr<MaterializationResponsibility>>
633 delegate(const SymbolNameSet &Symbols);
634
635 void addDependencies(const SymbolStringPtr &Name,
636 const SymbolDependenceMap &Dependencies);
637
638 /// Add dependencies that apply to all symbols covered by this instance.
639 void addDependenciesForAll(const SymbolDependenceMap &Dependencies);
640
641private:
642 /// Create a MaterializationResponsibility for the given JITDylib and
643 /// initial symbols.
644 MaterializationResponsibility(ResourceTrackerSP RT,
645 SymbolFlagsMap SymbolFlags,
646 SymbolStringPtr InitSymbol)
647 : JD(RT->getJITDylib()), RT(std::move(RT)),
648 SymbolFlags(std::move(SymbolFlags)), InitSymbol(std::move(InitSymbol)) {
649 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", 649, __extension__
__PRETTY_FUNCTION__))
;
650 }
651
652 JITDylib &JD;
653 ResourceTrackerSP RT;
654 SymbolFlagsMap SymbolFlags;
655 SymbolStringPtr InitSymbol;
656};
657
658/// A MaterializationUnit represents a set of symbol definitions that can
659/// be materialized as a group, or individually discarded (when
660/// overriding definitions are encountered).
661///
662/// MaterializationUnits are used when providing lazy definitions of symbols to
663/// JITDylibs. The JITDylib will call materialize when the address of a symbol
664/// is requested via the lookup method. The JITDylib will call discard if a
665/// stronger definition is added or already present.
666class MaterializationUnit {
667 friend class ExecutionSession;
668 friend class JITDylib;
669
670public:
671 static char ID;
672
673 struct Interface {
674 Interface() = default;
675 Interface(SymbolFlagsMap InitalSymbolFlags, SymbolStringPtr InitSymbol)
676 : SymbolFlags(std::move(InitalSymbolFlags)),
677 InitSymbol(std::move(InitSymbol)) {
678 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", 679, __extension__
__PRETTY_FUNCTION__))
679 "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", 679, __extension__
__PRETTY_FUNCTION__))
;
680 }
681
682 SymbolFlagsMap SymbolFlags;
683 SymbolStringPtr InitSymbol;
684 };
685
686 MaterializationUnit(Interface I)
687 : SymbolFlags(std::move(I.SymbolFlags)),
688 InitSymbol(std::move(I.InitSymbol)) {}
689 virtual ~MaterializationUnit() = default;
690
691 /// Return the name of this materialization unit. Useful for debugging
692 /// output.
693 virtual StringRef getName() const = 0;
694
695 /// Return the set of symbols that this source provides.
696 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
697
698 /// Returns the initialization symbol for this MaterializationUnit (if any).
699 const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; }
700
701 /// Implementations of this method should materialize all symbols
702 /// in the materialzation unit, except for those that have been
703 /// previously discarded.
704 virtual void
705 materialize(std::unique_ptr<MaterializationResponsibility> R) = 0;
706
707 /// Called by JITDylibs to notify MaterializationUnits that the given symbol
708 /// has been overridden.
709 void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) {
710 SymbolFlags.erase(Name);
711 discard(JD, std::move(Name));
712 }
713
714protected:
715 SymbolFlagsMap SymbolFlags;
716 SymbolStringPtr InitSymbol;
717
718private:
719 virtual void anchor();
720
721 /// Implementations of this method should discard the given symbol
722 /// from the source (e.g. if the source is an LLVM IR Module and the
723 /// symbol is a function, delete the function body or mark it available
724 /// externally).
725 virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0;
726};
727
728/// A MaterializationUnit implementation for pre-existing absolute symbols.
729///
730/// All symbols will be resolved and marked ready as soon as the unit is
731/// materialized.
732class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
733public:
734 AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols);
735
736 StringRef getName() const override;
737
738private:
739 void materialize(std::unique_ptr<MaterializationResponsibility> R) override;
740 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
741 static MaterializationUnit::Interface extractFlags(const SymbolMap &Symbols);
742
743 SymbolMap Symbols;
744};
745
746/// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
747/// Useful for inserting absolute symbols into a JITDylib. E.g.:
748/// \code{.cpp}
749/// JITDylib &JD = ...;
750/// SymbolStringPtr Foo = ...;
751/// JITEvaluatedSymbol FooSym = ...;
752/// if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}})))
753/// return Err;
754/// \endcode
755///
756inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit>
757absoluteSymbols(SymbolMap Symbols) {
758 return std::make_unique<AbsoluteSymbolsMaterializationUnit>(
759 std::move(Symbols));
760}
761
762/// A materialization unit for symbol aliases. Allows existing symbols to be
763/// aliased with alternate flags.
764class ReExportsMaterializationUnit : public MaterializationUnit {
765public:
766 /// SourceJD is allowed to be nullptr, in which case the source JITDylib is
767 /// taken to be whatever JITDylib these definitions are materialized in (and
768 /// MatchNonExported has no effect). This is useful for defining aliases
769 /// within a JITDylib.
770 ///
771 /// Note: Care must be taken that no sets of aliases form a cycle, as such
772 /// a cycle will result in a deadlock when any symbol in the cycle is
773 /// resolved.
774 ReExportsMaterializationUnit(JITDylib *SourceJD,
775 JITDylibLookupFlags SourceJDLookupFlags,
776 SymbolAliasMap Aliases);
777
778 StringRef getName() const override;
779
780private:
781 void materialize(std::unique_ptr<MaterializationResponsibility> R) override;
782 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
783 static MaterializationUnit::Interface
784 extractFlags(const SymbolAliasMap &Aliases);
785
786 JITDylib *SourceJD = nullptr;
787 JITDylibLookupFlags SourceJDLookupFlags;
788 SymbolAliasMap Aliases;
789};
790
791/// Create a ReExportsMaterializationUnit with the given aliases.
792/// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing
793/// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux"
794/// (for "bar") with: \code{.cpp}
795/// SymbolStringPtr Baz = ...;
796/// SymbolStringPtr Qux = ...;
797/// if (auto Err = JD.define(symbolAliases({
798/// {Baz, { Foo, JITSymbolFlags::Exported }},
799/// {Qux, { Bar, JITSymbolFlags::Weak }}}))
800/// return Err;
801/// \endcode
802inline std::unique_ptr<ReExportsMaterializationUnit>
803symbolAliases(SymbolAliasMap Aliases) {
804 return std::make_unique<ReExportsMaterializationUnit>(
805 nullptr, JITDylibLookupFlags::MatchAllSymbols, std::move(Aliases));
806}
807
808/// Create a materialization unit for re-exporting symbols from another JITDylib
809/// with alternative names/flags.
810/// SourceJD will be searched using the given JITDylibLookupFlags.
811inline std::unique_ptr<ReExportsMaterializationUnit>
812reexports(JITDylib &SourceJD, SymbolAliasMap Aliases,
813 JITDylibLookupFlags SourceJDLookupFlags =
814 JITDylibLookupFlags::MatchExportedSymbolsOnly) {
815 return std::make_unique<ReExportsMaterializationUnit>(
816 &SourceJD, SourceJDLookupFlags, std::move(Aliases));
817}
818
819/// Build a SymbolAliasMap for the common case where you want to re-export
820/// symbols from another JITDylib with the same linkage/flags.
821Expected<SymbolAliasMap>
822buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols);
823
824/// Represents the state that a symbol has reached during materialization.
825enum class SymbolState : uint8_t {
826 Invalid, /// No symbol should be in this state.
827 NeverSearched, /// Added to the symbol table, never queried.
828 Materializing, /// Queried, materialization begun.
829 Resolved, /// Assigned address, still materializing.
830 Emitted, /// Emitted to memory, but waiting on transitive dependencies.
831 Ready = 0x3f /// Ready and safe for clients to access.
832};
833
834/// A symbol query that returns results via a callback when results are
835/// ready.
836///
837/// makes a callback when all symbols are available.
838class AsynchronousSymbolQuery {
839 friend class ExecutionSession;
840 friend class InProgressFullLookupState;
841 friend class JITDylib;
842 friend class JITSymbolResolverAdapter;
843 friend class MaterializationResponsibility;
844
845public:
846 /// Create a query for the given symbols. The NotifyComplete
847 /// callback will be called once all queried symbols reach the given
848 /// minimum state.
849 AsynchronousSymbolQuery(const SymbolLookupSet &Symbols,
850 SymbolState RequiredState,
851 SymbolsResolvedCallback NotifyComplete);
852
853 /// Notify the query that a requested symbol has reached the required state.
854 void notifySymbolMetRequiredState(const SymbolStringPtr &Name,
855 JITEvaluatedSymbol Sym);
856
857 /// Returns true if all symbols covered by this query have been
858 /// resolved.
859 bool isComplete() const { return OutstandingSymbolsCount == 0; }
860
861
862private:
863 void handleComplete(ExecutionSession &ES);
864
865 SymbolState getRequiredState() { return RequiredState; }
866
867 void addQueryDependence(JITDylib &JD, SymbolStringPtr Name);
868
869 void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name);
870
871 void dropSymbol(const SymbolStringPtr &Name);
872
873 void handleFailed(Error Err);
874
875 void detach();
876
877 SymbolsResolvedCallback NotifyComplete;
878 SymbolDependenceMap QueryRegistrations;
879 SymbolMap ResolvedSymbols;
880 size_t OutstandingSymbolsCount;
881 SymbolState RequiredState;
882};
883
884/// Wraps state for a lookup-in-progress.
885/// DefinitionGenerators can optionally take ownership of a LookupState object
886/// to suspend a lookup-in-progress while they search for definitions.
887class LookupState {
888 friend class OrcV2CAPIHelper;
889 friend class ExecutionSession;
890
891public:
892 LookupState();
893 LookupState(LookupState &&);
894 LookupState &operator=(LookupState &&);
895 ~LookupState();
896
897 /// Continue the lookup. This can be called by DefinitionGenerators
898 /// to re-start a captured query-application operation.
899 void continueLookup(Error Err);
900
901private:
902 LookupState(std::unique_ptr<InProgressLookupState> IPLS);
903
904 // For C API.
905 void reset(InProgressLookupState *IPLS);
906
907 std::unique_ptr<InProgressLookupState> IPLS;
908};
909
910/// Definition generators can be attached to JITDylibs to generate new
911/// definitions for otherwise unresolved symbols during lookup.
912class DefinitionGenerator {
913public:
914 virtual ~DefinitionGenerator();
915
916 /// DefinitionGenerators should override this method to insert new
917 /// definitions into the parent JITDylib. K specifies the kind of this
918 /// lookup. JD specifies the target JITDylib being searched, and
919 /// JDLookupFlags specifies whether the search should match against
920 /// hidden symbols. Finally, Symbols describes the set of unresolved
921 /// symbols and their associated lookup flags.
922 virtual Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
923 JITDylibLookupFlags JDLookupFlags,
924 const SymbolLookupSet &LookupSet) = 0;
925};
926
927/// Represents a JIT'd dynamic library.
928///
929/// This class aims to mimic the behavior of a regular dylib or shared object,
930/// but without requiring the contained program representations to be compiled
931/// up-front. The JITDylib's content is defined by adding MaterializationUnits,
932/// and contained MaterializationUnits will typically rely on the JITDylib's
933/// links-against order to resolve external references (similar to a regular
934/// dylib).
935///
936/// The JITDylib object is a thin wrapper that references state held by the
937/// ExecutionSession. JITDylibs can be removed, clearing this underlying state
938/// and leaving the JITDylib object in a defunct state. In this state the
939/// JITDylib's name is guaranteed to remain accessible. If the ExecutionSession
940/// is still alive then other operations are callable but will return an Error
941/// or null result (depending on the API). It is illegal to call any operation
942/// other than getName on a JITDylib after the ExecutionSession has been torn
943/// down.
944///
945/// JITDylibs cannot be moved or copied. Their address is stable, and useful as
946/// a key in some JIT data structures.
947class JITDylib : public ThreadSafeRefCountedBase<JITDylib>,
948 public jitlink::JITLinkDylib {
949 friend class AsynchronousSymbolQuery;
950 friend class ExecutionSession;
951 friend class Platform;
952 friend class MaterializationResponsibility;
953public:
954
955 JITDylib(const JITDylib &) = delete;
956 JITDylib &operator=(const JITDylib &) = delete;
957 JITDylib(JITDylib &&) = delete;
958 JITDylib &operator=(JITDylib &&) = delete;
959 ~JITDylib();
960
961 /// Get a reference to the ExecutionSession for this JITDylib.
962 ///
963 /// It is legal to call this method on a defunct JITDylib, however the result
964 /// will only usable if the ExecutionSession is still alive. If this JITDylib
965 /// is held by an error that may have torn down the JIT then the result
966 /// should not be used.
967 ExecutionSession &getExecutionSession() const { return ES; }
968
969 /// Dump current JITDylib state to OS.
970 ///
971 /// It is legal to call this method on a defunct JITDylib.
972 void dump(raw_ostream &OS);
973
974 /// Calls remove on all trackers currently associated with this JITDylib.
975 /// Does not run static deinits.
976 ///
977 /// Note that removal happens outside the session lock, so new code may be
978 /// added concurrently while the clear is underway, and the newly added
979 /// code will *not* be cleared. Adding new code concurrently with a clear
980 /// is usually a bug and should be avoided.
981 ///
982 /// It is illegal to call this method on a defunct JITDylib and the client
983 /// is responsible for ensuring that they do not do so.
984 Error clear();
985
986 /// Get the default resource tracker for this JITDylib.
987 ///
988 /// It is illegal to call this method on a defunct JITDylib and the client
989 /// is responsible for ensuring that they do not do so.
990 ResourceTrackerSP getDefaultResourceTracker();
991
992 /// Create a resource tracker for this JITDylib.
993 ///
994 /// It is illegal to call this method on a defunct JITDylib and the client
995 /// is responsible for ensuring that they do not do so.
996 ResourceTrackerSP createResourceTracker();
997
998 /// Adds a definition generator to this JITDylib and returns a referenece to
999 /// it.
1000 ///
1001 /// When JITDylibs are searched during lookup, if no existing definition of
1002 /// a symbol is found, then any generators that have been added are run (in
1003 /// the order that they were added) to potentially generate a definition.
1004 ///
1005 /// It is illegal to call this method on a defunct JITDylib and the client
1006 /// is responsible for ensuring that they do not do so.
1007 template <typename GeneratorT>
1008 GeneratorT &addGenerator(std::unique_ptr<GeneratorT> DefGenerator);
1009
1010 /// Remove a definition generator from this JITDylib.
1011 ///
1012 /// The given generator must exist in this JITDylib's generators list (i.e.
1013 /// have been added and not yet removed).
1014 ///
1015 /// It is illegal to call this method on a defunct JITDylib and the client
1016 /// is responsible for ensuring that they do not do so.
1017 void removeGenerator(DefinitionGenerator &G);
1018
1019 /// Set the link order to be used when fixing up definitions in JITDylib.
1020 /// This will replace the previous link order, and apply to any symbol
1021 /// resolutions made for definitions in this JITDylib after the call to
1022 /// setLinkOrder (even if the definition itself was added before the
1023 /// call).
1024 ///
1025 /// If LinkAgainstThisJITDylibFirst is true (the default) then this JITDylib
1026 /// will add itself to the beginning of the LinkOrder (Clients should not
1027 /// put this JITDylib in the list in this case, to avoid redundant lookups).
1028 ///
1029 /// If LinkAgainstThisJITDylibFirst is false then the link order will be used
1030 /// as-is. The primary motivation for this feature is to support deliberate
1031 /// shadowing of symbols in this JITDylib by a facade JITDylib. For example,
1032 /// the facade may resolve function names to stubs, and the stubs may compile
1033 /// lazily by looking up symbols in this dylib. Adding the facade dylib
1034 /// as the first in the link order (instead of this dylib) ensures that
1035 /// definitions within this dylib resolve to the lazy-compiling stubs,
1036 /// rather than immediately materializing the definitions in this dylib.
1037 ///
1038 /// It is illegal to call this method on a defunct JITDylib and the client
1039 /// is responsible for ensuring that they do not do so.
1040 void setLinkOrder(JITDylibSearchOrder NewSearchOrder,
1041 bool LinkAgainstThisJITDylibFirst = true);
1042
1043 /// Add the given JITDylib to the link order for definitions in this
1044 /// JITDylib.
1045 ///
1046 /// It is illegal to call this method on a defunct JITDylib and the client
1047 /// is responsible for ensuring that they do not do so.
1048 void addToLinkOrder(JITDylib &JD,
1049 JITDylibLookupFlags JDLookupFlags =
1050 JITDylibLookupFlags::MatchExportedSymbolsOnly);
1051
1052 /// Replace OldJD with NewJD in the link order if OldJD is present.
1053 /// Otherwise this operation is a no-op.
1054 ///
1055 /// It is illegal to call this method on a defunct JITDylib and the client
1056 /// is responsible for ensuring that they do not do so.
1057 void replaceInLinkOrder(JITDylib &OldJD, JITDylib &NewJD,
1058 JITDylibLookupFlags JDLookupFlags =
1059 JITDylibLookupFlags::MatchExportedSymbolsOnly);
1060
1061 /// Remove the given JITDylib from the link order for this JITDylib if it is
1062 /// present. Otherwise this operation is a no-op.
1063 ///
1064 /// It is illegal to call this method on a defunct JITDylib and the client
1065 /// is responsible for ensuring that they do not do so.
1066 void removeFromLinkOrder(JITDylib &JD);
1067
1068 /// Do something with the link order (run under the session lock).
1069 ///
1070 /// It is illegal to call this method on a defunct JITDylib and the client
1071 /// is responsible for ensuring that they do not do so.
1072 template <typename Func>
1073 auto withLinkOrderDo(Func &&F)
1074 -> decltype(F(std::declval<const JITDylibSearchOrder &>()));
1075
1076 /// Define all symbols provided by the materialization unit to be part of this
1077 /// JITDylib.
1078 ///
1079 /// If RT is not specified then the default resource tracker will be used.
1080 ///
1081 /// This overload always takes ownership of the MaterializationUnit. If any
1082 /// errors occur, the MaterializationUnit consumed.
1083 ///
1084 /// It is illegal to call this method on a defunct JITDylib and the client
1085 /// is responsible for ensuring that they do not do so.
1086 template <typename MaterializationUnitType>
1087 Error define(std::unique_ptr<MaterializationUnitType> &&MU,
1088 ResourceTrackerSP RT = nullptr);
1089
1090 /// Define all symbols provided by the materialization unit to be part of this
1091 /// JITDylib.
1092 ///
1093 /// This overload only takes ownership of the MaterializationUnit no error is
1094 /// generated. If an error occurs, ownership remains with the caller. This
1095 /// may allow the caller to modify the MaterializationUnit to correct the
1096 /// issue, then re-call define.
1097 ///
1098 /// It is illegal to call this method on a defunct JITDylib and the client
1099 /// is responsible for ensuring that they do not do so.
1100 template <typename MaterializationUnitType>
1101 Error define(std::unique_ptr<MaterializationUnitType> &MU,
1102 ResourceTrackerSP RT = nullptr);
1103
1104 /// Tries to remove the given symbols.
1105 ///
1106 /// If any symbols are not defined in this JITDylib this method will return
1107 /// a SymbolsNotFound error covering the missing symbols.
1108 ///
1109 /// If all symbols are found but some symbols are in the process of being
1110 /// materialized this method will return a SymbolsCouldNotBeRemoved error.
1111 ///
1112 /// On success, all symbols are removed. On failure, the JITDylib state is
1113 /// left unmodified (no symbols are removed).
1114 ///
1115 /// It is illegal to call this method on a defunct JITDylib and the client
1116 /// is responsible for ensuring that they do not do so.
1117 Error remove(const SymbolNameSet &Names);
1118
1119 /// Returns the given JITDylibs and all of their transitive dependencies in
1120 /// DFS order (based on linkage relationships). Each JITDylib will appear
1121 /// only once.
1122 ///
1123 /// If any JITDylib in the order is defunct then this method will return an
1124 /// error, otherwise returns the order.
1125 static Expected<std::vector<JITDylibSP>>
1126 getDFSLinkOrder(ArrayRef<JITDylibSP> JDs);
1127
1128 /// Returns the given JITDylibs and all of their transitive dependencies in
1129 /// reverse DFS order (based on linkage relationships). Each JITDylib will
1130 /// appear only once.
1131 ///
1132 /// If any JITDylib in the order is defunct then this method will return an
1133 /// error, otherwise returns the order.
1134 static Expected<std::vector<JITDylibSP>>
1135 getReverseDFSLinkOrder(ArrayRef<JITDylibSP> JDs);
1136
1137 /// Return this JITDylib and its transitive dependencies in DFS order
1138 /// based on linkage relationships.
1139 ///
1140 /// If any JITDylib in the order is defunct then this method will return an
1141 /// error, otherwise returns the order.
1142 Expected<std::vector<JITDylibSP>> getDFSLinkOrder();
1143
1144 /// Rteurn this JITDylib and its transitive dependencies in reverse DFS order
1145 /// based on linkage relationships.
1146 ///
1147 /// If any JITDylib in the order is defunct then this method will return an
1148 /// error, otherwise returns the order.
1149 Expected<std::vector<JITDylibSP>> getReverseDFSLinkOrder();
1150
1151private:
1152 using AsynchronousSymbolQuerySet =
1153 std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
1154
1155 using AsynchronousSymbolQueryList =
1156 std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
1157
1158 struct UnmaterializedInfo {
1159 UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU,
1160 ResourceTracker *RT)
1161 : MU(std::move(MU)), RT(RT) {}
1162
1163 std::unique_ptr<MaterializationUnit> MU;
1164 ResourceTracker *RT;
1165 };
1166
1167 using UnmaterializedInfosMap =
1168 DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
1169
1170 using UnmaterializedInfosList =
1171 std::vector<std::shared_ptr<UnmaterializedInfo>>;
1172
1173 struct MaterializingInfo {
1174 SymbolDependenceMap Dependants;
1175 SymbolDependenceMap UnemittedDependencies;
1176
1177 void addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q);
1178 void removeQuery(const AsynchronousSymbolQuery &Q);
1179 AsynchronousSymbolQueryList takeQueriesMeeting(SymbolState RequiredState);
1180 AsynchronousSymbolQueryList takeAllPendingQueries() {
1181 return std::move(PendingQueries);
1182 }
1183 bool hasQueriesPending() const { return !PendingQueries.empty(); }
1184 const AsynchronousSymbolQueryList &pendingQueries() const {
1185 return PendingQueries;
1186 }
1187 private:
1188 AsynchronousSymbolQueryList PendingQueries;
1189 };
1190
1191 using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>;
1192
1193 class SymbolTableEntry {
1194 public:
1195 SymbolTableEntry() = default;
1196 SymbolTableEntry(JITSymbolFlags Flags)
1197 : Flags(Flags), State(static_cast<uint8_t>(SymbolState::NeverSearched)),
1198 MaterializerAttached(false), PendingRemoval(false) {}
1199
1200 JITTargetAddress getAddress() const { return Addr; }
1201 JITSymbolFlags getFlags() const { return Flags; }
1202 SymbolState getState() const { return static_cast<SymbolState>(State); }
1203
1204 bool hasMaterializerAttached() const { return MaterializerAttached; }
1205 bool isPendingRemoval() const { return PendingRemoval; }
1206
1207 void setAddress(JITTargetAddress Addr) { this->Addr = Addr; }
1208 void setFlags(JITSymbolFlags Flags) { this->Flags = Flags; }
1209 void setState(SymbolState State) {
1210 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", 1211, __extension__
__PRETTY_FUNCTION__))
1211 "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", 1211, __extension__
__PRETTY_FUNCTION__))
;
1212 this->State = static_cast<uint8_t>(State);
1213 }
1214
1215 void setMaterializerAttached(bool MaterializerAttached) {
1216 this->MaterializerAttached = MaterializerAttached;
1217 }
1218
1219 void setPendingRemoval(bool PendingRemoval) {
1220 this->PendingRemoval = PendingRemoval;
1221 }
1222
1223 JITEvaluatedSymbol getSymbol() const {
1224 return JITEvaluatedSymbol(Addr, Flags);
1225 }
1226
1227 private:
1228 JITTargetAddress Addr = 0;
1229 JITSymbolFlags Flags;
1230 uint8_t State : 6;
1231 uint8_t MaterializerAttached : 1;
1232 uint8_t PendingRemoval : 1;
1233 };
1234
1235 using SymbolTable = DenseMap<SymbolStringPtr, SymbolTableEntry>;
1236
1237 JITDylib(ExecutionSession &ES, std::string Name);
1238
1239 std::pair<AsynchronousSymbolQuerySet, std::shared_ptr<SymbolDependenceMap>>
1240 removeTracker(ResourceTracker &RT);
1241
1242 void transferTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT);
1243
1244 Error defineImpl(MaterializationUnit &MU);
1245
1246 void installMaterializationUnit(std::unique_ptr<MaterializationUnit> MU,
1247 ResourceTracker &RT);
1248
1249 void detachQueryHelper(AsynchronousSymbolQuery &Q,
1250 const SymbolNameSet &QuerySymbols);
1251
1252 void transferEmittedNodeDependencies(MaterializingInfo &DependantMI,
1253 const SymbolStringPtr &DependantName,
1254 MaterializingInfo &EmittedMI);
1255
1256 Expected<SymbolFlagsMap> defineMaterializing(SymbolFlagsMap SymbolFlags);
1257
1258 Error replace(MaterializationResponsibility &FromMR,
1259 std::unique_ptr<MaterializationUnit> MU);
1260
1261 Expected<std::unique_ptr<MaterializationResponsibility>>
1262 delegate(MaterializationResponsibility &FromMR, SymbolFlagsMap SymbolFlags,
1263 SymbolStringPtr InitSymbol);
1264
1265 SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const;
1266
1267 void addDependencies(const SymbolStringPtr &Name,
1268 const SymbolDependenceMap &Dependants);
1269
1270 Error resolve(MaterializationResponsibility &MR, const SymbolMap &Resolved);
1271
1272 Error emit(MaterializationResponsibility &MR, const SymbolFlagsMap &Emitted);
1273
1274 void unlinkMaterializationResponsibility(MaterializationResponsibility &MR);
1275
1276 using FailedSymbolsWorklist =
1277 std::vector<std::pair<JITDylib *, SymbolStringPtr>>;
1278
1279 static std::pair<AsynchronousSymbolQuerySet,
1280 std::shared_ptr<SymbolDependenceMap>>
1281 failSymbols(FailedSymbolsWorklist);
1282
1283 ExecutionSession &ES;
1284 enum { Open, Closing, Closed } State = Open;
1285 std::mutex GeneratorsMutex;
1286 SymbolTable Symbols;
1287 UnmaterializedInfosMap UnmaterializedInfos;
1288 MaterializingInfosMap MaterializingInfos;
1289 std::vector<std::shared_ptr<DefinitionGenerator>> DefGenerators;
1290 JITDylibSearchOrder LinkOrder;
1291 ResourceTrackerSP DefaultTracker;
1292
1293 // Map trackers to sets of symbols tracked.
1294 DenseMap<ResourceTracker *, SymbolNameVector> TrackerSymbols;
1295 DenseMap<ResourceTracker *, DenseSet<MaterializationResponsibility *>>
1296 TrackerMRs;
1297};
1298
1299/// Platforms set up standard symbols and mediate interactions between dynamic
1300/// initializers (e.g. C++ static constructors) and ExecutionSession state.
1301/// Note that Platforms do not automatically run initializers: clients are still
1302/// responsible for doing this.
1303class Platform {
1304public:
1305 virtual ~Platform();
1306
1307 /// This method will be called outside the session lock each time a JITDylib
1308 /// is created (unless it is created with EmptyJITDylib set) to allow the
1309 /// Platform to install any JITDylib specific standard symbols (e.g
1310 /// __dso_handle).
1311 virtual Error setupJITDylib(JITDylib &JD) = 0;
1312
1313 /// This method will be called outside the session lock each time a JITDylib
1314 /// is removed to allow the Platform to remove any JITDylib-specific data.
1315 virtual Error teardownJITDylib(JITDylib &JD) = 0;
1316
1317 /// This method will be called under the ExecutionSession lock each time a
1318 /// MaterializationUnit is added to a JITDylib.
1319 virtual Error notifyAdding(ResourceTracker &RT,
1320 const MaterializationUnit &MU) = 0;
1321
1322 /// This method will be called under the ExecutionSession lock when a
1323 /// ResourceTracker is removed.
1324 virtual Error notifyRemoving(ResourceTracker &RT) = 0;
1325
1326 /// A utility function for looking up initializer symbols. Performs a blocking
1327 /// lookup for the given symbols in each of the given JITDylibs.
1328 ///
1329 /// Note: This function is deprecated and will be removed in the near future.
1330 static Expected<DenseMap<JITDylib *, SymbolMap>>
1331 lookupInitSymbols(ExecutionSession &ES,
1332 const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms);
1333
1334 /// Performs an async lookup for the the given symbols in each of the given
1335 /// JITDylibs, calling the given handler once all lookups have completed.
1336 static void
1337 lookupInitSymbolsAsync(unique_function<void(Error)> OnComplete,
1338 ExecutionSession &ES,
1339 const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms);
1340};
1341
1342/// A materialization task.
1343class MaterializationTask : public RTTIExtends<MaterializationTask, Task> {
1344public:
1345 static char ID;
1346
1347 MaterializationTask(std::unique_ptr<MaterializationUnit> MU,
1348 std::unique_ptr<MaterializationResponsibility> MR)
1349 : MU(std::move(MU)), MR(std::move(MR)) {}
1350 void printDescription(raw_ostream &OS) override;
1351 void run() override;
1352
1353private:
1354 std::unique_ptr<MaterializationUnit> MU;
1355 std::unique_ptr<MaterializationResponsibility> MR;
1356};
1357
1358/// An ExecutionSession represents a running JIT program.
1359class ExecutionSession {
1360 friend class InProgressLookupFlagsState;
1361 friend class InProgressFullLookupState;
1362 friend class JITDylib;
1363 friend class LookupState;
1364 friend class MaterializationResponsibility;
1365 friend class ResourceTracker;
1366
1367public:
1368 /// For reporting errors.
1369 using ErrorReporter = std::function<void(Error)>;
1370
1371 /// Send a result to the remote.
1372 using SendResultFunction = unique_function<void(shared::WrapperFunctionResult)>;
1373
1374 /// For dispatching ORC tasks (typically materialization tasks).
1375 using DispatchTaskFunction = unique_function<void(std::unique_ptr<Task> T)>;
1376
1377 /// An asynchronous wrapper-function callable from the executor via
1378 /// jit-dispatch.
1379 using JITDispatchHandlerFunction = unique_function<void(
1380 SendResultFunction SendResult,
1381 const char *ArgData, size_t ArgSize)>;
1382
1383 /// A map associating tag names with asynchronous wrapper function
1384 /// implementations in the JIT.
1385 using JITDispatchHandlerAssociationMap =
1386 DenseMap<SymbolStringPtr, JITDispatchHandlerFunction>;
1387
1388 /// Construct an ExecutionSession with the given ExecutorProcessControl
1389 /// object.
1390 ExecutionSession(std::unique_ptr<ExecutorProcessControl> EPC);
1391
1392 /// End the session. Closes all JITDylibs and disconnects from the
1393 /// executor.
1394 Error endSession();
1395
1396 /// Get the ExecutorProcessControl object associated with this
1397 /// ExecutionSession.
1398 ExecutorProcessControl &getExecutorProcessControl() { return *EPC; }
1399
1400 /// Get the SymbolStringPool for this instance.
1401 std::shared_ptr<SymbolStringPool> getSymbolStringPool() {
1402 return EPC->getSymbolStringPool();
1403 }
1404
1405 /// Add a symbol name to the SymbolStringPool and return a pointer to it.
1406 SymbolStringPtr intern(StringRef SymName) { return EPC->intern(SymName); }
1407
1408 /// Set the Platform for this ExecutionSession.
1409 void setPlatform(std::unique_ptr<Platform> P) { this->P = std::move(P); }
1410
1411 /// Get the Platform for this session.
1412 /// Will return null if no Platform has been set for this ExecutionSession.
1413 Platform *getPlatform() { return P.get(); }
1414
1415 /// Run the given lambda with the session mutex locked.
1416 template <typename Func> decltype(auto) runSessionLocked(Func &&F) {
1417 std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
1418 return F();
1419 }
1420
1421 /// Register the given ResourceManager with this ExecutionSession.
1422 /// Managers will be notified of events in reverse order of registration.
1423 void registerResourceManager(ResourceManager &RM);
1424
1425 /// Deregister the given ResourceManager with this ExecutionSession.
1426 /// Manager must have been previously registered.
1427 void deregisterResourceManager(ResourceManager &RM);
1428
1429 /// Return a pointer to the "name" JITDylib.
1430 /// Ownership of JITDylib remains within Execution Session
1431 JITDylib *getJITDylibByName(StringRef Name);
1432
1433 /// Add a new bare JITDylib to this ExecutionSession.
1434 ///
1435 /// The JITDylib Name is required to be unique. Clients should verify that
1436 /// names are not being re-used (E.g. by calling getJITDylibByName) if names
1437 /// are based on user input.
1438 ///
1439 /// This call does not install any library code or symbols into the newly
1440 /// created JITDylib. The client is responsible for all configuration.
1441 JITDylib &createBareJITDylib(std::string Name);
1442
1443 /// Add a new JITDylib to this ExecutionSession.
1444 ///
1445 /// The JITDylib Name is required to be unique. Clients should verify that
1446 /// names are not being re-used (e.g. by calling getJITDylibByName) if names
1447 /// are based on user input.
1448 ///
1449 /// If a Platform is attached then Platform::setupJITDylib will be called to
1450 /// install standard platform symbols (e.g. standard library interposes).
1451 /// If no Platform is attached this call is equivalent to createBareJITDylib.
1452 Expected<JITDylib &> createJITDylib(std::string Name);
1453
1454 /// Closes the given JITDylib.
1455 ///
1456 /// This method clears all resources held for the JITDylib, puts it in the
1457 /// closed state, and clears all references held by the ExecutionSession and
1458 /// other JITDylibs. No further code can be added to the JITDylib, and the
1459 /// object will be freed once any remaining JITDylibSPs to it are destroyed.
1460 ///
1461 /// This method does *not* run static destructors.
1462 ///
1463 /// This method can only be called once for each JITDylib.
1464 Error removeJITDylib(JITDylib &JD);
1465
1466 /// Set the error reporter function.
1467 ExecutionSession &setErrorReporter(ErrorReporter ReportError) {
1468 this->ReportError = std::move(ReportError);
1469 return *this;
1470 }
1471
1472 /// Report a error for this execution session.
1473 ///
1474 /// Unhandled errors can be sent here to log them.
1475 void reportError(Error Err) { ReportError(std::move(Err)); }
1476
1477 /// Set the task dispatch function.
1478 ExecutionSession &setDispatchTask(DispatchTaskFunction DispatchTask) {
1479 this->DispatchTask = std::move(DispatchTask);
1480 return *this;
1481 }
1482
1483 /// Search the given JITDylibs to find the flags associated with each of the
1484 /// given symbols.
1485 void lookupFlags(LookupKind K, JITDylibSearchOrder SearchOrder,
1486 SymbolLookupSet Symbols,
1487 unique_function<void(Expected<SymbolFlagsMap>)> OnComplete);
1488
1489 /// Blocking version of lookupFlags.
1490 Expected<SymbolFlagsMap> lookupFlags(LookupKind K,
1491 JITDylibSearchOrder SearchOrder,
1492 SymbolLookupSet Symbols);
1493
1494 /// Search the given JITDylibs for the given symbols.
1495 ///
1496 /// SearchOrder lists the JITDylibs to search. For each dylib, the associated
1497 /// boolean indicates whether the search should match against non-exported
1498 /// (hidden visibility) symbols in that dylib (true means match against
1499 /// non-exported symbols, false means do not match).
1500 ///
1501 /// The NotifyComplete callback will be called once all requested symbols
1502 /// reach the required state.
1503 ///
1504 /// If all symbols are found, the RegisterDependencies function will be called
1505 /// while the session lock is held. This gives clients a chance to register
1506 /// dependencies for on the queried symbols for any symbols they are
1507 /// materializing (if a MaterializationResponsibility instance is present,
1508 /// this can be implemented by calling
1509 /// MaterializationResponsibility::addDependencies). If there are no
1510 /// dependenant symbols for this query (e.g. it is being made by a top level
1511 /// client to get an address to call) then the value NoDependenciesToRegister
1512 /// can be used.
1513 void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder,
1514 SymbolLookupSet Symbols, SymbolState RequiredState,
1515 SymbolsResolvedCallback NotifyComplete,
1516 RegisterDependenciesFunction RegisterDependencies);
1517
1518 /// Blocking version of lookup above. Returns the resolved symbol map.
1519 /// If WaitUntilReady is true (the default), will not return until all
1520 /// requested symbols are ready (or an error occurs). If WaitUntilReady is
1521 /// false, will return as soon as all requested symbols are resolved,
1522 /// or an error occurs. If WaitUntilReady is false and an error occurs
1523 /// after resolution, the function will return a success value, but the
1524 /// error will be reported via reportErrors.
1525 Expected<SymbolMap> lookup(const JITDylibSearchOrder &SearchOrder,
1526 const SymbolLookupSet &Symbols,
1527 LookupKind K = LookupKind::Static,
1528 SymbolState RequiredState = SymbolState::Ready,
1529 RegisterDependenciesFunction RegisterDependencies =
1530 NoDependenciesToRegister);
1531
1532 /// Convenience version of blocking lookup.
1533 /// Searches each of the JITDylibs in the search order in turn for the given
1534 /// symbol.
1535 Expected<JITEvaluatedSymbol>
1536 lookup(const JITDylibSearchOrder &SearchOrder, SymbolStringPtr Symbol,
1537 SymbolState RequiredState = SymbolState::Ready);
1538
1539 /// Convenience version of blocking lookup.
1540 /// Searches each of the JITDylibs in the search order in turn for the given
1541 /// symbol. The search will not find non-exported symbols.
1542 Expected<JITEvaluatedSymbol>
1543 lookup(ArrayRef<JITDylib *> SearchOrder, SymbolStringPtr Symbol,
1544 SymbolState RequiredState = SymbolState::Ready);
1545
1546 /// Convenience version of blocking lookup.
1547 /// Searches each of the JITDylibs in the search order in turn for the given
1548 /// symbol. The search will not find non-exported symbols.
1549 Expected<JITEvaluatedSymbol>
1550 lookup(ArrayRef<JITDylib *> SearchOrder, StringRef Symbol,
1551 SymbolState RequiredState = SymbolState::Ready);
1552
1553 /// Materialize the given unit.
1554 void dispatchTask(std::unique_ptr<Task> T) {
1555 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", 1555, __extension__
__PRETTY_FUNCTION__))
;
1556 DEBUG_WITH_TYPE("orc", dumpDispatchInfo(*T))do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { dumpDispatchInfo(*T); } } while (false)
;
1557 DispatchTask(std::move(T));
1558 }
1559
1560 /// Run a wrapper function in the executor.
1561 ///
1562 /// The wrapper function should be callable as:
1563 ///
1564 /// \code{.cpp}
1565 /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
1566 /// \endcode{.cpp}
1567 ///
1568 /// The given OnComplete function will be called to return the result.
1569 template <typename... ArgTs>
1570 void callWrapperAsync(ArgTs &&... Args) {
1571 EPC->callWrapperAsync(std::forward<ArgTs>(Args)...);
1572 }
1573
1574 /// Run a wrapper function in the executor. The wrapper function should be
1575 /// callable as:
1576 ///
1577 /// \code{.cpp}
1578 /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
1579 /// \endcode{.cpp}
1580 shared::WrapperFunctionResult callWrapper(ExecutorAddr WrapperFnAddr,
1581 ArrayRef<char> ArgBuffer) {
1582 return EPC->callWrapper(WrapperFnAddr, ArgBuffer);
1583 }
1584
1585 /// Run a wrapper function using SPS to serialize the arguments and
1586 /// deserialize the results.
1587 template <typename SPSSignature, typename SendResultT, typename... ArgTs>
1588 void callSPSWrapperAsync(ExecutorAddr WrapperFnAddr, SendResultT &&SendResult,
1589 const ArgTs &...Args) {
1590 EPC->callSPSWrapperAsync<SPSSignature, SendResultT, ArgTs...>(
1591 WrapperFnAddr, std::forward<SendResultT>(SendResult), Args...);
1592 }
1593
1594 /// Run a wrapper function using SPS to serialize the arguments and
1595 /// deserialize the results.
1596 ///
1597 /// If SPSSignature is a non-void function signature then the second argument
1598 /// (the first in the Args list) should be a reference to a return value.
1599 template <typename SPSSignature, typename... WrapperCallArgTs>
1600 Error callSPSWrapper(ExecutorAddr WrapperFnAddr,
1601 WrapperCallArgTs &&...WrapperCallArgs) {
1602 return EPC->callSPSWrapper<SPSSignature, WrapperCallArgTs...>(
12
Calling 'ExecutorProcessControl::callSPSWrapper'
23
Returning from 'ExecutorProcessControl::callSPSWrapper'
1603 WrapperFnAddr, std::forward<WrapperCallArgTs>(WrapperCallArgs)...);
1604 }
1605
1606 /// Wrap a handler that takes concrete argument types (and a sender for a
1607 /// concrete return type) to produce an AsyncHandlerWrapperFunction. Uses SPS
1608 /// to unpack the arguments and pack the result.
1609 ///
1610 /// This function is intended to support easy construction of
1611 /// AsyncHandlerWrapperFunctions that can be associated with a tag
1612 /// (using registerJITDispatchHandler) and called from the executor.
1613 template <typename SPSSignature, typename HandlerT>
1614 static JITDispatchHandlerFunction wrapAsyncWithSPS(HandlerT &&H) {
1615 return [H = std::forward<HandlerT>(H)](
1616 SendResultFunction SendResult,
1617 const char *ArgData, size_t ArgSize) mutable {
1618 shared::WrapperFunction<SPSSignature>::handleAsync(ArgData, ArgSize, H,
1619 std::move(SendResult));
1620 };
1621 }
1622
1623 /// Wrap a class method that takes concrete argument types (and a sender for
1624 /// a concrete return type) to produce an AsyncHandlerWrapperFunction. Uses
1625 /// SPS to unpack teh arguments and pack the result.
1626 ///
1627 /// This function is intended to support easy construction of
1628 /// AsyncHandlerWrapperFunctions that can be associated with a tag
1629 /// (using registerJITDispatchHandler) and called from the executor.
1630 template <typename SPSSignature, typename ClassT, typename... MethodArgTs>
1631 static JITDispatchHandlerFunction
1632 wrapAsyncWithSPS(ClassT *Instance, void (ClassT::*Method)(MethodArgTs...)) {
1633 return wrapAsyncWithSPS<SPSSignature>(
1634 [Instance, Method](MethodArgTs &&...MethodArgs) {
1635 (Instance->*Method)(std::forward<MethodArgTs>(MethodArgs)...);
1636 });
1637 }
1638
1639 /// For each tag symbol name, associate the corresponding
1640 /// AsyncHandlerWrapperFunction with the address of that symbol. The
1641 /// handler becomes callable from the executor using the ORC runtime
1642 /// __orc_rt_jit_dispatch function and the given tag.
1643 ///
1644 /// Tag symbols will be looked up in JD using LookupKind::Static,
1645 /// JITDylibLookupFlags::MatchAllSymbols (hidden tags will be found), and
1646 /// LookupFlags::WeaklyReferencedSymbol. Missing tag definitions will not
1647 /// cause an error, the handler will simply be dropped.
1648 Error registerJITDispatchHandlers(JITDylib &JD,
1649 JITDispatchHandlerAssociationMap WFs);
1650
1651 /// Run a registered jit-side wrapper function.
1652 /// This should be called by the ExecutorProcessControl instance in response
1653 /// to incoming jit-dispatch requests from the executor.
1654 void
1655 runJITDispatchHandler(SendResultFunction SendResult,
1656 JITTargetAddress HandlerFnTagAddr,
1657 ArrayRef<char> ArgBuffer);
1658
1659 /// Dump the state of all the JITDylibs in this session.
1660 void dump(raw_ostream &OS);
1661
1662private:
1663 static void logErrorsToStdErr(Error Err) {
1664 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
1665 }
1666
1667 static void runOnCurrentThread(std::unique_ptr<Task> T) { T->run(); }
1668
1669 void dispatchOutstandingMUs();
1670
1671 static std::unique_ptr<MaterializationResponsibility>
1672 createMaterializationResponsibility(ResourceTracker &RT,
1673 SymbolFlagsMap Symbols,
1674 SymbolStringPtr InitSymbol) {
1675 auto &JD = RT.getJITDylib();
1676 std::unique_ptr<MaterializationResponsibility> MR(
1677 new MaterializationResponsibility(&RT, std::move(Symbols),
1678 std::move(InitSymbol)));
1679 JD.TrackerMRs[&RT].insert(MR.get());
1680 return MR;
1681 }
1682
1683 Error removeResourceTracker(ResourceTracker &RT);
1684 void transferResourceTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT);
1685 void destroyResourceTracker(ResourceTracker &RT);
1686
1687 // State machine functions for query application..
1688
1689 /// IL_updateCandidatesFor is called to remove already-defined symbols that
1690 /// match a given query from the set of candidate symbols to generate
1691 /// definitions for (no need to generate a definition if one already exists).
1692 Error IL_updateCandidatesFor(JITDylib &JD, JITDylibLookupFlags JDLookupFlags,
1693 SymbolLookupSet &Candidates,
1694 SymbolLookupSet *NonCandidates);
1695
1696 /// OL_applyQueryPhase1 is an optionally re-startable loop for triggering
1697 /// definition generation. It is called when a lookup is performed, and again
1698 /// each time that LookupState::continueLookup is called.
1699 void OL_applyQueryPhase1(std::unique_ptr<InProgressLookupState> IPLS,
1700 Error Err);
1701
1702 /// OL_completeLookup is run once phase 1 successfully completes for a lookup
1703 /// call. It attempts to attach the symbol to all symbol table entries and
1704 /// collect all MaterializationUnits to dispatch. If this method fails then
1705 /// all MaterializationUnits will be left un-materialized.
1706 void OL_completeLookup(std::unique_ptr<InProgressLookupState> IPLS,
1707 std::shared_ptr<AsynchronousSymbolQuery> Q,
1708 RegisterDependenciesFunction RegisterDependencies);
1709
1710 /// OL_completeLookupFlags is run once phase 1 successfully completes for a
1711 /// lookupFlags call.
1712 void OL_completeLookupFlags(
1713 std::unique_ptr<InProgressLookupState> IPLS,
1714 unique_function<void(Expected<SymbolFlagsMap>)> OnComplete);
1715
1716 // State machine functions for MaterializationResponsibility.
1717 void OL_destroyMaterializationResponsibility(
1718 MaterializationResponsibility &MR);
1719 SymbolNameSet OL_getRequestedSymbols(const MaterializationResponsibility &MR);
1720 Error OL_notifyResolved(MaterializationResponsibility &MR,
1721 const SymbolMap &Symbols);
1722 Error OL_notifyEmitted(MaterializationResponsibility &MR);
1723 Error OL_defineMaterializing(MaterializationResponsibility &MR,
1724 SymbolFlagsMap SymbolFlags);
1725 void OL_notifyFailed(MaterializationResponsibility &MR);
1726 Error OL_replace(MaterializationResponsibility &MR,
1727 std::unique_ptr<MaterializationUnit> MU);
1728 Expected<std::unique_ptr<MaterializationResponsibility>>
1729 OL_delegate(MaterializationResponsibility &MR, const SymbolNameSet &Symbols);
1730 void OL_addDependencies(MaterializationResponsibility &MR,
1731 const SymbolStringPtr &Name,
1732 const SymbolDependenceMap &Dependencies);
1733 void OL_addDependenciesForAll(MaterializationResponsibility &MR,
1734 const SymbolDependenceMap &Dependencies);
1735
1736#ifndef NDEBUG
1737 void dumpDispatchInfo(Task &T);
1738#endif // NDEBUG
1739
1740 mutable std::recursive_mutex SessionMutex;
1741 bool SessionOpen = true;
1742 std::unique_ptr<ExecutorProcessControl> EPC;
1743 std::unique_ptr<Platform> P;
1744 ErrorReporter ReportError = logErrorsToStdErr;
1745 DispatchTaskFunction DispatchTask = runOnCurrentThread;
1746
1747 std::vector<ResourceManager *> ResourceManagers;
1748
1749 std::vector<JITDylibSP> JDs;
1750
1751 // FIXME: Remove this (and runOutstandingMUs) once the linking layer works
1752 // with callbacks from asynchronous queries.
1753 mutable std::recursive_mutex OutstandingMUsMutex;
1754 std::vector<std::pair<std::unique_ptr<MaterializationUnit>,
1755 std::unique_ptr<MaterializationResponsibility>>>
1756 OutstandingMUs;
1757
1758 mutable std::mutex JITDispatchHandlersMutex;
1759 DenseMap<JITTargetAddress, std::shared_ptr<JITDispatchHandlerFunction>>
1760 JITDispatchHandlers;
1761};
1762
1763inline ExecutionSession &
1764MaterializationResponsibility::getExecutionSession() const {
1765 return JD.getExecutionSession();
1766}
1767
1768template <typename Func>
1769Error MaterializationResponsibility::withResourceKeyDo(Func &&F) const {
1770 return JD.getExecutionSession().runSessionLocked([&]() -> Error {
1771 if (RT->isDefunct())
1772 return make_error<ResourceTrackerDefunct>(RT);
1773 F(RT->getKeyUnsafe());
1774 return Error::success();
1775 });
1776}
1777
1778template <typename GeneratorT>
1779GeneratorT &JITDylib::addGenerator(std::unique_ptr<GeneratorT> DefGenerator) {
1780 auto &G = *DefGenerator;
1781 ES.runSessionLocked([&] {
1782 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", 1782, __extension__
__PRETTY_FUNCTION__))
;
1783 DefGenerators.push_back(std::move(DefGenerator));
1784 });
1785 return G;
1786}
1787
1788template <typename Func>
1789auto JITDylib::withLinkOrderDo(Func &&F)
1790 -> decltype(F(std::declval<const JITDylibSearchOrder &>())) {
1791 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", 1791, __extension__
__PRETTY_FUNCTION__))
;
1792 return ES.runSessionLocked([&]() { return F(LinkOrder); });
1793}
1794
1795template <typename MaterializationUnitType>
1796Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU,
1797 ResourceTrackerSP RT) {
1798 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", 1798, __extension__
__PRETTY_FUNCTION__))
;
1799
1800 if (MU->getSymbols().empty()) {
1801 // Empty MUs are allowable but pathological, so issue a warning.
1802 DEBUG_WITH_TYPE("orc", {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "Warning: Discarding empty MU " <<
MU->getName() << " for " << getName() <<
"\n"; }; } } while (false)
1803 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)
1804 << getName() << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "Warning: Discarding empty MU " <<
MU->getName() << " for " << getName() <<
"\n"; }; } } while (false)
1805 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "Warning: Discarding empty MU " <<
MU->getName() << " for " << getName() <<
"\n"; }; } } while (false)
;
1806 return Error::success();
1807 } else
1808 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
)
1809 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
)
1810 << " (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
)
1811 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
)
1812 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
)
1813 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
)
1814 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
)
1815 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
)
1816 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
)
1817 })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
)
;
1818
1819 return ES.runSessionLocked([&, this]() -> Error {
1820 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", 1820, __extension__
__PRETTY_FUNCTION__))
;
1821
1822 if (auto Err = defineImpl(*MU))
1823 return Err;
1824
1825 if (!RT)
1826 RT = getDefaultResourceTracker();
1827
1828 if (auto *P = ES.getPlatform()) {
1829 if (auto Err = P->notifyAdding(*RT, *MU))
1830 return Err;
1831 }
1832
1833 installMaterializationUnit(std::move(MU), *RT);
1834 return Error::success();
1835 });
1836}
1837
1838template <typename MaterializationUnitType>
1839Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU,
1840 ResourceTrackerSP RT) {
1841 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", 1841, __extension__
__PRETTY_FUNCTION__))
;
1842
1843 if (MU->getSymbols().empty()) {
1844 // Empty MUs are allowable but pathological, so issue a warning.
1845 DEBUG_WITH_TYPE("orc", {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "Warning: Discarding empty MU " <<
MU->getName() << getName() << "\n"; }; } } while
(false)
1846 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)
1847 << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "Warning: Discarding empty MU " <<
MU->getName() << getName() << "\n"; }; } } while
(false)
1848 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "Warning: Discarding empty MU " <<
MU->getName() << getName() << "\n"; }; } } while
(false)
;
1849 return Error::success();
1850 } else
1851 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
)
1852 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
)
1853 << " (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
)
1854 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
)
1855 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
)
1856 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
)
1857 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
)
1858 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
)
1859 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
)
1860 })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
)
;
1861
1862 return ES.runSessionLocked([&, this]() -> Error {
1863 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", 1863, __extension__
__PRETTY_FUNCTION__))
;
1864
1865 if (auto Err = defineImpl(*MU))
1866 return Err;
1867
1868 if (!RT)
1869 RT = getDefaultResourceTracker();
1870
1871 if (auto *P = ES.getPlatform()) {
1872 if (auto Err = P->notifyAdding(*RT, *MU))
1873 return Err;
1874 }
1875
1876 installMaterializationUnit(std::move(MU), *RT);
1877 return Error::success();
1878 });
1879}
1880
1881/// ReexportsGenerator can be used with JITDylib::addGenerator to automatically
1882/// re-export a subset of the source JITDylib's symbols in the target.
1883class ReexportsGenerator : public DefinitionGenerator {
1884public:
1885 using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
1886
1887 /// Create a reexports generator. If an Allow predicate is passed, only
1888 /// symbols for which the predicate returns true will be reexported. If no
1889 /// Allow predicate is passed, all symbols will be exported.
1890 ReexportsGenerator(JITDylib &SourceJD,
1891 JITDylibLookupFlags SourceJDLookupFlags,
1892 SymbolPredicate Allow = SymbolPredicate());
1893
1894 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
1895 JITDylibLookupFlags JDLookupFlags,
1896 const SymbolLookupSet &LookupSet) override;
1897
1898private:
1899 JITDylib &SourceJD;
1900 JITDylibLookupFlags SourceJDLookupFlags;
1901 SymbolPredicate Allow;
1902};
1903
1904// --------------- IMPLEMENTATION --------------
1905// Implementations for inline functions/methods.
1906// ---------------------------------------------
1907
1908inline MaterializationResponsibility::~MaterializationResponsibility() {
1909 getExecutionSession().OL_destroyMaterializationResponsibility(*this);
1910}
1911
1912inline SymbolNameSet MaterializationResponsibility::getRequestedSymbols() const {
1913 return getExecutionSession().OL_getRequestedSymbols(*this);
1914}
1915
1916inline Error MaterializationResponsibility::notifyResolved(
1917 const SymbolMap &Symbols) {
1918 return getExecutionSession().OL_notifyResolved(*this, Symbols);
1919}
1920
1921inline Error MaterializationResponsibility::notifyEmitted() {
1922 return getExecutionSession().OL_notifyEmitted(*this);
1923}
1924
1925inline Error MaterializationResponsibility::defineMaterializing(
1926 SymbolFlagsMap SymbolFlags) {
1927 return getExecutionSession().OL_defineMaterializing(*this,
1928 std::move(SymbolFlags));
1929}
1930
1931inline void MaterializationResponsibility::failMaterialization() {
1932 getExecutionSession().OL_notifyFailed(*this);
1933}
1934
1935inline Error MaterializationResponsibility::replace(
1936 std::unique_ptr<MaterializationUnit> MU) {
1937 return getExecutionSession().OL_replace(*this, std::move(MU));
1938}
1939
1940inline Expected<std::unique_ptr<MaterializationResponsibility>>
1941MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) {
1942 return getExecutionSession().OL_delegate(*this, Symbols);
1943}
1944
1945inline void MaterializationResponsibility::addDependencies(
1946 const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) {
1947 getExecutionSession().OL_addDependencies(*this, Name, Dependencies);
1948}
1949
1950inline void MaterializationResponsibility::addDependenciesForAll(
1951 const SymbolDependenceMap &Dependencies) {
1952 getExecutionSession().OL_addDependenciesForAll(*this, Dependencies);
1953}
1954
1955} // End namespace orc
1956} // End namespace llvm
1957
1958#endif // LLVM_EXECUTIONENGINE_ORC_CORE_H

/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.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/ADT/Triple.h"
18#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
19#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
20#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
21#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
22#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
23#include "llvm/ExecutionEngine/Orc/TaskDispatch.h"
24#include "llvm/Support/DynamicLibrary.h"
25#include "llvm/Support/MSVCErrorWorkarounds.h"
26
27#include <future>
28#include <mutex>
29#include <vector>
30
31namespace llvm {
32namespace orc {
33
34class ExecutionSession;
35class SymbolLookupSet;
36
37/// ExecutorProcessControl supports interaction with a JIT target process.
38class ExecutorProcessControl {
39 friend class ExecutionSession;
40public:
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 symbol map.
222 const StringMap<ExecutorAddr> &getBootstrapSymbolsMap() const {
223 return BootstrapSymbols;
224 }
225
226 /// For each (ExecutorAddr&, StringRef) pair, looks up the string in the
227 /// bootstrap symbols map and writes its address to the ExecutorAddr if
228 /// found. If any symbol is not found then the function returns an error.
229 Error getBootstrapSymbols(
230 ArrayRef<std::pair<ExecutorAddr &, StringRef>> Pairs) const {
231 for (auto &KV : Pairs) {
232 auto I = BootstrapSymbols.find(KV.second);
233 if (I == BootstrapSymbols.end())
234 return make_error<StringError>("Symbol \"" + KV.second +
235 "\" not found "
236 "in bootstrap symbols map",
237 inconvertibleErrorCode());
238
239 KV.first = I->second;
240 }
241 return Error::success();
242 }
243
244 /// Load the dynamic library at the given path and return a handle to it.
245 /// If LibraryPath is null this function will return the global handle for
246 /// the target process.
247 virtual Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) = 0;
248
249 /// Search for symbols in the target process.
250 ///
251 /// The result of the lookup is a 2-dimentional array of target addresses
252 /// that correspond to the lookup order. If a required symbol is not
253 /// found then this method will return an error. If a weakly referenced
254 /// symbol is not found then it be assigned a '0' value.
255 virtual Expected<std::vector<tpctypes::LookupResult>>
256 lookupSymbols(ArrayRef<LookupRequest> Request) = 0;
257
258 /// Run function with a main-like signature.
259 virtual Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
260 ArrayRef<std::string> Args) = 0;
261
262 /// Run a wrapper function in the executor. The given WFRHandler will be
263 /// called on the result when it is returned.
264 ///
265 /// The wrapper function should be callable as:
266 ///
267 /// \code{.cpp}
268 /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
269 /// \endcode{.cpp}
270 virtual void callWrapperAsync(ExecutorAddr WrapperFnAddr,
271 IncomingWFRHandler OnComplete,
272 ArrayRef<char> ArgBuffer) = 0;
273
274 /// Run a wrapper function in the executor using the given Runner to dispatch
275 /// OnComplete when the result is ready.
276 template <typename RunPolicyT, typename FnT>
277 void callWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
278 FnT &&OnComplete, ArrayRef<char> ArgBuffer) {
279 callWrapperAsync(
280 WrapperFnAddr, Runner(std::forward<FnT>(OnComplete)), ArgBuffer);
281 }
282
283 /// Run a wrapper function in the executor. OnComplete will be dispatched
284 /// as a GenericNamedTask using this instance's TaskDispatch object.
285 template <typename FnT>
286 void callWrapperAsync(ExecutorAddr WrapperFnAddr, FnT &&OnComplete,
287 ArrayRef<char> ArgBuffer) {
288 callWrapperAsync(RunAsTask(*D), WrapperFnAddr,
289 std::forward<FnT>(OnComplete), ArgBuffer);
290 }
291
292 /// Run a wrapper function in the executor. The wrapper function should be
293 /// callable as:
294 ///
295 /// \code{.cpp}
296 /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
297 /// \endcode{.cpp}
298 shared::WrapperFunctionResult callWrapper(ExecutorAddr WrapperFnAddr,
299 ArrayRef<char> ArgBuffer) {
300 std::promise<shared::WrapperFunctionResult> RP;
301 auto RF = RP.get_future();
302 callWrapperAsync(
303 RunInPlace(), WrapperFnAddr,
304 [&](shared::WrapperFunctionResult R) {
305 RP.set_value(std::move(R));
306 }, ArgBuffer);
307 return RF.get();
308 }
309
310 /// Run a wrapper function using SPS to serialize the arguments and
311 /// deserialize the results.
312 template <typename SPSSignature, typename RunPolicyT, typename SendResultT,
313 typename... ArgTs>
314 void callSPSWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
315 SendResultT &&SendResult, const ArgTs &...Args) {
316 shared::WrapperFunction<SPSSignature>::callAsync(
317 [this, WrapperFnAddr, Runner = std::move(Runner)]
318 (auto &&SendResult, const char *ArgData, size_t ArgSize) mutable {
319 this->callWrapperAsync(std::move(Runner), WrapperFnAddr,
320 std::move(SendResult),
321 ArrayRef<char>(ArgData, ArgSize));
322 },
323 std::forward<SendResultT>(SendResult), Args...);
324 }
325
326 /// Run a wrapper function using SPS to serialize the arguments and
327 /// deserialize the results.
328 template <typename SPSSignature, typename SendResultT, typename... ArgTs>
329 void callSPSWrapperAsync(ExecutorAddr WrapperFnAddr, SendResultT &&SendResult,
330 const ArgTs &...Args) {
331 callSPSWrapperAsync<SPSSignature>(RunAsTask(*D), WrapperFnAddr,
332 std::forward<SendResultT>(SendResult),
333 Args...);
334 }
335
336 /// Run a wrapper function using SPS to serialize the arguments and
337 /// deserialize the results.
338 ///
339 /// If SPSSignature is a non-void function signature then the second argument
340 /// (the first in the Args list) should be a reference to a return value.
341 template <typename SPSSignature, typename... WrapperCallArgTs>
342 Error callSPSWrapper(ExecutorAddr WrapperFnAddr,
343 WrapperCallArgTs &&...WrapperCallArgs) {
344 return shared::WrapperFunction<SPSSignature>::call(
13
Calling 'WrapperFunction::call'
22
Returning from 'WrapperFunction::call'
345 [this, WrapperFnAddr](const char *ArgData, size_t ArgSize) {
346 return callWrapper(WrapperFnAddr, ArrayRef<char>(ArgData, ArgSize));
347 },
348 std::forward<WrapperCallArgTs>(WrapperCallArgs)...);
349 }
350
351 /// Disconnect from the target process.
352 ///
353 /// This should be called after the JIT session is shut down.
354 virtual Error disconnect() = 0;
355
356protected:
357
358 std::shared_ptr<SymbolStringPool> SSP;
359 std::unique_ptr<TaskDispatcher> D;
360 ExecutionSession *ES = nullptr;
361 Triple TargetTriple;
362 unsigned PageSize = 0;
363 JITDispatchInfo JDI;
364 MemoryAccess *MemAccess = nullptr;
365 jitlink::JITLinkMemoryManager *MemMgr = nullptr;
366 StringMap<ExecutorAddr> BootstrapSymbols;
367};
368
369/// A ExecutorProcessControl instance that asserts if any of its methods are
370/// used. Suitable for use is unit tests, and by ORC clients who haven't moved
371/// to ExecutorProcessControl-based APIs yet.
372class UnsupportedExecutorProcessControl : public ExecutorProcessControl {
373public:
374 UnsupportedExecutorProcessControl(
375 std::shared_ptr<SymbolStringPool> SSP = nullptr,
376 std::unique_ptr<TaskDispatcher> D = nullptr,
377 const std::string &TT = "", unsigned PageSize = 0)
378 : ExecutorProcessControl(SSP ? std::move(SSP)
379 : std::make_shared<SymbolStringPool>(),
380 D ? std::move(D)
381 : std::make_unique<InPlaceTaskDispatcher>()) {
382 this->TargetTriple = Triple(TT);
383 this->PageSize = PageSize;
384 }
385
386 Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override {
387 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 387)
;
388 }
389
390 Expected<std::vector<tpctypes::LookupResult>>
391 lookupSymbols(ArrayRef<LookupRequest> Request) override {
392 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 392)
;
393 }
394
395 Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
396 ArrayRef<std::string> Args) override {
397 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 397)
;
398 }
399
400 void callWrapperAsync(ExecutorAddr WrapperFnAddr,
401 IncomingWFRHandler OnComplete,
402 ArrayRef<char> ArgBuffer) override {
403 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 403)
;
404 }
405
406 Error disconnect() override { return Error::success(); }
407};
408
409/// A ExecutorProcessControl implementation targeting the current process.
410class SelfExecutorProcessControl
411 : public ExecutorProcessControl,
412 private ExecutorProcessControl::MemoryAccess {
413public:
414 SelfExecutorProcessControl(
415 std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D,
416 Triple TargetTriple, unsigned PageSize,
417 std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
418
419 /// Create a SelfExecutorProcessControl with the given symbol string pool and
420 /// memory manager.
421 /// If no symbol string pool is given then one will be created.
422 /// If no memory manager is given a jitlink::InProcessMemoryManager will
423 /// be created and used by default.
424 static Expected<std::unique_ptr<SelfExecutorProcessControl>>
425 Create(std::shared_ptr<SymbolStringPool> SSP = nullptr,
426 std::unique_ptr<TaskDispatcher> D = nullptr,
427 std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr);
428
429 Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;
430
431 Expected<std::vector<tpctypes::LookupResult>>
432 lookupSymbols(ArrayRef<LookupRequest> Request) override;
433
434 Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
435 ArrayRef<std::string> Args) override;
436
437 void callWrapperAsync(ExecutorAddr WrapperFnAddr,
438 IncomingWFRHandler OnComplete,
439 ArrayRef<char> ArgBuffer) override;
440
441 Error disconnect() override;
442
443private:
444 void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
445 WriteResultFn OnWriteComplete) override;
446
447 void writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws,
448 WriteResultFn OnWriteComplete) override;
449
450 void writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws,
451 WriteResultFn OnWriteComplete) override;
452
453 void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,
454 WriteResultFn OnWriteComplete) override;
455
456 void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,
457 WriteResultFn OnWriteComplete) override;
458
459 static shared::CWrapperFunctionResult
460 jitDispatchViaWrapperFunctionManager(void *Ctx, const void *FnTag,
461 const char *Data, size_t Size);
462
463 std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
464 char GlobalManglingPrefix = 0;
465 std::vector<std::unique_ptr<sys::DynamicLibrary>> DynamicLibraries;
466};
467
468} // end namespace orc
469} // end namespace llvm
470
471#endif // LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H

/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.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
22namespace llvm {
23namespace orc {
24namespace shared {
25
26// Must be kept in-sync with compiler-rt/lib/orc/c-api.h.
27union 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.
33typedef struct {
34 CWrapperFunctionResultDataUnion Data;
35 size_t Size;
36} CWrapperFunctionResult;
37
38/// C++ wrapper function result: Same as CWrapperFunctionResult but
39/// auto-releases memory.
40class WrapperFunctionResult {
41public:
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
160private:
161 static void init(CWrapperFunctionResult &R) {
162 R.Data.ValuePtr = nullptr;
163 R.Size = 0;
164 }
165
166 CWrapperFunctionResult R;
167};
168
169namespace detail {
170
171template <typename SPSArgListT, typename... ArgTs>
172WrapperFunctionResult
173serializeViaSPSToWrapperFunctionResult(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
182template <typename RetT> class WrapperFunctionHandlerCaller {
183public:
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
191template <> class WrapperFunctionHandlerCaller<void> {
192public:
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
201template <typename WrapperFunctionImplT,
202 template <typename> class ResultSerializer, typename... SPSTagTs>
203class WrapperFunctionHandlerHelper
204 : public WrapperFunctionHandlerHelper<
205 decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
206 ResultSerializer, SPSTagTs...> {};
207
208template <typename RetT, typename... ArgTs,
209 template <typename> class ResultSerializer, typename... SPSTagTs>
210class WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
211 SPSTagTs...> {
212public:
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
231private:
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.
241template <typename RetT, typename... ArgTs,
242 template <typename> class ResultSerializer, typename... SPSTagTs>
243class 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.
249template <typename ClassT, typename RetT, typename... ArgTs,
250 template <typename> class ResultSerializer, typename... SPSTagTs>
251class 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.
257template <typename ClassT, typename RetT, typename... ArgTs,
258 template <typename> class ResultSerializer, typename... SPSTagTs>
259class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
260 ResultSerializer, SPSTagTs...>
261 : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
262 SPSTagTs...> {};
263
264template <typename WrapperFunctionImplT,
265 template <typename> class ResultSerializer, typename... SPSTagTs>
266class WrapperFunctionAsyncHandlerHelper
267 : public WrapperFunctionAsyncHandlerHelper<
268 decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
269 ResultSerializer, SPSTagTs...> {};
270
271template <typename RetT, typename SendResultT, typename... ArgTs,
272 template <typename> class ResultSerializer, typename... SPSTagTs>
273class WrapperFunctionAsyncHandlerHelper<RetT(SendResultT, ArgTs...),
274 ResultSerializer, SPSTagTs...> {
275public:
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
300private:
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.
320template <typename RetT, typename... ArgTs,
321 template <typename> class ResultSerializer, typename... SPSTagTs>
322class 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.
328template <typename ClassT, typename RetT, typename... ArgTs,
329 template <typename> class ResultSerializer, typename... SPSTagTs>
330class 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.
336template <typename ClassT, typename RetT, typename... ArgTs,
337 template <typename> class ResultSerializer, typename... SPSTagTs>
338class WrapperFunctionAsyncHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
339 ResultSerializer, SPSTagTs...>
340 : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer,
341 SPSTagTs...> {};
342
343template <typename SPSRetTagT, typename RetT> class ResultSerializer {
344public:
345 static WrapperFunctionResult serialize(RetT Result) {
346 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
347 Result);
348 }
349};
350
351template <typename SPSRetTagT> class ResultSerializer<SPSRetTagT, Error> {
352public:
353 static WrapperFunctionResult serialize(Error Err) {
354 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
355 toSPSSerializable(std::move(Err)));
356 }
357};
358
359template <typename SPSRetTagT>
360class ResultSerializer<SPSRetTagT, ErrorSuccess> {
361public:
362 static WrapperFunctionResult serialize(ErrorSuccess Err) {
363 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
364 toSPSSerializable(std::move(Err)));
365 }
366};
367
368template <typename SPSRetTagT, typename T>
369class ResultSerializer<SPSRetTagT, Expected<T>> {
370public:
371 static WrapperFunctionResult serialize(Expected<T> E) {
372 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
373 toSPSSerializable(std::move(E)));
374 }
375};
376
377template <typename SPSRetTagT, typename RetT> class ResultDeserializer {
378public:
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
392template <> class ResultDeserializer<SPSError, Error> {
393public:
394 static Error makeValue() { return Error::success(); }
395 static void makeSafe(Error &Err) { cantFail(std::move(Err)); }
15
Calling move constructor for 'Error'
17
Returning from move constructor for 'Error'
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
409template <typename SPSTagT, typename T>
410class ResultDeserializer<SPSExpected<SPSTagT>, Expected<T>> {
411public:
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
428template <typename SPSRetTagT, typename RetT> class AsyncCallResultHelper {
429 // Did you forget to use Error / Expected in your handler?
430};
431
432} // end namespace detail
433
434template <typename SPSSignature> class WrapperFunction;
435
436template <typename SPSRetTagT, typename... SPSTagTs>
437class WrapperFunction<SPSRetTagT(SPSTagTs...)> {
438private:
439 template <typename RetT>
440 using ResultSerializer = detail::ResultSerializer<SPSRetTagT, RetT>;
441
442public:
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);
14
Calling 'ResultDeserializer::makeSafe'
18
Returning from 'ResultDeserializer::makeSafe'
453
454 auto ArgBuffer =
455 detail::serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSTagTs...>>(
456 Args...);
457 if (const char *ErrMsg
18.1
'ErrMsg' is null
18.1
'ErrMsg' is null
18.1
'ErrMsg' is null
18.1
'ErrMsg' is null
18.1
'ErrMsg' is null
= ArgBuffer.getOutOfBandError())
19
Taking false branch
458 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
459
460 WrapperFunctionResult ResultBuffer =
461 Caller(ArgBuffer.data(), ArgBuffer.size());
462 if (auto ErrMsg = ResultBuffer.getOutOfBandError())
20
Assuming 'ErrMsg' is non-null
21
Taking true branch
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
535private:
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
550template <typename... SPSTagTs>
551class WrapperFunction<void(SPSTagTs...)>
552 : private WrapperFunction<SPSEmpty(SPSTagTs...)> {
553
554public:
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///
601template <typename RetT, typename ClassT, typename... ArgTs>
602class MethodWrapperHandler {
603public:
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
610private:
611 MethodT M;
612};
613
614/// Create a MethodWrapperHandler object from the given method pointer.
615template <typename RetT, typename ClassT, typename... ArgTs>
616MethodWrapperHandler<RetT, ClassT, ArgTs...>
617makeMethodWrapperHandler(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.
628class WrapperFunctionCall {
629public:
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[0], ArgData.size());
640 if (SPSSerializer::serialize(OB, Args...))
641 return WrapperFunctionCall(FnAddr, std::move(ArgData));
642 return make_error<StringError>("Cannot serialize arguments for "
643 "AllocActionCall",
644 inconvertibleErrorCode());
645 }
646
647 WrapperFunctionCall() = default;
648
649 /// Create a WrapperFunctionCall from a target function and arg buffer.
650 WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData)
651 : FnAddr(FnAddr), ArgData(std::move(ArgData)) {}
652
653 /// Returns the address to be called.
654 const ExecutorAddr &getCallee() const { return FnAddr; }
655
656 /// Returns the argument data.
657 const ArgDataBufferType &getArgData() const { return ArgData; }
658
659 /// WrapperFunctionCalls convert to true if the callee is non-null.
660 explicit operator bool() const { return !!FnAddr; }
661
662 /// Run call returning raw WrapperFunctionResult.
663 shared::WrapperFunctionResult run() const {
664 using FnTy =
665 shared::CWrapperFunctionResult(const char *ArgData, size_t ArgSize);
666 return shared::WrapperFunctionResult(
667 FnAddr.toPtr<FnTy *>()(ArgData.data(), ArgData.size()));
668 }
669
670 /// Run call and deserialize result using SPS.
671 template <typename SPSRetT, typename RetT>
672 std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error>
673 runWithSPSRet(RetT &RetVal) const {
674 auto WFR = run();
675 if (const char *ErrMsg = WFR.getOutOfBandError())
676 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
677 shared::SPSInputBuffer IB(WFR.data(), WFR.size());
678 if (!shared::SPSSerializationTraits<SPSRetT, RetT>::deserialize(IB, RetVal))
679 return make_error<StringError>("Could not deserialize result from "
680 "serialized wrapper function call",
681 inconvertibleErrorCode());
682 return Error::success();
683 }
684
685 /// Overload for SPS functions returning void.
686 template <typename SPSRetT>
687 std::enable_if_t<std::is_same<SPSRetT, void>::value, Error>
688 runWithSPSRet() const {
689 shared::SPSEmpty E;
690 return runWithSPSRet<shared::SPSEmpty>(E);
691 }
692
693 /// Run call and deserialize an SPSError result. SPSError returns and
694 /// deserialization failures are merged into the returned error.
695 Error runWithSPSRetErrorMerged() const {
696 detail::SPSSerializableError RetErr;
697 if (auto Err = runWithSPSRet<SPSError>(RetErr))
698 return Err;
699 return detail::fromSPSSerializable(std::move(RetErr));
700 }
701
702private:
703 orc::ExecutorAddr FnAddr;
704 ArgDataBufferType ArgData;
705};
706
707using SPSWrapperFunctionCall = SPSTuple<SPSExecutorAddr, SPSSequence<char>>;
708
709template <>
710class SPSSerializationTraits<SPSWrapperFunctionCall, WrapperFunctionCall> {
711public:
712 static size_t size(const WrapperFunctionCall &WFC) {
713 return SPSWrapperFunctionCall::AsArgList::size(WFC.getCallee(),
714 WFC.getArgData());
715 }
716
717 static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC) {
718 return SPSWrapperFunctionCall::AsArgList::serialize(OB, WFC.getCallee(),
719 WFC.getArgData());
720 }
721
722 static bool deserialize(SPSInputBuffer &IB, WrapperFunctionCall &WFC) {
723 ExecutorAddr FnAddr;
724 WrapperFunctionCall::ArgDataBufferType ArgData;
725 if (!SPSWrapperFunctionCall::AsArgList::deserialize(IB, FnAddr, ArgData))
726 return false;
727 WFC = WrapperFunctionCall(FnAddr, std::move(ArgData));
728 return true;
729 }
730};
731
732} // end namespace shared
733} // end namespace orc
734} // end namespace llvm
735
736#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H

/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/include/llvm/Support/Error.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 <string>
35#include <system_error>
36#include <type_traits>
37#include <utility>
38#include <vector>
39
40namespace llvm {
41
42class ErrorSuccess;
43
44/// Base class for error info classes. Do not extend this directly: Extend
45/// the ErrorInfo template subclass instead.
46class ErrorInfoBase {
47public:
48 virtual ~ErrorInfoBase() = default;
49
50 /// Print an error message to an output stream.
51 virtual void log(raw_ostream &OS) const = 0;
52
53 /// Return the error message as a string.
54 virtual std::string message() const {
55 std::string Msg;
56 raw_string_ostream OS(Msg);
57 log(OS);
58 return OS.str();
59 }
60
61 /// Convert this error to a std::error_code.
62 ///
63 /// This is a temporary crutch to enable interaction with code still
64 /// using std::error_code. It will be removed in the future.
65 virtual std::error_code convertToErrorCode() const = 0;
66
67 // Returns the class ID for this type.
68 static const void *classID() { return &ID; }
69
70 // Returns the class ID for the dynamic type of this ErrorInfoBase instance.
71 virtual const void *dynamicClassID() const = 0;
72
73 // Check whether this instance is a subclass of the class identified by
74 // ClassID.
75 virtual bool isA(const void *const ClassID) const {
76 return ClassID == classID();
77 }
78
79 // Check whether this instance is a subclass of ErrorInfoT.
80 template <typename ErrorInfoT> bool isA() const {
81 return isA(ErrorInfoT::classID());
82 }
83
84private:
85 virtual void anchor();
86
87 static char ID;
88};
89
90/// Lightweight error class with error context and mandatory checking.
91///
92/// Instances of this class wrap a ErrorInfoBase pointer. Failure states
93/// are represented by setting the pointer to a ErrorInfoBase subclass
94/// instance containing information describing the failure. Success is
95/// represented by a null pointer value.
96///
97/// Instances of Error also contains a 'Checked' flag, which must be set
98/// before the destructor is called, otherwise the destructor will trigger a
99/// runtime error. This enforces at runtime the requirement that all Error
100/// instances be checked or returned to the caller.
101///
102/// There are two ways to set the checked flag, depending on what state the
103/// Error instance is in. For Error instances indicating success, it
104/// is sufficient to invoke the boolean conversion operator. E.g.:
105///
106/// @code{.cpp}
107/// Error foo(<...>);
108///
109/// if (auto E = foo(<...>))
110/// return E; // <- Return E if it is in the error state.
111/// // We have verified that E was in the success state. It can now be safely
112/// // destroyed.
113/// @endcode
114///
115/// A success value *can not* be dropped. For example, just calling 'foo(<...>)'
116/// without testing the return value will raise a runtime error, even if foo
117/// returns success.
118///
119/// For Error instances representing failure, you must use either the
120/// handleErrors or handleAllErrors function with a typed handler. E.g.:
121///
122/// @code{.cpp}
123/// class MyErrorInfo : public ErrorInfo<MyErrorInfo> {
124/// // Custom error info.
125/// };
126///
127/// Error foo(<...>) { return make_error<MyErrorInfo>(...); }
128///
129/// auto E = foo(<...>); // <- foo returns failure with MyErrorInfo.
130/// auto NewE =
131/// handleErrors(E,
132/// [](const MyErrorInfo &M) {
133/// // Deal with the error.
134/// },
135/// [](std::unique_ptr<OtherError> M) -> Error {
136/// if (canHandle(*M)) {
137/// // handle error.
138/// return Error::success();
139/// }
140/// // Couldn't handle this error instance. Pass it up the stack.
141/// return Error(std::move(M));
142/// );
143/// // Note - we must check or return NewE in case any of the handlers
144/// // returned a new error.
145/// @endcode
146///
147/// The handleAllErrors function is identical to handleErrors, except
148/// that it has a void return type, and requires all errors to be handled and
149/// no new errors be returned. It prevents errors (assuming they can all be
150/// handled) from having to be bubbled all the way to the top-level.
151///
152/// *All* Error instances must be checked before destruction, even if
153/// they're moved-assigned or constructed from Success values that have already
154/// been checked. This enforces checking through all levels of the call stack.
155class LLVM_NODISCARD[[clang::warn_unused_result]] Error {
156 // ErrorList needs to be able to yank ErrorInfoBase pointers out of Errors
157 // to add to the error list. It can't rely on handleErrors for this, since
158 // handleErrors does not support ErrorList handlers.
159 friend class ErrorList;
160
161 // handleErrors needs to be able to set the Checked flag.
162 template <typename... HandlerTs>
163 friend Error handleErrors(Error E, HandlerTs &&... Handlers);
164
165 // Expected<T> needs to be able to steal the payload when constructed from an
166 // error.
167 template <typename T> friend class Expected;
168
169 // wrap needs to be able to steal the payload.
170 friend LLVMErrorRef wrap(Error);
171
172protected:
173 /// Create a success value. Prefer using 'Error::success()' for readability
174 Error() {
175 setPtr(nullptr);
176 setChecked(false);
177 }
178
179public:
180 /// Create a success value.
181 static ErrorSuccess success();
182
183 // Errors are not copy-constructable.
184 Error(const Error &Other) = delete;
185
186 /// Move-construct an error value. The newly constructed error is considered
187 /// unchecked, even if the source error had been checked. The original error
188 /// becomes a checked Success value, regardless of its original state.
189 Error(Error &&Other) {
190 setChecked(true);
191 *this = std::move(Other);
16
Object 'ErrResult' is moved
192 }
193
194 /// Create an error value. Prefer using the 'make_error' function, but
195 /// this constructor can be useful when "re-throwing" errors from handlers.
196 Error(std::unique_ptr<ErrorInfoBase> Payload) {
197 setPtr(Payload.release());
198 setChecked(false);
199 }
200
201 // Errors are not copy-assignable.
202 Error &operator=(const Error &Other) = delete;
203
204 /// Move-assign an error value. The current error must represent success, you
205 /// you cannot overwrite an unhandled error. The current error is then
206 /// considered unchecked. The source error becomes a checked success value,
207 /// regardless of its original state.
208 Error &operator=(Error &&Other) {
209 // Don't allow overwriting of unchecked values.
210 assertIsChecked();
211 setPtr(Other.getPtr());
212
213 // This Error is unchecked, even if the source error was checked.
214 setChecked(false);
215
216 // Null out Other's payload and set its checked bit.
217 Other.setPtr(nullptr);
218 Other.setChecked(true);
219
220 return *this;
221 }
222
223 /// Destroy a Error. Fails with a call to abort() if the error is
224 /// unchecked.
225 ~Error() {
226 assertIsChecked();
227 delete getPtr();
228 }
229
230 /// Bool conversion. Returns true if this Error is in a failure state,
231 /// and false if it is in an accept state. If the error is in a Success state
232 /// it will be considered checked.
233 explicit operator bool() {
234 setChecked(getPtr() == nullptr);
235 return getPtr() != nullptr;
236 }
237
238 /// Check whether one error is a subclass of another.
239 template <typename ErrT> bool isA() const {
240 return getPtr() && getPtr()->isA(ErrT::classID());
241 }
242
243 /// Returns the dynamic class id of this error, or null if this is a success
244 /// value.
245 const void* dynamicClassID() const {
246 if (!getPtr())
247 return nullptr;
248 return getPtr()->dynamicClassID();
249 }
250
251private:
252#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
253 // assertIsChecked() happens very frequently, but under normal circumstances
254 // is supposed to be a no-op. So we want it to be inlined, but having a bunch
255 // of debug prints can cause the function to be too large for inlining. So
256 // it's important that we define this function out of line so that it can't be
257 // inlined.
258 [[noreturn]] void fatalUncheckedError() const;
259#endif
260
261 void assertIsChecked() {
262#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
263 if (LLVM_UNLIKELY(!getChecked() || getPtr())__builtin_expect((bool)(!getChecked() || getPtr()), false))
264 fatalUncheckedError();
265#endif
266 }
267
268 ErrorInfoBase *getPtr() const {
269#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
270 return reinterpret_cast<ErrorInfoBase*>(
271 reinterpret_cast<uintptr_t>(Payload) &
272 ~static_cast<uintptr_t>(0x1));
273#else
274 return Payload;
275#endif
276 }
277
278 void setPtr(ErrorInfoBase *EI) {
279#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
280 Payload = reinterpret_cast<ErrorInfoBase*>(
281 (reinterpret_cast<uintptr_t>(EI) &
282 ~static_cast<uintptr_t>(0x1)) |
283 (reinterpret_cast<uintptr_t>(Payload) & 0x1));
284#else
285 Payload = EI;
286#endif
287 }
288
289 bool getChecked() const {
290#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
291 return (reinterpret_cast<uintptr_t>(Payload) & 0x1) == 0;
292#else
293 return true;
294#endif
295 }
296
297 void setChecked(bool V) {
298#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
299 Payload = reinterpret_cast<ErrorInfoBase*>(
300 (reinterpret_cast<uintptr_t>(Payload) &
301 ~static_cast<uintptr_t>(0x1)) |
302 (V ? 0 : 1));
303#endif
304 }
305
306 std::unique_ptr<ErrorInfoBase> takePayload() {
307 std::unique_ptr<ErrorInfoBase> Tmp(getPtr());
308 setPtr(nullptr);
309 setChecked(true);
310 return Tmp;
311 }
312
313 friend raw_ostream &operator<<(raw_ostream &OS, const Error &E) {
314 if (auto *P = E.getPtr())
315 P->log(OS);
316 else
317 OS << "success";
318 return OS;
319 }
320
321 ErrorInfoBase *Payload = nullptr;
322};
323
324/// Subclass of Error for the sole purpose of identifying the success path in
325/// the type system. This allows to catch invalid conversion to Expected<T> at
326/// compile time.
327class ErrorSuccess final : public Error {};
328
329inline ErrorSuccess Error::success() { return ErrorSuccess(); }
330
331/// Make a Error instance representing failure using the given error info
332/// type.
333template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) {
334 return Error(std::make_unique<ErrT>(std::forward<ArgTs>(Args)...));
335}
336
337/// Base class for user error types. Users should declare their error types
338/// like:
339///
340/// class MyError : public ErrorInfo<MyError> {
341/// ....
342/// };
343///
344/// This class provides an implementation of the ErrorInfoBase::kind
345/// method, which is used by the Error RTTI system.
346template <typename ThisErrT, typename ParentErrT = ErrorInfoBase>
347class ErrorInfo : public ParentErrT {
348public:
349 using ParentErrT::ParentErrT; // inherit constructors
350
351 static const void *classID() { return &ThisErrT::ID; }
352
353 const void *dynamicClassID() const override { return &ThisErrT::ID; }
354
355 bool isA(const void *const ClassID) const override {
356 return ClassID == classID() || ParentErrT::isA(ClassID);
357 }
358};
359
360/// Special ErrorInfo subclass representing a list of ErrorInfos.
361/// Instances of this class are constructed by joinError.
362class ErrorList final : public ErrorInfo<ErrorList> {
363 // handleErrors needs to be able to iterate the payload list of an
364 // ErrorList.
365 template <typename... HandlerTs>
366 friend Error handleErrors(Error E, HandlerTs &&... Handlers);
367
368 // joinErrors is implemented in terms of join.
369 friend Error joinErrors(Error, Error);
370
371public:
372 void log(raw_ostream &OS) const override {
373 OS << "Multiple errors:\n";
374 for (const auto &ErrPayload : Payloads) {
375 ErrPayload->log(OS);
376 OS << "\n";
377 }
378 }
379
380 std::error_code convertToErrorCode() const override;
381
382 // Used by ErrorInfo::classID.
383 static char ID;
384
385private:
386 ErrorList(std::unique_ptr<ErrorInfoBase> Payload1,
387 std::unique_ptr<ErrorInfoBase> Payload2) {
388 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", 389, __extension__ __PRETTY_FUNCTION__
))
389 "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", 389, __extension__ __PRETTY_FUNCTION__
))
;
390 Payloads.push_back(std::move(Payload1));
391 Payloads.push_back(std::move(Payload2));
392 }
393
394 static Error join(Error E1, Error E2) {
395 if (!E1)
396 return E2;
397 if (!E2)
398 return E1;
399 if (E1.isA<ErrorList>()) {
400 auto &E1List = static_cast<ErrorList &>(*E1.getPtr());
401 if (E2.isA<ErrorList>()) {
402 auto E2Payload = E2.takePayload();
403 auto &E2List = static_cast<ErrorList &>(*E2Payload);
404 for (auto &Payload : E2List.Payloads)
405 E1List.Payloads.push_back(std::move(Payload));
406 } else
407 E1List.Payloads.push_back(E2.takePayload());
408
409 return E1;
410 }
411 if (E2.isA<ErrorList>()) {
412 auto &E2List = static_cast<ErrorList &>(*E2.getPtr());
413 E2List.Payloads.insert(E2List.Payloads.begin(), E1.takePayload());
414 return E2;
415 }
416 return Error(std::unique_ptr<ErrorList>(
417 new ErrorList(E1.takePayload(), E2.takePayload())));
418 }
419
420 std::vector<std::unique_ptr<ErrorInfoBase>> Payloads;
421};
422
423/// Concatenate errors. The resulting Error is unchecked, and contains the
424/// ErrorInfo(s), if any, contained in E1, followed by the
425/// ErrorInfo(s), if any, contained in E2.
426inline Error joinErrors(Error E1, Error E2) {
427 return ErrorList::join(std::move(E1), std::move(E2));
428}
429
430/// Tagged union holding either a T or a Error.
431///
432/// This class parallels ErrorOr, but replaces error_code with Error. Since
433/// Error cannot be copied, this class replaces getError() with
434/// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the
435/// error class type.
436///
437/// Example usage of 'Expected<T>' as a function return type:
438///
439/// @code{.cpp}
440/// Expected<int> myDivide(int A, int B) {
441/// if (B == 0) {
442/// // return an Error
443/// return createStringError(inconvertibleErrorCode(),
444/// "B must not be zero!");
445/// }
446/// // return an integer
447/// return A / B;
448/// }
449/// @endcode
450///
451/// Checking the results of to a function returning 'Expected<T>':
452/// @code{.cpp}
453/// if (auto E = Result.takeError()) {
454/// // We must consume the error. Typically one of:
455/// // - return the error to our caller
456/// // - toString(), when logging
457/// // - consumeError(), to silently swallow the error
458/// // - handleErrors(), to distinguish error types
459/// errs() << "Problem with division " << toString(std::move(E)) << "\n";
460/// return;
461/// }
462/// // use the result
463/// outs() << "The answer is " << *Result << "\n";
464/// @endcode
465///
466/// For unit-testing a function returning an 'Expceted<T>', see the
467/// 'EXPECT_THAT_EXPECTED' macros in llvm/Testing/Support/Error.h
468
469template <class T> class LLVM_NODISCARD[[clang::warn_unused_result]] Expected {
470 template <class T1> friend class ExpectedAsOutParameter;
471 template <class OtherT> friend class Expected;
472
473 static constexpr bool isRef = std::is_reference<T>::value;
474
475 using wrap = std::reference_wrapper<std::remove_reference_t<T>>;
476
477 using error_type = std::unique_ptr<ErrorInfoBase>;
478
479public:
480 using storage_type = std::conditional_t<isRef, wrap, T>;
481 using value_type = T;
482
483private:
484 using reference = std::remove_reference_t<T> &;
485 using const_reference = const std::remove_reference_t<T> &;
486 using pointer = std::remove_reference_t<T> *;
487 using const_pointer = const std::remove_reference_t<T> *;
488
489public:
490 /// Create an Expected<T> error value from the given Error.
491 Expected(Error Err)
492 : HasError(true)
493#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
494 // Expected is unchecked upon construction in Debug builds.
495 , Unchecked(true)
496#endif
497 {
498 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", 498, __extension__ __PRETTY_FUNCTION__
))
;
499 new (getErrorStorage()) error_type(Err.takePayload());
500 }
501
502 /// Forbid to convert from Error::success() implicitly, this avoids having
503 /// Expected<T> foo() { return Error::success(); } which compiles otherwise
504 /// but triggers the assertion above.
505 Expected(ErrorSuccess) = delete;
506
507 /// Create an Expected<T> success value from the given OtherT value, which
508 /// must be convertible to T.
509 template <typename OtherT>
510 Expected(OtherT &&Val,
511 std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr)
512 : HasError(false)
513#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
514 // Expected is unchecked upon construction in Debug builds.
515 ,
516 Unchecked(true)
517#endif
518 {
519 new (getStorage()) storage_type(std::forward<OtherT>(Val));
520 }
521
522 /// Move construct an Expected<T> value.
523 Expected(Expected &&Other) { moveConstruct(std::move(Other)); }
524
525 /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
526 /// must be convertible to T.
527 template <class OtherT>
528 Expected(
529 Expected<OtherT> &&Other,
530 std::enable_if_t<std::is_convertible<OtherT, T>::value> * = 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<OtherT, T>::value> * = 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(OtherT &Value,
581 std::enable_if_t<std::is_assignable<OtherT &, T &&>::value> * =
582 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
628private:
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
745inline 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
772template <typename T>
773T 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
803template <typename T>
804T& 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.
823template <typename HandlerT>
824class ErrorHandlerTraits
825 : public ErrorHandlerTraits<decltype(
826 &std::remove_reference<HandlerT>::type::operator())> {};
827
828// Specialization functions of the form 'Error (const ErrT&)'.
829template <typename ErrT> class ErrorHandlerTraits<Error (&)(ErrT &)> {
830public:
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&)'.
843template <typename ErrT> class ErrorHandlerTraits<void (&)(ErrT &)> {
844public:
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>)'.
858template <typename ErrT>
859class ErrorHandlerTraits<Error (&)(std::unique_ptr<ErrT>)> {
860public:
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>)'.
874template <typename ErrT>
875class ErrorHandlerTraits<void (&)(std::unique_ptr<ErrT>)> {
876public:
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&)'.
891template <typename C, typename RetT, typename ErrT>
892class ErrorHandlerTraits<RetT (C::*)(ErrT &)>
893 : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
894
895// Specialization for member functions of the form 'RetT (const ErrT&) const'.
896template <typename C, typename RetT, typename ErrT>
897class ErrorHandlerTraits<RetT (C::*)(ErrT &) const>
898 : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
899
900// Specialization for member functions of the form 'RetT (const ErrT&)'.
901template <typename C, typename RetT, typename ErrT>
902class ErrorHandlerTraits<RetT (C::*)(const ErrT &)>
903 : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
904
905// Specialization for member functions of the form 'RetT (const ErrT&) const'.
906template <typename C, typename RetT, typename ErrT>
907class 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>)'.
912template <typename C, typename RetT, typename ErrT>
913class 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'.
918template <typename C, typename RetT, typename ErrT>
919class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>) const>
920 : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
921
922inline Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload) {
923 return Error(std::move(Payload));
924}
925
926template <typename HandlerT, typename... HandlerTs>
927Error 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.
942template <typename... HandlerTs>
943Error 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).
965template <typename... HandlerTs>
966void 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.
972inline 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
1000template <typename T, typename RecoveryFtor, typename... HandlerTs>
1001Expected<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.
1024void 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.
1028inline 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 Optional<T>.
1043inline 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.
1054template <typename T> Optional<T> expectedToOptional(Expected<T> &&E) {
1055 if (E)
1056 return std::move(*E);
1057 consumeError(E.takeError());
1058 return None;
1059}
1060
1061/// Helper for converting an Error to a bool.
1062///
1063/// This method returns true if Err is in an error state, or false if it is
1064/// in a success state. Puts Err in a checked state in both cases (unlike
1065/// Error::operator bool(), which only does this for success states).
1066inline bool errorToBool(Error Err) {
1067 bool IsError = static_cast<bool>(Err);
1068 if (IsError)
1069 consumeError(std::move(Err));
1070 return IsError;
1071}
1072
1073/// Helper for Errors used as out-parameters.
1074///
1075/// This helper is for use with the Error-as-out-parameter idiom, where an error
1076/// is passed to a function or method by reference, rather than being returned.
1077/// In such cases it is helpful to set the checked bit on entry to the function
1078/// so that the error can be written to (unchecked Errors abort on assignment)
1079/// and clear the checked bit on exit so that clients cannot accidentally forget
1080/// to check the result. This helper performs these actions automatically using
1081/// RAII:
1082///
1083/// @code{.cpp}
1084/// Result foo(Error &Err) {
1085/// ErrorAsOutParameter ErrAsOutParam(&Err); // 'Checked' flag set
1086/// // <body of foo>
1087/// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed.
1088/// }
1089/// @endcode
1090///
1091/// ErrorAsOutParameter takes an Error* rather than Error& so that it can be
1092/// used with optional Errors (Error pointers that are allowed to be null). If
1093/// ErrorAsOutParameter took an Error reference, an instance would have to be
1094/// created inside every condition that verified that Error was non-null. By
1095/// taking an Error pointer we can just create one instance at the top of the
1096/// function.
1097class ErrorAsOutParameter {
1098public:
1099 ErrorAsOutParameter(Error *Err) : Err(Err) {
1100 // Raise the checked bit if Err is success.
1101 if (Err)
1102 (void)!!*Err;
1103 }
1104
1105 ~ErrorAsOutParameter() {
1106 // Clear the checked bit.
1107 if (Err && !*Err)
1108 *Err = Error::success();
1109 }
1110
1111private:
1112 Error *Err;
1113};
1114
1115/// Helper for Expected<T>s used as out-parameters.
1116///
1117/// See ErrorAsOutParameter.
1118template <typename T>
1119class ExpectedAsOutParameter {
1120public:
1121 ExpectedAsOutParameter(Expected<T> *ValOrErr)
1122 : ValOrErr(ValOrErr) {
1123 if (ValOrErr)
1124 (void)!!*ValOrErr;
1125 }
1126
1127 ~ExpectedAsOutParameter() {
1128 if (ValOrErr)
1129 ValOrErr->setUnchecked();
1130 }
1131
1132private:
1133 Expected<T> *ValOrErr;
1134};
1135
1136/// This class wraps a std::error_code in a Error.
1137///
1138/// This is useful if you're writing an interface that returns a Error
1139/// (or Expected) and you want to call code that still returns
1140/// std::error_codes.
1141class ECError : public ErrorInfo<ECError> {
1142 friend Error errorCodeToError(std::error_code);
1143
1144 virtual void anchor() override;
1145
1146public:
1147 void setErrorCode(std::error_code EC) { this->EC = EC; }
1148 std::error_code convertToErrorCode() const override { return EC; }
1149 void log(raw_ostream &OS) const override { OS << EC.message(); }
1150
1151 // Used by ErrorInfo::classID.
1152 static char ID;
1153
1154protected:
1155 ECError() = default;
1156 ECError(std::error_code EC) : EC(EC) {}
1157
1158 std::error_code EC;
1159};
1160
1161/// The value returned by this function can be returned from convertToErrorCode
1162/// for Error values where no sensible translation to std::error_code exists.
1163/// It should only be used in this situation, and should never be used where a
1164/// sensible conversion to std::error_code is available, as attempts to convert
1165/// to/from this error will result in a fatal error. (i.e. it is a programmatic
1166/// error to try to convert such a value).
1167std::error_code inconvertibleErrorCode();
1168
1169/// Helper for converting an std::error_code to a Error.
1170Error errorCodeToError(std::error_code EC);
1171
1172/// Helper for converting an ECError to a std::error_code.
1173///
1174/// This method requires that Err be Error() or an ECError, otherwise it
1175/// will trigger a call to abort().
1176std::error_code errorToErrorCode(Error Err);
1177
1178/// Convert an ErrorOr<T> to an Expected<T>.
1179template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> &&EO) {
1180 if (auto EC = EO.getError())
1181 return errorCodeToError(EC);
1182 return std::move(*EO);
1183}
1184
1185/// Convert an Expected<T> to an ErrorOr<T>.
1186template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> &&E) {
1187 if (auto Err = E.takeError())
1188 return errorToErrorCode(std::move(Err));
1189 return std::move(*E);
1190}
1191
1192/// This class wraps a string in an Error.
1193///
1194/// StringError is useful in cases where the client is not expected to be able
1195/// to consume the specific error message programmatically (for example, if the
1196/// error message is to be presented to the user).
1197///
1198/// StringError can also be used when additional information is to be printed
1199/// along with a error_code message. Depending on the constructor called, this
1200/// class can either display:
1201/// 1. the error_code message (ECError behavior)
1202/// 2. a string
1203/// 3. the error_code message and a string
1204///
1205/// These behaviors are useful when subtyping is required; for example, when a
1206/// specific library needs an explicit error type. In the example below,
1207/// PDBError is derived from StringError:
1208///
1209/// @code{.cpp}
1210/// Expected<int> foo() {
1211/// return llvm::make_error<PDBError>(pdb_error_code::dia_failed_loading,
1212/// "Additional information");
1213/// }
1214/// @endcode
1215///
1216class StringError : public ErrorInfo<StringError> {
1217public:
1218 static char ID;
1219
1220 // Prints EC + S and converts to EC
1221 StringError(std::error_code EC, const Twine &S = Twine());
1222
1223 // Prints S and converts to EC
1224 StringError(const Twine &S, std::error_code EC);
1225
1226 void log(raw_ostream &OS) const override;
1227 std::error_code convertToErrorCode() const override;
1228
1229 const std::string &getMessage() const { return Msg; }
1230
1231private:
1232 std::string Msg;
1233 std::error_code EC;
1234 const bool PrintMsgOnly = false;
1235};
1236
1237/// Create formatted StringError object.
1238template <typename... Ts>
1239inline Error createStringError(std::error_code EC, char const *Fmt,
1240 const Ts &... Vals) {
1241 std::string Buffer;
1242 raw_string_ostream Stream(Buffer);
1243 Stream << format(Fmt, Vals...);
1244 return make_error<StringError>(Stream.str(), EC);
1245}
1246
1247Error createStringError(std::error_code EC, char const *Msg);
1248
1249inline Error createStringError(std::error_code EC, const Twine &S) {
1250 return createStringError(EC, S.str().c_str());
1251}
1252
1253template <typename... Ts>
1254inline Error createStringError(std::errc EC, char const *Fmt,
1255 const Ts &... Vals) {
1256 return createStringError(std::make_error_code(EC), Fmt, Vals...);
1257}
1258
1259/// This class wraps a filename and another Error.
1260///
1261/// In some cases, an error needs to live along a 'source' name, in order to
1262/// show more detailed information to the user.
1263class FileError final : public ErrorInfo<FileError> {
1264
1265 friend Error createFileError(const Twine &, Error);
1266 friend Error createFileError(const Twine &, size_t, Error);
1267
1268public:
1269 void log(raw_ostream &OS) const override {
1270 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", 1270, __extension__ __PRETTY_FUNCTION__
))
;
1271 OS << "'" << FileName << "': ";
1272 if (Line.hasValue())
1273 OS << "line " << Line.getValue() << ": ";
1274 Err->log(OS);
1275 }
1276
1277 std::string messageWithoutFileInfo() const {
1278 std::string Msg;
1279 raw_string_ostream OS(Msg);
1280 Err->log(OS);
1281 return OS.str();
1282 }
1283
1284 StringRef getFileName() const { return FileName; }
1285
1286 Error takeError() { return Error(std::move(Err)); }
1287
1288 std::error_code convertToErrorCode() const override;
1289
1290 // Used by ErrorInfo::classID.
1291 static char ID;
1292
1293private:
1294 FileError(const Twine &F, Optional<size_t> LineNum,
1295 std::unique_ptr<ErrorInfoBase> E) {
1296 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", 1296, __extension__ __PRETTY_FUNCTION__
))
;
1297 FileName = F.str();
1298 Err = std::move(E);
1299 Line = std::move(LineNum);
1300 }
1301
1302 static Error build(const Twine &F, Optional<size_t> Line, Error E) {
1303 std::unique_ptr<ErrorInfoBase> Payload;
1304 handleAllErrors(std::move(E),
1305 [&](std::unique_ptr<ErrorInfoBase> EIB) -> Error {
1306 Payload = std::move(EIB);
1307 return Error::success();
1308 });
1309 return Error(
1310 std::unique_ptr<FileError>(new FileError(F, Line, std::move(Payload))));
1311 }
1312
1313 std::string FileName;
1314 Optional<size_t> Line;
1315 std::unique_ptr<ErrorInfoBase> Err;
1316};
1317
1318/// Concatenate a source file path and/or name with an Error. The resulting
1319/// Error is unchecked.
1320inline Error createFileError(const Twine &F, Error E) {
1321 return FileError::build(F, Optional<size_t>(), std::move(E));
1322}
1323
1324/// Concatenate a source file path and/or name with line number and an Error.
1325/// The resulting Error is unchecked.
1326inline Error createFileError(const Twine &F, size_t Line, Error E) {
1327 return FileError::build(F, Optional<size_t>(Line), std::move(E));
1328}
1329
1330/// Concatenate a source file path and/or name with a std::error_code
1331/// to form an Error object.
1332inline Error createFileError(const Twine &F, std::error_code EC) {
1333 return createFileError(F, errorCodeToError(EC));
1334}
1335
1336/// Concatenate a source file path and/or name with line number and
1337/// std::error_code to form an Error object.
1338inline Error createFileError(const Twine &F, size_t Line, std::error_code EC) {
1339 return createFileError(F, Line, errorCodeToError(EC));
1340}
1341
1342Error createFileError(const Twine &F, ErrorSuccess) = delete;
1343
1344/// Helper for check-and-exit error handling.
1345///
1346/// For tool use only. NOT FOR USE IN LIBRARY CODE.
1347///
1348class ExitOnError {
1349public:
1350 /// Create an error on exit helper.
1351 ExitOnError(std::string Banner = "", int DefaultErrorExitCode = 1)
1352 : Banner(std::move(Banner)),
1353 GetExitCode([=](const Error &) { return DefaultErrorExitCode; }) {}
1354
1355 /// Set the banner string for any errors caught by operator().
1356 void setBanner(std::string Banner) { this->Banner = std::move(Banner); }
1357
1358 /// Set the exit-code mapper function.
1359 void setExitCodeMapper(std::function<int(const Error &)> GetExitCode) {
1360 this->GetExitCode = std::move(GetExitCode);
1361 }
1362
1363 /// Check Err. If it's in a failure state log the error(s) and exit.
1364 void operator()(Error Err) const { checkError(std::move(Err)); }
1365
1366 /// Check E. If it's in a success state then return the contained value. If
1367 /// it's in a failure state log the error(s) and exit.
1368 template <typename T> T operator()(Expected<T> &&E) const {
1369 checkError(E.takeError());
1370 return std::move(*E);
1371 }
1372
1373 /// Check E. If it's in a success state then return the contained reference. 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 *E;
1378 }
1379
1380private:
1381 void checkError(Error Err) const {
1382 if (Err) {
1383 int ExitCode = GetExitCode(Err);
1384 logAllUnhandledErrors(std::move(Err), errs(), Banner);
1385 exit(ExitCode);
1386 }
1387 }
1388
1389 std::string Banner;
1390 std::function<int(const Error &)> GetExitCode;
1391};
1392
1393/// Conversion from Error to LLVMErrorRef for C error bindings.
1394inline LLVMErrorRef wrap(Error Err) {
1395 return reinterpret_cast<LLVMErrorRef>(Err.takePayload().release());
1396}
1397
1398/// Conversion from LLVMErrorRef to Error for C error bindings.
1399inline Error unwrap(LLVMErrorRef ErrRef) {
1400 return Error(std::unique_ptr<ErrorInfoBase>(
1401 reinterpret_cast<ErrorInfoBase *>(ErrRef)));
1402}
1403
1404} // end namespace llvm
1405
1406#endif // LLVM_SUPPORT_ERROR_H