Bug Summary

File:src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ADT/FunctionExtras.h
Warning:line 198, column 5
Undefined or garbage value returned to caller

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name RTDyldObjectLinkingLayer.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 -mrelocation-model pic -pic-level 1 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/gnu/usr.bin/clang/libLLVM/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/AMDGPU -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Analysis -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ASMParser -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/BinaryFormat -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Bitcode -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Bitcode -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Bitstream -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /include/llvm/CodeGen -I /include/llvm/CodeGen/PBQP -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/IR -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/IR -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms/Coroutines -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ProfileData/Coverage -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/DebugInfo/CodeView -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/DebugInfo/DWARF -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/DebugInfo -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/DebugInfo/MSF -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/DebugInfo/PDB -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Demangle -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ExecutionEngine -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ExecutionEngine/JITLink -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ExecutionEngine/Orc -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Frontend -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Frontend/OpenACC -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Frontend -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Frontend/OpenMP -I /include/llvm/CodeGen/GlobalISel -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/IRReader -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms/InstCombine -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/Transforms/InstCombine -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/LTO -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Linker -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/MC -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/MC/MCParser -I /include/llvm/CodeGen/MIRParser -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Object -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Option -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Passes -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ProfileData -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms/Scalar -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ADT -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Support -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/DebugInfo/Symbolize -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Target -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms/Utils -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms/Vectorize -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include/llvm/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/Target/X86 -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/Transforms/IPO -I /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include -I /usr/src/gnu/usr.bin/clang/libLLVM/../include -I /usr/src/gnu/usr.bin/clang/libLLVM/obj -I /usr/src/gnu/usr.bin/clang/libLLVM/obj/../include -D NDEBUG -D __STDC_LIMIT_MACROS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D LLVM_PREFIX="/usr" -D PIC -internal-isystem /usr/include/c++/v1 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/usr/src/gnu/usr.bin/clang/libLLVM/obj -ferror-limit 19 -fvisibility-inlines-hidden -fwrapv -D_RET_PROTECTOR -ret-protector -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c++ /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp

/usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp

1//===-- RTDyldObjectLinkingLayer.cpp - RuntimeDyld backed ORC ObjectLayer -===//
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/RTDyldObjectLinkingLayer.h"
10#include "llvm/Object/COFF.h"
11
12namespace {
13
14using namespace llvm;
15using namespace llvm::orc;
16
17class JITDylibSearchOrderResolver : public JITSymbolResolver {
18public:
19 JITDylibSearchOrderResolver(MaterializationResponsibility &MR) : MR(MR) {}
20
21 void lookup(const LookupSet &Symbols, OnResolvedFunction OnResolved) override {
22 auto &ES = MR.getTargetJITDylib().getExecutionSession();
23 SymbolLookupSet InternedSymbols;
24
25 // Intern the requested symbols: lookup takes interned strings.
26 for (auto &S : Symbols)
27 InternedSymbols.add(ES.intern(S));
28
29 // Build an OnResolve callback to unwrap the interned strings and pass them
30 // to the OnResolved callback.
31 auto OnResolvedWithUnwrap =
32 [OnResolved = std::move(OnResolved)](
1
Calling implicit move constructor
2
Calling defaulted move constructor for 'unique_function<void (llvm::Expected<std::map<llvm::StringRef, llvm::JITEvaluatedSymbol>>)>'
8
Returning from move constructor for 'unique_function<void (llvm::Expected<std::map<llvm::StringRef, llvm::JITEvaluatedSymbol>>)>'
9
Returning from move constructor
33 Expected<SymbolMap> InternedResult) mutable {
34 if (!InternedResult) {
35 OnResolved(InternedResult.takeError());
36 return;
37 }
38
39 LookupResult Result;
40 for (auto &KV : *InternedResult)
41 Result[*KV.first] = std::move(KV.second);
42 OnResolved(Result);
43 };
44
45 // Register dependencies for all symbols contained in this set.
46 auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) {
47 MR.addDependenciesForAll(Deps);
48 };
49
50 JITDylibSearchOrder LinkOrder;
51 MR.getTargetJITDylib().withLinkOrderDo(
52 [&](const JITDylibSearchOrder &LO) { LinkOrder = LO; });
53 ES.lookup(LookupKind::Static, LinkOrder, InternedSymbols,
54 SymbolState::Resolved, std::move(OnResolvedWithUnwrap),
10
Calling 'move<(lambda at /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp:32:9) &>'
11
Returning from 'move<(lambda at /usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp:32:9) &>'
12
Calling implicit move constructor
13
Calling defaulted move constructor for 'unique_function<void (llvm::Expected<std::map<llvm::StringRef, llvm::JITEvaluatedSymbol>>)>'
17
Returning from move constructor for 'unique_function<void (llvm::Expected<std::map<llvm::StringRef, llvm::JITEvaluatedSymbol>>)>'
18
Returning from move constructor
55 RegisterDependencies);
56 }
19
Calling implicit destructor
20
Calling implicit destructor for 'unique_function<void (llvm::Expected<std::map<llvm::StringRef, llvm::JITEvaluatedSymbol>>)>'
21
Calling '~UniqueFunctionBase'
57
58 Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) override {
59 LookupSet Result;
60
61 for (auto &KV : MR.getSymbols()) {
62 if (Symbols.count(*KV.first))
63 Result.insert(*KV.first);
64 }
65
66 return Result;
67 }
68
69private:
70 MaterializationResponsibility &MR;
71};
72
73} // end anonymous namespace
74
75namespace llvm {
76namespace orc {
77
78char RTDyldObjectLinkingLayer::ID;
79
80using BaseT = RTTIExtends<RTDyldObjectLinkingLayer, ObjectLayer>;
81
82RTDyldObjectLinkingLayer::RTDyldObjectLinkingLayer(
83 ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager)
84 : BaseT(ES), GetMemoryManager(GetMemoryManager) {
85 ES.registerResourceManager(*this);
86}
87
88RTDyldObjectLinkingLayer::~RTDyldObjectLinkingLayer() {
89 assert(MemMgrs.empty() && "Layer destroyed with resources still attached")((void)0);
90}
91
92void RTDyldObjectLinkingLayer::emit(
93 std::unique_ptr<MaterializationResponsibility> R,
94 std::unique_ptr<MemoryBuffer> O) {
95 assert(O && "Object must not be null")((void)0);
96
97 auto &ES = getExecutionSession();
98
99 auto Obj = object::ObjectFile::createObjectFile(*O);
100
101 if (!Obj) {
102 getExecutionSession().reportError(Obj.takeError());
103 R->failMaterialization();
104 return;
105 }
106
107 // Collect the internal symbols from the object file: We will need to
108 // filter these later.
109 auto InternalSymbols = std::make_shared<std::set<StringRef>>();
110 {
111 for (auto &Sym : (*Obj)->symbols()) {
112
113 // Skip file symbols.
114 if (auto SymType = Sym.getType()) {
115 if (*SymType == object::SymbolRef::ST_File)
116 continue;
117 } else {
118 ES.reportError(SymType.takeError());
119 R->failMaterialization();
120 return;
121 }
122
123 Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
124 if (!SymFlagsOrErr) {
125 // TODO: Test this error.
126 ES.reportError(SymFlagsOrErr.takeError());
127 R->failMaterialization();
128 return;
129 }
130
131 // Don't include symbols that aren't global.
132 if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) {
133 if (auto SymName = Sym.getName())
134 InternalSymbols->insert(*SymName);
135 else {
136 ES.reportError(SymName.takeError());
137 R->failMaterialization();
138 return;
139 }
140 }
141 }
142 }
143
144 auto MemMgr = GetMemoryManager();
145 auto &MemMgrRef = *MemMgr;
146
147 // Switch to shared ownership of MR so that it can be captured by both
148 // lambdas below.
149 std::shared_ptr<MaterializationResponsibility> SharedR(std::move(R));
150
151 JITDylibSearchOrderResolver Resolver(*SharedR);
152
153 jitLinkForORC(
154 object::OwningBinary<object::ObjectFile>(std::move(*Obj), std::move(O)),
155 MemMgrRef, Resolver, ProcessAllSections,
156 [this, SharedR, &MemMgrRef, InternalSymbols](
157 const object::ObjectFile &Obj,
158 RuntimeDyld::LoadedObjectInfo &LoadedObjInfo,
159 std::map<StringRef, JITEvaluatedSymbol> ResolvedSymbols) {
160 return onObjLoad(*SharedR, Obj, MemMgrRef, LoadedObjInfo,
161 ResolvedSymbols, *InternalSymbols);
162 },
163 [this, SharedR, MemMgr = std::move(MemMgr)](
164 object::OwningBinary<object::ObjectFile> Obj,
165 std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo,
166 Error Err) mutable {
167 onObjEmit(*SharedR, std::move(Obj), std::move(MemMgr),
168 std::move(LoadedObjInfo), std::move(Err));
169 });
170}
171
172void RTDyldObjectLinkingLayer::registerJITEventListener(JITEventListener &L) {
173 std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);
174 assert(!llvm::is_contained(EventListeners, &L) &&((void)0)
175 "Listener has already been registered")((void)0);
176 EventListeners.push_back(&L);
177}
178
179void RTDyldObjectLinkingLayer::unregisterJITEventListener(JITEventListener &L) {
180 std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);
181 auto I = llvm::find(EventListeners, &L);
182 assert(I != EventListeners.end() && "Listener not registered")((void)0);
183 EventListeners.erase(I);
184}
185
186Error RTDyldObjectLinkingLayer::onObjLoad(
187 MaterializationResponsibility &R, const object::ObjectFile &Obj,
188 RuntimeDyld::MemoryManager &MemMgr,
189 RuntimeDyld::LoadedObjectInfo &LoadedObjInfo,
190 std::map<StringRef, JITEvaluatedSymbol> Resolved,
191 std::set<StringRef> &InternalSymbols) {
192 SymbolFlagsMap ExtraSymbolsToClaim;
193 SymbolMap Symbols;
194
195 // Hack to support COFF constant pool comdats introduced during compilation:
196 // (See http://llvm.org/PR40074)
197 if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(&Obj)) {
198 auto &ES = getExecutionSession();
199
200 // For all resolved symbols that are not already in the responsibilty set:
201 // check whether the symbol is in a comdat section and if so mark it as
202 // weak.
203 for (auto &Sym : COFFObj->symbols()) {
204 // getFlags() on COFF symbols can't fail.
205 uint32_t SymFlags = cantFail(Sym.getFlags());
206 if (SymFlags & object::BasicSymbolRef::SF_Undefined)
207 continue;
208 auto Name = Sym.getName();
209 if (!Name)
210 return Name.takeError();
211 auto I = Resolved.find(*Name);
212
213 // Skip unresolved symbols, internal symbols, and symbols that are
214 // already in the responsibility set.
215 if (I == Resolved.end() || InternalSymbols.count(*Name) ||
216 R.getSymbols().count(ES.intern(*Name)))
217 continue;
218 auto Sec = Sym.getSection();
219 if (!Sec)
220 return Sec.takeError();
221 if (*Sec == COFFObj->section_end())
222 continue;
223 auto &COFFSec = *COFFObj->getCOFFSection(**Sec);
224 if (COFFSec.Characteristics & COFF::IMAGE_SCN_LNK_COMDAT)
225 I->second.setFlags(I->second.getFlags() | JITSymbolFlags::Weak);
226 }
227 }
228
229 for (auto &KV : Resolved) {
230 // Scan the symbols and add them to the Symbols map for resolution.
231
232 // We never claim internal symbols.
233 if (InternalSymbols.count(KV.first))
234 continue;
235
236 auto InternedName = getExecutionSession().intern(KV.first);
237 auto Flags = KV.second.getFlags();
238
239 // Override object flags and claim responsibility for symbols if
240 // requested.
241 if (OverrideObjectFlags || AutoClaimObjectSymbols) {
242 auto I = R.getSymbols().find(InternedName);
243
244 if (OverrideObjectFlags && I != R.getSymbols().end())
245 Flags = I->second;
246 else if (AutoClaimObjectSymbols && I == R.getSymbols().end())
247 ExtraSymbolsToClaim[InternedName] = Flags;
248 }
249
250 Symbols[InternedName] = JITEvaluatedSymbol(KV.second.getAddress(), Flags);
251 }
252
253 if (!ExtraSymbolsToClaim.empty()) {
254 if (auto Err = R.defineMaterializing(ExtraSymbolsToClaim))
255 return Err;
256
257 // If we claimed responsibility for any weak symbols but were rejected then
258 // we need to remove them from the resolved set.
259 for (auto &KV : ExtraSymbolsToClaim)
260 if (KV.second.isWeak() && !R.getSymbols().count(KV.first))
261 Symbols.erase(KV.first);
262 }
263
264 if (auto Err = R.notifyResolved(Symbols)) {
265 R.failMaterialization();
266 return Err;
267 }
268
269 if (NotifyLoaded)
270 NotifyLoaded(R, Obj, LoadedObjInfo);
271
272 return Error::success();
273}
274
275void RTDyldObjectLinkingLayer::onObjEmit(
276 MaterializationResponsibility &R,
277 object::OwningBinary<object::ObjectFile> O,
278 std::unique_ptr<RuntimeDyld::MemoryManager> MemMgr,
279 std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo, Error Err) {
280 if (Err) {
281 getExecutionSession().reportError(std::move(Err));
282 R.failMaterialization();
283 return;
284 }
285
286 if (auto Err = R.notifyEmitted()) {
287 getExecutionSession().reportError(std::move(Err));
288 R.failMaterialization();
289 return;
290 }
291
292 std::unique_ptr<object::ObjectFile> Obj;
293 std::unique_ptr<MemoryBuffer> ObjBuffer;
294 std::tie(Obj, ObjBuffer) = O.takeBinary();
295
296 // Run EventListener notifyLoaded callbacks.
297 {
298 std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);
299 for (auto *L : EventListeners)
300 L->notifyObjectLoaded(pointerToJITTargetAddress(MemMgr.get()), *Obj,
301 *LoadedObjInfo);
302 }
303
304 if (NotifyEmitted)
305 NotifyEmitted(R, std::move(ObjBuffer));
306
307 if (auto Err = R.withResourceKeyDo(
308 [&](ResourceKey K) { MemMgrs[K].push_back(std::move(MemMgr)); })) {
309 getExecutionSession().reportError(std::move(Err));
310 R.failMaterialization();
311 }
312}
313
314Error RTDyldObjectLinkingLayer::handleRemoveResources(ResourceKey K) {
315
316 std::vector<MemoryManagerUP> MemMgrsToRemove;
317
318 getExecutionSession().runSessionLocked([&] {
319 auto I = MemMgrs.find(K);
320 if (I != MemMgrs.end()) {
321 std::swap(MemMgrsToRemove, I->second);
322 MemMgrs.erase(I);
323 }
324 });
325
326 {
327 std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);
328 for (auto &MemMgr : MemMgrsToRemove) {
329 for (auto *L : EventListeners)
330 L->notifyFreeingObject(pointerToJITTargetAddress(MemMgr.get()));
331 MemMgr->deregisterEHFrames();
332 }
333 }
334
335 return Error::success();
336}
337
338void RTDyldObjectLinkingLayer::handleTransferResources(ResourceKey DstKey,
339 ResourceKey SrcKey) {
340 auto I = MemMgrs.find(SrcKey);
341 if (I != MemMgrs.end()) {
342 auto &SrcMemMgrs = I->second;
343 auto &DstMemMgrs = MemMgrs[DstKey];
344 DstMemMgrs.reserve(DstMemMgrs.size() + SrcMemMgrs.size());
345 for (auto &MemMgr : SrcMemMgrs)
346 DstMemMgrs.push_back(std::move(MemMgr));
347
348 // Erase SrcKey entry using value rather than iterator I: I may have been
349 // invalidated when we looked up DstKey.
350 MemMgrs.erase(SrcKey);
351 }
352}
353
354} // End namespace orc.
355} // End namespace llvm.

/usr/src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/ADT/FunctionExtras.h

1//===- FunctionExtras.h - Function type erasure utilities -------*- 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/// \file
9/// This file provides a collection of function (or more generally, callable)
10/// type erasure utilities supplementing those provided by the standard library
11/// in `<function>`.
12///
13/// It provides `unique_function`, which works like `std::function` but supports
14/// move-only callable objects and const-qualification.
15///
16/// Future plans:
17/// - Add a `function` that provides ref-qualified support, which doesn't work
18/// with `std::function`.
19/// - Provide support for specifying multiple signatures to type erase callable
20/// objects with an overload set, such as those produced by generic lambdas.
21/// - Expand to include a copyable utility that directly replaces std::function
22/// but brings the above improvements.
23///
24/// Note that LLVM's utilities are greatly simplified by not supporting
25/// allocators.
26///
27/// If the standard library ever begins to provide comparable facilities we can
28/// consider switching to those.
29///
30//===----------------------------------------------------------------------===//
31
32#ifndef LLVM_ADT_FUNCTIONEXTRAS_H
33#define LLVM_ADT_FUNCTIONEXTRAS_H
34
35#include "llvm/ADT/PointerIntPair.h"
36#include "llvm/ADT/PointerUnion.h"
37#include "llvm/ADT/STLForwardCompat.h"
38#include "llvm/Support/MemAlloc.h"
39#include "llvm/Support/type_traits.h"
40#include <memory>
41#include <type_traits>
42
43namespace llvm {
44
45/// unique_function is a type-erasing functor similar to std::function.
46///
47/// It can hold move-only function objects, like lambdas capturing unique_ptrs.
48/// Accordingly, it is movable but not copyable.
49///
50/// It supports const-qualification:
51/// - unique_function<int() const> has a const operator().
52/// It can only hold functions which themselves have a const operator().
53/// - unique_function<int()> has a non-const operator().
54/// It can hold functions with a non-const operator(), like mutable lambdas.
55template <typename FunctionT> class unique_function;
56
57namespace detail {
58
59template <typename T>
60using EnableIfTrivial =
61 std::enable_if_t<llvm::is_trivially_move_constructible<T>::value &&
62 std::is_trivially_destructible<T>::value>;
63template <typename CallableT, typename ThisT>
64using EnableUnlessSameType =
65 std::enable_if_t<!std::is_same<remove_cvref_t<CallableT>, ThisT>::value>;
66template <typename CallableT, typename Ret, typename... Params>
67using EnableIfCallable =
68 std::enable_if_t<std::is_void<Ret>::value ||
69 std::is_convertible<decltype(std::declval<CallableT>()(
70 std::declval<Params>()...)),
71 Ret>::value>;
72
73template <typename ReturnT, typename... ParamTs> class UniqueFunctionBase {
74protected:
75 static constexpr size_t InlineStorageSize = sizeof(void *) * 3;
76
77 template <typename T, class = void>
78 struct IsSizeLessThanThresholdT : std::false_type {};
79
80 template <typename T>
81 struct IsSizeLessThanThresholdT<
82 T, std::enable_if_t<sizeof(T) <= 2 * sizeof(void *)>> : std::true_type {};
83
84 // Provide a type function to map parameters that won't observe extra copies
85 // or moves and which are small enough to likely pass in register to values
86 // and all other types to l-value reference types. We use this to compute the
87 // types used in our erased call utility to minimize copies and moves unless
88 // doing so would force things unnecessarily into memory.
89 //
90 // The heuristic used is related to common ABI register passing conventions.
91 // It doesn't have to be exact though, and in one way it is more strict
92 // because we want to still be able to observe either moves *or* copies.
93 template <typename T> struct AdjustedParamTBase {
94 static_assert(!std::is_reference<T>::value,
95 "references should be handled by template specialization");
96 using type = typename std::conditional<
97 llvm::is_trivially_copy_constructible<T>::value &&
98 llvm::is_trivially_move_constructible<T>::value &&
99 IsSizeLessThanThresholdT<T>::value,
100 T, T &>::type;
101 };
102
103 // This specialization ensures that 'AdjustedParam<V<T>&>' or
104 // 'AdjustedParam<V<T>&&>' does not trigger a compile-time error when 'T' is
105 // an incomplete type and V a templated type.
106 template <typename T> struct AdjustedParamTBase<T &> { using type = T &; };
107 template <typename T> struct AdjustedParamTBase<T &&> { using type = T &; };
108
109 template <typename T>
110 using AdjustedParamT = typename AdjustedParamTBase<T>::type;
111
112 // The type of the erased function pointer we use as a callback to dispatch to
113 // the stored callable when it is trivial to move and destroy.
114 using CallPtrT = ReturnT (*)(void *CallableAddr,
115 AdjustedParamT<ParamTs>... Params);
116 using MovePtrT = void (*)(void *LHSCallableAddr, void *RHSCallableAddr);
117 using DestroyPtrT = void (*)(void *CallableAddr);
118
119 /// A struct to hold a single trivial callback with sufficient alignment for
120 /// our bitpacking.
121 struct alignas(8) TrivialCallback {
122 CallPtrT CallPtr;
123 };
124
125 /// A struct we use to aggregate three callbacks when we need full set of
126 /// operations.
127 struct alignas(8) NonTrivialCallbacks {
128 CallPtrT CallPtr;
129 MovePtrT MovePtr;
130 DestroyPtrT DestroyPtr;
131 };
132
133 // Create a pointer union between either a pointer to a static trivial call
134 // pointer in a struct or a pointer to a static struct of the call, move, and
135 // destroy pointers.
136 using CallbackPointerUnionT =
137 PointerUnion<TrivialCallback *, NonTrivialCallbacks *>;
138
139 // The main storage buffer. This will either have a pointer to out-of-line
140 // storage or an inline buffer storing the callable.
141 union StorageUnionT {
142 // For out-of-line storage we keep a pointer to the underlying storage and
143 // the size. This is enough to deallocate the memory.
144 struct OutOfLineStorageT {
145 void *StoragePtr;
146 size_t Size;
147 size_t Alignment;
148 } OutOfLineStorage;
149 static_assert(
150 sizeof(OutOfLineStorageT) <= InlineStorageSize,
151 "Should always use all of the out-of-line storage for inline storage!");
152
153 // For in-line storage, we just provide an aligned character buffer. We
154 // provide three pointers worth of storage here.
155 // This is mutable as an inlined `const unique_function<void() const>` may
156 // still modify its own mutable members.
157 mutable
158 typename std::aligned_storage<InlineStorageSize, alignof(void *)>::type
159 InlineStorage;
160 } StorageUnion;
161
162 // A compressed pointer to either our dispatching callback or our table of
163 // dispatching callbacks and the flag for whether the callable itself is
164 // stored inline or not.
165 PointerIntPair<CallbackPointerUnionT, 1, bool> CallbackAndInlineFlag;
166
167 bool isInlineStorage() const { return CallbackAndInlineFlag.getInt(); }
168
169 bool isTrivialCallback() const {
170 return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>();
171 }
172
173 CallPtrT getTrivialCallback() const {
174 return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr;
175 }
176
177 NonTrivialCallbacks *getNonTrivialCallbacks() const {
178 return CallbackAndInlineFlag.getPointer()
179 .template get<NonTrivialCallbacks *>();
180 }
181
182 CallPtrT getCallPtr() const {
183 return isTrivialCallback() ? getTrivialCallback()
184 : getNonTrivialCallbacks()->CallPtr;
185 }
186
187 // These three functions are only const in the narrow sense. They return
188 // mutable pointers to function state.
189 // This allows unique_function<T const>::operator() to be const, even if the
190 // underlying functor may be internally mutable.
191 //
192 // const callers must ensure they're only used in const-correct ways.
193 void *getCalleePtr() const {
194 return isInlineStorage() ? getInlineStorage() : getOutOfLineStorage();
195 }
196 void *getInlineStorage() const { return &StorageUnion.InlineStorage; }
197 void *getOutOfLineStorage() const {
198 return StorageUnion.OutOfLineStorage.StoragePtr;
28
Undefined or garbage value returned to caller
199 }
200
201 size_t getOutOfLineStorageSize() const {
202 return StorageUnion.OutOfLineStorage.Size;
203 }
204 size_t getOutOfLineStorageAlignment() const {
205 return StorageUnion.OutOfLineStorage.Alignment;
206 }
207
208 void setOutOfLineStorage(void *Ptr, size_t Size, size_t Alignment) {
209 StorageUnion.OutOfLineStorage = {Ptr, Size, Alignment};
210 }
211
212 template <typename CalledAsT>
213 static ReturnT CallImpl(void *CallableAddr,
214 AdjustedParamT<ParamTs>... Params) {
215 auto &Func = *reinterpret_cast<CalledAsT *>(CallableAddr);
216 return Func(std::forward<ParamTs>(Params)...);
217 }
218
219 template <typename CallableT>
220 static void MoveImpl(void *LHSCallableAddr, void *RHSCallableAddr) noexcept {
221 new (LHSCallableAddr)
222 CallableT(std::move(*reinterpret_cast<CallableT *>(RHSCallableAddr)));
223 }
224
225 template <typename CallableT>
226 static void DestroyImpl(void *CallableAddr) noexcept {
227 reinterpret_cast<CallableT *>(CallableAddr)->~CallableT();
228 }
229
230 // The pointers to call/move/destroy functions are determined for each
231 // callable type (and called-as type, which determines the overload chosen).
232 // (definitions are out-of-line).
233
234 // By default, we need an object that contains all the different
235 // type erased behaviors needed. Create a static instance of the struct type
236 // here and each instance will contain a pointer to it.
237 // Wrap in a struct to avoid https://gcc.gnu.org/PR71954
238 template <typename CallableT, typename CalledAs, typename Enable = void>
239 struct CallbacksHolder {
240 static NonTrivialCallbacks Callbacks;
241 };
242 // See if we can create a trivial callback. We need the callable to be
243 // trivially moved and trivially destroyed so that we don't have to store
244 // type erased callbacks for those operations.
245 template <typename CallableT, typename CalledAs>
246 struct CallbacksHolder<CallableT, CalledAs, EnableIfTrivial<CallableT>> {
247 static TrivialCallback Callbacks;
248 };
249
250 // A simple tag type so the call-as type to be passed to the constructor.
251 template <typename T> struct CalledAs {};
252
253 // Essentially the "main" unique_function constructor, but subclasses
254 // provide the qualified type to be used for the call.
255 // (We always store a T, even if the call will use a pointer to const T).
256 template <typename CallableT, typename CalledAsT>
257 UniqueFunctionBase(CallableT Callable, CalledAs<CalledAsT>) {
258 bool IsInlineStorage = true;
259 void *CallableAddr = getInlineStorage();
260 if (sizeof(CallableT) > InlineStorageSize ||
261 alignof(CallableT) > alignof(decltype(StorageUnion.InlineStorage))) {
262 IsInlineStorage = false;
263 // Allocate out-of-line storage. FIXME: Use an explicit alignment
264 // parameter in C++17 mode.
265 auto Size = sizeof(CallableT);
266 auto Alignment = alignof(CallableT);
267 CallableAddr = allocate_buffer(Size, Alignment);
268 setOutOfLineStorage(CallableAddr, Size, Alignment);
269 }
270
271 // Now move into the storage.
272 new (CallableAddr) CallableT(std::move(Callable));
273 CallbackAndInlineFlag.setPointerAndInt(
274 &CallbacksHolder<CallableT, CalledAsT>::Callbacks, IsInlineStorage);
275 }
276
277 ~UniqueFunctionBase() {
278 if (!CallbackAndInlineFlag.getPointer())
22
Taking false branch
279 return;
280
281 // Cache this value so we don't re-check it after type-erased operations.
282 bool IsInlineStorage = isInlineStorage();
283
284 if (!isTrivialCallback())
23
Assuming the condition is false
24
Taking false branch
285 getNonTrivialCallbacks()->DestroyPtr(
286 IsInlineStorage ? getInlineStorage() : getOutOfLineStorage());
287
288 if (!IsInlineStorage)
25
Assuming 'IsInlineStorage' is false
26
Taking true branch
289 deallocate_buffer(getOutOfLineStorage(), getOutOfLineStorageSize(),
27
Calling 'UniqueFunctionBase::getOutOfLineStorage'
290 getOutOfLineStorageAlignment());
291 }
292
293 UniqueFunctionBase(UniqueFunctionBase &&RHS) noexcept {
294 // Copy the callback and inline flag.
295 CallbackAndInlineFlag = RHS.CallbackAndInlineFlag;
296
297 // If the RHS is empty, just copying the above is sufficient.
298 if (!RHS)
4
Taking true branch
15
Taking true branch
299 return;
5
Returning without writing to 'this->StorageUnion.OutOfLineStorage.StoragePtr'
300
301 if (!isInlineStorage()) {
302 // The out-of-line case is easiest to move.
303 StorageUnion.OutOfLineStorage = RHS.StorageUnion.OutOfLineStorage;
304 } else if (isTrivialCallback()) {
305 // Move is trivial, just memcpy the bytes across.
306 memcpy(getInlineStorage(), RHS.getInlineStorage(), InlineStorageSize);
307 } else {
308 // Non-trivial move, so dispatch to a type-erased implementation.
309 getNonTrivialCallbacks()->MovePtr(getInlineStorage(),
310 RHS.getInlineStorage());
311 }
312
313 // Clear the old callback and inline flag to get back to as-if-null.
314 RHS.CallbackAndInlineFlag = {};
315
316#ifndef NDEBUG1
317 // In debug builds, we also scribble across the rest of the storage.
318 memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize);
319#endif
320 }
321
322 UniqueFunctionBase &operator=(UniqueFunctionBase &&RHS) noexcept {
323 if (this == &RHS)
324 return *this;
325
326 // Because we don't try to provide any exception safety guarantees we can
327 // implement move assignment very simply by first destroying the current
328 // object and then move-constructing over top of it.
329 this->~UniqueFunctionBase();
330 new (this) UniqueFunctionBase(std::move(RHS));
331 return *this;
332 }
333
334 UniqueFunctionBase() = default;
335
336public:
337 explicit operator bool() const {
338 return (bool)CallbackAndInlineFlag.getPointer();
339 }
340};
341
342template <typename R, typename... P>
343template <typename CallableT, typename CalledAsT, typename Enable>
344typename UniqueFunctionBase<R, P...>::NonTrivialCallbacks UniqueFunctionBase<
345 R, P...>::CallbacksHolder<CallableT, CalledAsT, Enable>::Callbacks = {
346 &CallImpl<CalledAsT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
347
348template <typename R, typename... P>
349template <typename CallableT, typename CalledAsT>
350typename UniqueFunctionBase<R, P...>::TrivialCallback
351 UniqueFunctionBase<R, P...>::CallbacksHolder<
352 CallableT, CalledAsT, EnableIfTrivial<CallableT>>::Callbacks{
353 &CallImpl<CalledAsT>};
354
355} // namespace detail
356
357template <typename R, typename... P>
358class unique_function<R(P...)> : public detail::UniqueFunctionBase<R, P...> {
359 using Base = detail::UniqueFunctionBase<R, P...>;
360
361public:
362 unique_function() = default;
363 unique_function(std::nullptr_t) {}
364 unique_function(unique_function &&) = default;
3
Calling move constructor for 'UniqueFunctionBase<void, llvm::Expected<std::map<llvm::StringRef, llvm::JITEvaluatedSymbol>>>'
6
Returning from move constructor for 'UniqueFunctionBase<void, llvm::Expected<std::map<llvm::StringRef, llvm::JITEvaluatedSymbol>>>'
7
Returning without writing to 'this->StorageUnion.OutOfLineStorage.StoragePtr'
14
Calling move constructor for 'UniqueFunctionBase<void, llvm::Expected<std::map<llvm::StringRef, llvm::JITEvaluatedSymbol>>>'
16
Returning from move constructor for 'UniqueFunctionBase<void, llvm::Expected<std::map<llvm::StringRef, llvm::JITEvaluatedSymbol>>>'
365 unique_function(const unique_function &) = delete;
366 unique_function &operator=(unique_function &&) = default;
367 unique_function &operator=(const unique_function &) = delete;
368
369 template <typename CallableT>
370 unique_function(
371 CallableT Callable,
372 detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
373 detail::EnableIfCallable<CallableT, R, P...> * = nullptr)
374 : Base(std::forward<CallableT>(Callable),
375 typename Base::template CalledAs<CallableT>{}) {}
376
377 R operator()(P... Params) {
378 return this->getCallPtr()(this->getCalleePtr(), Params...);
379 }
380};
381
382template <typename R, typename... P>
383class unique_function<R(P...) const>
384 : public detail::UniqueFunctionBase<R, P...> {
385 using Base = detail::UniqueFunctionBase<R, P...>;
386
387public:
388 unique_function() = default;
389 unique_function(std::nullptr_t) {}
390 unique_function(unique_function &&) = default;
391 unique_function(const unique_function &) = delete;
392 unique_function &operator=(unique_function &&) = default;
393 unique_function &operator=(const unique_function &) = delete;
394
395 template <typename CallableT>
396 unique_function(
397 CallableT Callable,
398 detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
399 detail::EnableIfCallable<const CallableT, R, P...> * = nullptr)
400 : Base(std::forward<CallableT>(Callable),
401 typename Base::template CalledAs<const CallableT>{}) {}
402
403 R operator()(P... Params) const {
404 return this->getCallPtr()(this->getCalleePtr(), Params...);
405 }
406};
407
408} // end namespace llvm
409
410#endif // LLVM_ADT_FUNCTIONEXTRAS_H