Bug Summary

File:llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
Warning:line 585, 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 MachOPlatform.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 -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~++20211030100902+82ed10656706/build-llvm -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~++20211030100902+82ed10656706/llvm/lib/ExecutionEngine/Orc -I include -I /build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/include -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 -O2 -Wno-unused-command-line-argument -Wno-unknown-warning-option -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~++20211030100902+82ed10656706/build-llvm -ferror-limit 19 -fvisibility-inlines-hidden -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-2021-10-31-051431-21669-1 -x c++ /build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp

/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp

1//===------ MachOPlatform.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/MachOPlatform.h"
10
11#include "llvm/BinaryFormat/MachO.h"
12#include "llvm/ExecutionEngine/JITLink/x86_64.h"
13#include "llvm/ExecutionEngine/Orc/DebugUtils.h"
14#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
15#include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.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 MachOHeaderMaterializationUnit : public MaterializationUnit {
28public:
29 MachOHeaderMaterializationUnit(MachOPlatform &MOP,
30 const SymbolStringPtr &HeaderStartSymbol)
31 : MaterializationUnit(createHeaderSymbols(MOP, HeaderStartSymbol),
32 HeaderStartSymbol),
33 MOP(MOP) {}
34
35 StringRef getName() const override { return "MachOHeaderMU"; }
36
37 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
38 unsigned PointerSize;
39 support::endianness Endianness;
40 const auto &TT =
41 MOP.getExecutionSession().getExecutorProcessControl().getTargetTriple();
42
43 switch (TT.getArch()) {
44 case Triple::aarch64:
45 case Triple::x86_64:
46 PointerSize = 8;
47 Endianness = support::endianness::little;
48 break;
49 default:
50 llvm_unreachable("Unrecognized architecture")::llvm::llvm_unreachable_internal("Unrecognized architecture"
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp"
, 50)
;
51 }
52
53 auto G = std::make_unique<jitlink::LinkGraph>(
54 "<MachOHeaderMU>", TT, PointerSize, Endianness,
55 jitlink::getGenericEdgeKindName);
56 auto &HeaderSection = G->createSection("__header", jitlink::MemProt::Read);
57 auto &HeaderBlock = createHeaderBlock(*G, HeaderSection);
58
59 // Init symbol is header-start symbol.
60 G->addDefinedSymbol(HeaderBlock, 0, *R->getInitializerSymbol(),
61 HeaderBlock.getSize(), jitlink::Linkage::Strong,
62 jitlink::Scope::Default, false, true);
63 for (auto &HS : AdditionalHeaderSymbols)
64 G->addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name,
65 HeaderBlock.getSize(), jitlink::Linkage::Strong,
66 jitlink::Scope::Default, false, true);
67
68 MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
69 }
70
71 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
72
73private:
74 struct HeaderSymbol {
75 const char *Name;
76 uint64_t Offset;
77 };
78
79 static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
80 {"___mh_executable_header", 0}};
81
82 static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G,
83 jitlink::Section &HeaderSection) {
84 MachO::mach_header_64 Hdr;
85 Hdr.magic = MachO::MH_MAGIC_64;
86 switch (G.getTargetTriple().getArch()) {
87 case Triple::aarch64:
88 Hdr.cputype = MachO::CPU_TYPE_ARM64;
89 Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
90 break;
91 case Triple::x86_64:
92 Hdr.cputype = MachO::CPU_TYPE_X86_64;
93 Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
94 break;
95 default:
96 llvm_unreachable("Unrecognized architecture")::llvm::llvm_unreachable_internal("Unrecognized architecture"
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp"
, 96)
;
97 }
98 Hdr.filetype = MachO::MH_DYLIB; // Custom file type?
99 Hdr.ncmds = 0;
100 Hdr.sizeofcmds = 0;
101 Hdr.flags = 0;
102 Hdr.reserved = 0;
103
104 if (G.getEndianness() != support::endian::system_endianness())
105 MachO::swapStruct(Hdr);
106
107 auto HeaderContent = G.allocateString(
108 StringRef(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr)));
109
110 return G.createContentBlock(HeaderSection, HeaderContent, 0, 8, 0);
111 }
112
113 static SymbolFlagsMap
114 createHeaderSymbols(MachOPlatform &MOP,
115 const SymbolStringPtr &HeaderStartSymbol) {
116 SymbolFlagsMap HeaderSymbolFlags;
117
118 HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
119 for (auto &HS : AdditionalHeaderSymbols)
120 HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =
121 JITSymbolFlags::Exported;
122
123 return HeaderSymbolFlags;
124 }
125
126 MachOPlatform &MOP;
127};
128
129constexpr MachOHeaderMaterializationUnit::HeaderSymbol
130 MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[];
131
132StringRef EHFrameSectionName = "__TEXT,__eh_frame";
133StringRef ModInitFuncSectionName = "__DATA,__mod_init_func";
134StringRef ObjCClassListSectionName = "__DATA,__objc_classlist";
135StringRef ObjCImageInfoSectionName = "__DATA,__objc_image_info";
136StringRef ObjCSelRefsSectionName = "__DATA,__objc_selrefs";
137StringRef Swift5ProtoSectionName = "__TEXT,__swift5_proto";
138StringRef Swift5ProtosSectionName = "__TEXT,__swift5_protos";
139StringRef ThreadBSSSectionName = "__DATA,__thread_bss";
140StringRef ThreadDataSectionName = "__DATA,__thread_data";
141StringRef ThreadVarsSectionName = "__DATA,__thread_vars";
142
143StringRef InitSectionNames[] = {
144 ModInitFuncSectionName, ObjCSelRefsSectionName, ObjCClassListSectionName,
145 Swift5ProtosSectionName, Swift5ProtoSectionName};
146
147} // end anonymous namespace
148
149namespace llvm {
150namespace orc {
151
152Expected<std::unique_ptr<MachOPlatform>>
153MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
154 JITDylib &PlatformJD, const char *OrcRuntimePath,
155 Optional<SymbolAliasMap> RuntimeAliases) {
156
157 auto &EPC = ES.getExecutorProcessControl();
158
159 // If the target is not supported then bail out immediately.
160 if (!supportedTarget(EPC.getTargetTriple()))
161 return make_error<StringError>("Unsupported MachOPlatform triple: " +
162 EPC.getTargetTriple().str(),
163 inconvertibleErrorCode());
164
165 // Create default aliases if the caller didn't supply any.
166 if (!RuntimeAliases)
167 RuntimeAliases = standardPlatformAliases(ES);
168
169 // Define the aliases.
170 if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
171 return std::move(Err);
172
173 // Add JIT-dispatch function support symbols.
174 if (auto Err = PlatformJD.define(absoluteSymbols(
175 {{ES.intern("___orc_rt_jit_dispatch"),
176 {EPC.getJITDispatchInfo().JITDispatchFunction.getValue(),
177 JITSymbolFlags::Exported}},
178 {ES.intern("___orc_rt_jit_dispatch_ctx"),
179 {EPC.getJITDispatchInfo().JITDispatchContext.getValue(),
180 JITSymbolFlags::Exported}}})))
181 return std::move(Err);
182
183 // Create a generator for the ORC runtime archive.
184 auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Load(
185 ObjLinkingLayer, OrcRuntimePath, EPC.getTargetTriple());
186 if (!OrcRuntimeArchiveGenerator)
187 return OrcRuntimeArchiveGenerator.takeError();
188
189 // Create the instance.
190 Error Err = Error::success();
191 auto P = std::unique_ptr<MachOPlatform>(
192 new MachOPlatform(ES, ObjLinkingLayer, PlatformJD,
193 std::move(*OrcRuntimeArchiveGenerator), Err));
194 if (Err)
195 return std::move(Err);
196 return std::move(P);
197}
198
199Error MachOPlatform::setupJITDylib(JITDylib &JD) {
200 return JD.define(std::make_unique<MachOHeaderMaterializationUnit>(
201 *this, MachOHeaderStartSymbol));
202}
203
204Error MachOPlatform::notifyAdding(ResourceTracker &RT,
205 const MaterializationUnit &MU) {
206 auto &JD = RT.getJITDylib();
207 const auto &InitSym = MU.getInitializerSymbol();
208 if (!InitSym)
209 return Error::success();
210
211 RegisteredInitSymbols[&JD].add(InitSym,
212 SymbolLookupFlags::WeaklyReferencedSymbol);
213 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Registered init symbol "
<< *InitSym << " for MU " << MU.getName() <<
"\n"; }; } } while (false)
214 dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Registered init symbol "
<< *InitSym << " for MU " << MU.getName() <<
"\n"; }; } } while (false)
215 << MU.getName() << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Registered init symbol "
<< *InitSym << " for MU " << MU.getName() <<
"\n"; }; } } while (false)
216 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Registered init symbol "
<< *InitSym << " for MU " << MU.getName() <<
"\n"; }; } } while (false)
;
217 return Error::success();
218}
219
220Error MachOPlatform::notifyRemoving(ResourceTracker &RT) {
221 llvm_unreachable("Not supported yet")::llvm::llvm_unreachable_internal("Not supported yet", "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp"
, 221)
;
222}
223
224static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
225 ArrayRef<std::pair<const char *, const char *>> AL) {
226 for (auto &KV : AL) {
227 auto AliasName = ES.intern(KV.first);
228 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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp"
, 228, __extension__ __PRETTY_FUNCTION__))
;
229 Aliases[std::move(AliasName)] = {ES.intern(KV.second),
230 JITSymbolFlags::Exported};
231 }
232}
233
234SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) {
235 SymbolAliasMap Aliases;
236 addAliases(ES, Aliases, requiredCXXAliases());
237 addAliases(ES, Aliases, standardRuntimeUtilityAliases());
238 return Aliases;
239}
240
241ArrayRef<std::pair<const char *, const char *>>
242MachOPlatform::requiredCXXAliases() {
243 static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
244 {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}};
245
246 return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
247}
248
249ArrayRef<std::pair<const char *, const char *>>
250MachOPlatform::standardRuntimeUtilityAliases() {
251 static const std::pair<const char *, const char *>
252 StandardRuntimeUtilityAliases[] = {
253 {"___orc_rt_run_program", "___orc_rt_macho_run_program"},
254 {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};
255
256 return ArrayRef<std::pair<const char *, const char *>>(
257 StandardRuntimeUtilityAliases);
258}
259
260bool MachOPlatform::isInitializerSection(StringRef SegName,
261 StringRef SectName) {
262 for (auto &Name : InitSectionNames) {
263 if (Name.startswith(SegName) && Name.substr(7) == SectName)
264 return true;
265 }
266 return false;
267}
268
269bool MachOPlatform::supportedTarget(const Triple &TT) {
270 switch (TT.getArch()) {
271 case Triple::aarch64:
272 case Triple::x86_64:
273 return true;
274 default:
275 return false;
276 }
277}
278
279MachOPlatform::MachOPlatform(
280 ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
281 JITDylib &PlatformJD,
282 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
283 : ES(ES), ObjLinkingLayer(ObjLinkingLayer),
284 MachOHeaderStartSymbol(ES.intern("___dso_handle")) {
285 ErrorAsOutParameter _(&Err);
286
287 ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this));
288
289 PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
290
291 // PlatformJD hasn't been 'set-up' by the platform yet (since we're creating
292 // the platform now), so set it up.
293 if (auto E2 = setupJITDylib(PlatformJD)) {
294 Err = std::move(E2);
295 return;
296 }
297
298 RegisteredInitSymbols[&PlatformJD].add(
299 MachOHeaderStartSymbol, SymbolLookupFlags::WeaklyReferencedSymbol);
300
301 // Associate wrapper function tags with JIT-side function implementations.
302 if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) {
303 Err = std::move(E2);
304 return;
305 }
306
307 // Lookup addresses of runtime functions callable by the platform,
308 // call the platform bootstrap function to initialize the platform-state
309 // object in the executor.
310 if (auto E2 = bootstrapMachORuntime(PlatformJD)) {
311 Err = std::move(E2);
312 return;
313 }
314}
315
316Error MachOPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) {
317 ExecutionSession::JITDispatchHandlerAssociationMap WFs;
318
319 using GetInitializersSPSSig =
320 SPSExpected<SPSMachOJITDylibInitializerSequence>(SPSString);
321 WFs[ES.intern("___orc_rt_macho_get_initializers_tag")] =
322 ES.wrapAsyncWithSPS<GetInitializersSPSSig>(
323 this, &MachOPlatform::rt_getInitializers);
324
325 using GetDeinitializersSPSSig =
326 SPSExpected<SPSMachOJITDylibDeinitializerSequence>(SPSExecutorAddr);
327 WFs[ES.intern("___orc_rt_macho_get_deinitializers_tag")] =
328 ES.wrapAsyncWithSPS<GetDeinitializersSPSSig>(
329 this, &MachOPlatform::rt_getDeinitializers);
330
331 using LookupSymbolSPSSig =
332 SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString);
333 WFs[ES.intern("___orc_rt_macho_symbol_lookup_tag")] =
334 ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
335 &MachOPlatform::rt_lookupSymbol);
336
337 return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
338}
339
340void MachOPlatform::getInitializersBuildSequencePhase(
341 SendInitializerSequenceFn SendResult, JITDylib &JD,
342 std::vector<JITDylibSP> DFSLinkOrder) {
343 MachOJITDylibInitializerSequence FullInitSeq;
344 {
345 std::lock_guard<std::mutex> Lock(PlatformMutex);
346 for (auto &InitJD : reverse(DFSLinkOrder)) {
347 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Appending inits for \""
<< InitJD->getName() << "\" to sequence\n"; }
; } } while (false)
348 dbgs() << "MachOPlatform: Appending inits for \"" << InitJD->getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Appending inits for \""
<< InitJD->getName() << "\" to sequence\n"; }
; } } while (false)
349 << "\" to sequence\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Appending inits for \""
<< InitJD->getName() << "\" to sequence\n"; }
; } } while (false)
350 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Appending inits for \""
<< InitJD->getName() << "\" to sequence\n"; }
; } } while (false)
;
351 auto ISItr = InitSeqs.find(InitJD.get());
352 if (ISItr != InitSeqs.end()) {
353 FullInitSeq.emplace_back(std::move(ISItr->second));
354 InitSeqs.erase(ISItr);
355 }
356 }
357 }
358
359 SendResult(std::move(FullInitSeq));
360}
361
362void MachOPlatform::getInitializersLookupPhase(
363 SendInitializerSequenceFn SendResult, JITDylib &JD) {
364
365 auto DFSLinkOrder = JD.getDFSLinkOrder();
366 DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
367 ES.runSessionLocked([&]() {
368 for (auto &InitJD : DFSLinkOrder) {
369 auto RISItr = RegisteredInitSymbols.find(InitJD.get());
370 if (RISItr != RegisteredInitSymbols.end()) {
371 NewInitSymbols[InitJD.get()] = std::move(RISItr->second);
372 RegisteredInitSymbols.erase(RISItr);
373 }
374 }
375 });
376
377 // If there are no further init symbols to look up then move on to the next
378 // phase.
379 if (NewInitSymbols.empty()) {
380 getInitializersBuildSequencePhase(std::move(SendResult), JD,
381 std::move(DFSLinkOrder));
382 return;
383 }
384
385 // Otherwise issue a lookup and re-run this phase when it completes.
386 lookupInitSymbolsAsync(
387 [this, SendResult = std::move(SendResult), &JD](Error Err) mutable {
388 if (Err)
389 SendResult(std::move(Err));
390 else
391 getInitializersLookupPhase(std::move(SendResult), JD);
392 },
393 ES, std::move(NewInitSymbols));
394}
395
396void MachOPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult,
397 StringRef JDName) {
398 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform::rt_getInitializers(\""
<< JDName << "\")\n"; }; } } while (false)
399 dbgs() << "MachOPlatform::rt_getInitializers(\"" << JDName << "\")\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform::rt_getInitializers(\""
<< JDName << "\")\n"; }; } } while (false)
400 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform::rt_getInitializers(\""
<< JDName << "\")\n"; }; } } while (false)
;
401
402 JITDylib *JD = ES.getJITDylibByName(JDName);
403 if (!JD) {
404 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No such JITDylib \"" <<
JDName << "\". Sending error.\n"; }; } } while (false)
405 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)
406 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No such JITDylib \"" <<
JDName << "\". Sending error.\n"; }; } } while (false)
;
407 SendResult(make_error<StringError>("No JITDylib named " + JDName,
408 inconvertibleErrorCode()));
409 return;
410 }
411
412 getInitializersLookupPhase(std::move(SendResult), *JD);
413}
414
415void MachOPlatform::rt_getDeinitializers(SendDeinitializerSequenceFn SendResult,
416 ExecutorAddr Handle) {
417 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform::rt_getDeinitializers(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
418 dbgs() << "MachOPlatform::rt_getDeinitializers(\""do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform::rt_getDeinitializers(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
419 << formatv("{0:x}", Handle.getValue()) << "\")\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform::rt_getDeinitializers(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
420 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform::rt_getDeinitializers(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
;
421
422 JITDylib *JD = nullptr;
423
424 {
425 std::lock_guard<std::mutex> Lock(PlatformMutex);
426 auto I = HeaderAddrToJITDylib.find(Handle.getValue());
427 if (I != HeaderAddrToJITDylib.end())
428 JD = I->second;
429 }
430
431 if (!JD) {
432 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No JITDylib for handle " <<
formatv("{0:x}", Handle.getValue()) << "\n"; }; } } while
(false)
433 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)
434 << 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)
435 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No JITDylib for handle " <<
formatv("{0:x}", Handle.getValue()) << "\n"; }; } } while
(false)
;
436 SendResult(make_error<StringError>("No JITDylib associated with handle " +
437 formatv("{0:x}", Handle.getValue()),
438 inconvertibleErrorCode()));
439 return;
440 }
441
442 SendResult(MachOJITDylibDeinitializerSequence());
443}
444
445void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
446 ExecutorAddr Handle, StringRef SymbolName) {
447 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform::rt_lookupSymbol(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
448 dbgs() << "MachOPlatform::rt_lookupSymbol(\""do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform::rt_lookupSymbol(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
449 << formatv("{0:x}", Handle.getValue()) << "\")\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform::rt_lookupSymbol(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
450 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform::rt_lookupSymbol(\""
<< formatv("{0:x}", Handle.getValue()) << "\")\n"
; }; } } while (false)
;
451
452 JITDylib *JD = nullptr;
453
454 {
455 std::lock_guard<std::mutex> Lock(PlatformMutex);
456 auto I = HeaderAddrToJITDylib.find(Handle.getValue());
457 if (I != HeaderAddrToJITDylib.end())
458 JD = I->second;
459 }
460
461 if (!JD) {
462 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No JITDylib for handle " <<
formatv("{0:x}", Handle.getValue()) << "\n"; }; } } while
(false)
463 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)
464 << 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)
465 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << " No JITDylib for handle " <<
formatv("{0:x}", Handle.getValue()) << "\n"; }; } } while
(false)
;
466 SendResult(make_error<StringError>("No JITDylib associated with handle " +
467 formatv("{0:x}", Handle.getValue()),
468 inconvertibleErrorCode()));
469 return;
470 }
471
472 // Use functor class to work around XL build compiler issue on AIX.
473 class RtLookupNotifyComplete {
474 public:
475 RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)
476 : SendResult(std::move(SendResult)) {}
477 void operator()(Expected<SymbolMap> Result) {
478 if (Result) {
479 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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp"
, 479, __extension__ __PRETTY_FUNCTION__))
;
480 SendResult(ExecutorAddr(Result->begin()->second.getAddress()));
481 } else {
482 SendResult(Result.takeError());
483 }
484 }
485
486 private:
487 SendSymbolAddressFn SendResult;
488 };
489
490 // FIXME: Proper mangling.
491 auto MangledName = ("_" + SymbolName).str();
492 ES.lookup(
493 LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
494 SymbolLookupSet(ES.intern(MangledName)), SymbolState::Ready,
495 RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
496}
497
498Error MachOPlatform::bootstrapMachORuntime(JITDylib &PlatformJD) {
499
500 if (auto Err = lookupAndRecordAddrs(
501 ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD),
502 {{ES.intern("___orc_rt_macho_platform_bootstrap"),
503 &orc_rt_macho_platform_bootstrap},
504 {ES.intern("___orc_rt_macho_platform_shutdown"),
505 &orc_rt_macho_platform_shutdown},
506 {ES.intern("___orc_rt_macho_register_object_sections"),
507 &orc_rt_macho_register_object_sections},
508 {ES.intern("___orc_rt_macho_create_pthread_key"),
509 &orc_rt_macho_create_pthread_key}}))
510 return Err;
511
512 if (auto Err = ES.callSPSWrapper<void()>(orc_rt_macho_platform_bootstrap))
513 return Err;
514
515 // FIXME: Ordering is fuzzy here. We're probably best off saying
516 // "behavior is undefined if code that uses the runtime is added before
517 // the platform constructor returns", then move all this to the constructor.
518 RuntimeBootstrapped = true;
519 std::vector<MachOPerObjectSectionsToRegister> DeferredPOSRs;
520 {
521 std::lock_guard<std::mutex> Lock(PlatformMutex);
522 DeferredPOSRs = std::move(BootstrapPOSRs);
523 }
524
525 for (auto &D : DeferredPOSRs)
526 if (auto Err = registerPerObjectSections(D))
527 return Err;
528
529 return Error::success();
530}
531
532Error MachOPlatform::registerInitInfo(
533 JITDylib &JD, ExecutorAddr ObjCImageInfoAddr,
534 ArrayRef<jitlink::Section *> InitSections) {
535
536 std::unique_lock<std::mutex> Lock(PlatformMutex);
537
538 MachOJITDylibInitializers *InitSeq = nullptr;
539 {
540 auto I = InitSeqs.find(&JD);
541 if (I == InitSeqs.end()) {
542 // If there's no init sequence entry yet then we need to look up the
543 // header symbol to force creation of one.
544 Lock.unlock();
545
546 auto SearchOrder =
547 JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; });
548 if (auto Err = ES.lookup(SearchOrder, MachOHeaderStartSymbol).takeError())
549 return Err;
550
551 Lock.lock();
552 I = InitSeqs.find(&JD);
553 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?\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp"
, 554, __extension__ __PRETTY_FUNCTION__))
554 "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?\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp"
, 554, __extension__ __PRETTY_FUNCTION__))
;
555 }
556 InitSeq = &I->second;
557 }
558
559 InitSeq->ObjCImageInfoAddress = ObjCImageInfoAddr;
560
561 for (auto *Sec : InitSections) {
562 // FIXME: Avoid copy here.
563 jitlink::SectionRange R(*Sec);
564 InitSeq->InitSections[Sec->getName()].push_back(
565 {ExecutorAddr(R.getStart()), ExecutorAddr(R.getEnd())});
566 }
567
568 return Error::success();
569}
570
571Error MachOPlatform::registerPerObjectSections(
572 const MachOPerObjectSectionsToRegister &POSR) {
573
574 if (!orc_rt_macho_register_object_sections)
11
Taking false branch
575 return make_error<StringError>("Attempting to register per-object "
576 "sections, but runtime support has not "
577 "been loaded yet",
578 inconvertibleErrorCode());
579
580 Error ErrResult = Error::success();
581 if (auto Err = ES.callSPSWrapper<shared::SPSError(
12
Calling 'ExecutionSession::callSPSWrapper'
25
Returning from 'ExecutionSession::callSPSWrapper'
26
Assuming the condition is false
27
Taking false branch
582 SPSMachOPerObjectSectionsToRegister)>(
583 orc_rt_macho_register_object_sections, ErrResult, POSR))
584 return Err;
585 return ErrResult;
28
Moved-from object 'ErrResult' is moved
586}
587
588Expected<uint64_t> MachOPlatform::createPThreadKey() {
589 if (!orc_rt_macho_create_pthread_key)
590 return make_error<StringError>(
591 "Attempting to create pthread key in target, but runtime support has "
592 "not been loaded yet",
593 inconvertibleErrorCode());
594
595 Expected<uint64_t> Result(0);
596 if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(
597 orc_rt_macho_create_pthread_key, Result))
598 return std::move(Err);
599 return Result;
600}
601
602void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
603 MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
604 jitlink::PassConfiguration &Config) {
605
606 // --- Handle Initializers ---
607 if (auto InitSymbol = MR.getInitializerSymbol()) {
608
609 // If the initializer symbol is the MachOHeader start symbol then just
610 // register it and then bail out -- the header materialization unit
611 // definitely doesn't need any other passes.
612 if (InitSymbol == MP.MachOHeaderStartSymbol) {
613 Config.PostAllocationPasses.push_back([this, &MR](jitlink::LinkGraph &G) {
614 return associateJITDylibHeaderSymbol(G, MR);
615 });
616 return;
617 }
618
619 // If the object contains an init symbol other than the header start symbol
620 // then add passes to preserve, process and register the init
621 // sections/symbols.
622 Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) {
623 if (auto Err = preserveInitSections(G, MR))
624 return Err;
625 return processObjCImageInfo(G, MR);
626 });
627
628 Config.PostFixupPasses.push_back(
629 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
630 return registerInitSections(G, JD);
631 });
632 }
633
634 // --- Add passes for eh-frame and TLV support ---
635
636 // Insert TLV lowering at the start of the PostPrunePasses, since we want
637 // it to run before GOT/PLT lowering.
638 Config.PostPrunePasses.insert(
639 Config.PostPrunePasses.begin(),
640 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
641 return fixTLVSectionsAndEdges(G, JD);
642 });
643
644 // Add a pass to register the final addresses of the eh-frame and TLV sections
645 // with the runtime.
646 Config.PostFixupPasses.push_back(
647 [this](jitlink::LinkGraph &G) { return registerEHAndTLVSections(G); });
1
Calling 'MachOPlatformPlugin::registerEHAndTLVSections'
648}
649
650ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
651MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies(
652 MaterializationResponsibility &MR) {
653 std::lock_guard<std::mutex> Lock(PluginMutex);
654 auto I = InitSymbolDeps.find(&MR);
655 if (I != InitSymbolDeps.end()) {
656 SyntheticSymbolDependenciesMap Result;
657 Result[MR.getInitializerSymbol()] = std::move(I->second);
658 InitSymbolDeps.erase(&MR);
659 return Result;
660 }
661 return SyntheticSymbolDependenciesMap();
662}
663
664Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol(
665 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
666
667 auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
668 return Sym->getName() == *MP.MachOHeaderStartSymbol;
669 });
670 assert(I != G.defined_symbols().end() && "Missing MachO header start symbol")(static_cast <bool> (I != G.defined_symbols().end() &&
"Missing MachO header start symbol") ? void (0) : __assert_fail
("I != G.defined_symbols().end() && \"Missing MachO header start symbol\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp"
, 670, __extension__ __PRETTY_FUNCTION__))
;
671
672 auto &JD = MR.getTargetJITDylib();
673 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
674 JITTargetAddress HeaderAddr = (*I)->getAddress();
675 MP.HeaderAddrToJITDylib[HeaderAddr] = &JD;
676 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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp"
, 676, __extension__ __PRETTY_FUNCTION__))
;
677 MP.InitSeqs.insert(std::make_pair(
678 &JD, MachOJITDylibInitializers(JD.getName(), ExecutorAddr(HeaderAddr))));
679 return Error::success();
680}
681
682Error MachOPlatform::MachOPlatformPlugin::preserveInitSections(
683 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
684
685 JITLinkSymbolSet InitSectionSymbols;
686 for (auto &InitSectionName : InitSectionNames) {
687 // Skip non-init sections.
688 auto *InitSection = G.findSectionByName(InitSectionName);
689 if (!InitSection)
690 continue;
691
692 // Make a pass over live symbols in the section: those blocks are already
693 // preserved.
694 DenseSet<jitlink::Block *> AlreadyLiveBlocks;
695 for (auto &Sym : InitSection->symbols()) {
696 auto &B = Sym->getBlock();
697 if (Sym->isLive() && Sym->getOffset() == 0 &&
698 Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) {
699 InitSectionSymbols.insert(Sym);
700 AlreadyLiveBlocks.insert(&B);
701 }
702 }
703
704 // Add anonymous symbols to preserve any not-already-preserved blocks.
705 for (auto *B : InitSection->blocks())
706 if (!AlreadyLiveBlocks.count(B))
707 InitSectionSymbols.insert(
708 &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true));
709 }
710
711 if (!InitSectionSymbols.empty()) {
712 std::lock_guard<std::mutex> Lock(PluginMutex);
713 InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
714 }
715
716 return Error::success();
717}
718
719Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
720 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
721
722 // If there's an ObjC imagine info then either
723 // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In
724 // this case we name and record it.
725 // OR
726 // (2) We already have a recorded __objc_imageinfo for this JITDylib,
727 // in which case we just verify it.
728 auto *ObjCImageInfo = G.findSectionByName(ObjCImageInfoSectionName);
729 if (!ObjCImageInfo)
730 return Error::success();
731
732 auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();
733
734 // Check that the section is not empty if present.
735 if (llvm::empty(ObjCImageInfoBlocks))
736 return make_error<StringError>("Empty " + ObjCImageInfoSectionName +
737 " section in " + G.getName(),
738 inconvertibleErrorCode());
739
740 // Check that there's only one block in the section.
741 if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end())
742 return make_error<StringError>("Multiple blocks in " +
743 ObjCImageInfoSectionName +
744 " section in " + G.getName(),
745 inconvertibleErrorCode());
746
747 // Check that the __objc_imageinfo section is unreferenced.
748 // FIXME: We could optimize this check if Symbols had a ref-count.
749 for (auto &Sec : G.sections()) {
750 if (&Sec != ObjCImageInfo)
751 for (auto *B : Sec.blocks())
752 for (auto &E : B->edges())
753 if (E.getTarget().isDefined() &&
754 &E.getTarget().getBlock().getSection() == ObjCImageInfo)
755 return make_error<StringError>(ObjCImageInfoSectionName +
756 " is referenced within file " +
757 G.getName(),
758 inconvertibleErrorCode());
759 }
760
761 auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin();
762 auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data();
763 auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness());
764 auto Flags =
765 support::endian::read32(ObjCImageInfoData + 4, G.getEndianness());
766
767 // Lock the mutex while we verify / update the ObjCImageInfos map.
768 std::lock_guard<std::mutex> Lock(PluginMutex);
769
770 auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib());
771 if (ObjCImageInfoItr != ObjCImageInfos.end()) {
772 // We've already registered an __objc_imageinfo section. Verify the
773 // content of this new section matches, then delete it.
774 if (ObjCImageInfoItr->second.first != Version)
775 return make_error<StringError>(
776 "ObjC version in " + G.getName() +
777 " does not match first registered version",
778 inconvertibleErrorCode());
779 if (ObjCImageInfoItr->second.second != Flags)
780 return make_error<StringError>("ObjC flags in " + G.getName() +
781 " do not match first registered flags",
782 inconvertibleErrorCode());
783
784 // __objc_imageinfo is valid. Delete the block.
785 for (auto *S : ObjCImageInfo->symbols())
786 G.removeDefinedSymbol(*S);
787 G.removeBlock(ObjCImageInfoBlock);
788 } else {
789 // We haven't registered an __objc_imageinfo section yet. Register and
790 // move on. The section should already be marked no-dead-strip.
791 ObjCImageInfos[&MR.getTargetJITDylib()] = std::make_pair(Version, Flags);
792 }
793
794 return Error::success();
795}
796
797Error MachOPlatform::MachOPlatformPlugin::registerInitSections(
798 jitlink::LinkGraph &G, JITDylib &JD) {
799
800 ExecutorAddr ObjCImageInfoAddr;
801 SmallVector<jitlink::Section *> InitSections;
802
803 if (auto *ObjCImageInfoSec = G.findSectionByName(ObjCImageInfoSectionName)) {
804 if (auto Addr = jitlink::SectionRange(*ObjCImageInfoSec).getStart())
805 ObjCImageInfoAddr.setValue(Addr);
806 }
807
808 for (auto InitSectionName : InitSectionNames)
809 if (auto *Sec = G.findSectionByName(InitSectionName))
810 InitSections.push_back(Sec);
811
812 // Dump the scraped inits.
813 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Scraped " <<
G.getName() << " init sections:\n"; if (ObjCImageInfoAddr
) dbgs() << " " << ObjCImageInfoSectionName <<
": " << formatv("{0:x}", ObjCImageInfoAddr.getValue())
<< "\n"; for (auto *Sec : InitSections) { jitlink::SectionRange
R(*Sec); dbgs() << " " << Sec->getName() <<
": " << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.
getEnd()) << "\n"; } }; } } while (false)
814 dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Scraped " <<
G.getName() << " init sections:\n"; if (ObjCImageInfoAddr
) dbgs() << " " << ObjCImageInfoSectionName <<
": " << formatv("{0:x}", ObjCImageInfoAddr.getValue())
<< "\n"; for (auto *Sec : InitSections) { jitlink::SectionRange
R(*Sec); dbgs() << " " << Sec->getName() <<
": " << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.
getEnd()) << "\n"; } }; } } while (false)
815 if (ObjCImageInfoAddr)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Scraped " <<
G.getName() << " init sections:\n"; if (ObjCImageInfoAddr
) dbgs() << " " << ObjCImageInfoSectionName <<
": " << formatv("{0:x}", ObjCImageInfoAddr.getValue())
<< "\n"; for (auto *Sec : InitSections) { jitlink::SectionRange
R(*Sec); dbgs() << " " << Sec->getName() <<
": " << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.
getEnd()) << "\n"; } }; } } while (false)
816 dbgs() << " " << ObjCImageInfoSectionName << ": "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Scraped " <<
G.getName() << " init sections:\n"; if (ObjCImageInfoAddr
) dbgs() << " " << ObjCImageInfoSectionName <<
": " << formatv("{0:x}", ObjCImageInfoAddr.getValue())
<< "\n"; for (auto *Sec : InitSections) { jitlink::SectionRange
R(*Sec); dbgs() << " " << Sec->getName() <<
": " << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.
getEnd()) << "\n"; } }; } } while (false)
817 << formatv("{0:x}", ObjCImageInfoAddr.getValue()) << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Scraped " <<
G.getName() << " init sections:\n"; if (ObjCImageInfoAddr
) dbgs() << " " << ObjCImageInfoSectionName <<
": " << formatv("{0:x}", ObjCImageInfoAddr.getValue())
<< "\n"; for (auto *Sec : InitSections) { jitlink::SectionRange
R(*Sec); dbgs() << " " << Sec->getName() <<
": " << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.
getEnd()) << "\n"; } }; } } while (false)
818 for (auto *Sec : InitSections) {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Scraped " <<
G.getName() << " init sections:\n"; if (ObjCImageInfoAddr
) dbgs() << " " << ObjCImageInfoSectionName <<
": " << formatv("{0:x}", ObjCImageInfoAddr.getValue())
<< "\n"; for (auto *Sec : InitSections) { jitlink::SectionRange
R(*Sec); dbgs() << " " << Sec->getName() <<
": " << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.
getEnd()) << "\n"; } }; } } while (false)
819 jitlink::SectionRange R(*Sec);do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Scraped " <<
G.getName() << " init sections:\n"; if (ObjCImageInfoAddr
) dbgs() << " " << ObjCImageInfoSectionName <<
": " << formatv("{0:x}", ObjCImageInfoAddr.getValue())
<< "\n"; for (auto *Sec : InitSections) { jitlink::SectionRange
R(*Sec); dbgs() << " " << Sec->getName() <<
": " << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.
getEnd()) << "\n"; } }; } } while (false)
820 dbgs() << " " << Sec->getName() << ": "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Scraped " <<
G.getName() << " init sections:\n"; if (ObjCImageInfoAddr
) dbgs() << " " << ObjCImageInfoSectionName <<
": " << formatv("{0:x}", ObjCImageInfoAddr.getValue())
<< "\n"; for (auto *Sec : InitSections) { jitlink::SectionRange
R(*Sec); dbgs() << " " << Sec->getName() <<
": " << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.
getEnd()) << "\n"; } }; } } while (false)
821 << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.getEnd()) << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Scraped " <<
G.getName() << " init sections:\n"; if (ObjCImageInfoAddr
) dbgs() << " " << ObjCImageInfoSectionName <<
": " << formatv("{0:x}", ObjCImageInfoAddr.getValue())
<< "\n"; for (auto *Sec : InitSections) { jitlink::SectionRange
R(*Sec); dbgs() << " " << Sec->getName() <<
": " << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.
getEnd()) << "\n"; } }; } } while (false)
822 }do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Scraped " <<
G.getName() << " init sections:\n"; if (ObjCImageInfoAddr
) dbgs() << " " << ObjCImageInfoSectionName <<
": " << formatv("{0:x}", ObjCImageInfoAddr.getValue())
<< "\n"; for (auto *Sec : InitSections) { jitlink::SectionRange
R(*Sec); dbgs() << " " << Sec->getName() <<
": " << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.
getEnd()) << "\n"; } }; } } while (false)
823 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("orc")) { { dbgs() << "MachOPlatform: Scraped " <<
G.getName() << " init sections:\n"; if (ObjCImageInfoAddr
) dbgs() << " " << ObjCImageInfoSectionName <<
": " << formatv("{0:x}", ObjCImageInfoAddr.getValue())
<< "\n"; for (auto *Sec : InitSections) { jitlink::SectionRange
R(*Sec); dbgs() << " " << Sec->getName() <<
": " << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.
getEnd()) << "\n"; } }; } } while (false)
;
824
825 return MP.registerInitInfo(JD, ObjCImageInfoAddr, InitSections);
826}
827
828Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(
829 jitlink::LinkGraph &G, JITDylib &JD) {
830
831 // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr.
832 for (auto *Sym : G.external_symbols())
833 if (Sym->getName() == "__tlv_bootstrap") {
834 Sym->setName("___orc_rt_macho_tlv_get_addr");
835 break;
836 }
837
838 // Store key in __thread_vars struct fields.
839 if (auto *ThreadDataSec = G.findSectionByName(ThreadVarsSectionName)) {
840 Optional<uint64_t> Key;
841 {
842 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
843 auto I = MP.JITDylibToPThreadKey.find(&JD);
844 if (I != MP.JITDylibToPThreadKey.end())
845 Key = I->second;
846 }
847
848 if (!Key) {
849 if (auto KeyOrErr = MP.createPThreadKey())
850 Key = *KeyOrErr;
851 else
852 return KeyOrErr.takeError();
853 }
854
855 uint64_t PlatformKeyBits =
856 support::endian::byte_swap(*Key, G.getEndianness());
857
858 for (auto *B : ThreadDataSec->blocks()) {
859 if (B->getSize() != 3 * G.getPointerSize())
860 return make_error<StringError>("__thread_vars block at " +
861 formatv("{0:x}", B->getAddress()) +
862 " has unexpected size",
863 inconvertibleErrorCode());
864
865 auto NewBlockContent = G.allocateBuffer(B->getSize());
866 llvm::copy(B->getContent(), NewBlockContent.data());
867 memcpy(NewBlockContent.data() + G.getPointerSize(), &PlatformKeyBits,
868 G.getPointerSize());
869 B->setContent(NewBlockContent);
870 }
871 }
872
873 // Transform any TLV edges into GOT edges.
874 for (auto *B : G.blocks())
875 for (auto &E : B->edges())
876 if (E.getKind() ==
877 jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable)
878 E.setKind(jitlink::x86_64::
879 RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable);
880
881 return Error::success();
882}
883
884Error MachOPlatform::MachOPlatformPlugin::registerEHAndTLVSections(
885 jitlink::LinkGraph &G) {
886 MachOPerObjectSectionsToRegister POSR;
887
888 if (auto *EHFrameSection
1.1
'EHFrameSection' is null
1.1
'EHFrameSection' is null
1.1
'EHFrameSection' is null
1.1
'EHFrameSection' is null
1.1
'EHFrameSection' is null
= G.findSectionByName(EHFrameSectionName)) {
2
Taking false branch
889 jitlink::SectionRange R(*EHFrameSection);
890 if (!R.empty())
891 POSR.EHFrameSection = {ExecutorAddr(R.getStart()),
892 ExecutorAddr(R.getEnd())};
893 }
894
895 // Get a pointer to the thread data section if there is one. It will be used
896 // below.
897 jitlink::Section *ThreadDataSection =
898 G.findSectionByName(ThreadDataSectionName);
899
900 // Handle thread BSS section if there is one.
901 if (auto *ThreadBSSSection
2.1
'ThreadBSSSection' is non-null
2.1
'ThreadBSSSection' is non-null
2.1
'ThreadBSSSection' is non-null
2.1
'ThreadBSSSection' is non-null
2.1
'ThreadBSSSection' is non-null
= G.findSectionByName(ThreadBSSSectionName)) {
3
Taking true branch
902 // If there's already a thread data section in this graph then merge the
903 // thread BSS section content into it, otherwise just treat the thread
904 // BSS section as the thread data section.
905 if (ThreadDataSection
3.1
'ThreadDataSection' is null
3.1
'ThreadDataSection' is null
3.1
'ThreadDataSection' is null
3.1
'ThreadDataSection' is null
3.1
'ThreadDataSection' is null
)
4
Taking false branch
906 G.mergeSections(*ThreadDataSection, *ThreadBSSSection);
907 else
908 ThreadDataSection = ThreadBSSSection;
909 }
910
911 // Having merged thread BSS (if present) and thread data (if present),
912 // record the resulting section range.
913 if (ThreadDataSection
4.1
'ThreadDataSection' is non-null
4.1
'ThreadDataSection' is non-null
4.1
'ThreadDataSection' is non-null
4.1
'ThreadDataSection' is non-null
4.1
'ThreadDataSection' is non-null
) {
5
Taking true branch
914 jitlink::SectionRange R(*ThreadDataSection);
915 if (!R.empty())
6
Taking true branch
916 POSR.ThreadDataSection = {ExecutorAddr(R.getStart()),
917 ExecutorAddr(R.getEnd())};
918 }
919
920 if (POSR.EHFrameSection.Start || POSR.ThreadDataSection.Start) {
7
Taking true branch
921
922 // If we're still bootstrapping the runtime then just record this
923 // frame for now.
924 if (!MP.RuntimeBootstrapped) {
8
Assuming the condition is false
9
Taking false branch
925 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
926 MP.BootstrapPOSRs.push_back(POSR);
927 return Error::success();
928 }
929
930 // Otherwise register it immediately.
931 if (auto Err = MP.registerPerObjectSections(POSR))
10
Calling 'MachOPlatform::registerPerObjectSections'
932 return Err;
933 }
934
935 return Error::success();
936}
937
938} // End namespace orc.
939} // End namespace llvm.

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

/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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.\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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(
14
Calling 'WrapperFunction::call'
23
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", "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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", "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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", "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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", "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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::detail::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~++20211030100902+82ed10656706/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
26namespace detail {
27
28// DO NOT USE DIRECTLY.
29// Must be kept in-sync with compiler-rt/lib/orc/c-api.h.
30union CWrapperFunctionResultDataUnion {
31 char *ValuePtr;
32 char Value[sizeof(ValuePtr)];
33};
34
35// DO NOT USE DIRECTLY.
36// Must be kept in-sync with compiler-rt/lib/orc/c-api.h.
37typedef struct {
38 CWrapperFunctionResultDataUnion Data;
39 size_t Size;
40} CWrapperFunctionResult;
41
42} // end namespace detail
43
44/// C++ wrapper function result: Same as CWrapperFunctionResult but
45/// auto-releases memory.
46class WrapperFunctionResult {
47public:
48 /// Create a default WrapperFunctionResult.
49 WrapperFunctionResult() { init(R); }
50
51 /// Create a WrapperFunctionResult by taking ownership of a
52 /// detail::CWrapperFunctionResult.
53 ///
54 /// Warning: This should only be used by clients writing wrapper-function
55 /// caller utilities (like TargetProcessControl).
56 WrapperFunctionResult(detail::CWrapperFunctionResult R) : R(R) {
57 // Reset R.
58 init(R);
59 }
60
61 WrapperFunctionResult(const WrapperFunctionResult &) = delete;
62 WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
63
64 WrapperFunctionResult(WrapperFunctionResult &&Other) {
65 init(R);
66 std::swap(R, Other.R);
67 }
68
69 WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
70 WrapperFunctionResult Tmp(std::move(Other));
71 std::swap(R, Tmp.R);
72 return *this;
73 }
74
75 ~WrapperFunctionResult() {
76 if ((R.Size > sizeof(R.Data.Value)) ||
77 (R.Size == 0 && R.Data.ValuePtr != nullptr))
78 free(R.Data.ValuePtr);
79 }
80
81 /// Release ownership of the contained detail::CWrapperFunctionResult.
82 /// Warning: Do not use -- this method will be removed in the future. It only
83 /// exists to temporarily support some code that will eventually be moved to
84 /// the ORC runtime.
85 detail::CWrapperFunctionResult release() {
86 detail::CWrapperFunctionResult Tmp;
87 init(Tmp);
88 std::swap(R, Tmp);
89 return Tmp;
90 }
91
92 /// Get a pointer to the data contained in this instance.
93 char *data() {
94 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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
, 95, __extension__ __PRETTY_FUNCTION__))
95 "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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
, 95, __extension__ __PRETTY_FUNCTION__))
;
96 return R.Size > sizeof(R.Data.Value) ? R.Data.ValuePtr : R.Data.Value;
97 }
98
99 /// Get a const pointer to the data contained in this instance.
100 const char *data() const {
101 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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
, 102, __extension__ __PRETTY_FUNCTION__))
102 "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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
, 102, __extension__ __PRETTY_FUNCTION__))
;
103 return R.Size > sizeof(R.Data.Value) ? R.Data.ValuePtr : R.Data.Value;
104 }
105
106 /// Returns the size of the data contained in this instance.
107 size_t size() const {
108 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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
, 109, __extension__ __PRETTY_FUNCTION__))
109 "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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
, 109, __extension__ __PRETTY_FUNCTION__))
;
110 return R.Size;
111 }
112
113 /// Returns true if this value is equivalent to a default-constructed
114 /// WrapperFunctionResult.
115 bool empty() const { return R.Size == 0 && R.Data.ValuePtr == nullptr; }
116
117 /// Create a WrapperFunctionResult with the given size and return a pointer
118 /// to the underlying memory.
119 static WrapperFunctionResult allocate(size_t Size) {
120 // Reset.
121 WrapperFunctionResult WFR;
122 WFR.R.Size = Size;
123 if (WFR.R.Size > sizeof(WFR.R.Data.Value))
124 WFR.R.Data.ValuePtr = (char *)malloc(WFR.R.Size);
125 return WFR;
126 }
127
128 /// Copy from the given char range.
129 static WrapperFunctionResult copyFrom(const char *Source, size_t Size) {
130 auto WFR = allocate(Size);
131 memcpy(WFR.data(), Source, Size);
132 return WFR;
133 }
134
135 /// Copy from the given null-terminated string (includes the null-terminator).
136 static WrapperFunctionResult copyFrom(const char *Source) {
137 return copyFrom(Source, strlen(Source) + 1);
138 }
139
140 /// Copy from the given std::string (includes the null terminator).
141 static WrapperFunctionResult copyFrom(const std::string &Source) {
142 return copyFrom(Source.c_str());
143 }
144
145 /// Create an out-of-band error by copying the given string.
146 static WrapperFunctionResult createOutOfBandError(const char *Msg) {
147 // Reset.
148 WrapperFunctionResult WFR;
149 char *Tmp = (char *)malloc(strlen(Msg) + 1);
150 strcpy(Tmp, Msg);
151 WFR.R.Data.ValuePtr = Tmp;
152 return WFR;
153 }
154
155 /// Create an out-of-band error by copying the given string.
156 static WrapperFunctionResult createOutOfBandError(const std::string &Msg) {
157 return createOutOfBandError(Msg.c_str());
158 }
159
160 /// If this value is an out-of-band error then this returns the error message,
161 /// otherwise returns nullptr.
162 const char *getOutOfBandError() const {
163 return R.Size == 0 ? R.Data.ValuePtr : nullptr;
164 }
165
166private:
167 static void init(detail::CWrapperFunctionResult &R) {
168 R.Data.ValuePtr = nullptr;
169 R.Size = 0;
170 }
171
172 detail::CWrapperFunctionResult R;
173};
174
175namespace detail {
176
177template <typename SPSArgListT, typename... ArgTs>
178WrapperFunctionResult
179serializeViaSPSToWrapperFunctionResult(const ArgTs &...Args) {
180 auto Result = WrapperFunctionResult::allocate(SPSArgListT::size(Args...));
181 SPSOutputBuffer OB(Result.data(), Result.size());
182 if (!SPSArgListT::serialize(OB, Args...))
183 return WrapperFunctionResult::createOutOfBandError(
184 "Error serializing arguments to blob in call");
185 return Result;
186}
187
188template <typename RetT> class WrapperFunctionHandlerCaller {
189public:
190 template <typename HandlerT, typename ArgTupleT, std::size_t... I>
191 static decltype(auto) call(HandlerT &&H, ArgTupleT &Args,
192 std::index_sequence<I...>) {
193 return std::forward<HandlerT>(H)(std::get<I>(Args)...);
194 }
195};
196
197template <> class WrapperFunctionHandlerCaller<void> {
198public:
199 template <typename HandlerT, typename ArgTupleT, std::size_t... I>
200 static SPSEmpty call(HandlerT &&H, ArgTupleT &Args,
201 std::index_sequence<I...>) {
202 std::forward<HandlerT>(H)(std::get<I>(Args)...);
203 return SPSEmpty();
204 }
205};
206
207template <typename WrapperFunctionImplT,
208 template <typename> class ResultSerializer, typename... SPSTagTs>
209class WrapperFunctionHandlerHelper
210 : public WrapperFunctionHandlerHelper<
211 decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
212 ResultSerializer, SPSTagTs...> {};
213
214template <typename RetT, typename... ArgTs,
215 template <typename> class ResultSerializer, typename... SPSTagTs>
216class WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
217 SPSTagTs...> {
218public:
219 using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
220 using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
221
222 template <typename HandlerT>
223 static WrapperFunctionResult apply(HandlerT &&H, const char *ArgData,
224 size_t ArgSize) {
225 ArgTuple Args;
226 if (!deserialize(ArgData, ArgSize, Args, ArgIndices{}))
227 return WrapperFunctionResult::createOutOfBandError(
228 "Could not deserialize arguments for wrapper function call");
229
230 auto HandlerResult = WrapperFunctionHandlerCaller<RetT>::call(
231 std::forward<HandlerT>(H), Args, ArgIndices{});
232
233 return ResultSerializer<decltype(HandlerResult)>::serialize(
234 std::move(HandlerResult));
235 }
236
237private:
238 template <std::size_t... I>
239 static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args,
240 std::index_sequence<I...>) {
241 SPSInputBuffer IB(ArgData, ArgSize);
242 return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...);
243 }
244};
245
246// Map function pointers to function types.
247template <typename RetT, typename... ArgTs,
248 template <typename> class ResultSerializer, typename... SPSTagTs>
249class WrapperFunctionHandlerHelper<RetT (*)(ArgTs...), ResultSerializer,
250 SPSTagTs...>
251 : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
252 SPSTagTs...> {};
253
254// Map non-const member function types to function types.
255template <typename ClassT, typename RetT, typename... ArgTs,
256 template <typename> class ResultSerializer, typename... SPSTagTs>
257class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...), ResultSerializer,
258 SPSTagTs...>
259 : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
260 SPSTagTs...> {};
261
262// Map const member function types to function types.
263template <typename ClassT, typename RetT, typename... ArgTs,
264 template <typename> class ResultSerializer, typename... SPSTagTs>
265class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
266 ResultSerializer, SPSTagTs...>
267 : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
268 SPSTagTs...> {};
269
270template <typename WrapperFunctionImplT,
271 template <typename> class ResultSerializer, typename... SPSTagTs>
272class WrapperFunctionAsyncHandlerHelper
273 : public WrapperFunctionAsyncHandlerHelper<
274 decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
275 ResultSerializer, SPSTagTs...> {};
276
277template <typename RetT, typename SendResultT, typename... ArgTs,
278 template <typename> class ResultSerializer, typename... SPSTagTs>
279class WrapperFunctionAsyncHandlerHelper<RetT(SendResultT, ArgTs...),
280 ResultSerializer, SPSTagTs...> {
281public:
282 using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
283 using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
284
285 template <typename HandlerT, typename SendWrapperFunctionResultT>
286 static void applyAsync(HandlerT &&H,
287 SendWrapperFunctionResultT &&SendWrapperFunctionResult,
288 const char *ArgData, size_t ArgSize) {
289 ArgTuple Args;
290 if (!deserialize(ArgData, ArgSize, Args, ArgIndices{})) {
291 SendWrapperFunctionResult(WrapperFunctionResult::createOutOfBandError(
292 "Could not deserialize arguments for wrapper function call"));
293 return;
294 }
295
296 auto SendResult =
297 [SendWFR = std::move(SendWrapperFunctionResult)](auto Result) mutable {
298 using ResultT = decltype(Result);
299 SendWFR(ResultSerializer<ResultT>::serialize(std::move(Result)));
300 };
301
302 callAsync(std::forward<HandlerT>(H), std::move(SendResult), std::move(Args),
303 ArgIndices{});
304 }
305
306private:
307 template <std::size_t... I>
308 static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args,
309 std::index_sequence<I...>) {
310 SPSInputBuffer IB(ArgData, ArgSize);
311 return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...);
312 }
313
314 template <typename HandlerT, typename SerializeAndSendResultT,
315 typename ArgTupleT, std::size_t... I>
316 static void callAsync(HandlerT &&H,
317 SerializeAndSendResultT &&SerializeAndSendResult,
318 ArgTupleT Args, std::index_sequence<I...>) {
319 (void)Args; // Silence a buggy GCC warning.
320 return std::forward<HandlerT>(H)(std::move(SerializeAndSendResult),
321 std::move(std::get<I>(Args))...);
322 }
323};
324
325// Map function pointers to function types.
326template <typename RetT, typename... ArgTs,
327 template <typename> class ResultSerializer, typename... SPSTagTs>
328class WrapperFunctionAsyncHandlerHelper<RetT (*)(ArgTs...), ResultSerializer,
329 SPSTagTs...>
330 : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer,
331 SPSTagTs...> {};
332
333// Map non-const member function types to function types.
334template <typename ClassT, typename RetT, typename... ArgTs,
335 template <typename> class ResultSerializer, typename... SPSTagTs>
336class WrapperFunctionAsyncHandlerHelper<RetT (ClassT::*)(ArgTs...),
337 ResultSerializer, SPSTagTs...>
338 : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer,
339 SPSTagTs...> {};
340
341// Map const member function types to function types.
342template <typename ClassT, typename RetT, typename... ArgTs,
343 template <typename> class ResultSerializer, typename... SPSTagTs>
344class WrapperFunctionAsyncHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
345 ResultSerializer, SPSTagTs...>
346 : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer,
347 SPSTagTs...> {};
348
349template <typename SPSRetTagT, typename RetT> class ResultSerializer {
350public:
351 static WrapperFunctionResult serialize(RetT Result) {
352 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
353 Result);
354 }
355};
356
357template <typename SPSRetTagT> class ResultSerializer<SPSRetTagT, Error> {
358public:
359 static WrapperFunctionResult serialize(Error Err) {
360 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
361 toSPSSerializable(std::move(Err)));
362 }
363};
364
365template <typename SPSRetTagT, typename T>
366class ResultSerializer<SPSRetTagT, Expected<T>> {
367public:
368 static WrapperFunctionResult serialize(Expected<T> E) {
369 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
370 toSPSSerializable(std::move(E)));
371 }
372};
373
374template <typename SPSRetTagT, typename RetT> class ResultDeserializer {
375public:
376 static RetT makeValue() { return RetT(); }
377 static void makeSafe(RetT &Result) {}
378
379 static Error deserialize(RetT &Result, const char *ArgData, size_t ArgSize) {
380 SPSInputBuffer IB(ArgData, ArgSize);
381 if (!SPSArgList<SPSRetTagT>::deserialize(IB, Result))
382 return make_error<StringError>(
383 "Error deserializing return value from blob in call",
384 inconvertibleErrorCode());
385 return Error::success();
386 }
387};
388
389template <> class ResultDeserializer<SPSError, Error> {
390public:
391 static Error makeValue() { return Error::success(); }
392 static void makeSafe(Error &Err) { cantFail(std::move(Err)); }
16
Calling move constructor for 'Error'
18
Returning from move constructor for 'Error'
393
394 static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize) {
395 SPSInputBuffer IB(ArgData, ArgSize);
396 SPSSerializableError BSE;
397 if (!SPSArgList<SPSError>::deserialize(IB, BSE))
398 return make_error<StringError>(
399 "Error deserializing return value from blob in call",
400 inconvertibleErrorCode());
401 Err = fromSPSSerializable(std::move(BSE));
402 return Error::success();
403 }
404};
405
406template <typename SPSTagT, typename T>
407class ResultDeserializer<SPSExpected<SPSTagT>, Expected<T>> {
408public:
409 static Expected<T> makeValue() { return T(); }
410 static void makeSafe(Expected<T> &E) { cantFail(E.takeError()); }
411
412 static Error deserialize(Expected<T> &E, const char *ArgData,
413 size_t ArgSize) {
414 SPSInputBuffer IB(ArgData, ArgSize);
415 SPSSerializableExpected<T> BSE;
416 if (!SPSArgList<SPSExpected<SPSTagT>>::deserialize(IB, BSE))
417 return make_error<StringError>(
418 "Error deserializing return value from blob in call",
419 inconvertibleErrorCode());
420 E = fromSPSSerializable(std::move(BSE));
421 return Error::success();
422 }
423};
424
425template <typename SPSRetTagT, typename RetT> class AsyncCallResultHelper {
426 // Did you forget to use Error / Expected in your handler?
427};
428
429} // end namespace detail
430
431template <typename SPSSignature> class WrapperFunction;
432
433template <typename SPSRetTagT, typename... SPSTagTs>
434class WrapperFunction<SPSRetTagT(SPSTagTs...)> {
435private:
436 template <typename RetT>
437 using ResultSerializer = detail::ResultSerializer<SPSRetTagT, RetT>;
438
439public:
440 /// Call a wrapper function. Caller should be callable as
441 /// WrapperFunctionResult Fn(const char *ArgData, size_t ArgSize);
442 template <typename CallerFn, typename RetT, typename... ArgTs>
443 static Error call(const CallerFn &Caller, RetT &Result,
444 const ArgTs &...Args) {
445
446 // RetT might be an Error or Expected value. Set the checked flag now:
447 // we don't want the user to have to check the unused result if this
448 // operation fails.
449 detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(Result);
15
Calling 'ResultDeserializer::makeSafe'
19
Returning from 'ResultDeserializer::makeSafe'
450
451 auto ArgBuffer =
452 detail::serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSTagTs...>>(
453 Args...);
454 if (const char *ErrMsg
19.1
'ErrMsg' is null
19.1
'ErrMsg' is null
19.1
'ErrMsg' is null
19.1
'ErrMsg' is null
19.1
'ErrMsg' is null
= ArgBuffer.getOutOfBandError())
20
Taking false branch
455 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
456
457 WrapperFunctionResult ResultBuffer =
458 Caller(ArgBuffer.data(), ArgBuffer.size());
459 if (auto ErrMsg = ResultBuffer.getOutOfBandError())
21
Assuming 'ErrMsg' is non-null
22
Taking true branch
460 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
461
462 return detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize(
463 Result, ResultBuffer.data(), ResultBuffer.size());
464 }
465
466 /// Call an async wrapper function.
467 /// Caller should be callable as
468 /// void Fn(unique_function<void(WrapperFunctionResult)> SendResult,
469 /// WrapperFunctionResult ArgBuffer);
470 template <typename AsyncCallerFn, typename SendDeserializedResultFn,
471 typename... ArgTs>
472 static void callAsync(AsyncCallerFn &&Caller,
473 SendDeserializedResultFn &&SendDeserializedResult,
474 const ArgTs &...Args) {
475 using RetT = typename std::tuple_element<
476 1, typename detail::WrapperFunctionHandlerHelper<
477 std::remove_reference_t<SendDeserializedResultFn>,
478 ResultSerializer, SPSRetTagT>::ArgTuple>::type;
479
480 auto ArgBuffer =
481 detail::serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSTagTs...>>(
482 Args...);
483 if (auto *ErrMsg = ArgBuffer.getOutOfBandError()) {
484 SendDeserializedResult(
485 make_error<StringError>(ErrMsg, inconvertibleErrorCode()),
486 detail::ResultDeserializer<SPSRetTagT, RetT>::makeValue());
487 return;
488 }
489
490 auto SendSerializedResult = [SDR = std::move(SendDeserializedResult)](
491 WrapperFunctionResult R) mutable {
492 RetT RetVal = detail::ResultDeserializer<SPSRetTagT, RetT>::makeValue();
493 detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(RetVal);
494
495 if (auto *ErrMsg = R.getOutOfBandError()) {
496 SDR(make_error<StringError>(ErrMsg, inconvertibleErrorCode()),
497 std::move(RetVal));
498 return;
499 }
500
501 SPSInputBuffer IB(R.data(), R.size());
502 if (auto Err = detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize(
503 RetVal, R.data(), R.size()))
504 SDR(std::move(Err), std::move(RetVal));
505
506 SDR(Error::success(), std::move(RetVal));
507 };
508
509 Caller(std::move(SendSerializedResult), ArgBuffer.data(), ArgBuffer.size());
510 }
511
512 /// Handle a call to a wrapper function.
513 template <typename HandlerT>
514 static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize,
515 HandlerT &&Handler) {
516 using WFHH =
517 detail::WrapperFunctionHandlerHelper<std::remove_reference_t<HandlerT>,
518 ResultSerializer, SPSTagTs...>;
519 return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize);
520 }
521
522 /// Handle a call to an async wrapper function.
523 template <typename HandlerT, typename SendResultT>
524 static void handleAsync(const char *ArgData, size_t ArgSize,
525 HandlerT &&Handler, SendResultT &&SendResult) {
526 using WFAHH = detail::WrapperFunctionAsyncHandlerHelper<
527 std::remove_reference_t<HandlerT>, ResultSerializer, SPSTagTs...>;
528 WFAHH::applyAsync(std::forward<HandlerT>(Handler),
529 std::forward<SendResultT>(SendResult), ArgData, ArgSize);
530 }
531
532private:
533 template <typename T> static const T &makeSerializable(const T &Value) {
534 return Value;
535 }
536
537 static detail::SPSSerializableError makeSerializable(Error Err) {
538 return detail::toSPSSerializable(std::move(Err));
539 }
540
541 template <typename T>
542 static detail::SPSSerializableExpected<T> makeSerializable(Expected<T> E) {
543 return detail::toSPSSerializable(std::move(E));
544 }
545};
546
547template <typename... SPSTagTs>
548class WrapperFunction<void(SPSTagTs...)>
549 : private WrapperFunction<SPSEmpty(SPSTagTs...)> {
550
551public:
552 template <typename CallerFn, typename... ArgTs>
553 static Error call(const CallerFn &Caller, const ArgTs &...Args) {
554 SPSEmpty BE;
555 return WrapperFunction<SPSEmpty(SPSTagTs...)>::call(Caller, BE, Args...);
556 }
557
558 template <typename AsyncCallerFn, typename SendDeserializedResultFn,
559 typename... ArgTs>
560 static void callAsync(AsyncCallerFn &&Caller,
561 SendDeserializedResultFn &&SendDeserializedResult,
562 const ArgTs &...Args) {
563 WrapperFunction<SPSEmpty(SPSTagTs...)>::callAsync(
564 std::forward<AsyncCallerFn>(Caller),
565 [SDR = std::move(SendDeserializedResult)](Error SerializeErr,
566 SPSEmpty E) mutable {
567 SDR(std::move(SerializeErr));
568 },
569 Args...);
570 }
571
572 using WrapperFunction<SPSEmpty(SPSTagTs...)>::handle;
573 using WrapperFunction<SPSEmpty(SPSTagTs...)>::handleAsync;
574};
575
576/// A function object that takes an ExecutorAddr as its first argument,
577/// casts that address to a ClassT*, then calls the given method on that
578/// pointer passing in the remaining function arguments. This utility
579/// removes some of the boilerplate from writing wrappers for method calls.
580///
581/// @code{.cpp}
582/// class MyClass {
583/// public:
584/// void myMethod(uint32_t, bool) { ... }
585/// };
586///
587/// // SPS Method signature -- note MyClass object address as first argument.
588/// using SPSMyMethodWrapperSignature =
589/// SPSTuple<SPSExecutorAddr, uint32_t, bool>;
590///
591/// WrapperFunctionResult
592/// myMethodCallWrapper(const char *ArgData, size_t ArgSize) {
593/// return WrapperFunction<SPSMyMethodWrapperSignature>::handle(
594/// ArgData, ArgSize, makeMethodWrapperHandler(&MyClass::myMethod));
595/// }
596/// @endcode
597///
598template <typename RetT, typename ClassT, typename... ArgTs>
599class MethodWrapperHandler {
600public:
601 using MethodT = RetT (ClassT::*)(ArgTs...);
602 MethodWrapperHandler(MethodT M) : M(M) {}
603 RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args) {
604 return (ObjAddr.toPtr<ClassT*>()->*M)(std::forward<ArgTs>(Args)...);
605 }
606
607private:
608 MethodT M;
609};
610
611/// Create a MethodWrapperHandler object from the given method pointer.
612template <typename RetT, typename ClassT, typename... ArgTs>
613MethodWrapperHandler<RetT, ClassT, ArgTs...>
614makeMethodWrapperHandler(RetT (ClassT::*Method)(ArgTs...)) {
615 return MethodWrapperHandler<RetT, ClassT, ArgTs...>(Method);
616}
617
618} // end namespace shared
619} // end namespace orc
620} // end namespace llvm
621
622#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H

/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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);
17
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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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.\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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!\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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!\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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!\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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!\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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().\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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.\""
, "/build/llvm-toolchain-snapshot-14~++20211030100902+82ed10656706/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