Bug Summary

File:build/source/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
Warning:line 567, 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/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I lib/ExecutionEngine/Orc -I /build/source/llvm/lib/ExecutionEngine/Orc -I include -I /build/source/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-17/lib/clang/17/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/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -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/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -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-2023-05-10-133810-16478-1 -x c++ /build/source/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp

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

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

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

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