Bug Summary

File:llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
Warning:line 555, column 10
Moved-from object 'ErrResult' is moved

Annotated Source Code

Press '?' to see keyboard shortcuts

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

/build/llvm-toolchain-snapshot-14~++20220116100644+5f782d25a742/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp

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

/build/llvm-toolchain-snapshot-14~++20220116100644+5f782d25a742/llvm/include/llvm/ExecutionEngine/Orc/Core.h

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

/build/llvm-toolchain-snapshot-14~++20220116100644+5f782d25a742/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h

1//===- ExecutorProcessControl.h - Executor process control APIs -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Utilities for interacting with the executor processes.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H
14#define LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H
15
16#include "llvm/ADT/StringRef.h"
17#include "llvm/ADT/Triple.h"
18#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
19#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
20#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
21#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
22#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
23#include "llvm/ExecutionEngine/Orc/TaskDispatch.h"
24#include "llvm/Support/DynamicLibrary.h"
25#include "llvm/Support/MSVCErrorWorkarounds.h"
26
27#include <future>
28#include <mutex>
29#include <vector>
30
31namespace llvm {
32namespace orc {
33
34class ExecutionSession;
35class SymbolLookupSet;
36
37/// ExecutorProcessControl supports interaction with a JIT target process.
38class ExecutorProcessControl {
39 friend class ExecutionSession;
40public:
41
42 /// A handler or incoming WrapperFunctionResults -- either return values from
43 /// callWrapper* calls, or incoming JIT-dispatch requests.
44 ///
45 /// IncomingWFRHandlers are constructible from
46 /// unique_function<void(shared::WrapperFunctionResult)>s using the
47 /// runInPlace function or a RunWithDispatch object.
48 class IncomingWFRHandler {
49 friend class ExecutorProcessControl;
50 public:
51 IncomingWFRHandler() = default;
52 explicit operator bool() const { return !!H; }
53 void operator()(shared::WrapperFunctionResult WFR) { H(std::move(WFR)); }
54 private:
55 template <typename FnT> IncomingWFRHandler(FnT &&Fn)
56 : H(std::forward<FnT>(Fn)) {}
57
58 unique_function<void(shared::WrapperFunctionResult)> H;
59 };
60
61 /// Constructs an IncomingWFRHandler from a function object that is callable
62 /// as void(shared::WrapperFunctionResult). The function object will be called
63 /// directly. This should be used with care as it may block listener threads
64 /// in remote EPCs. It is only suitable for simple tasks (e.g. setting a
65 /// future), or for performing some quick analysis before dispatching "real"
66 /// work as a Task.
67 class RunInPlace {
68 public:
69 template <typename FnT>
70 IncomingWFRHandler operator()(FnT &&Fn) {
71 return IncomingWFRHandler(std::forward<FnT>(Fn));
72 }
73 };
74
75 /// Constructs an IncomingWFRHandler from a function object by creating a new
76 /// function object that dispatches the original using a TaskDispatcher,
77 /// wrapping the original as a GenericNamedTask.
78 ///
79 /// This is the default approach for running WFR handlers.
80 class RunAsTask {
81 public:
82 RunAsTask(TaskDispatcher &D) : D(D) {}
83
84 template <typename FnT>
85 IncomingWFRHandler operator()(FnT &&Fn) {
86 return IncomingWFRHandler(
87 [&D = this->D, Fn = std::move(Fn)]
88 (shared::WrapperFunctionResult WFR) mutable {
89 D.dispatch(
90 makeGenericNamedTask(
91 [Fn = std::move(Fn), WFR = std::move(WFR)]() mutable {
92 Fn(std::move(WFR));
93 }, "WFR handler task"));
94 });
95 }
96 private:
97 TaskDispatcher &D;
98 };
99
100 /// APIs for manipulating memory in the target process.
101 class MemoryAccess {
102 public:
103 /// Callback function for asynchronous writes.
104 using WriteResultFn = unique_function<void(Error)>;
105
106 virtual ~MemoryAccess();
107
108 virtual void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
109 WriteResultFn OnWriteComplete) = 0;
110
111 virtual void writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws,
112 WriteResultFn OnWriteComplete) = 0;
113
114 virtual void writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws,
115 WriteResultFn OnWriteComplete) = 0;
116
117 virtual void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,
118 WriteResultFn OnWriteComplete) = 0;
119
120 virtual void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,
121 WriteResultFn OnWriteComplete) = 0;
122
123 Error writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws) {
124 std::promise<MSVCPError> ResultP;
125 auto ResultF = ResultP.get_future();
126 writeUInt8sAsync(Ws,
127 [&](Error Err) { ResultP.set_value(std::move(Err)); });
128 return ResultF.get();
129 }
130
131 Error writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws) {
132 std::promise<MSVCPError> ResultP;
133 auto ResultF = ResultP.get_future();
134 writeUInt16sAsync(Ws,
135 [&](Error Err) { ResultP.set_value(std::move(Err)); });
136 return ResultF.get();
137 }
138
139 Error writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws) {
140 std::promise<MSVCPError> ResultP;
141 auto ResultF = ResultP.get_future();
142 writeUInt32sAsync(Ws,
143 [&](Error Err) { ResultP.set_value(std::move(Err)); });
144 return ResultF.get();
145 }
146
147 Error writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws) {
148 std::promise<MSVCPError> ResultP;
149 auto ResultF = ResultP.get_future();
150 writeUInt64sAsync(Ws,
151 [&](Error Err) { ResultP.set_value(std::move(Err)); });
152 return ResultF.get();
153 }
154
155 Error writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws) {
156 std::promise<MSVCPError> ResultP;
157 auto ResultF = ResultP.get_future();
158 writeBuffersAsync(Ws,
159 [&](Error Err) { ResultP.set_value(std::move(Err)); });
160 return ResultF.get();
161 }
162 };
163
164 /// A pair of a dylib and a set of symbols to be looked up.
165 struct LookupRequest {
166 LookupRequest(tpctypes::DylibHandle Handle, const SymbolLookupSet &Symbols)
167 : Handle(Handle), Symbols(Symbols) {}
168 tpctypes::DylibHandle Handle;
169 const SymbolLookupSet &Symbols;
170 };
171
172 /// Contains the address of the dispatch function and context that the ORC
173 /// runtime can use to call functions in the JIT.
174 struct JITDispatchInfo {
175 ExecutorAddr JITDispatchFunction;
176 ExecutorAddr JITDispatchContext;
177 };
178
179 ExecutorProcessControl(std::shared_ptr<SymbolStringPool> SSP,
180 std::unique_ptr<TaskDispatcher> D)
181 : SSP(std::move(SSP)), D(std::move(D)) {}
182
183 virtual ~ExecutorProcessControl();
184
185 /// Return the ExecutionSession associated with this instance.
186 /// Not callable until the ExecutionSession has been associated.
187 ExecutionSession &getExecutionSession() {
188 assert(ES && "No ExecutionSession associated yet")(static_cast <bool> (ES && "No ExecutionSession associated yet"
) ? void (0) : __assert_fail ("ES && \"No ExecutionSession associated yet\""
, "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 188, __extension__ __PRETTY_FUNCTION__))
;
189 return *ES;
190 }
191
192 /// Intern a symbol name in the SymbolStringPool.
193 SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
194
195 /// Return a shared pointer to the SymbolStringPool for this instance.
196 std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
197
198 TaskDispatcher &getDispatcher() { return *D; }
199
200 /// Return the Triple for the target process.
201 const Triple &getTargetTriple() const { return TargetTriple; }
202
203 /// Get the page size for the target process.
204 unsigned getPageSize() const { return PageSize; }
205
206 /// Get the JIT dispatch function and context address for the executor.
207 const JITDispatchInfo &getJITDispatchInfo() const { return JDI; }
208
209 /// Return a MemoryAccess object for the target process.
210 MemoryAccess &getMemoryAccess() const {
211 assert(MemAccess && "No MemAccess object set.")(static_cast <bool> (MemAccess && "No MemAccess object set."
) ? void (0) : __assert_fail ("MemAccess && \"No MemAccess object set.\""
, "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 211, __extension__ __PRETTY_FUNCTION__))
;
212 return *MemAccess;
213 }
214
215 /// Return a JITLinkMemoryManager for the target process.
216 jitlink::JITLinkMemoryManager &getMemMgr() const {
217 assert(MemMgr && "No MemMgr object set")(static_cast <bool> (MemMgr && "No MemMgr object set"
) ? void (0) : __assert_fail ("MemMgr && \"No MemMgr object set\""
, "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 217, __extension__ __PRETTY_FUNCTION__))
;
218 return *MemMgr;
219 }
220
221 /// Returns the bootstrap symbol map.
222 const StringMap<ExecutorAddr> &getBootstrapSymbolsMap() const {
223 return BootstrapSymbols;
224 }
225
226 /// For each (ExecutorAddr&, StringRef) pair, looks up the string in the
227 /// bootstrap symbols map and writes its address to the ExecutorAddr if
228 /// found. If any symbol is not found then the function returns an error.
229 Error getBootstrapSymbols(
230 ArrayRef<std::pair<ExecutorAddr &, StringRef>> Pairs) const {
231 for (auto &KV : Pairs) {
232 auto I = BootstrapSymbols.find(KV.second);
233 if (I == BootstrapSymbols.end())
234 return make_error<StringError>("Symbol \"" + KV.second +
235 "\" not found "
236 "in bootstrap symbols map",
237 inconvertibleErrorCode());
238
239 KV.first = I->second;
240 }
241 return Error::success();
242 }
243
244 /// Load the dynamic library at the given path and return a handle to it.
245 /// If LibraryPath is null this function will return the global handle for
246 /// the target process.
247 virtual Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) = 0;
248
249 /// Search for symbols in the target process.
250 ///
251 /// The result of the lookup is a 2-dimentional array of target addresses
252 /// that correspond to the lookup order. If a required symbol is not
253 /// found then this method will return an error. If a weakly referenced
254 /// symbol is not found then it be assigned a '0' value.
255 virtual Expected<std::vector<tpctypes::LookupResult>>
256 lookupSymbols(ArrayRef<LookupRequest> Request) = 0;
257
258 /// Run function with a main-like signature.
259 virtual Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
260 ArrayRef<std::string> Args) = 0;
261
262 /// Run a wrapper function in the executor. The given WFRHandler will be
263 /// called on the result when it is returned.
264 ///
265 /// The wrapper function should be callable as:
266 ///
267 /// \code{.cpp}
268 /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
269 /// \endcode{.cpp}
270 virtual void callWrapperAsync(ExecutorAddr WrapperFnAddr,
271 IncomingWFRHandler OnComplete,
272 ArrayRef<char> ArgBuffer) = 0;
273
274 /// Run a wrapper function in the executor using the given Runner to dispatch
275 /// OnComplete when the result is ready.
276 template <typename RunPolicyT, typename FnT>
277 void callWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
278 FnT &&OnComplete, ArrayRef<char> ArgBuffer) {
279 callWrapperAsync(
280 WrapperFnAddr, Runner(std::forward<FnT>(OnComplete)), ArgBuffer);
281 }
282
283 /// Run a wrapper function in the executor. OnComplete will be dispatched
284 /// as a GenericNamedTask using this instance's TaskDispatch object.
285 template <typename FnT>
286 void callWrapperAsync(ExecutorAddr WrapperFnAddr, FnT &&OnComplete,
287 ArrayRef<char> ArgBuffer) {
288 callWrapperAsync(RunAsTask(*D), WrapperFnAddr,
289 std::forward<FnT>(OnComplete), ArgBuffer);
290 }
291
292 /// Run a wrapper function in the executor. The wrapper function should be
293 /// callable as:
294 ///
295 /// \code{.cpp}
296 /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
297 /// \endcode{.cpp}
298 shared::WrapperFunctionResult callWrapper(ExecutorAddr WrapperFnAddr,
299 ArrayRef<char> ArgBuffer) {
300 std::promise<shared::WrapperFunctionResult> RP;
301 auto RF = RP.get_future();
302 callWrapperAsync(
303 RunInPlace(), WrapperFnAddr,
304 [&](shared::WrapperFunctionResult R) {
305 RP.set_value(std::move(R));
306 }, ArgBuffer);
307 return RF.get();
308 }
309
310 /// Run a wrapper function using SPS to serialize the arguments and
311 /// deserialize the results.
312 template <typename SPSSignature, typename RunPolicyT, typename SendResultT,
313 typename... ArgTs>
314 void callSPSWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
315 SendResultT &&SendResult, const ArgTs &...Args) {
316 shared::WrapperFunction<SPSSignature>::callAsync(
317 [this, WrapperFnAddr, Runner = std::move(Runner)]
318 (auto &&SendResult, const char *ArgData, size_t ArgSize) mutable {
319 this->callWrapperAsync(std::move(Runner), WrapperFnAddr,
320 std::move(SendResult),
321 ArrayRef<char>(ArgData, ArgSize));
322 },
323 std::forward<SendResultT>(SendResult), Args...);
324 }
325
326 /// Run a wrapper function using SPS to serialize the arguments and
327 /// deserialize the results.
328 template <typename SPSSignature, typename SendResultT, typename... ArgTs>
329 void callSPSWrapperAsync(ExecutorAddr WrapperFnAddr, SendResultT &&SendResult,
330 const ArgTs &...Args) {
331 callSPSWrapperAsync<SPSSignature>(RunAsTask(*D), WrapperFnAddr,
332 std::forward<SendResultT>(SendResult),
333 Args...);
334 }
335
336 /// Run a wrapper function using SPS to serialize the arguments and
337 /// deserialize the results.
338 ///
339 /// If SPSSignature is a non-void function signature then the second argument
340 /// (the first in the Args list) should be a reference to a return value.
341 template <typename SPSSignature, typename... WrapperCallArgTs>
342 Error callSPSWrapper(ExecutorAddr WrapperFnAddr,
343 WrapperCallArgTs &&...WrapperCallArgs) {
344 return shared::WrapperFunction<SPSSignature>::call(
13
Calling 'WrapperFunction::call'
22
Returning from 'WrapperFunction::call'
345 [this, WrapperFnAddr](const char *ArgData, size_t ArgSize) {
346 return callWrapper(WrapperFnAddr, ArrayRef<char>(ArgData, ArgSize));
347 },
348 std::forward<WrapperCallArgTs>(WrapperCallArgs)...);
349 }
350
351 /// Disconnect from the target process.
352 ///
353 /// This should be called after the JIT session is shut down.
354 virtual Error disconnect() = 0;
355
356protected:
357
358 std::shared_ptr<SymbolStringPool> SSP;
359 std::unique_ptr<TaskDispatcher> D;
360 ExecutionSession *ES = nullptr;
361 Triple TargetTriple;
362 unsigned PageSize = 0;
363 JITDispatchInfo JDI;
364 MemoryAccess *MemAccess = nullptr;
365 jitlink::JITLinkMemoryManager *MemMgr = nullptr;
366 StringMap<ExecutorAddr> BootstrapSymbols;
367};
368
369/// A ExecutorProcessControl instance that asserts if any of its methods are
370/// used. Suitable for use is unit tests, and by ORC clients who haven't moved
371/// to ExecutorProcessControl-based APIs yet.
372class UnsupportedExecutorProcessControl : public ExecutorProcessControl {
373public:
374 UnsupportedExecutorProcessControl(
375 std::shared_ptr<SymbolStringPool> SSP = nullptr,
376 std::unique_ptr<TaskDispatcher> D = nullptr,
377 const std::string &TT = "", unsigned PageSize = 0)
378 : ExecutorProcessControl(SSP ? std::move(SSP)
379 : std::make_shared<SymbolStringPool>(),
380 D ? std::move(D)
381 : std::make_unique<InPlaceTaskDispatcher>()) {
382 this->TargetTriple = Triple(TT);
383 this->PageSize = PageSize;
384 }
385
386 Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override {
387 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 387)
;
388 }
389
390 Expected<std::vector<tpctypes::LookupResult>>
391 lookupSymbols(ArrayRef<LookupRequest> Request) override {
392 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 392)
;
393 }
394
395 Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
396 ArrayRef<std::string> Args) override {
397 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 397)
;
398 }
399
400 void callWrapperAsync(ExecutorAddr WrapperFnAddr,
401 IncomingWFRHandler OnComplete,
402 ArrayRef<char> ArgBuffer) override {
403 llvm_unreachable("Unsupported")::llvm::llvm_unreachable_internal("Unsupported", "llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
, 403)
;
404 }
405
406 Error disconnect() override { return Error::success(); }
407};
408
409/// A ExecutorProcessControl implementation targeting the current process.
410class SelfExecutorProcessControl
411 : public ExecutorProcessControl,
412 private ExecutorProcessControl::MemoryAccess {
413public:
414 SelfExecutorProcessControl(
415 std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D,
416 Triple TargetTriple, unsigned PageSize,
417 std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
418
419 /// Create a SelfExecutorProcessControl with the given symbol string pool and
420 /// memory manager.
421 /// If no symbol string pool is given then one will be created.
422 /// If no memory manager is given a jitlink::InProcessMemoryManager will
423 /// be created and used by default.
424 static Expected<std::unique_ptr<SelfExecutorProcessControl>>
425 Create(std::shared_ptr<SymbolStringPool> SSP = nullptr,
426 std::unique_ptr<TaskDispatcher> D = nullptr,
427 std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr);
428
429 Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;
430
431 Expected<std::vector<tpctypes::LookupResult>>
432 lookupSymbols(ArrayRef<LookupRequest> Request) override;
433
434 Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
435 ArrayRef<std::string> Args) override;
436
437 void callWrapperAsync(ExecutorAddr WrapperFnAddr,
438 IncomingWFRHandler OnComplete,
439 ArrayRef<char> ArgBuffer) override;
440
441 Error disconnect() override;
442
443private:
444 void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
445 WriteResultFn OnWriteComplete) override;
446
447 void writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws,
448 WriteResultFn OnWriteComplete) override;
449
450 void writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws,
451 WriteResultFn OnWriteComplete) override;
452
453 void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,
454 WriteResultFn OnWriteComplete) override;
455
456 void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,
457 WriteResultFn OnWriteComplete) override;
458
459 static shared::CWrapperFunctionResult
460 jitDispatchViaWrapperFunctionManager(void *Ctx, const void *FnTag,
461 const char *Data, size_t Size);
462
463 std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
464 char GlobalManglingPrefix = 0;
465 std::vector<std::unique_ptr<sys::DynamicLibrary>> DynamicLibraries;
466};
467
468} // end namespace orc
469} // end namespace llvm
470
471#endif // LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H

/build/llvm-toolchain-snapshot-14~++20220116100644+5f782d25a742/llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h

1//===- WrapperFunctionUtils.h - Utilities for wrapper functions -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// A buffer for serialized results.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H
14#define LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H
15
16#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
17#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
18#include "llvm/Support/Error.h"
19
20#include <type_traits>
21
22namespace llvm {
23namespace orc {
24namespace shared {
25
26// Must be kept in-sync with compiler-rt/lib/orc/c-api.h.
27union CWrapperFunctionResultDataUnion {
28 char *ValuePtr;
29 char Value[sizeof(ValuePtr)];
30};
31
32// Must be kept in-sync with compiler-rt/lib/orc/c-api.h.
33typedef struct {
34 CWrapperFunctionResultDataUnion Data;
35 size_t Size;
36} CWrapperFunctionResult;
37
38/// C++ wrapper function result: Same as CWrapperFunctionResult but
39/// auto-releases memory.
40class WrapperFunctionResult {
41public:
42 /// Create a default WrapperFunctionResult.
43 WrapperFunctionResult() { init(R); }
44
45 /// Create a WrapperFunctionResult by taking ownership of a
46 /// CWrapperFunctionResult.
47 ///
48 /// Warning: This should only be used by clients writing wrapper-function
49 /// caller utilities (like TargetProcessControl).
50 WrapperFunctionResult(CWrapperFunctionResult R) : R(R) {
51 // Reset R.
52 init(R);
53 }
54
55 WrapperFunctionResult(const WrapperFunctionResult &) = delete;
56 WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
57
58 WrapperFunctionResult(WrapperFunctionResult &&Other) {
59 init(R);
60 std::swap(R, Other.R);
61 }
62
63 WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
64 WrapperFunctionResult Tmp(std::move(Other));
65 std::swap(R, Tmp.R);
66 return *this;
67 }
68
69 ~WrapperFunctionResult() {
70 if ((R.Size > sizeof(R.Data.Value)) ||
71 (R.Size == 0 && R.Data.ValuePtr != nullptr))
72 free(R.Data.ValuePtr);
73 }
74
75 /// Release ownership of the contained CWrapperFunctionResult.
76 /// Warning: Do not use -- this method will be removed in the future. It only
77 /// exists to temporarily support some code that will eventually be moved to
78 /// the ORC runtime.
79 CWrapperFunctionResult release() {
80 CWrapperFunctionResult Tmp;
81 init(Tmp);
82 std::swap(R, Tmp);
83 return Tmp;
84 }
85
86 /// Get a pointer to the data contained in this instance.
87 char *data() {
88 assert((R.Size != 0 || R.Data.ValuePtr == nullptr) &&(static_cast <bool> ((R.Size != 0 || R.Data.ValuePtr ==
nullptr) && "Cannot get data for out-of-band error value"
) ? void (0) : __assert_fail ("(R.Size != 0 || R.Data.ValuePtr == nullptr) && \"Cannot get data for out-of-band error value\""
, "llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
, 89, __extension__ __PRETTY_FUNCTION__))
89 "Cannot get data for out-of-band error value")(static_cast <bool> ((R.Size != 0 || R.Data.ValuePtr ==
nullptr) && "Cannot get data for out-of-band error value"
) ? void (0) : __assert_fail ("(R.Size != 0 || R.Data.ValuePtr == nullptr) && \"Cannot get data for out-of-band error value\""
, "llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
, 89, __extension__ __PRETTY_FUNCTION__))
;
90 return R.Size > sizeof(R.Data.Value) ? R.Data.ValuePtr : R.Data.Value;
91 }
92
93 /// Get a const pointer to the data contained in this instance.
94 const char *data() const {
95 assert((R.Size != 0 || R.Data.ValuePtr == nullptr) &&(static_cast <bool> ((R.Size != 0 || R.Data.ValuePtr ==
nullptr) && "Cannot get data for out-of-band error value"
) ? void (0) : __assert_fail ("(R.Size != 0 || R.Data.ValuePtr == nullptr) && \"Cannot get data for out-of-band error value\""
, "llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
, 96, __extension__ __PRETTY_FUNCTION__))
96 "Cannot get data for out-of-band error value")(static_cast <bool> ((R.Size != 0 || R.Data.ValuePtr ==
nullptr) && "Cannot get data for out-of-band error value"
) ? void (0) : __assert_fail ("(R.Size != 0 || R.Data.ValuePtr == nullptr) && \"Cannot get data for out-of-band error value\""
, "llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
, 96, __extension__ __PRETTY_FUNCTION__))
;
97 return R.Size > sizeof(R.Data.Value) ? R.Data.ValuePtr : R.Data.Value;
98 }
99
100 /// Returns the size of the data contained in this instance.
101 size_t size() const {
102 assert((R.Size != 0 || R.Data.ValuePtr == nullptr) &&(static_cast <bool> ((R.Size != 0 || R.Data.ValuePtr ==
nullptr) && "Cannot get data for out-of-band error value"
) ? void (0) : __assert_fail ("(R.Size != 0 || R.Data.ValuePtr == nullptr) && \"Cannot get data for out-of-band error value\""
, "llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
, 103, __extension__ __PRETTY_FUNCTION__))
103 "Cannot get data for out-of-band error value")(static_cast <bool> ((R.Size != 0 || R.Data.ValuePtr ==
nullptr) && "Cannot get data for out-of-band error value"
) ? void (0) : __assert_fail ("(R.Size != 0 || R.Data.ValuePtr == nullptr) && \"Cannot get data for out-of-band error value\""
, "llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
, 103, __extension__ __PRETTY_FUNCTION__))
;
104 return R.Size;
105 }
106
107 /// Returns true if this value is equivalent to a default-constructed
108 /// WrapperFunctionResult.
109 bool empty() const { return R.Size == 0 && R.Data.ValuePtr == nullptr; }
110
111 /// Create a WrapperFunctionResult with the given size and return a pointer
112 /// to the underlying memory.
113 static WrapperFunctionResult allocate(size_t Size) {
114 // Reset.
115 WrapperFunctionResult WFR;
116 WFR.R.Size = Size;
117 if (WFR.R.Size > sizeof(WFR.R.Data.Value))
118 WFR.R.Data.ValuePtr = (char *)malloc(WFR.R.Size);
119 return WFR;
120 }
121
122 /// Copy from the given char range.
123 static WrapperFunctionResult copyFrom(const char *Source, size_t Size) {
124 auto WFR = allocate(Size);
125 memcpy(WFR.data(), Source, Size);
126 return WFR;
127 }
128
129 /// Copy from the given null-terminated string (includes the null-terminator).
130 static WrapperFunctionResult copyFrom(const char *Source) {
131 return copyFrom(Source, strlen(Source) + 1);
132 }
133
134 /// Copy from the given std::string (includes the null terminator).
135 static WrapperFunctionResult copyFrom(const std::string &Source) {
136 return copyFrom(Source.c_str());
137 }
138
139 /// Create an out-of-band error by copying the given string.
140 static WrapperFunctionResult createOutOfBandError(const char *Msg) {
141 // Reset.
142 WrapperFunctionResult WFR;
143 char *Tmp = (char *)malloc(strlen(Msg) + 1);
144 strcpy(Tmp, Msg);
145 WFR.R.Data.ValuePtr = Tmp;
146 return WFR;
147 }
148
149 /// Create an out-of-band error by copying the given string.
150 static WrapperFunctionResult createOutOfBandError(const std::string &Msg) {
151 return createOutOfBandError(Msg.c_str());
152 }
153
154 /// If this value is an out-of-band error then this returns the error message,
155 /// otherwise returns nullptr.
156 const char *getOutOfBandError() const {
157 return R.Size == 0 ? R.Data.ValuePtr : nullptr;
158 }
159
160private:
161 static void init(CWrapperFunctionResult &R) {
162 R.Data.ValuePtr = nullptr;
163 R.Size = 0;
164 }
165
166 CWrapperFunctionResult R;
167};
168
169namespace detail {
170
171template <typename SPSArgListT, typename... ArgTs>
172WrapperFunctionResult
173serializeViaSPSToWrapperFunctionResult(const ArgTs &...Args) {
174 auto Result = WrapperFunctionResult::allocate(SPSArgListT::size(Args...));
175 SPSOutputBuffer OB(Result.data(), Result.size());
176 if (!SPSArgListT::serialize(OB, Args...))
177 return WrapperFunctionResult::createOutOfBandError(
178 "Error serializing arguments to blob in call");
179 return Result;
180}
181
182template <typename RetT> class WrapperFunctionHandlerCaller {
183public:
184 template <typename HandlerT, typename ArgTupleT, std::size_t... I>
185 static decltype(auto) call(HandlerT &&H, ArgTupleT &Args,
186 std::index_sequence<I...>) {
187 return std::forward<HandlerT>(H)(std::get<I>(Args)...);
188 }
189};
190
191template <> class WrapperFunctionHandlerCaller<void> {
192public:
193 template <typename HandlerT, typename ArgTupleT, std::size_t... I>
194 static SPSEmpty call(HandlerT &&H, ArgTupleT &Args,
195 std::index_sequence<I...>) {
196 std::forward<HandlerT>(H)(std::get<I>(Args)...);
197 return SPSEmpty();
198 }
199};
200
201template <typename WrapperFunctionImplT,
202 template <typename> class ResultSerializer, typename... SPSTagTs>
203class WrapperFunctionHandlerHelper
204 : public WrapperFunctionHandlerHelper<
205 decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
206 ResultSerializer, SPSTagTs...> {};
207
208template <typename RetT, typename... ArgTs,
209 template <typename> class ResultSerializer, typename... SPSTagTs>
210class WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
211 SPSTagTs...> {
212public:
213 using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
214 using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
215
216 template <typename HandlerT>
217 static WrapperFunctionResult apply(HandlerT &&H, const char *ArgData,
218 size_t ArgSize) {
219 ArgTuple Args;
220 if (!deserialize(ArgData, ArgSize, Args, ArgIndices{}))
221 return WrapperFunctionResult::createOutOfBandError(
222 "Could not deserialize arguments for wrapper function call");
223
224 auto HandlerResult = WrapperFunctionHandlerCaller<RetT>::call(
225 std::forward<HandlerT>(H), Args, ArgIndices{});
226
227 return ResultSerializer<decltype(HandlerResult)>::serialize(
228 std::move(HandlerResult));
229 }
230
231private:
232 template <std::size_t... I>
233 static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args,
234 std::index_sequence<I...>) {
235 SPSInputBuffer IB(ArgData, ArgSize);
236 return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...);
237 }
238};
239
240// Map function pointers to function types.
241template <typename RetT, typename... ArgTs,
242 template <typename> class ResultSerializer, typename... SPSTagTs>
243class WrapperFunctionHandlerHelper<RetT (*)(ArgTs...), ResultSerializer,
244 SPSTagTs...>
245 : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
246 SPSTagTs...> {};
247
248// Map non-const member function types to function types.
249template <typename ClassT, typename RetT, typename... ArgTs,
250 template <typename> class ResultSerializer, typename... SPSTagTs>
251class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...), ResultSerializer,
252 SPSTagTs...>
253 : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
254 SPSTagTs...> {};
255
256// Map const member function types to function types.
257template <typename ClassT, typename RetT, typename... ArgTs,
258 template <typename> class ResultSerializer, typename... SPSTagTs>
259class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
260 ResultSerializer, SPSTagTs...>
261 : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
262 SPSTagTs...> {};
263
264template <typename WrapperFunctionImplT,
265 template <typename> class ResultSerializer, typename... SPSTagTs>
266class WrapperFunctionAsyncHandlerHelper
267 : public WrapperFunctionAsyncHandlerHelper<
268 decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
269 ResultSerializer, SPSTagTs...> {};
270
271template <typename RetT, typename SendResultT, typename... ArgTs,
272 template <typename> class ResultSerializer, typename... SPSTagTs>
273class WrapperFunctionAsyncHandlerHelper<RetT(SendResultT, ArgTs...),
274 ResultSerializer, SPSTagTs...> {
275public:
276 using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
277 using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
278
279 template <typename HandlerT, typename SendWrapperFunctionResultT>
280 static void applyAsync(HandlerT &&H,
281 SendWrapperFunctionResultT &&SendWrapperFunctionResult,
282 const char *ArgData, size_t ArgSize) {
283 ArgTuple Args;
284 if (!deserialize(ArgData, ArgSize, Args, ArgIndices{})) {
285 SendWrapperFunctionResult(WrapperFunctionResult::createOutOfBandError(
286 "Could not deserialize arguments for wrapper function call"));
287 return;
288 }
289
290 auto SendResult =
291 [SendWFR = std::move(SendWrapperFunctionResult)](auto Result) mutable {
292 using ResultT = decltype(Result);
293 SendWFR(ResultSerializer<ResultT>::serialize(std::move(Result)));
294 };
295
296 callAsync(std::forward<HandlerT>(H), std::move(SendResult), std::move(Args),
297 ArgIndices{});
298 }
299
300private:
301 template <std::size_t... I>
302 static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args,
303 std::index_sequence<I...>) {
304 SPSInputBuffer IB(ArgData, ArgSize);
305 return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...);
306 }
307
308 template <typename HandlerT, typename SerializeAndSendResultT,
309 typename ArgTupleT, std::size_t... I>
310 static void callAsync(HandlerT &&H,
311 SerializeAndSendResultT &&SerializeAndSendResult,
312 ArgTupleT Args, std::index_sequence<I...>) {
313 (void)Args; // Silence a buggy GCC warning.
314 return std::forward<HandlerT>(H)(std::move(SerializeAndSendResult),
315 std::move(std::get<I>(Args))...);
316 }
317};
318
319// Map function pointers to function types.
320template <typename RetT, typename... ArgTs,
321 template <typename> class ResultSerializer, typename... SPSTagTs>
322class WrapperFunctionAsyncHandlerHelper<RetT (*)(ArgTs...), ResultSerializer,
323 SPSTagTs...>
324 : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer,
325 SPSTagTs...> {};
326
327// Map non-const member function types to function types.
328template <typename ClassT, typename RetT, typename... ArgTs,
329 template <typename> class ResultSerializer, typename... SPSTagTs>
330class WrapperFunctionAsyncHandlerHelper<RetT (ClassT::*)(ArgTs...),
331 ResultSerializer, SPSTagTs...>
332 : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer,
333 SPSTagTs...> {};
334
335// Map const member function types to function types.
336template <typename ClassT, typename RetT, typename... ArgTs,
337 template <typename> class ResultSerializer, typename... SPSTagTs>
338class WrapperFunctionAsyncHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
339 ResultSerializer, SPSTagTs...>
340 : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer,
341 SPSTagTs...> {};
342
343template <typename SPSRetTagT, typename RetT> class ResultSerializer {
344public:
345 static WrapperFunctionResult serialize(RetT Result) {
346 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
347 Result);
348 }
349};
350
351template <typename SPSRetTagT> class ResultSerializer<SPSRetTagT, Error> {
352public:
353 static WrapperFunctionResult serialize(Error Err) {
354 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
355 toSPSSerializable(std::move(Err)));
356 }
357};
358
359template <typename SPSRetTagT>
360class ResultSerializer<SPSRetTagT, ErrorSuccess> {
361public:
362 static WrapperFunctionResult serialize(ErrorSuccess Err) {
363 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
364 toSPSSerializable(std::move(Err)));
365 }
366};
367
368template <typename SPSRetTagT, typename T>
369class ResultSerializer<SPSRetTagT, Expected<T>> {
370public:
371 static WrapperFunctionResult serialize(Expected<T> E) {
372 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
373 toSPSSerializable(std::move(E)));
374 }
375};
376
377template <typename SPSRetTagT, typename RetT> class ResultDeserializer {
378public:
379 static RetT makeValue() { return RetT(); }
380 static void makeSafe(RetT &Result) {}
381
382 static Error deserialize(RetT &Result, const char *ArgData, size_t ArgSize) {
383 SPSInputBuffer IB(ArgData, ArgSize);
384 if (!SPSArgList<SPSRetTagT>::deserialize(IB, Result))
385 return make_error<StringError>(
386 "Error deserializing return value from blob in call",
387 inconvertibleErrorCode());
388 return Error::success();
389 }
390};
391
392template <> class ResultDeserializer<SPSError, Error> {
393public:
394 static Error makeValue() { return Error::success(); }
395 static void makeSafe(Error &Err) { cantFail(std::move(Err)); }
15
Calling move constructor for 'Error'
17
Returning from move constructor for 'Error'
396
397 static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize) {
398 SPSInputBuffer IB(ArgData, ArgSize);
399 SPSSerializableError BSE;
400 if (!SPSArgList<SPSError>::deserialize(IB, BSE))
401 return make_error<StringError>(
402 "Error deserializing return value from blob in call",
403 inconvertibleErrorCode());
404 Err = fromSPSSerializable(std::move(BSE));
405 return Error::success();
406 }
407};
408
409template <typename SPSTagT, typename T>
410class ResultDeserializer<SPSExpected<SPSTagT>, Expected<T>> {
411public:
412 static Expected<T> makeValue() { return T(); }
413 static void makeSafe(Expected<T> &E) { cantFail(E.takeError()); }
414
415 static Error deserialize(Expected<T> &E, const char *ArgData,
416 size_t ArgSize) {
417 SPSInputBuffer IB(ArgData, ArgSize);
418 SPSSerializableExpected<T> BSE;
419 if (!SPSArgList<SPSExpected<SPSTagT>>::deserialize(IB, BSE))
420 return make_error<StringError>(
421 "Error deserializing return value from blob in call",
422 inconvertibleErrorCode());
423 E = fromSPSSerializable(std::move(BSE));
424 return Error::success();
425 }
426};
427
428template <typename SPSRetTagT, typename RetT> class AsyncCallResultHelper {
429 // Did you forget to use Error / Expected in your handler?
430};
431
432} // end namespace detail
433
434template <typename SPSSignature> class WrapperFunction;
435
436template <typename SPSRetTagT, typename... SPSTagTs>
437class WrapperFunction<SPSRetTagT(SPSTagTs...)> {
438private:
439 template <typename RetT>
440 using ResultSerializer = detail::ResultSerializer<SPSRetTagT, RetT>;
441
442public:
443 /// Call a wrapper function. Caller should be callable as
444 /// WrapperFunctionResult Fn(const char *ArgData, size_t ArgSize);
445 template <typename CallerFn, typename RetT, typename... ArgTs>
446 static Error call(const CallerFn &Caller, RetT &Result,
447 const ArgTs &...Args) {
448
449 // RetT might be an Error or Expected value. Set the checked flag now:
450 // we don't want the user to have to check the unused result if this
451 // operation fails.
452 detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(Result);
14
Calling 'ResultDeserializer::makeSafe'
18
Returning from 'ResultDeserializer::makeSafe'
453
454 auto ArgBuffer =
455 detail::serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSTagTs...>>(
456 Args...);
457 if (const char *ErrMsg
18.1
'ErrMsg' is null
18.1
'ErrMsg' is null
18.1
'ErrMsg' is null
18.1
'ErrMsg' is null
18.1
'ErrMsg' is null
= ArgBuffer.getOutOfBandError())
19
Taking false branch
458 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
459
460 WrapperFunctionResult ResultBuffer =
461 Caller(ArgBuffer.data(), ArgBuffer.size());
462 if (auto ErrMsg = ResultBuffer.getOutOfBandError())
20
Assuming 'ErrMsg' is non-null
21
Taking true branch
463 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
464
465 return detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize(
466 Result, ResultBuffer.data(), ResultBuffer.size());
467 }
468
469 /// Call an async wrapper function.
470 /// Caller should be callable as
471 /// void Fn(unique_function<void(WrapperFunctionResult)> SendResult,
472 /// WrapperFunctionResult ArgBuffer);
473 template <typename AsyncCallerFn, typename SendDeserializedResultFn,
474 typename... ArgTs>
475 static void callAsync(AsyncCallerFn &&Caller,
476 SendDeserializedResultFn &&SendDeserializedResult,
477 const ArgTs &...Args) {
478 using RetT = typename std::tuple_element<
479 1, typename detail::WrapperFunctionHandlerHelper<
480 std::remove_reference_t<SendDeserializedResultFn>,
481 ResultSerializer, SPSRetTagT>::ArgTuple>::type;
482
483 auto ArgBuffer =
484 detail::serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSTagTs...>>(
485 Args...);
486 if (auto *ErrMsg = ArgBuffer.getOutOfBandError()) {
487 SendDeserializedResult(
488 make_error<StringError>(ErrMsg, inconvertibleErrorCode()),
489 detail::ResultDeserializer<SPSRetTagT, RetT>::makeValue());
490 return;
491 }
492
493 auto SendSerializedResult = [SDR = std::move(SendDeserializedResult)](
494 WrapperFunctionResult R) mutable {
495 RetT RetVal = detail::ResultDeserializer<SPSRetTagT, RetT>::makeValue();
496 detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(RetVal);
497
498 if (auto *ErrMsg = R.getOutOfBandError()) {
499 SDR(make_error<StringError>(ErrMsg, inconvertibleErrorCode()),
500 std::move(RetVal));
501 return;
502 }
503
504 SPSInputBuffer IB(R.data(), R.size());
505 if (auto Err = detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize(
506 RetVal, R.data(), R.size()))
507 SDR(std::move(Err), std::move(RetVal));
508
509 SDR(Error::success(), std::move(RetVal));
510 };
511
512 Caller(std::move(SendSerializedResult), ArgBuffer.data(), ArgBuffer.size());
513 }
514
515 /// Handle a call to a wrapper function.
516 template <typename HandlerT>
517 static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize,
518 HandlerT &&Handler) {
519 using WFHH =
520 detail::WrapperFunctionHandlerHelper<std::remove_reference_t<HandlerT>,
521 ResultSerializer, SPSTagTs...>;
522 return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize);
523 }
524
525 /// Handle a call to an async wrapper function.
526 template <typename HandlerT, typename SendResultT>
527 static void handleAsync(const char *ArgData, size_t ArgSize,
528 HandlerT &&Handler, SendResultT &&SendResult) {
529 using WFAHH = detail::WrapperFunctionAsyncHandlerHelper<
530 std::remove_reference_t<HandlerT>, ResultSerializer, SPSTagTs...>;
531 WFAHH::applyAsync(std::forward<HandlerT>(Handler),
532 std::forward<SendResultT>(SendResult), ArgData, ArgSize);
533 }
534
535private:
536 template <typename T> static const T &makeSerializable(const T &Value) {
537 return Value;
538 }
539
540 static detail::SPSSerializableError makeSerializable(Error Err) {
541 return detail::toSPSSerializable(std::move(Err));
542 }
543
544 template <typename T>
545 static detail::SPSSerializableExpected<T> makeSerializable(Expected<T> E) {
546 return detail::toSPSSerializable(std::move(E));
547 }
548};
549
550template <typename... SPSTagTs>
551class WrapperFunction<void(SPSTagTs...)>
552 : private WrapperFunction<SPSEmpty(SPSTagTs...)> {
553
554public:
555 template <typename CallerFn, typename... ArgTs>
556 static Error call(const CallerFn &Caller, const ArgTs &...Args) {
557 SPSEmpty BE;
558 return WrapperFunction<SPSEmpty(SPSTagTs...)>::call(Caller, BE, Args...);
559 }
560
561 template <typename AsyncCallerFn, typename SendDeserializedResultFn,
562 typename... ArgTs>
563 static void callAsync(AsyncCallerFn &&Caller,
564 SendDeserializedResultFn &&SendDeserializedResult,
565 const ArgTs &...Args) {
566 WrapperFunction<SPSEmpty(SPSTagTs...)>::callAsync(
567 std::forward<AsyncCallerFn>(Caller),
568 [SDR = std::move(SendDeserializedResult)](Error SerializeErr,
569 SPSEmpty E) mutable {
570 SDR(std::move(SerializeErr));
571 },
572 Args...);
573 }
574
575 using WrapperFunction<SPSEmpty(SPSTagTs...)>::handle;
576 using WrapperFunction<SPSEmpty(SPSTagTs...)>::handleAsync;
577};
578
579/// A function object that takes an ExecutorAddr as its first argument,
580/// casts that address to a ClassT*, then calls the given method on that
581/// pointer passing in the remaining function arguments. This utility
582/// removes some of the boilerplate from writing wrappers for method calls.
583///
584/// @code{.cpp}
585/// class MyClass {
586/// public:
587/// void myMethod(uint32_t, bool) { ... }
588/// };
589///
590/// // SPS Method signature -- note MyClass object address as first argument.
591/// using SPSMyMethodWrapperSignature =
592/// SPSTuple<SPSExecutorAddr, uint32_t, bool>;
593///
594/// WrapperFunctionResult
595/// myMethodCallWrapper(const char *ArgData, size_t ArgSize) {
596/// return WrapperFunction<SPSMyMethodWrapperSignature>::handle(
597/// ArgData, ArgSize, makeMethodWrapperHandler(&MyClass::myMethod));
598/// }
599/// @endcode
600///
601template <typename RetT, typename ClassT, typename... ArgTs>
602class MethodWrapperHandler {
603public:
604 using MethodT = RetT (ClassT::*)(ArgTs...);
605 MethodWrapperHandler(MethodT M) : M(M) {}
606 RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args) {
607 return (ObjAddr.toPtr<ClassT*>()->*M)(std::forward<ArgTs>(Args)...);
608 }
609
610private:
611 MethodT M;
612};
613
614/// Create a MethodWrapperHandler object from the given method pointer.
615template <typename RetT, typename ClassT, typename... ArgTs>
616MethodWrapperHandler<RetT, ClassT, ArgTs...>
617makeMethodWrapperHandler(RetT (ClassT::*Method)(ArgTs...)) {
618 return MethodWrapperHandler<RetT, ClassT, ArgTs...>(Method);
619}
620
621/// Represents a serialized wrapper function call.
622/// Serializing calls themselves allows us to batch them: We can make one
623/// "run-wrapper-functions" utility and send it a list of calls to run.
624///
625/// The motivating use-case for this API is JITLink allocation actions, where
626/// we want to run multiple functions to finalize linked memory without having
627/// to make separate IPC calls for each one.
628class WrapperFunctionCall {
629public:
630 using ArgDataBufferType = SmallVector<char, 24>;
631
632 /// Create a WrapperFunctionCall using the given SPS serializer to serialize
633 /// the arguments.
634 template <typename SPSSerializer, typename... ArgTs>
635 static Expected<WrapperFunctionCall> Create(ExecutorAddr FnAddr,
636 const ArgTs &...Args) {
637 ArgDataBufferType ArgData;
638 ArgData.resize(SPSSerializer::size(Args...));
639 SPSOutputBuffer OB(&ArgData[0], ArgData.size());
640 if (SPSSerializer::serialize(OB, Args...))
641 return WrapperFunctionCall(FnAddr, std::move(ArgData));
642 return make_error<StringError>("Cannot serialize arguments for "
643 "AllocActionCall",
644 inconvertibleErrorCode());
645 }
646
647 WrapperFunctionCall() = default;
648
649 /// Create a WrapperFunctionCall from a target function and arg buffer.
650 WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData)
651 : FnAddr(FnAddr), ArgData(std::move(ArgData)) {}
652
653 /// Returns the address to be called.
654 const ExecutorAddr &getCallee() const { return FnAddr; }
655
656 /// Returns the argument data.
657 const ArgDataBufferType &getArgData() const { return ArgData; }
658
659 /// WrapperFunctionCalls convert to true if the callee is non-null.
660 explicit operator bool() const { return !!FnAddr; }
661
662 /// Run call returning raw WrapperFunctionResult.
663 shared::WrapperFunctionResult run() const {
664 using FnTy =
665 shared::CWrapperFunctionResult(const char *ArgData, size_t ArgSize);
666 return shared::WrapperFunctionResult(
667 FnAddr.toPtr<FnTy *>()(ArgData.data(), ArgData.size()));
668 }
669
670 /// Run call and deserialize result using SPS.
671 template <typename SPSRetT, typename RetT>
672 std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error>
673 runWithSPSRet(RetT &RetVal) const {
674 auto WFR = run();
675 if (const char *ErrMsg = WFR.getOutOfBandError())
676 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
677 shared::SPSInputBuffer IB(WFR.data(), WFR.size());
678 if (!shared::SPSSerializationTraits<SPSRetT, RetT>::deserialize(IB, RetVal))
679 return make_error<StringError>("Could not deserialize result from "
680 "serialized wrapper function call",
681 inconvertibleErrorCode());
682 return Error::success();
683 }
684
685 /// Overload for SPS functions returning void.
686 template <typename SPSRetT>
687 std::enable_if_t<std::is_same<SPSRetT, void>::value, Error>
688 runWithSPSRet() const {
689 shared::SPSEmpty E;
690 return runWithSPSRet<shared::SPSEmpty>(E);
691 }
692
693 /// Run call and deserialize an SPSError result. SPSError returns and
694 /// deserialization failures are merged into the returned error.
695 Error runWithSPSRetErrorMerged() const {
696 detail::SPSSerializableError RetErr;
697 if (auto Err = runWithSPSRet<SPSError>(RetErr))
698 return Err;
699 return detail::fromSPSSerializable(std::move(RetErr));
700 }
701
702private:
703 orc::ExecutorAddr FnAddr;
704 ArgDataBufferType ArgData;
705};
706
707using SPSWrapperFunctionCall = SPSTuple<SPSExecutorAddr, SPSSequence<char>>;
708
709template <>
710class SPSSerializationTraits<SPSWrapperFunctionCall, WrapperFunctionCall> {
711public:
712 static size_t size(const WrapperFunctionCall &WFC) {
713 return SPSWrapperFunctionCall::AsArgList::size(WFC.getCallee(),
714 WFC.getArgData());
715 }
716
717 static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC) {
718 return SPSWrapperFunctionCall::AsArgList::serialize(OB, WFC.getCallee(),
719 WFC.getArgData());
720 }
721
722 static bool deserialize(SPSInputBuffer &IB, WrapperFunctionCall &WFC) {
723 ExecutorAddr FnAddr;
724 WrapperFunctionCall::ArgDataBufferType ArgData;
725 if (!SPSWrapperFunctionCall::AsArgList::deserialize(IB, FnAddr, ArgData))
726 return false;
727 WFC = WrapperFunctionCall(FnAddr, std::move(ArgData));
728 return true;
729 }
730};
731
732} // end namespace shared
733} // end namespace orc
734} // end namespace llvm
735
736#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H

/build/llvm-toolchain-snapshot-14~++20220116100644+5f782d25a742/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/STLExtras.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/StringExtras.h"
20#include "llvm/ADT/Twine.h"
21#include "llvm/Config/abi-breaking.h"
22#include "llvm/Support/AlignOf.h"
23#include "llvm/Support/Compiler.h"
24#include "llvm/Support/Debug.h"
25#include "llvm/Support/ErrorHandling.h"
26#include "llvm/Support/ErrorOr.h"
27#include "llvm/Support/Format.h"
28#include "llvm/Support/raw_ostream.h"
29#include <algorithm>
30#include <cassert>
31#include <cstdint>
32#include <cstdlib>
33#include <functional>
34#include <memory>
35#include <new>
36#include <string>
37#include <system_error>
38#include <type_traits>
39#include <utility>
40#include <vector>
41
42namespace llvm {
43
44class ErrorSuccess;
45
46/// Base class for error info classes. Do not extend this directly: Extend
47/// the ErrorInfo template subclass instead.
48class ErrorInfoBase {
49public:
50 virtual ~ErrorInfoBase() = default;
51
52 /// Print an error message to an output stream.
53 virtual void log(raw_ostream &OS) const = 0;
54
55 /// Return the error message as a string.
56 virtual std::string message() const {
57 std::string Msg;
58 raw_string_ostream OS(Msg);
59 log(OS);
60 return OS.str();
61 }
62
63 /// Convert this error to a std::error_code.
64 ///
65 /// This is a temporary crutch to enable interaction with code still
66 /// using std::error_code. It will be removed in the future.
67 virtual std::error_code convertToErrorCode() const = 0;
68
69 // Returns the class ID for this type.
70 static const void *classID() { return &ID; }
71
72 // Returns the class ID for the dynamic type of this ErrorInfoBase instance.
73 virtual const void *dynamicClassID() const = 0;
74
75 // Check whether this instance is a subclass of the class identified by
76 // ClassID.
77 virtual bool isA(const void *const ClassID) const {
78 return ClassID == classID();
79 }
80
81 // Check whether this instance is a subclass of ErrorInfoT.
82 template <typename ErrorInfoT> bool isA() const {
83 return isA(ErrorInfoT::classID());
84 }
85
86private:
87 virtual void anchor();
88
89 static char ID;
90};
91
92/// Lightweight error class with error context and mandatory checking.
93///
94/// Instances of this class wrap a ErrorInfoBase pointer. Failure states
95/// are represented by setting the pointer to a ErrorInfoBase subclass
96/// instance containing information describing the failure. Success is
97/// represented by a null pointer value.
98///
99/// Instances of Error also contains a 'Checked' flag, which must be set
100/// before the destructor is called, otherwise the destructor will trigger a
101/// runtime error. This enforces at runtime the requirement that all Error
102/// instances be checked or returned to the caller.
103///
104/// There are two ways to set the checked flag, depending on what state the
105/// Error instance is in. For Error instances indicating success, it
106/// is sufficient to invoke the boolean conversion operator. E.g.:
107///
108/// @code{.cpp}
109/// Error foo(<...>);
110///
111/// if (auto E = foo(<...>))
112/// return E; // <- Return E if it is in the error state.
113/// // We have verified that E was in the success state. It can now be safely
114/// // destroyed.
115/// @endcode
116///
117/// A success value *can not* be dropped. For example, just calling 'foo(<...>)'
118/// without testing the return value will raise a runtime error, even if foo
119/// returns success.
120///
121/// For Error instances representing failure, you must use either the
122/// handleErrors or handleAllErrors function with a typed handler. E.g.:
123///
124/// @code{.cpp}
125/// class MyErrorInfo : public ErrorInfo<MyErrorInfo> {
126/// // Custom error info.
127/// };
128///
129/// Error foo(<...>) { return make_error<MyErrorInfo>(...); }
130///
131/// auto E = foo(<...>); // <- foo returns failure with MyErrorInfo.
132/// auto NewE =
133/// handleErrors(E,
134/// [](const MyErrorInfo &M) {
135/// // Deal with the error.
136/// },
137/// [](std::unique_ptr<OtherError> M) -> Error {
138/// if (canHandle(*M)) {
139/// // handle error.
140/// return Error::success();
141/// }
142/// // Couldn't handle this error instance. Pass it up the stack.
143/// return Error(std::move(M));
144/// );
145/// // Note - we must check or return NewE in case any of the handlers
146/// // returned a new error.
147/// @endcode
148///
149/// The handleAllErrors function is identical to handleErrors, except
150/// that it has a void return type, and requires all errors to be handled and
151/// no new errors be returned. It prevents errors (assuming they can all be
152/// handled) from having to be bubbled all the way to the top-level.
153///
154/// *All* Error instances must be checked before destruction, even if
155/// they're moved-assigned or constructed from Success values that have already
156/// been checked. This enforces checking through all levels of the call stack.
157class LLVM_NODISCARD[[clang::warn_unused_result]] Error {
158 // ErrorList needs to be able to yank ErrorInfoBase pointers out of Errors
159 // to add to the error list. It can't rely on handleErrors for this, since
160 // handleErrors does not support ErrorList handlers.
161 friend class ErrorList;
162
163 // handleErrors needs to be able to set the Checked flag.
164 template <typename... HandlerTs>
165 friend Error handleErrors(Error E, HandlerTs &&... Handlers);
166
167 // Expected<T> needs to be able to steal the payload when constructed from an
168 // error.
169 template <typename T> friend class Expected;
170
171 // wrap needs to be able to steal the payload.
172 friend LLVMErrorRef wrap(Error);
173
174protected:
175 /// Create a success value. Prefer using 'Error::success()' for readability
176 Error() {
177 setPtr(nullptr);
178 setChecked(false);
179 }
180
181public:
182 /// Create a success value.
183 static ErrorSuccess success();
184
185 // Errors are not copy-constructable.
186 Error(const Error &Other) = delete;
187
188 /// Move-construct an error value. The newly constructed error is considered
189 /// unchecked, even if the source error had been checked. The original error
190 /// becomes a checked Success value, regardless of its original state.
191 Error(Error &&Other) {
192 setChecked(true);
193 *this = std::move(Other);
16
Object 'ErrResult' is moved
194 }
195
196 /// Create an error value. Prefer using the 'make_error' function, but
197 /// this constructor can be useful when "re-throwing" errors from handlers.
198 Error(std::unique_ptr<ErrorInfoBase> Payload) {
199 setPtr(Payload.release());
200 setChecked(false);
201 }
202
203 // Errors are not copy-assignable.
204 Error &operator=(const Error &Other) = delete;
205
206 /// Move-assign an error value. The current error must represent success, you
207 /// you cannot overwrite an unhandled error. The current error is then
208 /// considered unchecked. The source error becomes a checked success value,
209 /// regardless of its original state.
210 Error &operator=(Error &&Other) {
211 // Don't allow overwriting of unchecked values.
212 assertIsChecked();
213 setPtr(Other.getPtr());
214
215 // This Error is unchecked, even if the source error was checked.
216 setChecked(false);
217
218 // Null out Other's payload and set its checked bit.
219 Other.setPtr(nullptr);
220 Other.setChecked(true);
221
222 return *this;
223 }
224
225 /// Destroy a Error. Fails with a call to abort() if the error is
226 /// unchecked.
227 ~Error() {
228 assertIsChecked();
229 delete getPtr();
230 }
231
232 /// Bool conversion. Returns true if this Error is in a failure state,
233 /// and false if it is in an accept state. If the error is in a Success state
234 /// it will be considered checked.
235 explicit operator bool() {
236 setChecked(getPtr() == nullptr);
237 return getPtr() != nullptr;
238 }
239
240 /// Check whether one error is a subclass of another.
241 template <typename ErrT> bool isA() const {
242 return getPtr() && getPtr()->isA(ErrT::classID());
243 }
244
245 /// Returns the dynamic class id of this error, or null if this is a success
246 /// value.
247 const void* dynamicClassID() const {
248 if (!getPtr())
249 return nullptr;
250 return getPtr()->dynamicClassID();
251 }
252
253private:
254#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
255 // assertIsChecked() happens very frequently, but under normal circumstances
256 // is supposed to be a no-op. So we want it to be inlined, but having a bunch
257 // of debug prints can cause the function to be too large for inlining. So
258 // it's important that we define this function out of line so that it can't be
259 // inlined.
260 [[noreturn]] void fatalUncheckedError() const;
261#endif
262
263 void assertIsChecked() {
264#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
265 if (LLVM_UNLIKELY(!getChecked() || getPtr())__builtin_expect((bool)(!getChecked() || getPtr()), false))
266 fatalUncheckedError();
267#endif
268 }
269
270 ErrorInfoBase *getPtr() const {
271#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
272 return reinterpret_cast<ErrorInfoBase*>(
273 reinterpret_cast<uintptr_t>(Payload) &
274 ~static_cast<uintptr_t>(0x1));
275#else
276 return Payload;
277#endif
278 }
279
280 void setPtr(ErrorInfoBase *EI) {
281#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
282 Payload = reinterpret_cast<ErrorInfoBase*>(
283 (reinterpret_cast<uintptr_t>(EI) &
284 ~static_cast<uintptr_t>(0x1)) |
285 (reinterpret_cast<uintptr_t>(Payload) & 0x1));
286#else
287 Payload = EI;
288#endif
289 }
290
291 bool getChecked() const {
292#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
293 return (reinterpret_cast<uintptr_t>(Payload) & 0x1) == 0;
294#else
295 return true;
296#endif
297 }
298
299 void setChecked(bool V) {
300#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
301 Payload = reinterpret_cast<ErrorInfoBase*>(
302 (reinterpret_cast<uintptr_t>(Payload) &
303 ~static_cast<uintptr_t>(0x1)) |
304 (V ? 0 : 1));
305#endif
306 }
307
308 std::unique_ptr<ErrorInfoBase> takePayload() {
309 std::unique_ptr<ErrorInfoBase> Tmp(getPtr());
310 setPtr(nullptr);
311 setChecked(true);
312 return Tmp;
313 }
314
315 friend raw_ostream &operator<<(raw_ostream &OS, const Error &E) {
316 if (auto *P = E.getPtr())
317 P->log(OS);
318 else
319 OS << "success";
320 return OS;
321 }
322
323 ErrorInfoBase *Payload = nullptr;
324};
325
326/// Subclass of Error for the sole purpose of identifying the success path in
327/// the type system. This allows to catch invalid conversion to Expected<T> at
328/// compile time.
329class ErrorSuccess final : public Error {};
330
331inline ErrorSuccess Error::success() { return ErrorSuccess(); }
332
333/// Make a Error instance representing failure using the given error info
334/// type.
335template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) {
336 return Error(std::make_unique<ErrT>(std::forward<ArgTs>(Args)...));
337}
338
339/// Base class for user error types. Users should declare their error types
340/// like:
341///
342/// class MyError : public ErrorInfo<MyError> {
343/// ....
344/// };
345///
346/// This class provides an implementation of the ErrorInfoBase::kind
347/// method, which is used by the Error RTTI system.
348template <typename ThisErrT, typename ParentErrT = ErrorInfoBase>
349class ErrorInfo : public ParentErrT {
350public:
351 using ParentErrT::ParentErrT; // inherit constructors
352
353 static const void *classID() { return &ThisErrT::ID; }
354
355 const void *dynamicClassID() const override { return &ThisErrT::ID; }
356
357 bool isA(const void *const ClassID) const override {
358 return ClassID == classID() || ParentErrT::isA(ClassID);
359 }
360};
361
362/// Special ErrorInfo subclass representing a list of ErrorInfos.
363/// Instances of this class are constructed by joinError.
364class ErrorList final : public ErrorInfo<ErrorList> {
365 // handleErrors needs to be able to iterate the payload list of an
366 // ErrorList.
367 template <typename... HandlerTs>
368 friend Error handleErrors(Error E, HandlerTs &&... Handlers);
369
370 // joinErrors is implemented in terms of join.
371 friend Error joinErrors(Error, Error);
372
373public:
374 void log(raw_ostream &OS) const override {
375 OS << "Multiple errors:\n";
376 for (const auto &ErrPayload : Payloads) {
377 ErrPayload->log(OS);
378 OS << "\n";
379 }
380 }
381
382 std::error_code convertToErrorCode() const override;
383
384 // Used by ErrorInfo::classID.
385 static char ID;
386
387private:
388 ErrorList(std::unique_ptr<ErrorInfoBase> Payload1,
389 std::unique_ptr<ErrorInfoBase> Payload2) {
390 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", 391, __extension__ __PRETTY_FUNCTION__
))
391 "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", 391, __extension__ __PRETTY_FUNCTION__
))
;
392 Payloads.push_back(std::move(Payload1));
393 Payloads.push_back(std::move(Payload2));
394 }
395
396 static Error join(Error E1, Error E2) {
397 if (!E1)
398 return E2;
399 if (!E2)
400 return E1;
401 if (E1.isA<ErrorList>()) {
402 auto &E1List = static_cast<ErrorList &>(*E1.getPtr());
403 if (E2.isA<ErrorList>()) {
404 auto E2Payload = E2.takePayload();
405 auto &E2List = static_cast<ErrorList &>(*E2Payload);
406 for (auto &Payload : E2List.Payloads)
407 E1List.Payloads.push_back(std::move(Payload));
408 } else
409 E1List.Payloads.push_back(E2.takePayload());
410
411 return E1;
412 }
413 if (E2.isA<ErrorList>()) {
414 auto &E2List = static_cast<ErrorList &>(*E2.getPtr());
415 E2List.Payloads.insert(E2List.Payloads.begin(), E1.takePayload());
416 return E2;
417 }
418 return Error(std::unique_ptr<ErrorList>(
419 new ErrorList(E1.takePayload(), E2.takePayload())));
420 }
421
422 std::vector<std::unique_ptr<ErrorInfoBase>> Payloads;
423};
424
425/// Concatenate errors. The resulting Error is unchecked, and contains the
426/// ErrorInfo(s), if any, contained in E1, followed by the
427/// ErrorInfo(s), if any, contained in E2.
428inline Error joinErrors(Error E1, Error E2) {
429 return ErrorList::join(std::move(E1), std::move(E2));
430}
431
432/// Tagged union holding either a T or a Error.
433///
434/// This class parallels ErrorOr, but replaces error_code with Error. Since
435/// Error cannot be copied, this class replaces getError() with
436/// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the
437/// error class type.
438///
439/// Example usage of 'Expected<T>' as a function return type:
440///
441/// @code{.cpp}
442/// Expected<int> myDivide(int A, int B) {
443/// if (B == 0) {
444/// // return an Error
445/// return createStringError(inconvertibleErrorCode(),
446/// "B must not be zero!");
447/// }
448/// // return an integer
449/// return A / B;
450/// }
451/// @endcode
452///
453/// Checking the results of to a function returning 'Expected<T>':
454/// @code{.cpp}
455/// if (auto E = Result.takeError()) {
456/// // We must consume the error. Typically one of:
457/// // - return the error to our caller
458/// // - toString(), when logging
459/// // - consumeError(), to silently swallow the error
460/// // - handleErrors(), to distinguish error types
461/// errs() << "Problem with division " << toString(std::move(E)) << "\n";
462/// return;
463/// }
464/// // use the result
465/// outs() << "The answer is " << *Result << "\n";
466/// @endcode
467///
468/// For unit-testing a function returning an 'Expceted<T>', see the
469/// 'EXPECT_THAT_EXPECTED' macros in llvm/Testing/Support/Error.h
470
471template <class T> class LLVM_NODISCARD[[clang::warn_unused_result]] Expected {
472 template <class T1> friend class ExpectedAsOutParameter;
473 template <class OtherT> friend class Expected;
474
475 static constexpr bool isRef = std::is_reference<T>::value;
476
477 using wrap = std::reference_wrapper<std::remove_reference_t<T>>;
478
479 using error_type = std::unique_ptr<ErrorInfoBase>;
480
481public:
482 using storage_type = std::conditional_t<isRef, wrap, T>;
483 using value_type = T;
484
485private:
486 using reference = std::remove_reference_t<T> &;
487 using const_reference = const std::remove_reference_t<T> &;
488 using pointer = std::remove_reference_t<T> *;
489 using const_pointer = const std::remove_reference_t<T> *;
490
491public:
492 /// Create an Expected<T> error value from the given Error.
493 Expected(Error Err)
494 : HasError(true)
495#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
496 // Expected is unchecked upon construction in Debug builds.
497 , Unchecked(true)
498#endif
499 {
500 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", 500, __extension__ __PRETTY_FUNCTION__
))
;
501 new (getErrorStorage()) error_type(Err.takePayload());
502 }
503
504 /// Forbid to convert from Error::success() implicitly, this avoids having
505 /// Expected<T> foo() { return Error::success(); } which compiles otherwise
506 /// but triggers the assertion above.
507 Expected(ErrorSuccess) = delete;
508
509 /// Create an Expected<T> success value from the given OtherT value, which
510 /// must be convertible to T.
511 template <typename OtherT>
512 Expected(OtherT &&Val,
513 std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr)
514 : HasError(false)
515#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
516 // Expected is unchecked upon construction in Debug builds.
517 ,
518 Unchecked(true)
519#endif
520 {
521 new (getStorage()) storage_type(std::forward<OtherT>(Val));
522 }
523
524 /// Move construct an Expected<T> value.
525 Expected(Expected &&Other) { moveConstruct(std::move(Other)); }
526
527 /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
528 /// must be convertible to T.
529 template <class OtherT>
530 Expected(
531 Expected<OtherT> &&Other,
532 std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) {
533 moveConstruct(std::move(Other));
534 }
535
536 /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
537 /// isn't convertible to T.
538 template <class OtherT>
539 explicit Expected(
540 Expected<OtherT> &&Other,
541 std::enable_if_t<!std::is_convertible<OtherT, T>::value> * = nullptr) {
542 moveConstruct(std::move(Other));
543 }
544
545 /// Move-assign from another Expected<T>.
546 Expected &operator=(Expected &&Other) {
547 moveAssign(std::move(Other));
548 return *this;
549 }
550
551 /// Destroy an Expected<T>.
552 ~Expected() {
553 assertIsChecked();
554 if (!HasError)
555 getStorage()->~storage_type();
556 else
557 getErrorStorage()->~error_type();
558 }
559
560 /// Return false if there is an error.
561 explicit operator bool() {
562#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
563 Unchecked = HasError;
564#endif
565 return !HasError;
566 }
567
568 /// Returns a reference to the stored T value.
569 reference get() {
570 assertIsChecked();
571 return *getStorage();
572 }
573
574 /// Returns a const reference to the stored T value.
575 const_reference get() const {
576 assertIsChecked();
577 return const_cast<Expected<T> *>(this)->get();
578 }
579
580 /// Returns \a takeError() after moving the held T (if any) into \p V.
581 template <class OtherT>
582 Error moveInto(OtherT &Value,
583 std::enable_if_t<std::is_assignable<OtherT &, T &&>::value> * =
584 nullptr) && {
585 if (*this)
586 Value = std::move(get());
587 return takeError();
588 }
589
590 /// Check that this Expected<T> is an error of type ErrT.
591 template <typename ErrT> bool errorIsA() const {
592 return HasError && (*getErrorStorage())->template isA<ErrT>();
593 }
594
595 /// Take ownership of the stored error.
596 /// After calling this the Expected<T> is in an indeterminate state that can
597 /// only be safely destructed. No further calls (beside the destructor) should
598 /// be made on the Expected<T> value.
599 Error takeError() {
600#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
601 Unchecked = false;
602#endif
603 return HasError ? Error(std::move(*getErrorStorage())) : Error::success();
604 }
605
606 /// Returns a pointer to the stored T value.
607 pointer operator->() {
608 assertIsChecked();
609 return toPointer(getStorage());
610 }
611
612 /// Returns a const pointer to the stored T value.
613 const_pointer operator->() const {
614 assertIsChecked();
615 return toPointer(getStorage());
616 }
617
618 /// Returns a reference to the stored T value.
619 reference operator*() {
620 assertIsChecked();
621 return *getStorage();
622 }
623
624 /// Returns a const reference to the stored T value.
625 const_reference operator*() const {
626 assertIsChecked();
627 return *getStorage();
628 }
629
630private:
631 template <class T1>
632 static bool compareThisIfSameType(const T1 &a, const T1 &b) {
633 return &a == &b;
634 }
635
636 template <class T1, class T2>
637 static bool compareThisIfSameType(const T1 &, const T2 &) {
638 return false;
639 }
640
641 template <class OtherT> void moveConstruct(Expected<OtherT> &&Other) {
642 HasError = Other.HasError;
643#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
644 Unchecked = true;
645 Other.Unchecked = false;
646#endif
647
648 if (!HasError)
649 new (getStorage()) storage_type(std::move(*Other.getStorage()));
650 else
651 new (getErrorStorage()) error_type(std::move(*Other.getErrorStorage()));
652 }
653
654 template <class OtherT> void moveAssign(Expected<OtherT> &&Other) {
655 assertIsChecked();
656
657 if (compareThisIfSameType(*this, Other))
658 return;
659
660 this->~Expected();
661 new (this) Expected(std::move(Other));
662 }
663
664 pointer toPointer(pointer Val) { return Val; }
665
666 const_pointer toPointer(const_pointer Val) const { return Val; }
667
668 pointer toPointer(wrap *Val) { return &Val->get(); }
669
670 const_pointer toPointer(const wrap *Val) const { return &Val->get(); }
671
672 storage_type *getStorage() {
673 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", 673, __extension__ __PRETTY_FUNCTION__
))
;
674 return reinterpret_cast<storage_type *>(&TStorage);
675 }
676
677 const storage_type *getStorage() const {
678 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", 678, __extension__ __PRETTY_FUNCTION__
))
;
679 return reinterpret_cast<const storage_type *>(&TStorage);
680 }
681
682 error_type *getErrorStorage() {
683 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", 683, __extension__ __PRETTY_FUNCTION__
))
;
684 return reinterpret_cast<error_type *>(&ErrorStorage);
685 }
686
687 const error_type *getErrorStorage() const {
688 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", 688, __extension__ __PRETTY_FUNCTION__
))
;
689 return reinterpret_cast<const error_type *>(&ErrorStorage);
690 }
691
692 // Used by ExpectedAsOutParameter to reset the checked flag.
693 void setUnchecked() {
694#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
695 Unchecked = true;
696#endif
697 }
698
699#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
700 [[noreturn]] LLVM_ATTRIBUTE_NOINLINE__attribute__((noinline)) void fatalUncheckedExpected() const {
701 dbgs() << "Expected<T> must be checked before access or destruction.\n";
702 if (HasError) {
703 dbgs() << "Unchecked Expected<T> contained error:\n";
704 (*getErrorStorage())->log(dbgs());
705 } else
706 dbgs() << "Expected<T> value was in success state. (Note: Expected<T> "
707 "values in success mode must still be checked prior to being "
708 "destroyed).\n";
709 abort();
710 }
711#endif
712
713 void assertIsChecked() const {
714#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
715 if (LLVM_UNLIKELY(Unchecked)__builtin_expect((bool)(Unchecked), false))
716 fatalUncheckedExpected();
717#endif
718 }
719
720 union {
721 AlignedCharArrayUnion<storage_type> TStorage;
722 AlignedCharArrayUnion<error_type> ErrorStorage;
723 };
724 bool HasError : 1;
725#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
726 bool Unchecked : 1;
727#endif
728};
729
730/// Report a serious error, calling any installed error handler. See
731/// ErrorHandling.h.
732[[noreturn]] void report_fatal_error(Error Err, bool gen_crash_diag = true);
733
734/// Report a fatal error if Err is a failure value.
735///
736/// This function can be used to wrap calls to fallible functions ONLY when it
737/// is known that the Error will always be a success value. E.g.
738///
739/// @code{.cpp}
740/// // foo only attempts the fallible operation if DoFallibleOperation is
741/// // true. If DoFallibleOperation is false then foo always returns
742/// // Error::success().
743/// Error foo(bool DoFallibleOperation);
744///
745/// cantFail(foo(false));
746/// @endcode
747inline void cantFail(Error Err, const char *Msg = nullptr) {
748 if (Err) {
749 if (!Msg)
750 Msg = "Failure value returned from cantFail wrapped call";
751#ifndef NDEBUG
752 std::string Str;
753 raw_string_ostream OS(Str);
754 OS << Msg << "\n" << Err;
755 Msg = OS.str().c_str();
756#endif
757 llvm_unreachable(Msg)::llvm::llvm_unreachable_internal(Msg, "llvm/include/llvm/Support/Error.h"
, 757)
;
758 }
759}
760
761/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
762/// returns the contained value.
763///
764/// This function can be used to wrap calls to fallible functions ONLY when it
765/// is known that the Error will always be a success value. E.g.
766///
767/// @code{.cpp}
768/// // foo only attempts the fallible operation if DoFallibleOperation is
769/// // true. If DoFallibleOperation is false then foo always returns an int.
770/// Expected<int> foo(bool DoFallibleOperation);
771///
772/// int X = cantFail(foo(false));
773/// @endcode
774template <typename T>
775T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) {
776 if (ValOrErr)
777 return std::move(*ValOrErr);
778 else {
779 if (!Msg)
780 Msg = "Failure value returned from cantFail wrapped call";
781#ifndef NDEBUG
782 std::string Str;
783 raw_string_ostream OS(Str);
784 auto E = ValOrErr.takeError();
785 OS << Msg << "\n" << E;
786 Msg = OS.str().c_str();
787#endif
788 llvm_unreachable(Msg)::llvm::llvm_unreachable_internal(Msg, "llvm/include/llvm/Support/Error.h"
, 788)
;
789 }
790}
791
792/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
793/// returns the contained reference.
794///
795/// This function can be used to wrap calls to fallible functions ONLY when it
796/// is known that the Error will always be a success value. E.g.
797///
798/// @code{.cpp}
799/// // foo only attempts the fallible operation if DoFallibleOperation is
800/// // true. If DoFallibleOperation is false then foo always returns a Bar&.
801/// Expected<Bar&> foo(bool DoFallibleOperation);
802///
803/// Bar &X = cantFail(foo(false));
804/// @endcode
805template <typename T>
806T& cantFail(Expected<T&> ValOrErr, const char *Msg = nullptr) {
807 if (ValOrErr)
808 return *ValOrErr;
809 else {
810 if (!Msg)
811 Msg = "Failure value returned from cantFail wrapped call";
812#ifndef NDEBUG
813 std::string Str;
814 raw_string_ostream OS(Str);
815 auto E = ValOrErr.takeError();
816 OS << Msg << "\n" << E;
817 Msg = OS.str().c_str();
818#endif
819 llvm_unreachable(Msg)::llvm::llvm_unreachable_internal(Msg, "llvm/include/llvm/Support/Error.h"
, 819)
;
820 }
821}
822
823/// Helper for testing applicability of, and applying, handlers for
824/// ErrorInfo types.
825template <typename HandlerT>
826class ErrorHandlerTraits
827 : public ErrorHandlerTraits<decltype(
828 &std::remove_reference<HandlerT>::type::operator())> {};
829
830// Specialization functions of the form 'Error (const ErrT&)'.
831template <typename ErrT> class ErrorHandlerTraits<Error (&)(ErrT &)> {
832public:
833 static bool appliesTo(const ErrorInfoBase &E) {
834 return E.template isA<ErrT>();
835 }
836
837 template <typename HandlerT>
838 static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
839 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", 839, __extension__ __PRETTY_FUNCTION__
))
;
840 return H(static_cast<ErrT &>(*E));
841 }
842};
843
844// Specialization functions of the form 'void (const ErrT&)'.
845template <typename ErrT> class ErrorHandlerTraits<void (&)(ErrT &)> {
846public:
847 static bool appliesTo(const ErrorInfoBase &E) {
848 return E.template isA<ErrT>();
849 }
850
851 template <typename HandlerT>
852 static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
853 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", 853, __extension__ __PRETTY_FUNCTION__
))
;
854 H(static_cast<ErrT &>(*E));
855 return Error::success();
856 }
857};
858
859/// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'.
860template <typename ErrT>
861class ErrorHandlerTraits<Error (&)(std::unique_ptr<ErrT>)> {
862public:
863 static bool appliesTo(const ErrorInfoBase &E) {
864 return E.template isA<ErrT>();
865 }
866
867 template <typename HandlerT>
868 static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
869 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", 869, __extension__ __PRETTY_FUNCTION__
))
;
870 std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
871 return H(std::move(SubE));
872 }
873};
874
875/// Specialization for functions of the form 'void (std::unique_ptr<ErrT>)'.
876template <typename ErrT>
877class ErrorHandlerTraits<void (&)(std::unique_ptr<ErrT>)> {
878public:
879 static bool appliesTo(const ErrorInfoBase &E) {
880 return E.template isA<ErrT>();
881 }
882
883 template <typename HandlerT>
884 static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
885 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", 885, __extension__ __PRETTY_FUNCTION__
))
;
886 std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
887 H(std::move(SubE));
888 return Error::success();
889 }
890};
891
892// Specialization for member functions of the form 'RetT (const ErrT&)'.
893template <typename C, typename RetT, typename ErrT>
894class ErrorHandlerTraits<RetT (C::*)(ErrT &)>
895 : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
896
897// Specialization for member functions of the form 'RetT (const ErrT&) const'.
898template <typename C, typename RetT, typename ErrT>
899class ErrorHandlerTraits<RetT (C::*)(ErrT &) const>
900 : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
901
902// Specialization for member functions of the form 'RetT (const ErrT&)'.
903template <typename C, typename RetT, typename ErrT>
904class ErrorHandlerTraits<RetT (C::*)(const ErrT &)>
905 : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
906
907// Specialization for member functions of the form 'RetT (const ErrT&) const'.
908template <typename C, typename RetT, typename ErrT>
909class ErrorHandlerTraits<RetT (C::*)(const ErrT &) const>
910 : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
911
912/// Specialization for member functions of the form
913/// 'RetT (std::unique_ptr<ErrT>)'.
914template <typename C, typename RetT, typename ErrT>
915class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>)>
916 : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
917
918/// Specialization for member functions of the form
919/// 'RetT (std::unique_ptr<ErrT>) const'.
920template <typename C, typename RetT, typename ErrT>
921class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>) const>
922 : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
923
924inline Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload) {
925 return Error(std::move(Payload));
926}
927
928template <typename HandlerT, typename... HandlerTs>
929Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload,
930 HandlerT &&Handler, HandlerTs &&... Handlers) {
931 if (ErrorHandlerTraits<HandlerT>::appliesTo(*Payload))
932 return ErrorHandlerTraits<HandlerT>::apply(std::forward<HandlerT>(Handler),
933 std::move(Payload));
934 return handleErrorImpl(std::move(Payload),
935 std::forward<HandlerTs>(Handlers)...);
936}
937
938/// Pass the ErrorInfo(s) contained in E to their respective handlers. Any
939/// unhandled errors (or Errors returned by handlers) are re-concatenated and
940/// returned.
941/// Because this function returns an error, its result must also be checked
942/// or returned. If you intend to handle all errors use handleAllErrors
943/// (which returns void, and will abort() on unhandled errors) instead.
944template <typename... HandlerTs>
945Error handleErrors(Error E, HandlerTs &&... Hs) {
946 if (!E)
947 return Error::success();
948
949 std::unique_ptr<ErrorInfoBase> Payload = E.takePayload();
950
951 if (Payload->isA<ErrorList>()) {
952 ErrorList &List = static_cast<ErrorList &>(*Payload);
953 Error R;
954 for (auto &P : List.Payloads)
955 R = ErrorList::join(
956 std::move(R),
957 handleErrorImpl(std::move(P), std::forward<HandlerTs>(Hs)...));
958 return R;
959 }
960
961 return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...);
962}
963
964/// Behaves the same as handleErrors, except that by contract all errors
965/// *must* be handled by the given handlers (i.e. there must be no remaining
966/// errors after running the handlers, or llvm_unreachable is called).
967template <typename... HandlerTs>
968void handleAllErrors(Error E, HandlerTs &&... Handlers) {
969 cantFail(handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...));
970}
971
972/// Check that E is a non-error, then drop it.
973/// If E is an error, llvm_unreachable will be called.
974inline void handleAllErrors(Error E) {
975 cantFail(std::move(E));
976}
977
978/// Handle any errors (if present) in an Expected<T>, then try a recovery path.
979///
980/// If the incoming value is a success value it is returned unmodified. If it
981/// is a failure value then it the contained error is passed to handleErrors.
982/// If handleErrors is able to handle the error then the RecoveryPath functor
983/// is called to supply the final result. If handleErrors is not able to
984/// handle all errors then the unhandled errors are returned.
985///
986/// This utility enables the follow pattern:
987///
988/// @code{.cpp}
989/// enum FooStrategy { Aggressive, Conservative };
990/// Expected<Foo> foo(FooStrategy S);
991///
992/// auto ResultOrErr =
993/// handleExpected(
994/// foo(Aggressive),
995/// []() { return foo(Conservative); },
996/// [](AggressiveStrategyError&) {
997/// // Implicitly conusme this - we'll recover by using a conservative
998/// // strategy.
999/// });
1000///
1001/// @endcode
1002template <typename T, typename RecoveryFtor, typename... HandlerTs>
1003Expected<T> handleExpected(Expected<T> ValOrErr, RecoveryFtor &&RecoveryPath,
1004 HandlerTs &&... Handlers) {
1005 if (ValOrErr)
1006 return ValOrErr;
1007
1008 if (auto Err = handleErrors(ValOrErr.takeError(),
1009 std::forward<HandlerTs>(Handlers)...))
1010 return std::move(Err);
1011
1012 return RecoveryPath();
1013}
1014
1015/// Log all errors (if any) in E to OS. If there are any errors, ErrorBanner
1016/// will be printed before the first one is logged. A newline will be printed
1017/// after each error.
1018///
1019/// This function is compatible with the helpers from Support/WithColor.h. You
1020/// can pass any of them as the OS. Please consider using them instead of
1021/// including 'error: ' in the ErrorBanner.
1022///
1023/// This is useful in the base level of your program to allow clean termination
1024/// (allowing clean deallocation of resources, etc.), while reporting error
1025/// information to the user.
1026void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner = {});
1027
1028/// Write all error messages (if any) in E to a string. The newline character
1029/// is used to separate error messages.
1030inline std::string toString(Error E) {
1031 SmallVector<std::string, 2> Errors;
1032 handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) {
1033 Errors.push_back(EI.message());
1034 });
1035 return join(Errors.begin(), Errors.end(), "\n");
1036}
1037
1038/// Consume a Error without doing anything. This method should be used
1039/// only where an error can be considered a reasonable and expected return
1040/// value.
1041///
1042/// Uses of this method are potentially indicative of design problems: If it's
1043/// legitimate to do nothing while processing an "error", the error-producer
1044/// might be more clearly refactored to return an Optional<T>.
1045inline void consumeError(Error Err) {
1046 handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {});
1047}
1048
1049/// Convert an Expected to an Optional without doing anything. This method
1050/// should be used only where an error can be considered a reasonable and
1051/// expected return value.
1052///
1053/// Uses of this method are potentially indicative of problems: perhaps the
1054/// error should be propagated further, or the error-producer should just
1055/// return an Optional in the first place.
1056template <typename T> Optional<T> expectedToOptional(Expected<T> &&E) {
1057 if (E)
1058 return std::move(*E);
1059 consumeError(E.takeError());
1060 return None;
1061}
1062
1063/// Helper for converting an Error to a bool.
1064///
1065/// This method returns true if Err is in an error state, or false if it is
1066/// in a success state. Puts Err in a checked state in both cases (unlike
1067/// Error::operator bool(), which only does this for success states).
1068inline bool errorToBool(Error Err) {
1069 bool IsError = static_cast<bool>(Err);
1070 if (IsError)
1071 consumeError(std::move(Err));
1072 return IsError;
1073}
1074
1075/// Helper for Errors used as out-parameters.
1076///
1077/// This helper is for use with the Error-as-out-parameter idiom, where an error
1078/// is passed to a function or method by reference, rather than being returned.
1079/// In such cases it is helpful to set the checked bit on entry to the function
1080/// so that the error can be written to (unchecked Errors abort on assignment)
1081/// and clear the checked bit on exit so that clients cannot accidentally forget
1082/// to check the result. This helper performs these actions automatically using
1083/// RAII:
1084///
1085/// @code{.cpp}
1086/// Result foo(Error &Err) {
1087/// ErrorAsOutParameter ErrAsOutParam(&Err); // 'Checked' flag set
1088/// // <body of foo>
1089/// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed.
1090/// }
1091/// @endcode
1092///
1093/// ErrorAsOutParameter takes an Error* rather than Error& so that it can be
1094/// used with optional Errors (Error pointers that are allowed to be null). If
1095/// ErrorAsOutParameter took an Error reference, an instance would have to be
1096/// created inside every condition that verified that Error was non-null. By
1097/// taking an Error pointer we can just create one instance at the top of the
1098/// function.
1099class ErrorAsOutParameter {
1100public:
1101 ErrorAsOutParameter(Error *Err) : Err(Err) {
1102 // Raise the checked bit if Err is success.
1103 if (Err)
1104 (void)!!*Err;
1105 }
1106
1107 ~ErrorAsOutParameter() {
1108 // Clear the checked bit.
1109 if (Err && !*Err)
1110 *Err = Error::success();
1111 }
1112
1113private:
1114 Error *Err;
1115};
1116
1117/// Helper for Expected<T>s used as out-parameters.
1118///
1119/// See ErrorAsOutParameter.
1120template <typename T>
1121class ExpectedAsOutParameter {
1122public:
1123 ExpectedAsOutParameter(Expected<T> *ValOrErr)
1124 : ValOrErr(ValOrErr) {
1125 if (ValOrErr)
1126 (void)!!*ValOrErr;
1127 }
1128
1129 ~ExpectedAsOutParameter() {
1130 if (ValOrErr)
1131 ValOrErr->setUnchecked();
1132 }
1133
1134private:
1135 Expected<T> *ValOrErr;
1136};
1137
1138/// This class wraps a std::error_code in a Error.
1139///
1140/// This is useful if you're writing an interface that returns a Error
1141/// (or Expected) and you want to call code that still returns
1142/// std::error_codes.
1143class ECError : public ErrorInfo<ECError> {
1144 friend Error errorCodeToError(std::error_code);
1145
1146 virtual void anchor() override;
1147
1148public:
1149 void setErrorCode(std::error_code EC) { this->EC = EC; }
1150 std::error_code convertToErrorCode() const override { return EC; }
1151 void log(raw_ostream &OS) const override { OS << EC.message(); }
1152
1153 // Used by ErrorInfo::classID.
1154 static char ID;
1155
1156protected:
1157 ECError() = default;
1158 ECError(std::error_code EC) : EC(EC) {}
1159
1160 std::error_code EC;
1161};
1162
1163/// The value returned by this function can be returned from convertToErrorCode
1164/// for Error values where no sensible translation to std::error_code exists.
1165/// It should only be used in this situation, and should never be used where a
1166/// sensible conversion to std::error_code is available, as attempts to convert
1167/// to/from this error will result in a fatal error. (i.e. it is a programmatic
1168/// error to try to convert such a value).
1169std::error_code inconvertibleErrorCode();
1170
1171/// Helper for converting an std::error_code to a Error.
1172Error errorCodeToError(std::error_code EC);
1173
1174/// Helper for converting an ECError to a std::error_code.
1175///
1176/// This method requires that Err be Error() or an ECError, otherwise it
1177/// will trigger a call to abort().
1178std::error_code errorToErrorCode(Error Err);
1179
1180/// Convert an ErrorOr<T> to an Expected<T>.
1181template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> &&EO) {
1182 if (auto EC = EO.getError())
1183 return errorCodeToError(EC);
1184 return std::move(*EO);
1185}
1186
1187/// Convert an Expected<T> to an ErrorOr<T>.
1188template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> &&E) {
1189 if (auto Err = E.takeError())
1190 return errorToErrorCode(std::move(Err));
1191 return std::move(*E);
1192}
1193
1194/// This class wraps a string in an Error.
1195///
1196/// StringError is useful in cases where the client is not expected to be able
1197/// to consume the specific error message programmatically (for example, if the
1198/// error message is to be presented to the user).
1199///
1200/// StringError can also be used when additional information is to be printed
1201/// along with a error_code message. Depending on the constructor called, this
1202/// class can either display:
1203/// 1. the error_code message (ECError behavior)
1204/// 2. a string
1205/// 3. the error_code message and a string
1206///
1207/// These behaviors are useful when subtyping is required; for example, when a
1208/// specific library needs an explicit error type. In the example below,
1209/// PDBError is derived from StringError:
1210///
1211/// @code{.cpp}
1212/// Expected<int> foo() {
1213/// return llvm::make_error<PDBError>(pdb_error_code::dia_failed_loading,
1214/// "Additional information");
1215/// }
1216/// @endcode
1217///
1218class StringError : public ErrorInfo<StringError> {
1219public:
1220 static char ID;
1221
1222 // Prints EC + S and converts to EC
1223 StringError(std::error_code EC, const Twine &S = Twine());
1224
1225 // Prints S and converts to EC
1226 StringError(const Twine &S, std::error_code EC);
1227
1228 void log(raw_ostream &OS) const override;
1229 std::error_code convertToErrorCode() const override;
1230
1231 const std::string &getMessage() const { return Msg; }
1232
1233private:
1234 std::string Msg;
1235 std::error_code EC;
1236 const bool PrintMsgOnly = false;
1237};
1238
1239/// Create formatted StringError object.
1240template <typename... Ts>
1241inline Error createStringError(std::error_code EC, char const *Fmt,
1242 const Ts &... Vals) {
1243 std::string Buffer;
1244 raw_string_ostream Stream(Buffer);
1245 Stream << format(Fmt, Vals...);
1246 return make_error<StringError>(Stream.str(), EC);
1247}
1248
1249Error createStringError(std::error_code EC, char const *Msg);
1250
1251inline Error createStringError(std::error_code EC, const Twine &S) {
1252 return createStringError(EC, S.str().c_str());
1253}
1254
1255template <typename... Ts>
1256inline Error createStringError(std::errc EC, char const *Fmt,
1257 const Ts &... Vals) {
1258 return createStringError(std::make_error_code(EC), Fmt, Vals...);
1259}
1260
1261/// This class wraps a filename and another Error.
1262///
1263/// In some cases, an error needs to live along a 'source' name, in order to
1264/// show more detailed information to the user.
1265class FileError final : public ErrorInfo<FileError> {
1266
1267 friend Error createFileError(const Twine &, Error);
1268 friend Error createFileError(const Twine &, size_t, Error);
1269
1270public:
1271 void log(raw_ostream &OS) const override {
1272 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", 1272, __extension__ __PRETTY_FUNCTION__
))
;
1273 OS << "'" << FileName << "': ";
1274 if (Line.hasValue())
1275 OS << "line " << Line.getValue() << ": ";
1276 Err->log(OS);
1277 }
1278
1279 std::string messageWithoutFileInfo() const {
1280 std::string Msg;
1281 raw_string_ostream OS(Msg);
1282 Err->log(OS);
1283 return OS.str();
1284 }
1285
1286 StringRef getFileName() { return FileName; }
1287
1288 Error takeError() { return Error(std::move(Err)); }
1289
1290 std::error_code convertToErrorCode() const override;
1291
1292 // Used by ErrorInfo::classID.
1293 static char ID;
1294
1295private:
1296 FileError(const Twine &F, Optional<size_t> LineNum,
1297 std::unique_ptr<ErrorInfoBase> E) {
1298 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", 1298, __extension__ __PRETTY_FUNCTION__
))
;
1299 FileName = F.str();
1300 Err = std::move(E);
1301 Line = std::move(LineNum);
1302 }
1303
1304 static Error build(const Twine &F, Optional<size_t> Line, Error E) {
1305 std::unique_ptr<ErrorInfoBase> Payload;
1306 handleAllErrors(std::move(E),
1307 [&](std::unique_ptr<ErrorInfoBase> EIB) -> Error {
1308 Payload = std::move(EIB);
1309 return Error::success();
1310 });
1311 return Error(
1312 std::unique_ptr<FileError>(new FileError(F, Line, std::move(Payload))));
1313 }
1314
1315 std::string FileName;
1316 Optional<size_t> Line;
1317 std::unique_ptr<ErrorInfoBase> Err;
1318};
1319
1320/// Concatenate a source file path and/or name with an Error. The resulting
1321/// Error is unchecked.
1322inline Error createFileError(const Twine &F, Error E) {
1323 return FileError::build(F, Optional<size_t>(), std::move(E));
1324}
1325
1326/// Concatenate a source file path and/or name with line number and an Error.
1327/// The resulting Error is unchecked.
1328inline Error createFileError(const Twine &F, size_t Line, Error E) {
1329 return FileError::build(F, Optional<size_t>(Line), std::move(E));
1330}
1331
1332/// Concatenate a source file path and/or name with a std::error_code
1333/// to form an Error object.
1334inline Error createFileError(const Twine &F, std::error_code EC) {
1335 return createFileError(F, errorCodeToError(EC));
1336}
1337
1338/// Concatenate a source file path and/or name with line number and
1339/// std::error_code to form an Error object.
1340inline Error createFileError(const Twine &F, size_t Line, std::error_code EC) {
1341 return createFileError(F, Line, errorCodeToError(EC));
1342}
1343
1344Error createFileError(const Twine &F, ErrorSuccess) = delete;
1345
1346/// Helper for check-and-exit error handling.
1347///
1348/// For tool use only. NOT FOR USE IN LIBRARY CODE.
1349///
1350class ExitOnError {
1351public:
1352 /// Create an error on exit helper.
1353 ExitOnError(std::string Banner = "", int DefaultErrorExitCode = 1)
1354 : Banner(std::move(Banner)),
1355 GetExitCode([=](const Error &) { return DefaultErrorExitCode; }) {}
1356
1357 /// Set the banner string for any errors caught by operator().
1358 void setBanner(std::string Banner) { this->Banner = std::move(Banner); }
1359
1360 /// Set the exit-code mapper function.
1361 void setExitCodeMapper(std::function<int(const Error &)> GetExitCode) {
1362 this->GetExitCode = std::move(GetExitCode);
1363 }
1364
1365 /// Check Err. If it's in a failure state log the error(s) and exit.
1366 void operator()(Error Err) const { checkError(std::move(Err)); }
1367
1368 /// Check E. If it's in a success state then return the contained value. If
1369 /// it's in a failure state log the error(s) and exit.
1370 template <typename T> T operator()(Expected<T> &&E) const {
1371 checkError(E.takeError());
1372 return std::move(*E);
1373 }
1374
1375 /// Check E. If it's in a success state then return the contained reference. If
1376 /// it's in a failure state log the error(s) and exit.
1377 template <typename T> T& operator()(Expected<T&> &&E) const {
1378 checkError(E.takeError());
1379 return *E;
1380 }
1381
1382private:
1383 void checkError(Error Err) const {
1384 if (Err) {
1385 int ExitCode = GetExitCode(Err);
1386 logAllUnhandledErrors(std::move(Err), errs(), Banner);
1387 exit(ExitCode);
1388 }
1389 }
1390
1391 std::string Banner;
1392 std::function<int(const Error &)> GetExitCode;
1393};
1394
1395/// Conversion from Error to LLVMErrorRef for C error bindings.
1396inline LLVMErrorRef wrap(Error Err) {
1397 return reinterpret_cast<LLVMErrorRef>(Err.takePayload().release());
1398}
1399
1400/// Conversion from LLVMErrorRef to Error for C error bindings.
1401inline Error unwrap(LLVMErrorRef ErrRef) {
1402 return Error(std::unique_ptr<ErrorInfoBase>(
1403 reinterpret_cast<ErrorInfoBase *>(ErrRef)));
1404}
1405
1406} // end namespace llvm
1407
1408#endif // LLVM_SUPPORT_ERROR_H