Bug Summary

File:build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
Warning:line 619, 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-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-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-16/lib/clang/16.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-16~++20221003111214+1fa2019828ca/llvm/lib/ExecutionEngine/Orc -I include -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/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-16/lib/clang/16.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-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -O2 -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 -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -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-10-03-140002-15933-1 -x c++ /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp

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

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

/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/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 (const 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 // TODO: move this to ORC runtime.
263 /// Run function with a int (*)(void) signature.
264 virtual Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) = 0;
265
266 // TODO: move this to ORC runtime.
267 /// Run function with a int (*)(int) signature.
268 virtual Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr,
269 int Arg) = 0;
270
271 /// Run a wrapper function in the executor. The given WFRHandler will be
272 /// called on the result when it is returned.
273 ///
274 /// The wrapper function should be callable as:
275 ///
276 /// \code{.cpp}
277 /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
278 /// \endcode{.cpp}
279 virtual void callWrapperAsync(ExecutorAddr WrapperFnAddr,
280 IncomingWFRHandler OnComplete,
281 ArrayRef<char> ArgBuffer) = 0;
282
283 /// Run a wrapper function in the executor using the given Runner to dispatch
284 /// OnComplete when the result is ready.
285 template <typename RunPolicyT, typename FnT>
286 void callWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
287 FnT &&OnComplete, ArrayRef<char> ArgBuffer) {
288 callWrapperAsync(
289 WrapperFnAddr, Runner(std::forward<FnT>(OnComplete)), ArgBuffer);
290 }
291
292 /// Run a wrapper function in the executor. OnComplete will be dispatched
293 /// as a GenericNamedTask using this instance's TaskDispatch object.
294 template <typename FnT>
295 void callWrapperAsync(ExecutorAddr WrapperFnAddr, FnT &&OnComplete,
296 ArrayRef<char> ArgBuffer) {
297 callWrapperAsync(RunAsTask(*D), WrapperFnAddr,
298 std::forward<FnT>(OnComplete), ArgBuffer);
299 }
300
301 /// Run a wrapper function in the executor. The wrapper function should be
302 /// callable as:
303 ///
304 /// \code{.cpp}
305 /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
306 /// \endcode{.cpp}
307 shared::WrapperFunctionResult callWrapper(ExecutorAddr WrapperFnAddr,
308 ArrayRef<char> ArgBuffer) {
309 std::promise<shared::WrapperFunctionResult> RP;
310 auto RF = RP.get_future();
311 callWrapperAsync(
312 RunInPlace(), WrapperFnAddr,
313 [&](shared::WrapperFunctionResult R) {
314 RP.set_value(std::move(R));
315 }, ArgBuffer);
316 return RF.get();
317 }
318
319 /// Run a wrapper function using SPS to serialize the arguments and
320 /// deserialize the results.
321 template <typename SPSSignature, typename RunPolicyT, typename SendResultT,
322 typename... ArgTs>
323 void callSPSWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
324 SendResultT &&SendResult, const ArgTs &...Args) {
325 shared::WrapperFunction<SPSSignature>::callAsync(
326 [this, WrapperFnAddr, Runner = std::move(Runner)]
327 (auto &&SendResult, const char *ArgData, size_t ArgSize) mutable {
328 this->callWrapperAsync(std::move(Runner), WrapperFnAddr,
329 std::move(SendResult),
330 ArrayRef<char>(ArgData, ArgSize));
331 },
332 std::forward<SendResultT>(SendResult), Args...);
333 }
334
335 /// Run a wrapper function using SPS to serialize the arguments and
336 /// deserialize the results.
337 template <typename SPSSignature, typename SendResultT, typename... ArgTs>
338 void callSPSWrapperAsync(ExecutorAddr WrapperFnAddr, SendResultT &&SendResult,
339 const ArgTs &...Args) {
340 callSPSWrapperAsync<SPSSignature>(RunAsTask(*D), WrapperFnAddr,
341 std::forward<SendResultT>(SendResult),
342 Args...);
343 }
344
345 /// Run a wrapper function using SPS to serialize the arguments and
346 /// deserialize the results.
347 ///
348 /// If SPSSignature is a non-void function signature then the second argument
349 /// (the first in the Args list) should be a reference to a return value.
350 template <typename SPSSignature, typename... WrapperCallArgTs>
351 Error callSPSWrapper(ExecutorAddr WrapperFnAddr,
352 WrapperCallArgTs &&...WrapperCallArgs) {
353 return shared::WrapperFunction<SPSSignature>::call(
13
Calling 'WrapperFunction::call'
22
Returning from 'WrapperFunction::call'
354 [this, WrapperFnAddr](const char *ArgData, size_t ArgSize) {
355 return callWrapper(WrapperFnAddr, ArrayRef<char>(ArgData, ArgSize));
356 },
357 std::forward<WrapperCallArgTs>(WrapperCallArgs)...);
358 }
359
360 /// Disconnect from the target process.
361 ///
362 /// This should be called after the JIT session is shut down.
363 virtual Error disconnect() = 0;
364
365protected:
366
367 std::shared_ptr<SymbolStringPool> SSP;
368 std::unique_ptr<TaskDispatcher> D;
369 ExecutionSession *ES = nullptr;
370 Triple TargetTriple;
371 unsigned PageSize = 0;
372 JITDispatchInfo JDI;
373 MemoryAccess *MemAccess = nullptr;
374 jitlink::JITLinkMemoryManager *MemMgr = nullptr;
375 StringMap<ExecutorAddr> BootstrapSymbols;
376};
377
378/// A ExecutorProcessControl instance that asserts if any of its methods are
379/// used. Suitable for use is unit tests, and by ORC clients who haven't moved
380/// to ExecutorProcessControl-based APIs yet.
381class UnsupportedExecutorProcessControl : public ExecutorProcessControl {
382public:
383 UnsupportedExecutorProcessControl(
384 std::shared_ptr<SymbolStringPool> SSP = nullptr,
385 std::unique_ptr<TaskDispatcher> D = nullptr,
386 const std::string &TT = "", unsigned PageSize = 0)
387 : ExecutorProcessControl(SSP ? std::move(SSP)
388 : std::make_shared<SymbolStringPool>(),
389 D ? std::move(D)
390 : std::make_unique<InPlaceTaskDispatcher>()) {
391 this->TargetTriple = Triple(TT);
392 this->PageSize = PageSize;
393 }
394
395 Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override {
396 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 396)
;
397 }
398
399 Expected<std::vector<tpctypes::LookupResult>>
400 lookupSymbols(ArrayRef<LookupRequest> Request) override {
401 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 401)
;
402 }
403
404 Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
405 ArrayRef<std::string> Args) override {
406 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 406)
;
407 }
408
409 Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) override {
410 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 410)
;
411 }
412
413 Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override {
414 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 414)
;
415 }
416
417 void callWrapperAsync(ExecutorAddr WrapperFnAddr,
418 IncomingWFRHandler OnComplete,
419 ArrayRef<char> ArgBuffer) override {
420 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 420)
;
421 }
422
423 Error disconnect() override { return Error::success(); }
424};
425
426/// A ExecutorProcessControl implementation targeting the current process.
427class SelfExecutorProcessControl
428 : public ExecutorProcessControl,
429 private ExecutorProcessControl::MemoryAccess {
430public:
431 SelfExecutorProcessControl(
432 std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D,
433 Triple TargetTriple, unsigned PageSize,
434 std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
435
436 /// Create a SelfExecutorProcessControl with the given symbol string pool and
437 /// memory manager.
438 /// If no symbol string pool is given then one will be created.
439 /// If no memory manager is given a jitlink::InProcessMemoryManager will
440 /// be created and used by default.
441 static Expected<std::unique_ptr<SelfExecutorProcessControl>>
442 Create(std::shared_ptr<SymbolStringPool> SSP = nullptr,
443 std::unique_ptr<TaskDispatcher> D = nullptr,
444 std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr);
445
446 Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;
447
448 Expected<std::vector<tpctypes::LookupResult>>
449 lookupSymbols(ArrayRef<LookupRequest> Request) override;
450
451 Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
452 ArrayRef<std::string> Args) override;
453
454 Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) override;
455
456 Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override;
457
458 void callWrapperAsync(ExecutorAddr WrapperFnAddr,
459 IncomingWFRHandler OnComplete,
460 ArrayRef<char> ArgBuffer) override;
461
462 Error disconnect() override;
463
464private:
465 void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
466 WriteResultFn OnWriteComplete) override;
467
468 void writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws,
469 WriteResultFn OnWriteComplete) override;
470
471 void writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws,
472 WriteResultFn OnWriteComplete) override;
473
474 void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,
475 WriteResultFn OnWriteComplete) override;
476
477 void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,
478 WriteResultFn OnWriteComplete) override;
479
480 static shared::CWrapperFunctionResult
481 jitDispatchViaWrapperFunctionManager(void *Ctx, const void *FnTag,
482 const char *Data, size_t Size);
483
484 std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
485 char GlobalManglingPrefix = 0;
486 std::vector<std::unique_ptr<sys::DynamicLibrary>> DynamicLibraries;
487};
488
489} // end namespace orc
490} // end namespace llvm
491
492#endif // LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H

/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/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.empty() ? nullptr : ArgData.data(),
640 ArgData.size());
641 if (SPSSerializer::serialize(OB, Args...))
642 return WrapperFunctionCall(FnAddr, std::move(ArgData));
643 return make_error<StringError>("Cannot serialize arguments for "
644 "AllocActionCall",
645 inconvertibleErrorCode());
646 }
647
648 WrapperFunctionCall() = default;
649
650 /// Create a WrapperFunctionCall from a target function and arg buffer.
651 WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData)
652 : FnAddr(FnAddr), ArgData(std::move(ArgData)) {}
653
654 /// Returns the address to be called.
655 const ExecutorAddr &getCallee() const { return FnAddr; }
656
657 /// Returns the argument data.
658 const ArgDataBufferType &getArgData() const { return ArgData; }
659
660 /// WrapperFunctionCalls convert to true if the callee is non-null.
661 explicit operator bool() const { return !!FnAddr; }
662
663 /// Run call returning raw WrapperFunctionResult.
664 shared::WrapperFunctionResult run() const {
665 using FnTy =
666 shared::CWrapperFunctionResult(const char *ArgData, size_t ArgSize);
667 return shared::WrapperFunctionResult(
668 FnAddr.toPtr<FnTy *>()(ArgData.data(), ArgData.size()));
669 }
670
671 /// Run call and deserialize result using SPS.
672 template <typename SPSRetT, typename RetT>
673 std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error>
674 runWithSPSRet(RetT &RetVal) const {
675 auto WFR = run();
676 if (const char *ErrMsg = WFR.getOutOfBandError())
677 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
678 shared::SPSInputBuffer IB(WFR.data(), WFR.size());
679 if (!shared::SPSSerializationTraits<SPSRetT, RetT>::deserialize(IB, RetVal))
680 return make_error<StringError>("Could not deserialize result from "
681 "serialized wrapper function call",
682 inconvertibleErrorCode());
683 return Error::success();
684 }
685
686 /// Overload for SPS functions returning void.
687 template <typename SPSRetT>
688 std::enable_if_t<std::is_same<SPSRetT, void>::value, Error>
689 runWithSPSRet() const {
690 shared::SPSEmpty E;
691 return runWithSPSRet<shared::SPSEmpty>(E);
692 }
693
694 /// Run call and deserialize an SPSError result. SPSError returns and
695 /// deserialization failures are merged into the returned error.
696 Error runWithSPSRetErrorMerged() const {
697 detail::SPSSerializableError RetErr;
698 if (auto Err = runWithSPSRet<SPSError>(RetErr))
699 return Err;
700 return detail::fromSPSSerializable(std::move(RetErr));
701 }
702
703private:
704 orc::ExecutorAddr FnAddr;
705 ArgDataBufferType ArgData;
706};
707
708using SPSWrapperFunctionCall = SPSTuple<SPSExecutorAddr, SPSSequence<char>>;
709
710template <>
711class SPSSerializationTraits<SPSWrapperFunctionCall, WrapperFunctionCall> {
712public:
713 static size_t size(const WrapperFunctionCall &WFC) {
714 return SPSWrapperFunctionCall::AsArgList::size(WFC.getCallee(),
715 WFC.getArgData());
716 }
717
718 static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC) {
719 return SPSWrapperFunctionCall::AsArgList::serialize(OB, WFC.getCallee(),
720 WFC.getArgData());
721 }
722
723 static bool deserialize(SPSInputBuffer &IB, WrapperFunctionCall &WFC) {
724 ExecutorAddr FnAddr;
725 WrapperFunctionCall::ArgDataBufferType ArgData;
726 if (!SPSWrapperFunctionCall::AsArgList::deserialize(IB, FnAddr, ArgData))
727 return false;
728 WFC = WrapperFunctionCall(FnAddr, std::move(ArgData));
729 return true;
730 }
731};
732
733} // end namespace shared
734} // end namespace orc
735} // end namespace llvm
736
737#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H

/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/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 [[nodiscard]] 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 'Expected<T>', see the
467/// 'EXPECT_THAT_EXPECTED' macros in llvm/Testing/Support/Error.h
468
469template <class T> class [[nodiscard]] 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<
826 decltype(&std::remove_reference_t<HandlerT>::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 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)
1273 OS << "line " << Line.value() << ": ";
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