1 //===--- Core.cpp - Core ORC APIs (MaterializationUnit, JITDylib, etc.) ---===//
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/Core.h"
10
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/Config/llvm-config.h"
13 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
14 #include "llvm/ExecutionEngine/Orc/OrcError.h"
15
16 #include <condition_variable>
17 #if LLVM_ENABLE_THREADS
18 #include <future>
19 #endif
20
21 #define DEBUG_TYPE "orc"
22
23 namespace llvm {
24 namespace orc {
25
26 char FailedToMaterialize::ID = 0;
27 char SymbolsNotFound::ID = 0;
28 char SymbolsCouldNotBeRemoved::ID = 0;
29 char MissingSymbolDefinitions::ID = 0;
30 char UnexpectedSymbolDefinitions::ID = 0;
31
32 RegisterDependenciesFunction NoDependenciesToRegister =
33 RegisterDependenciesFunction();
34
anchor()35 void MaterializationUnit::anchor() {}
36
FailedToMaterialize(std::shared_ptr<SymbolDependenceMap> Symbols)37 FailedToMaterialize::FailedToMaterialize(
38 std::shared_ptr<SymbolDependenceMap> Symbols)
39 : Symbols(std::move(Symbols)) {
40 assert(!this->Symbols->empty() && "Can not fail to resolve an empty set");
41 }
42
convertToErrorCode() const43 std::error_code FailedToMaterialize::convertToErrorCode() const {
44 return orcError(OrcErrorCode::UnknownORCError);
45 }
46
log(raw_ostream & OS) const47 void FailedToMaterialize::log(raw_ostream &OS) const {
48 OS << "Failed to materialize symbols: " << *Symbols;
49 }
50
SymbolsNotFound(SymbolNameSet Symbols)51 SymbolsNotFound::SymbolsNotFound(SymbolNameSet Symbols) {
52 for (auto &Sym : Symbols)
53 this->Symbols.push_back(Sym);
54 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
55 }
56
SymbolsNotFound(SymbolNameVector Symbols)57 SymbolsNotFound::SymbolsNotFound(SymbolNameVector Symbols)
58 : Symbols(std::move(Symbols)) {
59 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
60 }
61
convertToErrorCode() const62 std::error_code SymbolsNotFound::convertToErrorCode() const {
63 return orcError(OrcErrorCode::UnknownORCError);
64 }
65
log(raw_ostream & OS) const66 void SymbolsNotFound::log(raw_ostream &OS) const {
67 OS << "Symbols not found: " << Symbols;
68 }
69
SymbolsCouldNotBeRemoved(SymbolNameSet Symbols)70 SymbolsCouldNotBeRemoved::SymbolsCouldNotBeRemoved(SymbolNameSet Symbols)
71 : Symbols(std::move(Symbols)) {
72 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
73 }
74
convertToErrorCode() const75 std::error_code SymbolsCouldNotBeRemoved::convertToErrorCode() const {
76 return orcError(OrcErrorCode::UnknownORCError);
77 }
78
log(raw_ostream & OS) const79 void SymbolsCouldNotBeRemoved::log(raw_ostream &OS) const {
80 OS << "Symbols could not be removed: " << Symbols;
81 }
82
convertToErrorCode() const83 std::error_code MissingSymbolDefinitions::convertToErrorCode() const {
84 return orcError(OrcErrorCode::MissingSymbolDefinitions);
85 }
86
log(raw_ostream & OS) const87 void MissingSymbolDefinitions::log(raw_ostream &OS) const {
88 OS << "Missing definitions in module " << ModuleName
89 << ": " << Symbols;
90 }
91
convertToErrorCode() const92 std::error_code UnexpectedSymbolDefinitions::convertToErrorCode() const {
93 return orcError(OrcErrorCode::UnexpectedSymbolDefinitions);
94 }
95
log(raw_ostream & OS) const96 void UnexpectedSymbolDefinitions::log(raw_ostream &OS) const {
97 OS << "Unexpected definitions in module " << ModuleName
98 << ": " << Symbols;
99 }
100
AsynchronousSymbolQuery(const SymbolLookupSet & Symbols,SymbolState RequiredState,SymbolsResolvedCallback NotifyComplete)101 AsynchronousSymbolQuery::AsynchronousSymbolQuery(
102 const SymbolLookupSet &Symbols, SymbolState RequiredState,
103 SymbolsResolvedCallback NotifyComplete)
104 : NotifyComplete(std::move(NotifyComplete)), RequiredState(RequiredState) {
105 assert(RequiredState >= SymbolState::Resolved &&
106 "Cannot query for a symbols that have not reached the resolve state "
107 "yet");
108
109 OutstandingSymbolsCount = Symbols.size();
110
111 for (auto &KV : Symbols)
112 ResolvedSymbols[KV.first] = nullptr;
113 }
114
notifySymbolMetRequiredState(const SymbolStringPtr & Name,JITEvaluatedSymbol Sym)115 void AsynchronousSymbolQuery::notifySymbolMetRequiredState(
116 const SymbolStringPtr &Name, JITEvaluatedSymbol Sym) {
117 auto I = ResolvedSymbols.find(Name);
118 assert(I != ResolvedSymbols.end() &&
119 "Resolving symbol outside the requested set");
120 assert(I->second.getAddress() == 0 && "Redundantly resolving symbol Name");
121
122 // If this is a materialization-side-effects-only symbol then drop it,
123 // otherwise update its map entry with its resolved address.
124 if (Sym.getFlags().hasMaterializationSideEffectsOnly())
125 ResolvedSymbols.erase(I);
126 else
127 I->second = std::move(Sym);
128 --OutstandingSymbolsCount;
129 }
130
handleComplete()131 void AsynchronousSymbolQuery::handleComplete() {
132 assert(OutstandingSymbolsCount == 0 &&
133 "Symbols remain, handleComplete called prematurely");
134
135 auto TmpNotifyComplete = std::move(NotifyComplete);
136 NotifyComplete = SymbolsResolvedCallback();
137 TmpNotifyComplete(std::move(ResolvedSymbols));
138 }
139
canStillFail()140 bool AsynchronousSymbolQuery::canStillFail() { return !!NotifyComplete; }
141
handleFailed(Error Err)142 void AsynchronousSymbolQuery::handleFailed(Error Err) {
143 assert(QueryRegistrations.empty() && ResolvedSymbols.empty() &&
144 OutstandingSymbolsCount == 0 &&
145 "Query should already have been abandoned");
146 NotifyComplete(std::move(Err));
147 NotifyComplete = SymbolsResolvedCallback();
148 }
149
addQueryDependence(JITDylib & JD,SymbolStringPtr Name)150 void AsynchronousSymbolQuery::addQueryDependence(JITDylib &JD,
151 SymbolStringPtr Name) {
152 bool Added = QueryRegistrations[&JD].insert(std::move(Name)).second;
153 (void)Added;
154 assert(Added && "Duplicate dependence notification?");
155 }
156
removeQueryDependence(JITDylib & JD,const SymbolStringPtr & Name)157 void AsynchronousSymbolQuery::removeQueryDependence(
158 JITDylib &JD, const SymbolStringPtr &Name) {
159 auto QRI = QueryRegistrations.find(&JD);
160 assert(QRI != QueryRegistrations.end() &&
161 "No dependencies registered for JD");
162 assert(QRI->second.count(Name) && "No dependency on Name in JD");
163 QRI->second.erase(Name);
164 if (QRI->second.empty())
165 QueryRegistrations.erase(QRI);
166 }
167
dropSymbol(const SymbolStringPtr & Name)168 void AsynchronousSymbolQuery::dropSymbol(const SymbolStringPtr &Name) {
169 auto I = ResolvedSymbols.find(Name);
170 assert(I != ResolvedSymbols.end() &&
171 "Redundant removal of weakly-referenced symbol");
172 ResolvedSymbols.erase(I);
173 --OutstandingSymbolsCount;
174 }
175
detach()176 void AsynchronousSymbolQuery::detach() {
177 ResolvedSymbols.clear();
178 OutstandingSymbolsCount = 0;
179 for (auto &KV : QueryRegistrations)
180 KV.first->detachQueryHelper(*this, KV.second);
181 QueryRegistrations.clear();
182 }
183
~MaterializationResponsibility()184 MaterializationResponsibility::~MaterializationResponsibility() {
185 assert(SymbolFlags.empty() &&
186 "All symbols should have been explicitly materialized or failed");
187 }
188
getRequestedSymbols() const189 SymbolNameSet MaterializationResponsibility::getRequestedSymbols() const {
190 return JD->getRequestedSymbols(SymbolFlags);
191 }
192
notifyResolved(const SymbolMap & Symbols)193 Error MaterializationResponsibility::notifyResolved(const SymbolMap &Symbols) {
194 LLVM_DEBUG({
195 dbgs() << "In " << JD->getName() << " resolving " << Symbols << "\n";
196 });
197 #ifndef NDEBUG
198 for (auto &KV : Symbols) {
199 auto WeakFlags = JITSymbolFlags::Weak | JITSymbolFlags::Common;
200 auto I = SymbolFlags.find(KV.first);
201 assert(I != SymbolFlags.end() &&
202 "Resolving symbol outside this responsibility set");
203 assert(!I->second.hasMaterializationSideEffectsOnly() &&
204 "Can't resolve materialization-side-effects-only symbol");
205 assert((KV.second.getFlags() & ~WeakFlags) == (I->second & ~WeakFlags) &&
206 "Resolving symbol with incorrect flags");
207 }
208 #endif
209
210 return JD->resolve(Symbols);
211 }
212
notifyEmitted()213 Error MaterializationResponsibility::notifyEmitted() {
214
215 LLVM_DEBUG({
216 dbgs() << "In " << JD->getName() << " emitting " << SymbolFlags << "\n";
217 });
218
219 if (auto Err = JD->emit(SymbolFlags))
220 return Err;
221
222 SymbolFlags.clear();
223 return Error::success();
224 }
225
defineMaterializing(SymbolFlagsMap NewSymbolFlags)226 Error MaterializationResponsibility::defineMaterializing(
227 SymbolFlagsMap NewSymbolFlags) {
228
229 LLVM_DEBUG({
230 dbgs() << "In " << JD->getName() << " defining materializing symbols "
231 << NewSymbolFlags << "\n";
232 });
233 if (auto AcceptedDefs = JD->defineMaterializing(std::move(NewSymbolFlags))) {
234 // Add all newly accepted symbols to this responsibility object.
235 for (auto &KV : *AcceptedDefs)
236 SymbolFlags.insert(KV);
237 return Error::success();
238 } else
239 return AcceptedDefs.takeError();
240 }
241
failMaterialization()242 void MaterializationResponsibility::failMaterialization() {
243
244 LLVM_DEBUG({
245 dbgs() << "In " << JD->getName() << " failing materialization for "
246 << SymbolFlags << "\n";
247 });
248
249 JITDylib::FailedSymbolsWorklist Worklist;
250
251 for (auto &KV : SymbolFlags)
252 Worklist.push_back(std::make_pair(JD.get(), KV.first));
253 SymbolFlags.clear();
254
255 JD->notifyFailed(std::move(Worklist));
256 }
257
replace(std::unique_ptr<MaterializationUnit> MU)258 void MaterializationResponsibility::replace(
259 std::unique_ptr<MaterializationUnit> MU) {
260
261 // If the replacement MU is empty then return.
262 if (MU->getSymbols().empty())
263 return;
264
265 for (auto &KV : MU->getSymbols()) {
266 assert(SymbolFlags.count(KV.first) &&
267 "Replacing definition outside this responsibility set");
268 SymbolFlags.erase(KV.first);
269 }
270
271 if (MU->getInitializerSymbol() == InitSymbol)
272 InitSymbol = nullptr;
273
274 LLVM_DEBUG(JD->getExecutionSession().runSessionLocked([&]() {
275 dbgs() << "In " << JD->getName() << " replacing symbols with " << *MU
276 << "\n";
277 }););
278
279 JD->replace(std::move(MU));
280 }
281
282 MaterializationResponsibility
delegate(const SymbolNameSet & Symbols,VModuleKey NewKey)283 MaterializationResponsibility::delegate(const SymbolNameSet &Symbols,
284 VModuleKey NewKey) {
285
286 if (NewKey == VModuleKey())
287 NewKey = K;
288
289 SymbolStringPtr DelegatedInitSymbol;
290 SymbolFlagsMap DelegatedFlags;
291
292 for (auto &Name : Symbols) {
293 auto I = SymbolFlags.find(Name);
294 assert(I != SymbolFlags.end() &&
295 "Symbol is not tracked by this MaterializationResponsibility "
296 "instance");
297
298 DelegatedFlags[Name] = std::move(I->second);
299 if (Name == InitSymbol)
300 std::swap(InitSymbol, DelegatedInitSymbol);
301
302 SymbolFlags.erase(I);
303 }
304
305 return MaterializationResponsibility(JD, std::move(DelegatedFlags),
306 std::move(DelegatedInitSymbol),
307 std::move(NewKey));
308 }
309
addDependencies(const SymbolStringPtr & Name,const SymbolDependenceMap & Dependencies)310 void MaterializationResponsibility::addDependencies(
311 const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) {
312 LLVM_DEBUG({
313 dbgs() << "Adding dependencies for " << Name << ": " << Dependencies
314 << "\n";
315 });
316 assert(SymbolFlags.count(Name) &&
317 "Symbol not covered by this MaterializationResponsibility instance");
318 JD->addDependencies(Name, Dependencies);
319 }
320
addDependenciesForAll(const SymbolDependenceMap & Dependencies)321 void MaterializationResponsibility::addDependenciesForAll(
322 const SymbolDependenceMap &Dependencies) {
323 LLVM_DEBUG({
324 dbgs() << "Adding dependencies for all symbols in " << SymbolFlags << ": "
325 << Dependencies << "\n";
326 });
327 for (auto &KV : SymbolFlags)
328 JD->addDependencies(KV.first, Dependencies);
329 }
330
AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols,VModuleKey K)331 AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit(
332 SymbolMap Symbols, VModuleKey K)
333 : MaterializationUnit(extractFlags(Symbols), nullptr, std::move(K)),
334 Symbols(std::move(Symbols)) {}
335
getName() const336 StringRef AbsoluteSymbolsMaterializationUnit::getName() const {
337 return "<Absolute Symbols>";
338 }
339
materialize(MaterializationResponsibility R)340 void AbsoluteSymbolsMaterializationUnit::materialize(
341 MaterializationResponsibility R) {
342 // No dependencies, so these calls can't fail.
343 cantFail(R.notifyResolved(Symbols));
344 cantFail(R.notifyEmitted());
345 }
346
discard(const JITDylib & JD,const SymbolStringPtr & Name)347 void AbsoluteSymbolsMaterializationUnit::discard(const JITDylib &JD,
348 const SymbolStringPtr &Name) {
349 assert(Symbols.count(Name) && "Symbol is not part of this MU");
350 Symbols.erase(Name);
351 }
352
353 SymbolFlagsMap
extractFlags(const SymbolMap & Symbols)354 AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) {
355 SymbolFlagsMap Flags;
356 for (const auto &KV : Symbols)
357 Flags[KV.first] = KV.second.getFlags();
358 return Flags;
359 }
360
ReExportsMaterializationUnit(JITDylib * SourceJD,JITDylibLookupFlags SourceJDLookupFlags,SymbolAliasMap Aliases,VModuleKey K)361 ReExportsMaterializationUnit::ReExportsMaterializationUnit(
362 JITDylib *SourceJD, JITDylibLookupFlags SourceJDLookupFlags,
363 SymbolAliasMap Aliases, VModuleKey K)
364 : MaterializationUnit(extractFlags(Aliases), nullptr, std::move(K)),
365 SourceJD(SourceJD), SourceJDLookupFlags(SourceJDLookupFlags),
366 Aliases(std::move(Aliases)) {}
367
getName() const368 StringRef ReExportsMaterializationUnit::getName() const {
369 return "<Reexports>";
370 }
371
materialize(MaterializationResponsibility R)372 void ReExportsMaterializationUnit::materialize(
373 MaterializationResponsibility R) {
374
375 auto &ES = R.getTargetJITDylib().getExecutionSession();
376 JITDylib &TgtJD = R.getTargetJITDylib();
377 JITDylib &SrcJD = SourceJD ? *SourceJD : TgtJD;
378
379 // Find the set of requested aliases and aliasees. Return any unrequested
380 // aliases back to the JITDylib so as to not prematurely materialize any
381 // aliasees.
382 auto RequestedSymbols = R.getRequestedSymbols();
383 SymbolAliasMap RequestedAliases;
384
385 for (auto &Name : RequestedSymbols) {
386 auto I = Aliases.find(Name);
387 assert(I != Aliases.end() && "Symbol not found in aliases map?");
388 RequestedAliases[Name] = std::move(I->second);
389 Aliases.erase(I);
390 }
391
392 LLVM_DEBUG({
393 ES.runSessionLocked([&]() {
394 dbgs() << "materializing reexports: target = " << TgtJD.getName()
395 << ", source = " << SrcJD.getName() << " " << RequestedAliases
396 << "\n";
397 });
398 });
399
400 if (!Aliases.empty()) {
401 if (SourceJD)
402 R.replace(reexports(*SourceJD, std::move(Aliases), SourceJDLookupFlags));
403 else
404 R.replace(symbolAliases(std::move(Aliases)));
405 }
406
407 // The OnResolveInfo struct will hold the aliases and responsibilty for each
408 // query in the list.
409 struct OnResolveInfo {
410 OnResolveInfo(MaterializationResponsibility R, SymbolAliasMap Aliases)
411 : R(std::move(R)), Aliases(std::move(Aliases)) {}
412
413 MaterializationResponsibility R;
414 SymbolAliasMap Aliases;
415 };
416
417 // Build a list of queries to issue. In each round we build a query for the
418 // largest set of aliases that we can resolve without encountering a chain of
419 // aliases (e.g. Foo -> Bar, Bar -> Baz). Such a chain would deadlock as the
420 // query would be waiting on a symbol that it itself had to resolve. Creating
421 // a new query for each link in such a chain eliminates the possibility of
422 // deadlock. In practice chains are likely to be rare, and this algorithm will
423 // usually result in a single query to issue.
424
425 std::vector<std::pair<SymbolLookupSet, std::shared_ptr<OnResolveInfo>>>
426 QueryInfos;
427 while (!RequestedAliases.empty()) {
428 SymbolNameSet ResponsibilitySymbols;
429 SymbolLookupSet QuerySymbols;
430 SymbolAliasMap QueryAliases;
431
432 // Collect as many aliases as we can without including a chain.
433 for (auto &KV : RequestedAliases) {
434 // Chain detected. Skip this symbol for this round.
435 if (&SrcJD == &TgtJD && (QueryAliases.count(KV.second.Aliasee) ||
436 RequestedAliases.count(KV.second.Aliasee)))
437 continue;
438
439 ResponsibilitySymbols.insert(KV.first);
440 QuerySymbols.add(KV.second.Aliasee,
441 KV.second.AliasFlags.hasMaterializationSideEffectsOnly()
442 ? SymbolLookupFlags::WeaklyReferencedSymbol
443 : SymbolLookupFlags::RequiredSymbol);
444 QueryAliases[KV.first] = std::move(KV.second);
445 }
446
447 // Remove the aliases collected this round from the RequestedAliases map.
448 for (auto &KV : QueryAliases)
449 RequestedAliases.erase(KV.first);
450
451 assert(!QuerySymbols.empty() && "Alias cycle detected!");
452
453 auto QueryInfo = std::make_shared<OnResolveInfo>(
454 R.delegate(ResponsibilitySymbols), std::move(QueryAliases));
455 QueryInfos.push_back(
456 make_pair(std::move(QuerySymbols), std::move(QueryInfo)));
457 }
458
459 // Issue the queries.
460 while (!QueryInfos.empty()) {
461 auto QuerySymbols = std::move(QueryInfos.back().first);
462 auto QueryInfo = std::move(QueryInfos.back().second);
463
464 QueryInfos.pop_back();
465
466 auto RegisterDependencies = [QueryInfo,
467 &SrcJD](const SymbolDependenceMap &Deps) {
468 // If there were no materializing symbols, just bail out.
469 if (Deps.empty())
470 return;
471
472 // Otherwise the only deps should be on SrcJD.
473 assert(Deps.size() == 1 && Deps.count(&SrcJD) &&
474 "Unexpected dependencies for reexports");
475
476 auto &SrcJDDeps = Deps.find(&SrcJD)->second;
477 SymbolDependenceMap PerAliasDepsMap;
478 auto &PerAliasDeps = PerAliasDepsMap[&SrcJD];
479
480 for (auto &KV : QueryInfo->Aliases)
481 if (SrcJDDeps.count(KV.second.Aliasee)) {
482 PerAliasDeps = {KV.second.Aliasee};
483 QueryInfo->R.addDependencies(KV.first, PerAliasDepsMap);
484 }
485 };
486
487 auto OnComplete = [QueryInfo](Expected<SymbolMap> Result) {
488 auto &ES = QueryInfo->R.getTargetJITDylib().getExecutionSession();
489 if (Result) {
490 SymbolMap ResolutionMap;
491 for (auto &KV : QueryInfo->Aliases) {
492 assert((KV.second.AliasFlags.hasMaterializationSideEffectsOnly() ||
493 Result->count(KV.second.Aliasee)) &&
494 "Result map missing entry?");
495 // Don't try to resolve materialization-side-effects-only symbols.
496 if (KV.second.AliasFlags.hasMaterializationSideEffectsOnly())
497 continue;
498
499 ResolutionMap[KV.first] = JITEvaluatedSymbol(
500 (*Result)[KV.second.Aliasee].getAddress(), KV.second.AliasFlags);
501 }
502 if (auto Err = QueryInfo->R.notifyResolved(ResolutionMap)) {
503 ES.reportError(std::move(Err));
504 QueryInfo->R.failMaterialization();
505 return;
506 }
507 if (auto Err = QueryInfo->R.notifyEmitted()) {
508 ES.reportError(std::move(Err));
509 QueryInfo->R.failMaterialization();
510 return;
511 }
512 } else {
513 ES.reportError(Result.takeError());
514 QueryInfo->R.failMaterialization();
515 }
516 };
517
518 ES.lookup(LookupKind::Static,
519 JITDylibSearchOrder({{&SrcJD, SourceJDLookupFlags}}),
520 QuerySymbols, SymbolState::Resolved, std::move(OnComplete),
521 std::move(RegisterDependencies));
522 }
523 }
524
discard(const JITDylib & JD,const SymbolStringPtr & Name)525 void ReExportsMaterializationUnit::discard(const JITDylib &JD,
526 const SymbolStringPtr &Name) {
527 assert(Aliases.count(Name) &&
528 "Symbol not covered by this MaterializationUnit");
529 Aliases.erase(Name);
530 }
531
532 SymbolFlagsMap
extractFlags(const SymbolAliasMap & Aliases)533 ReExportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
534 SymbolFlagsMap SymbolFlags;
535 for (auto &KV : Aliases)
536 SymbolFlags[KV.first] = KV.second.AliasFlags;
537
538 return SymbolFlags;
539 }
540
541 Expected<SymbolAliasMap>
buildSimpleReexportsAliasMap(JITDylib & SourceJD,const SymbolNameSet & Symbols)542 buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols) {
543 SymbolLookupSet LookupSet(Symbols);
544 auto Flags = SourceJD.lookupFlags(
545 LookupKind::Static, JITDylibLookupFlags::MatchAllSymbols, LookupSet);
546
547 if (!Flags)
548 return Flags.takeError();
549
550 if (!LookupSet.empty()) {
551 LookupSet.sortByName();
552 return make_error<SymbolsNotFound>(LookupSet.getSymbolNames());
553 }
554
555 SymbolAliasMap Result;
556 for (auto &Name : Symbols) {
557 assert(Flags->count(Name) && "Missing entry in flags map");
558 Result[Name] = SymbolAliasMapEntry(Name, (*Flags)[Name]);
559 }
560
561 return Result;
562 }
563
ReexportsGenerator(JITDylib & SourceJD,JITDylibLookupFlags SourceJDLookupFlags,SymbolPredicate Allow)564 ReexportsGenerator::ReexportsGenerator(JITDylib &SourceJD,
565 JITDylibLookupFlags SourceJDLookupFlags,
566 SymbolPredicate Allow)
567 : SourceJD(SourceJD), SourceJDLookupFlags(SourceJDLookupFlags),
568 Allow(std::move(Allow)) {}
569
tryToGenerate(LookupKind K,JITDylib & JD,JITDylibLookupFlags JDLookupFlags,const SymbolLookupSet & LookupSet)570 Error ReexportsGenerator::tryToGenerate(LookupKind K, JITDylib &JD,
571 JITDylibLookupFlags JDLookupFlags,
572 const SymbolLookupSet &LookupSet) {
573 assert(&JD != &SourceJD && "Cannot re-export from the same dylib");
574
575 // Use lookupFlags to find the subset of symbols that match our lookup.
576 auto Flags = SourceJD.lookupFlags(K, JDLookupFlags, LookupSet);
577 if (!Flags)
578 return Flags.takeError();
579
580 // Create an alias map.
581 orc::SymbolAliasMap AliasMap;
582 for (auto &KV : *Flags)
583 if (!Allow || Allow(KV.first))
584 AliasMap[KV.first] = SymbolAliasMapEntry(KV.first, KV.second);
585
586 if (AliasMap.empty())
587 return Error::success();
588
589 // Define the re-exports.
590 return JD.define(reexports(SourceJD, AliasMap, SourceJDLookupFlags));
591 }
592
~DefinitionGenerator()593 JITDylib::DefinitionGenerator::~DefinitionGenerator() {}
594
removeGenerator(DefinitionGenerator & G)595 void JITDylib::removeGenerator(DefinitionGenerator &G) {
596 ES.runSessionLocked([&]() {
597 auto I = std::find_if(DefGenerators.begin(), DefGenerators.end(),
598 [&](const std::unique_ptr<DefinitionGenerator> &H) {
599 return H.get() == &G;
600 });
601 assert(I != DefGenerators.end() && "Generator not found");
602 DefGenerators.erase(I);
603 });
604 }
605
606 Expected<SymbolFlagsMap>
defineMaterializing(SymbolFlagsMap SymbolFlags)607 JITDylib::defineMaterializing(SymbolFlagsMap SymbolFlags) {
608
609 return ES.runSessionLocked([&]() -> Expected<SymbolFlagsMap> {
610 std::vector<SymbolTable::iterator> AddedSyms;
611 std::vector<SymbolFlagsMap::iterator> RejectedWeakDefs;
612
613 for (auto SFItr = SymbolFlags.begin(), SFEnd = SymbolFlags.end();
614 SFItr != SFEnd; ++SFItr) {
615
616 auto &Name = SFItr->first;
617 auto &Flags = SFItr->second;
618
619 auto EntryItr = Symbols.find(Name);
620
621 // If the entry already exists...
622 if (EntryItr != Symbols.end()) {
623
624 // If this is a strong definition then error out.
625 if (!Flags.isWeak()) {
626 // Remove any symbols already added.
627 for (auto &SI : AddedSyms)
628 Symbols.erase(SI);
629
630 // FIXME: Return all duplicates.
631 return make_error<DuplicateDefinition>(std::string(*Name));
632 }
633
634 // Otherwise just make a note to discard this symbol after the loop.
635 RejectedWeakDefs.push_back(SFItr);
636 continue;
637 } else
638 EntryItr =
639 Symbols.insert(std::make_pair(Name, SymbolTableEntry(Flags))).first;
640
641 AddedSyms.push_back(EntryItr);
642 EntryItr->second.setState(SymbolState::Materializing);
643 }
644
645 // Remove any rejected weak definitions from the SymbolFlags map.
646 while (!RejectedWeakDefs.empty()) {
647 SymbolFlags.erase(RejectedWeakDefs.back());
648 RejectedWeakDefs.pop_back();
649 }
650
651 return SymbolFlags;
652 });
653 }
654
replace(std::unique_ptr<MaterializationUnit> MU)655 void JITDylib::replace(std::unique_ptr<MaterializationUnit> MU) {
656 assert(MU != nullptr && "Can not replace with a null MaterializationUnit");
657
658 auto MustRunMU =
659 ES.runSessionLocked([&, this]() -> std::unique_ptr<MaterializationUnit> {
660
661 #ifndef NDEBUG
662 for (auto &KV : MU->getSymbols()) {
663 auto SymI = Symbols.find(KV.first);
664 assert(SymI != Symbols.end() && "Replacing unknown symbol");
665 assert(SymI->second.getState() == SymbolState::Materializing &&
666 "Can not replace a symbol that ha is not materializing");
667 assert(!SymI->second.hasMaterializerAttached() &&
668 "Symbol should not have materializer attached already");
669 assert(UnmaterializedInfos.count(KV.first) == 0 &&
670 "Symbol being replaced should have no UnmaterializedInfo");
671 }
672 #endif // NDEBUG
673
674 // If any symbol has pending queries against it then we need to
675 // materialize MU immediately.
676 for (auto &KV : MU->getSymbols()) {
677 auto MII = MaterializingInfos.find(KV.first);
678 if (MII != MaterializingInfos.end()) {
679 if (MII->second.hasQueriesPending())
680 return std::move(MU);
681 }
682 }
683
684 // Otherwise, make MU responsible for all the symbols.
685 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
686 for (auto &KV : UMI->MU->getSymbols()) {
687 auto SymI = Symbols.find(KV.first);
688 assert(SymI->second.getState() == SymbolState::Materializing &&
689 "Can not replace a symbol that is not materializing");
690 assert(!SymI->second.hasMaterializerAttached() &&
691 "Can not replace a symbol that has a materializer attached");
692 assert(UnmaterializedInfos.count(KV.first) == 0 &&
693 "Unexpected materializer entry in map");
694 SymI->second.setAddress(SymI->second.getAddress());
695 SymI->second.setMaterializerAttached(true);
696
697 auto &UMIEntry = UnmaterializedInfos[KV.first];
698 assert((!UMIEntry || !UMIEntry->MU) &&
699 "Replacing symbol with materializer still attached");
700 UMIEntry = UMI;
701 }
702
703 return nullptr;
704 });
705
706 if (MustRunMU) {
707 auto MR =
708 MustRunMU->createMaterializationResponsibility(shared_from_this());
709 ES.dispatchMaterialization(std::move(MustRunMU), std::move(MR));
710 }
711 }
712
713 SymbolNameSet
getRequestedSymbols(const SymbolFlagsMap & SymbolFlags) const714 JITDylib::getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const {
715 return ES.runSessionLocked([&]() {
716 SymbolNameSet RequestedSymbols;
717
718 for (auto &KV : SymbolFlags) {
719 assert(Symbols.count(KV.first) && "JITDylib does not cover this symbol?");
720 assert(Symbols.find(KV.first)->second.getState() !=
721 SymbolState::NeverSearched &&
722 Symbols.find(KV.first)->second.getState() != SymbolState::Ready &&
723 "getRequestedSymbols can only be called for symbols that have "
724 "started materializing");
725 auto I = MaterializingInfos.find(KV.first);
726 if (I == MaterializingInfos.end())
727 continue;
728
729 if (I->second.hasQueriesPending())
730 RequestedSymbols.insert(KV.first);
731 }
732
733 return RequestedSymbols;
734 });
735 }
736
addDependencies(const SymbolStringPtr & Name,const SymbolDependenceMap & Dependencies)737 void JITDylib::addDependencies(const SymbolStringPtr &Name,
738 const SymbolDependenceMap &Dependencies) {
739 assert(Symbols.count(Name) && "Name not in symbol table");
740 assert(Symbols[Name].getState() < SymbolState::Emitted &&
741 "Can not add dependencies for a symbol that is not materializing");
742
743 LLVM_DEBUG({
744 dbgs() << "In " << getName() << " adding dependencies for "
745 << *Name << ": " << Dependencies << "\n";
746 });
747
748 // If Name is already in an error state then just bail out.
749 if (Symbols[Name].getFlags().hasError())
750 return;
751
752 auto &MI = MaterializingInfos[Name];
753 assert(Symbols[Name].getState() != SymbolState::Emitted &&
754 "Can not add dependencies to an emitted symbol");
755
756 bool DependsOnSymbolInErrorState = false;
757
758 // Register dependencies, record whether any depenendency is in the error
759 // state.
760 for (auto &KV : Dependencies) {
761 assert(KV.first && "Null JITDylib in dependency?");
762 auto &OtherJITDylib = *KV.first;
763 auto &DepsOnOtherJITDylib = MI.UnemittedDependencies[&OtherJITDylib];
764
765 for (auto &OtherSymbol : KV.second) {
766
767 // Check the sym entry for the dependency.
768 auto OtherSymI = OtherJITDylib.Symbols.find(OtherSymbol);
769
770 // Assert that this symbol exists and has not reached the ready state
771 // already.
772 assert(OtherSymI != OtherJITDylib.Symbols.end() &&
773 "Dependency on unknown symbol");
774
775 auto &OtherSymEntry = OtherSymI->second;
776
777 // If the other symbol is already in the Ready state then there's no
778 // dependency to add.
779 if (OtherSymEntry.getState() == SymbolState::Ready)
780 continue;
781
782 // If the dependency is in an error state then note this and continue,
783 // we will move this symbol to the error state below.
784 if (OtherSymEntry.getFlags().hasError()) {
785 DependsOnSymbolInErrorState = true;
786 continue;
787 }
788
789 // If the dependency was not in the error state then add it to
790 // our list of dependencies.
791 auto &OtherMI = OtherJITDylib.MaterializingInfos[OtherSymbol];
792
793 if (OtherSymEntry.getState() == SymbolState::Emitted)
794 transferEmittedNodeDependencies(MI, Name, OtherMI);
795 else if (&OtherJITDylib != this || OtherSymbol != Name) {
796 OtherMI.Dependants[this].insert(Name);
797 DepsOnOtherJITDylib.insert(OtherSymbol);
798 }
799 }
800
801 if (DepsOnOtherJITDylib.empty())
802 MI.UnemittedDependencies.erase(&OtherJITDylib);
803 }
804
805 // If this symbol dependended on any symbols in the error state then move
806 // this symbol to the error state too.
807 if (DependsOnSymbolInErrorState)
808 Symbols[Name].setFlags(Symbols[Name].getFlags() | JITSymbolFlags::HasError);
809 }
810
resolve(const SymbolMap & Resolved)811 Error JITDylib::resolve(const SymbolMap &Resolved) {
812 SymbolNameSet SymbolsInErrorState;
813 AsynchronousSymbolQuerySet CompletedQueries;
814
815 ES.runSessionLocked([&, this]() {
816 struct WorklistEntry {
817 SymbolTable::iterator SymI;
818 JITEvaluatedSymbol ResolvedSym;
819 };
820
821 std::vector<WorklistEntry> Worklist;
822 Worklist.reserve(Resolved.size());
823
824 // Build worklist and check for any symbols in the error state.
825 for (const auto &KV : Resolved) {
826
827 assert(!KV.second.getFlags().hasError() &&
828 "Resolution result can not have error flag set");
829
830 auto SymI = Symbols.find(KV.first);
831
832 assert(SymI != Symbols.end() && "Symbol not found");
833 assert(!SymI->second.hasMaterializerAttached() &&
834 "Resolving symbol with materializer attached?");
835 assert(SymI->second.getState() == SymbolState::Materializing &&
836 "Symbol should be materializing");
837 assert(SymI->second.getAddress() == 0 &&
838 "Symbol has already been resolved");
839
840 if (SymI->second.getFlags().hasError())
841 SymbolsInErrorState.insert(KV.first);
842 else {
843 auto Flags = KV.second.getFlags();
844 Flags &= ~(JITSymbolFlags::Weak | JITSymbolFlags::Common);
845 assert(Flags == (SymI->second.getFlags() &
846 ~(JITSymbolFlags::Weak | JITSymbolFlags::Common)) &&
847 "Resolved flags should match the declared flags");
848
849 Worklist.push_back(
850 {SymI, JITEvaluatedSymbol(KV.second.getAddress(), Flags)});
851 }
852 }
853
854 // If any symbols were in the error state then bail out.
855 if (!SymbolsInErrorState.empty())
856 return;
857
858 while (!Worklist.empty()) {
859 auto SymI = Worklist.back().SymI;
860 auto ResolvedSym = Worklist.back().ResolvedSym;
861 Worklist.pop_back();
862
863 auto &Name = SymI->first;
864
865 // Resolved symbols can not be weak: discard the weak flag.
866 JITSymbolFlags ResolvedFlags = ResolvedSym.getFlags();
867 SymI->second.setAddress(ResolvedSym.getAddress());
868 SymI->second.setFlags(ResolvedFlags);
869 SymI->second.setState(SymbolState::Resolved);
870
871 auto MII = MaterializingInfos.find(Name);
872 if (MII == MaterializingInfos.end())
873 continue;
874
875 auto &MI = MII->second;
876 for (auto &Q : MI.takeQueriesMeeting(SymbolState::Resolved)) {
877 Q->notifySymbolMetRequiredState(Name, ResolvedSym);
878 Q->removeQueryDependence(*this, Name);
879 if (Q->isComplete())
880 CompletedQueries.insert(std::move(Q));
881 }
882 }
883 });
884
885 assert((SymbolsInErrorState.empty() || CompletedQueries.empty()) &&
886 "Can't fail symbols and completed queries at the same time");
887
888 // If we failed any symbols then return an error.
889 if (!SymbolsInErrorState.empty()) {
890 auto FailedSymbolsDepMap = std::make_shared<SymbolDependenceMap>();
891 (*FailedSymbolsDepMap)[this] = std::move(SymbolsInErrorState);
892 return make_error<FailedToMaterialize>(std::move(FailedSymbolsDepMap));
893 }
894
895 // Otherwise notify all the completed queries.
896 for (auto &Q : CompletedQueries) {
897 assert(Q->isComplete() && "Q not completed");
898 Q->handleComplete();
899 }
900
901 return Error::success();
902 }
903
emit(const SymbolFlagsMap & Emitted)904 Error JITDylib::emit(const SymbolFlagsMap &Emitted) {
905 AsynchronousSymbolQuerySet CompletedQueries;
906 SymbolNameSet SymbolsInErrorState;
907 DenseMap<JITDylib *, SymbolNameVector> ReadySymbols;
908
909 ES.runSessionLocked([&, this]() {
910 std::vector<SymbolTable::iterator> Worklist;
911
912 // Scan to build worklist, record any symbols in the erorr state.
913 for (const auto &KV : Emitted) {
914 auto &Name = KV.first;
915
916 auto SymI = Symbols.find(Name);
917 assert(SymI != Symbols.end() && "No symbol table entry for Name");
918
919 if (SymI->second.getFlags().hasError())
920 SymbolsInErrorState.insert(Name);
921 else
922 Worklist.push_back(SymI);
923 }
924
925 // If any symbols were in the error state then bail out.
926 if (!SymbolsInErrorState.empty())
927 return;
928
929 // Otherwise update dependencies and move to the emitted state.
930 while (!Worklist.empty()) {
931 auto SymI = Worklist.back();
932 Worklist.pop_back();
933
934 auto &Name = SymI->first;
935 auto &SymEntry = SymI->second;
936
937 // Move symbol to the emitted state.
938 assert(((SymEntry.getFlags().hasMaterializationSideEffectsOnly() &&
939 SymEntry.getState() == SymbolState::Materializing) ||
940 SymEntry.getState() == SymbolState::Resolved) &&
941 "Emitting from state other than Resolved");
942 SymEntry.setState(SymbolState::Emitted);
943
944 auto MII = MaterializingInfos.find(Name);
945
946 // If this symbol has no MaterializingInfo then it's trivially ready.
947 // Update its state and continue.
948 if (MII == MaterializingInfos.end()) {
949 SymEntry.setState(SymbolState::Ready);
950 continue;
951 }
952
953 auto &MI = MII->second;
954
955 // For each dependant, transfer this node's emitted dependencies to
956 // it. If the dependant node is ready (i.e. has no unemitted
957 // dependencies) then notify any pending queries.
958 for (auto &KV : MI.Dependants) {
959 auto &DependantJD = *KV.first;
960 auto &DependantJDReadySymbols = ReadySymbols[&DependantJD];
961 for (auto &DependantName : KV.second) {
962 auto DependantMII =
963 DependantJD.MaterializingInfos.find(DependantName);
964 assert(DependantMII != DependantJD.MaterializingInfos.end() &&
965 "Dependant should have MaterializingInfo");
966
967 auto &DependantMI = DependantMII->second;
968
969 // Remove the dependant's dependency on this node.
970 assert(DependantMI.UnemittedDependencies.count(this) &&
971 "Dependant does not have an unemitted dependencies record for "
972 "this JITDylib");
973 assert(DependantMI.UnemittedDependencies[this].count(Name) &&
974 "Dependant does not count this symbol as a dependency?");
975
976 DependantMI.UnemittedDependencies[this].erase(Name);
977 if (DependantMI.UnemittedDependencies[this].empty())
978 DependantMI.UnemittedDependencies.erase(this);
979
980 // Transfer unemitted dependencies from this node to the dependant.
981 DependantJD.transferEmittedNodeDependencies(DependantMI,
982 DependantName, MI);
983
984 auto DependantSymI = DependantJD.Symbols.find(DependantName);
985 assert(DependantSymI != DependantJD.Symbols.end() &&
986 "Dependant has no entry in the Symbols table");
987 auto &DependantSymEntry = DependantSymI->second;
988
989 // If the dependant is emitted and this node was the last of its
990 // unemitted dependencies then the dependant node is now ready, so
991 // notify any pending queries on the dependant node.
992 if (DependantSymEntry.getState() == SymbolState::Emitted &&
993 DependantMI.UnemittedDependencies.empty()) {
994 assert(DependantMI.Dependants.empty() &&
995 "Dependants should be empty by now");
996
997 // Since this dependant is now ready, we erase its MaterializingInfo
998 // and update its materializing state.
999 DependantSymEntry.setState(SymbolState::Ready);
1000 DependantJDReadySymbols.push_back(DependantName);
1001
1002 for (auto &Q : DependantMI.takeQueriesMeeting(SymbolState::Ready)) {
1003 Q->notifySymbolMetRequiredState(
1004 DependantName, DependantSymI->second.getSymbol());
1005 if (Q->isComplete())
1006 CompletedQueries.insert(Q);
1007 Q->removeQueryDependence(DependantJD, DependantName);
1008 }
1009 }
1010 }
1011 }
1012
1013 auto &ThisJDReadySymbols = ReadySymbols[this];
1014 MI.Dependants.clear();
1015 if (MI.UnemittedDependencies.empty()) {
1016 SymI->second.setState(SymbolState::Ready);
1017 ThisJDReadySymbols.push_back(Name);
1018 for (auto &Q : MI.takeQueriesMeeting(SymbolState::Ready)) {
1019 Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol());
1020 if (Q->isComplete())
1021 CompletedQueries.insert(Q);
1022 Q->removeQueryDependence(*this, Name);
1023 }
1024 }
1025 }
1026 });
1027
1028 assert((SymbolsInErrorState.empty() || CompletedQueries.empty()) &&
1029 "Can't fail symbols and completed queries at the same time");
1030
1031 // If we failed any symbols then return an error.
1032 if (!SymbolsInErrorState.empty()) {
1033 auto FailedSymbolsDepMap = std::make_shared<SymbolDependenceMap>();
1034 (*FailedSymbolsDepMap)[this] = std::move(SymbolsInErrorState);
1035 return make_error<FailedToMaterialize>(std::move(FailedSymbolsDepMap));
1036 }
1037
1038 // Otherwise notify all the completed queries.
1039 for (auto &Q : CompletedQueries) {
1040 assert(Q->isComplete() && "Q is not complete");
1041 Q->handleComplete();
1042 }
1043
1044 return Error::success();
1045 }
1046
notifyFailed(FailedSymbolsWorklist Worklist)1047 void JITDylib::notifyFailed(FailedSymbolsWorklist Worklist) {
1048 AsynchronousSymbolQuerySet FailedQueries;
1049 auto FailedSymbolsMap = std::make_shared<SymbolDependenceMap>();
1050
1051 // Failing no symbols is a no-op.
1052 if (Worklist.empty())
1053 return;
1054
1055 auto &ES = Worklist.front().first->getExecutionSession();
1056
1057 ES.runSessionLocked([&]() {
1058 while (!Worklist.empty()) {
1059 assert(Worklist.back().first && "Failed JITDylib can not be null");
1060 auto &JD = *Worklist.back().first;
1061 auto Name = std::move(Worklist.back().second);
1062 Worklist.pop_back();
1063
1064 (*FailedSymbolsMap)[&JD].insert(Name);
1065
1066 assert(JD.Symbols.count(Name) && "No symbol table entry for Name");
1067 auto &Sym = JD.Symbols[Name];
1068
1069 // Move the symbol into the error state.
1070 // Note that this may be redundant: The symbol might already have been
1071 // moved to this state in response to the failure of a dependence.
1072 Sym.setFlags(Sym.getFlags() | JITSymbolFlags::HasError);
1073
1074 // FIXME: Come up with a sane mapping of state to
1075 // presence-of-MaterializingInfo so that we can assert presence / absence
1076 // here, rather than testing it.
1077 auto MII = JD.MaterializingInfos.find(Name);
1078
1079 if (MII == JD.MaterializingInfos.end())
1080 continue;
1081
1082 auto &MI = MII->second;
1083
1084 // Move all dependants to the error state and disconnect from them.
1085 for (auto &KV : MI.Dependants) {
1086 auto &DependantJD = *KV.first;
1087 for (auto &DependantName : KV.second) {
1088 assert(DependantJD.Symbols.count(DependantName) &&
1089 "No symbol table entry for DependantName");
1090 auto &DependantSym = DependantJD.Symbols[DependantName];
1091 DependantSym.setFlags(DependantSym.getFlags() |
1092 JITSymbolFlags::HasError);
1093
1094 assert(DependantJD.MaterializingInfos.count(DependantName) &&
1095 "No MaterializingInfo for dependant");
1096 auto &DependantMI = DependantJD.MaterializingInfos[DependantName];
1097
1098 auto UnemittedDepI = DependantMI.UnemittedDependencies.find(&JD);
1099 assert(UnemittedDepI != DependantMI.UnemittedDependencies.end() &&
1100 "No UnemittedDependencies entry for this JITDylib");
1101 assert(UnemittedDepI->second.count(Name) &&
1102 "No UnemittedDependencies entry for this symbol");
1103 UnemittedDepI->second.erase(Name);
1104 if (UnemittedDepI->second.empty())
1105 DependantMI.UnemittedDependencies.erase(UnemittedDepI);
1106
1107 // If this symbol is already in the emitted state then we need to
1108 // take responsibility for failing its queries, so add it to the
1109 // worklist.
1110 if (DependantSym.getState() == SymbolState::Emitted) {
1111 assert(DependantMI.Dependants.empty() &&
1112 "Emitted symbol should not have dependants");
1113 Worklist.push_back(std::make_pair(&DependantJD, DependantName));
1114 }
1115 }
1116 }
1117 MI.Dependants.clear();
1118
1119 // Disconnect from all unemitted depenencies.
1120 for (auto &KV : MI.UnemittedDependencies) {
1121 auto &UnemittedDepJD = *KV.first;
1122 for (auto &UnemittedDepName : KV.second) {
1123 auto UnemittedDepMII =
1124 UnemittedDepJD.MaterializingInfos.find(UnemittedDepName);
1125 assert(UnemittedDepMII != UnemittedDepJD.MaterializingInfos.end() &&
1126 "Missing MII for unemitted dependency");
1127 assert(UnemittedDepMII->second.Dependants.count(&JD) &&
1128 "JD not listed as a dependant of unemitted dependency");
1129 assert(UnemittedDepMII->second.Dependants[&JD].count(Name) &&
1130 "Name is not listed as a dependant of unemitted dependency");
1131 UnemittedDepMII->second.Dependants[&JD].erase(Name);
1132 if (UnemittedDepMII->second.Dependants[&JD].empty())
1133 UnemittedDepMII->second.Dependants.erase(&JD);
1134 }
1135 }
1136 MI.UnemittedDependencies.clear();
1137
1138 // Collect queries to be failed for this MII.
1139 AsynchronousSymbolQueryList ToDetach;
1140 for (auto &Q : MII->second.pendingQueries()) {
1141 // Add the query to the list to be failed and detach it.
1142 FailedQueries.insert(Q);
1143 ToDetach.push_back(Q);
1144 }
1145 for (auto &Q : ToDetach)
1146 Q->detach();
1147
1148 assert(MI.Dependants.empty() &&
1149 "Can not delete MaterializingInfo with dependants still attached");
1150 assert(MI.UnemittedDependencies.empty() &&
1151 "Can not delete MaterializingInfo with unemitted dependencies "
1152 "still attached");
1153 assert(!MI.hasQueriesPending() &&
1154 "Can not delete MaterializingInfo with queries pending");
1155 JD.MaterializingInfos.erase(MII);
1156 }
1157 });
1158
1159 for (auto &Q : FailedQueries)
1160 Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbolsMap));
1161 }
1162
setLinkOrder(JITDylibSearchOrder NewLinkOrder,bool LinkAgainstThisJITDylibFirst)1163 void JITDylib::setLinkOrder(JITDylibSearchOrder NewLinkOrder,
1164 bool LinkAgainstThisJITDylibFirst) {
1165 ES.runSessionLocked([&]() {
1166 if (LinkAgainstThisJITDylibFirst) {
1167 LinkOrder.clear();
1168 if (NewLinkOrder.empty() || NewLinkOrder.front().first != this)
1169 LinkOrder.push_back(
1170 std::make_pair(this, JITDylibLookupFlags::MatchAllSymbols));
1171 LinkOrder.insert(LinkOrder.end(), NewLinkOrder.begin(),
1172 NewLinkOrder.end());
1173 } else
1174 LinkOrder = std::move(NewLinkOrder);
1175 });
1176 }
1177
addToLinkOrder(JITDylib & JD,JITDylibLookupFlags JDLookupFlags)1178 void JITDylib::addToLinkOrder(JITDylib &JD, JITDylibLookupFlags JDLookupFlags) {
1179 ES.runSessionLocked([&]() { LinkOrder.push_back({&JD, JDLookupFlags}); });
1180 }
1181
replaceInLinkOrder(JITDylib & OldJD,JITDylib & NewJD,JITDylibLookupFlags JDLookupFlags)1182 void JITDylib::replaceInLinkOrder(JITDylib &OldJD, JITDylib &NewJD,
1183 JITDylibLookupFlags JDLookupFlags) {
1184 ES.runSessionLocked([&]() {
1185 for (auto &KV : LinkOrder)
1186 if (KV.first == &OldJD) {
1187 KV = {&NewJD, JDLookupFlags};
1188 break;
1189 }
1190 });
1191 }
1192
removeFromLinkOrder(JITDylib & JD)1193 void JITDylib::removeFromLinkOrder(JITDylib &JD) {
1194 ES.runSessionLocked([&]() {
1195 auto I = std::find_if(LinkOrder.begin(), LinkOrder.end(),
1196 [&](const JITDylibSearchOrder::value_type &KV) {
1197 return KV.first == &JD;
1198 });
1199 if (I != LinkOrder.end())
1200 LinkOrder.erase(I);
1201 });
1202 }
1203
remove(const SymbolNameSet & Names)1204 Error JITDylib::remove(const SymbolNameSet &Names) {
1205 return ES.runSessionLocked([&]() -> Error {
1206 using SymbolMaterializerItrPair =
1207 std::pair<SymbolTable::iterator, UnmaterializedInfosMap::iterator>;
1208 std::vector<SymbolMaterializerItrPair> SymbolsToRemove;
1209 SymbolNameSet Missing;
1210 SymbolNameSet Materializing;
1211
1212 for (auto &Name : Names) {
1213 auto I = Symbols.find(Name);
1214
1215 // Note symbol missing.
1216 if (I == Symbols.end()) {
1217 Missing.insert(Name);
1218 continue;
1219 }
1220
1221 // Note symbol materializing.
1222 if (I->second.getState() != SymbolState::NeverSearched &&
1223 I->second.getState() != SymbolState::Ready) {
1224 Materializing.insert(Name);
1225 continue;
1226 }
1227
1228 auto UMII = I->second.hasMaterializerAttached()
1229 ? UnmaterializedInfos.find(Name)
1230 : UnmaterializedInfos.end();
1231 SymbolsToRemove.push_back(std::make_pair(I, UMII));
1232 }
1233
1234 // If any of the symbols are not defined, return an error.
1235 if (!Missing.empty())
1236 return make_error<SymbolsNotFound>(std::move(Missing));
1237
1238 // If any of the symbols are currently materializing, return an error.
1239 if (!Materializing.empty())
1240 return make_error<SymbolsCouldNotBeRemoved>(std::move(Materializing));
1241
1242 // Remove the symbols.
1243 for (auto &SymbolMaterializerItrPair : SymbolsToRemove) {
1244 auto UMII = SymbolMaterializerItrPair.second;
1245
1246 // If there is a materializer attached, call discard.
1247 if (UMII != UnmaterializedInfos.end()) {
1248 UMII->second->MU->doDiscard(*this, UMII->first);
1249 UnmaterializedInfos.erase(UMII);
1250 }
1251
1252 auto SymI = SymbolMaterializerItrPair.first;
1253 Symbols.erase(SymI);
1254 }
1255
1256 return Error::success();
1257 });
1258 }
1259
1260 Expected<SymbolFlagsMap>
lookupFlags(LookupKind K,JITDylibLookupFlags JDLookupFlags,SymbolLookupSet LookupSet)1261 JITDylib::lookupFlags(LookupKind K, JITDylibLookupFlags JDLookupFlags,
1262 SymbolLookupSet LookupSet) {
1263 return ES.runSessionLocked([&, this]() -> Expected<SymbolFlagsMap> {
1264 SymbolFlagsMap Result;
1265 lookupFlagsImpl(Result, K, JDLookupFlags, LookupSet);
1266
1267 // Run any definition generators.
1268 for (auto &DG : DefGenerators) {
1269
1270 // Bail out early if we found everything.
1271 if (LookupSet.empty())
1272 break;
1273
1274 // Run this generator.
1275 if (auto Err = DG->tryToGenerate(K, *this, JDLookupFlags, LookupSet))
1276 return std::move(Err);
1277
1278 // Re-try the search.
1279 lookupFlagsImpl(Result, K, JDLookupFlags, LookupSet);
1280 }
1281
1282 return Result;
1283 });
1284 }
1285
lookupFlagsImpl(SymbolFlagsMap & Result,LookupKind K,JITDylibLookupFlags JDLookupFlags,SymbolLookupSet & LookupSet)1286 void JITDylib::lookupFlagsImpl(SymbolFlagsMap &Result, LookupKind K,
1287 JITDylibLookupFlags JDLookupFlags,
1288 SymbolLookupSet &LookupSet) {
1289
1290 LookupSet.forEachWithRemoval(
1291 [&](const SymbolStringPtr &Name, SymbolLookupFlags Flags) -> bool {
1292 auto I = Symbols.find(Name);
1293 if (I == Symbols.end())
1294 return false;
1295 assert(!Result.count(Name) && "Symbol already present in Flags map");
1296 Result[Name] = I->second.getFlags();
1297 return true;
1298 });
1299 }
1300
lodgeQuery(MaterializationUnitList & MUs,std::shared_ptr<AsynchronousSymbolQuery> & Q,LookupKind K,JITDylibLookupFlags JDLookupFlags,SymbolLookupSet & Unresolved)1301 Error JITDylib::lodgeQuery(MaterializationUnitList &MUs,
1302 std::shared_ptr<AsynchronousSymbolQuery> &Q,
1303 LookupKind K, JITDylibLookupFlags JDLookupFlags,
1304 SymbolLookupSet &Unresolved) {
1305 assert(Q && "Query can not be null");
1306
1307 if (auto Err = lodgeQueryImpl(MUs, Q, K, JDLookupFlags, Unresolved))
1308 return Err;
1309
1310 // Run any definition generators.
1311 for (auto &DG : DefGenerators) {
1312
1313 // Bail out early if we have resolved everything.
1314 if (Unresolved.empty())
1315 break;
1316
1317 // Run the generator.
1318 if (auto Err = DG->tryToGenerate(K, *this, JDLookupFlags, Unresolved))
1319 return Err;
1320
1321 // Lodge query. This can not fail as any new definitions were added
1322 // by the generator under the session locked. Since they can't have
1323 // started materializing yet they can not have failed.
1324 cantFail(lodgeQueryImpl(MUs, Q, K, JDLookupFlags, Unresolved));
1325 }
1326
1327 return Error::success();
1328 }
1329
lodgeQueryImpl(MaterializationUnitList & MUs,std::shared_ptr<AsynchronousSymbolQuery> & Q,LookupKind K,JITDylibLookupFlags JDLookupFlags,SymbolLookupSet & Unresolved)1330 Error JITDylib::lodgeQueryImpl(MaterializationUnitList &MUs,
1331 std::shared_ptr<AsynchronousSymbolQuery> &Q,
1332 LookupKind K, JITDylibLookupFlags JDLookupFlags,
1333 SymbolLookupSet &Unresolved) {
1334
1335 return Unresolved.forEachWithRemoval(
1336 [&](const SymbolStringPtr &Name,
1337 SymbolLookupFlags SymLookupFlags) -> Expected<bool> {
1338 // Search for name in symbols. If not found then continue without
1339 // removal.
1340 auto SymI = Symbols.find(Name);
1341 if (SymI == Symbols.end())
1342 return false;
1343
1344 // If we match against a materialization-side-effects only symbol then
1345 // make sure it is weakly-referenced. Otherwise bail out with an error.
1346 if (SymI->second.getFlags().hasMaterializationSideEffectsOnly() &&
1347 SymLookupFlags != SymbolLookupFlags::WeaklyReferencedSymbol)
1348 return make_error<SymbolsNotFound>(SymbolNameVector({Name}));
1349
1350 // If this is a non exported symbol and we're matching exported symbols
1351 // only then skip this symbol without removal.
1352 if (!SymI->second.getFlags().isExported() &&
1353 JDLookupFlags == JITDylibLookupFlags::MatchExportedSymbolsOnly)
1354 return false;
1355
1356 // If we matched against this symbol but it is in the error state then
1357 // bail out and treat it as a failure to materialize.
1358 if (SymI->second.getFlags().hasError()) {
1359 auto FailedSymbolsMap = std::make_shared<SymbolDependenceMap>();
1360 (*FailedSymbolsMap)[this] = {Name};
1361 return make_error<FailedToMaterialize>(std::move(FailedSymbolsMap));
1362 }
1363
1364 // If this symbol already meets the required state for then notify the
1365 // query, then remove the symbol and continue.
1366 if (SymI->second.getState() >= Q->getRequiredState()) {
1367 Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol());
1368 return true;
1369 }
1370
1371 // Otherwise this symbol does not yet meet the required state. Check
1372 // whether it has a materializer attached, and if so prepare to run it.
1373 if (SymI->second.hasMaterializerAttached()) {
1374 assert(SymI->second.getAddress() == 0 &&
1375 "Symbol not resolved but already has address?");
1376 auto UMII = UnmaterializedInfos.find(Name);
1377 assert(UMII != UnmaterializedInfos.end() &&
1378 "Lazy symbol should have UnmaterializedInfo");
1379 auto MU = std::move(UMII->second->MU);
1380 assert(MU != nullptr && "Materializer should not be null");
1381
1382 // Move all symbols associated with this MaterializationUnit into
1383 // materializing state.
1384 for (auto &KV : MU->getSymbols()) {
1385 auto SymK = Symbols.find(KV.first);
1386 SymK->second.setMaterializerAttached(false);
1387 SymK->second.setState(SymbolState::Materializing);
1388 UnmaterializedInfos.erase(KV.first);
1389 }
1390
1391 // Add MU to the list of MaterializationUnits to be materialized.
1392 MUs.push_back(std::move(MU));
1393 }
1394
1395 // Add the query to the PendingQueries list and continue, deleting the
1396 // element.
1397 assert(SymI->second.getState() != SymbolState::NeverSearched &&
1398 SymI->second.getState() != SymbolState::Ready &&
1399 "By this line the symbol should be materializing");
1400 auto &MI = MaterializingInfos[Name];
1401 MI.addQuery(Q);
1402 Q->addQueryDependence(*this, Name);
1403 return true;
1404 });
1405 }
1406
1407 Expected<SymbolNameSet>
legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,SymbolNameSet Names)1408 JITDylib::legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
1409 SymbolNameSet Names) {
1410 assert(Q && "Query can not be null");
1411
1412 ES.runOutstandingMUs();
1413
1414 bool QueryComplete = false;
1415 std::vector<std::unique_ptr<MaterializationUnit>> MUs;
1416
1417 SymbolLookupSet Unresolved(Names);
1418 auto Err = ES.runSessionLocked([&, this]() -> Error {
1419 QueryComplete = lookupImpl(Q, MUs, Unresolved);
1420
1421 // Run any definition generators.
1422 for (auto &DG : DefGenerators) {
1423
1424 // Bail out early if we have resolved everything.
1425 if (Unresolved.empty())
1426 break;
1427
1428 assert(!QueryComplete && "query complete but unresolved symbols remain?");
1429 if (auto Err = DG->tryToGenerate(LookupKind::Static, *this,
1430 JITDylibLookupFlags::MatchAllSymbols,
1431 Unresolved))
1432 return Err;
1433
1434 if (!Unresolved.empty())
1435 QueryComplete = lookupImpl(Q, MUs, Unresolved);
1436 }
1437 return Error::success();
1438 });
1439
1440 if (Err)
1441 return std::move(Err);
1442
1443 assert((MUs.empty() || !QueryComplete) &&
1444 "If action flags are set, there should be no work to do (so no MUs)");
1445
1446 if (QueryComplete)
1447 Q->handleComplete();
1448
1449 // FIXME: Swap back to the old code below once RuntimeDyld works with
1450 // callbacks from asynchronous queries.
1451 // Add MUs to the OutstandingMUs list.
1452 {
1453 std::lock_guard<std::recursive_mutex> Lock(ES.OutstandingMUsMutex);
1454 auto ThisJD = shared_from_this();
1455 for (auto &MU : MUs) {
1456 auto MR = MU->createMaterializationResponsibility(ThisJD);
1457 ES.OutstandingMUs.push_back(make_pair(std::move(MU), std::move(MR)));
1458 }
1459 }
1460 ES.runOutstandingMUs();
1461
1462 // Dispatch any required MaterializationUnits for materialization.
1463 // for (auto &MU : MUs)
1464 // ES.dispatchMaterialization(*this, std::move(MU));
1465
1466 SymbolNameSet RemainingSymbols;
1467 for (auto &KV : Unresolved)
1468 RemainingSymbols.insert(KV.first);
1469
1470 return RemainingSymbols;
1471 }
1472
lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> & Q,std::vector<std::unique_ptr<MaterializationUnit>> & MUs,SymbolLookupSet & Unresolved)1473 bool JITDylib::lookupImpl(
1474 std::shared_ptr<AsynchronousSymbolQuery> &Q,
1475 std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
1476 SymbolLookupSet &Unresolved) {
1477 bool QueryComplete = false;
1478
1479 std::vector<SymbolStringPtr> ToRemove;
1480 Unresolved.forEachWithRemoval(
1481 [&](const SymbolStringPtr &Name, SymbolLookupFlags Flags) -> bool {
1482 // Search for the name in Symbols. Skip without removing if not found.
1483 auto SymI = Symbols.find(Name);
1484 if (SymI == Symbols.end())
1485 return false;
1486
1487 // If the symbol is already in the required state then notify the query
1488 // and remove.
1489 if (SymI->second.getState() >= Q->getRequiredState()) {
1490 Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol());
1491 if (Q->isComplete())
1492 QueryComplete = true;
1493 return true;
1494 }
1495
1496 // If the symbol is lazy, get the MaterialiaztionUnit for it.
1497 if (SymI->second.hasMaterializerAttached()) {
1498 assert(SymI->second.getAddress() == 0 &&
1499 "Lazy symbol should not have a resolved address");
1500 auto UMII = UnmaterializedInfos.find(Name);
1501 assert(UMII != UnmaterializedInfos.end() &&
1502 "Lazy symbol should have UnmaterializedInfo");
1503 auto MU = std::move(UMII->second->MU);
1504 assert(MU != nullptr && "Materializer should not be null");
1505
1506 // Kick all symbols associated with this MaterializationUnit into
1507 // materializing state.
1508 for (auto &KV : MU->getSymbols()) {
1509 auto SymK = Symbols.find(KV.first);
1510 assert(SymK != Symbols.end() && "Missing symbol table entry");
1511 SymK->second.setState(SymbolState::Materializing);
1512 SymK->second.setMaterializerAttached(false);
1513 UnmaterializedInfos.erase(KV.first);
1514 }
1515
1516 // Add MU to the list of MaterializationUnits to be materialized.
1517 MUs.push_back(std::move(MU));
1518 }
1519
1520 // Add the query to the PendingQueries list.
1521 assert(SymI->second.getState() != SymbolState::NeverSearched &&
1522 SymI->second.getState() != SymbolState::Ready &&
1523 "By this line the symbol should be materializing");
1524 auto &MI = MaterializingInfos[Name];
1525 MI.addQuery(Q);
1526 Q->addQueryDependence(*this, Name);
1527 return true;
1528 });
1529
1530 return QueryComplete;
1531 }
1532
dump(raw_ostream & OS)1533 void JITDylib::dump(raw_ostream &OS) {
1534 ES.runSessionLocked([&, this]() {
1535 OS << "JITDylib \"" << JITDylibName << "\" (ES: "
1536 << format("0x%016" PRIx64, reinterpret_cast<uintptr_t>(&ES)) << "):\n"
1537 << "Link order: " << LinkOrder << "\n"
1538 << "Symbol table:\n";
1539
1540 for (auto &KV : Symbols) {
1541 OS << " \"" << *KV.first << "\": ";
1542 if (auto Addr = KV.second.getAddress())
1543 OS << format("0x%016" PRIx64, Addr) << ", " << KV.second.getFlags()
1544 << " ";
1545 else
1546 OS << "<not resolved> ";
1547
1548 OS << KV.second.getFlags() << " " << KV.second.getState();
1549
1550 if (KV.second.hasMaterializerAttached()) {
1551 OS << " (Materializer ";
1552 auto I = UnmaterializedInfos.find(KV.first);
1553 assert(I != UnmaterializedInfos.end() &&
1554 "Lazy symbol should have UnmaterializedInfo");
1555 OS << I->second->MU.get() << ", " << I->second->MU->getName() << ")\n";
1556 } else
1557 OS << "\n";
1558 }
1559
1560 if (!MaterializingInfos.empty())
1561 OS << " MaterializingInfos entries:\n";
1562 for (auto &KV : MaterializingInfos) {
1563 OS << " \"" << *KV.first << "\":\n"
1564 << " " << KV.second.pendingQueries().size()
1565 << " pending queries: { ";
1566 for (const auto &Q : KV.second.pendingQueries())
1567 OS << Q.get() << " (" << Q->getRequiredState() << ") ";
1568 OS << "}\n Dependants:\n";
1569 for (auto &KV2 : KV.second.Dependants)
1570 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n";
1571 OS << " Unemitted Dependencies:\n";
1572 for (auto &KV2 : KV.second.UnemittedDependencies)
1573 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n";
1574 }
1575 });
1576 }
1577
addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q)1578 void JITDylib::MaterializingInfo::addQuery(
1579 std::shared_ptr<AsynchronousSymbolQuery> Q) {
1580
1581 auto I = std::lower_bound(
1582 PendingQueries.rbegin(), PendingQueries.rend(), Q->getRequiredState(),
1583 [](const std::shared_ptr<AsynchronousSymbolQuery> &V, SymbolState S) {
1584 return V->getRequiredState() <= S;
1585 });
1586 PendingQueries.insert(I.base(), std::move(Q));
1587 }
1588
removeQuery(const AsynchronousSymbolQuery & Q)1589 void JITDylib::MaterializingInfo::removeQuery(
1590 const AsynchronousSymbolQuery &Q) {
1591 // FIXME: Implement 'find_as' for shared_ptr<T>/T*.
1592 auto I =
1593 std::find_if(PendingQueries.begin(), PendingQueries.end(),
1594 [&Q](const std::shared_ptr<AsynchronousSymbolQuery> &V) {
1595 return V.get() == &Q;
1596 });
1597 assert(I != PendingQueries.end() &&
1598 "Query is not attached to this MaterializingInfo");
1599 PendingQueries.erase(I);
1600 }
1601
1602 JITDylib::AsynchronousSymbolQueryList
takeQueriesMeeting(SymbolState RequiredState)1603 JITDylib::MaterializingInfo::takeQueriesMeeting(SymbolState RequiredState) {
1604 AsynchronousSymbolQueryList Result;
1605 while (!PendingQueries.empty()) {
1606 if (PendingQueries.back()->getRequiredState() > RequiredState)
1607 break;
1608
1609 Result.push_back(std::move(PendingQueries.back()));
1610 PendingQueries.pop_back();
1611 }
1612
1613 return Result;
1614 }
1615
JITDylib(ExecutionSession & ES,std::string Name)1616 JITDylib::JITDylib(ExecutionSession &ES, std::string Name)
1617 : ES(ES), JITDylibName(std::move(Name)) {
1618 LinkOrder.push_back({this, JITDylibLookupFlags::MatchAllSymbols});
1619 }
1620
defineImpl(MaterializationUnit & MU)1621 Error JITDylib::defineImpl(MaterializationUnit &MU) {
1622
1623 LLVM_DEBUG({ dbgs() << " " << MU.getSymbols() << "\n"; });
1624
1625 SymbolNameSet Duplicates;
1626 std::vector<SymbolStringPtr> ExistingDefsOverridden;
1627 std::vector<SymbolStringPtr> MUDefsOverridden;
1628
1629 for (const auto &KV : MU.getSymbols()) {
1630 auto I = Symbols.find(KV.first);
1631
1632 if (I != Symbols.end()) {
1633 if (KV.second.isStrong()) {
1634 if (I->second.getFlags().isStrong() ||
1635 I->second.getState() > SymbolState::NeverSearched)
1636 Duplicates.insert(KV.first);
1637 else {
1638 assert(I->second.getState() == SymbolState::NeverSearched &&
1639 "Overridden existing def should be in the never-searched "
1640 "state");
1641 ExistingDefsOverridden.push_back(KV.first);
1642 }
1643 } else
1644 MUDefsOverridden.push_back(KV.first);
1645 }
1646 }
1647
1648 // If there were any duplicate definitions then bail out.
1649 if (!Duplicates.empty()) {
1650 LLVM_DEBUG(
1651 { dbgs() << " Error: Duplicate symbols " << Duplicates << "\n"; });
1652 return make_error<DuplicateDefinition>(std::string(**Duplicates.begin()));
1653 }
1654
1655 // Discard any overridden defs in this MU.
1656 LLVM_DEBUG({
1657 if (!MUDefsOverridden.empty())
1658 dbgs() << " Defs in this MU overridden: " << MUDefsOverridden << "\n";
1659 });
1660 for (auto &S : MUDefsOverridden)
1661 MU.doDiscard(*this, S);
1662
1663 // Discard existing overridden defs.
1664 LLVM_DEBUG({
1665 if (!ExistingDefsOverridden.empty())
1666 dbgs() << " Existing defs overridden by this MU: " << MUDefsOverridden
1667 << "\n";
1668 });
1669 for (auto &S : ExistingDefsOverridden) {
1670
1671 auto UMII = UnmaterializedInfos.find(S);
1672 assert(UMII != UnmaterializedInfos.end() &&
1673 "Overridden existing def should have an UnmaterializedInfo");
1674 UMII->second->MU->doDiscard(*this, S);
1675 }
1676
1677 // Finally, add the defs from this MU.
1678 for (auto &KV : MU.getSymbols()) {
1679 auto &SymEntry = Symbols[KV.first];
1680 SymEntry.setFlags(KV.second);
1681 SymEntry.setState(SymbolState::NeverSearched);
1682 SymEntry.setMaterializerAttached(true);
1683 }
1684
1685 return Error::success();
1686 }
1687
detachQueryHelper(AsynchronousSymbolQuery & Q,const SymbolNameSet & QuerySymbols)1688 void JITDylib::detachQueryHelper(AsynchronousSymbolQuery &Q,
1689 const SymbolNameSet &QuerySymbols) {
1690 for (auto &QuerySymbol : QuerySymbols) {
1691 assert(MaterializingInfos.count(QuerySymbol) &&
1692 "QuerySymbol does not have MaterializingInfo");
1693 auto &MI = MaterializingInfos[QuerySymbol];
1694 MI.removeQuery(Q);
1695 }
1696 }
1697
transferEmittedNodeDependencies(MaterializingInfo & DependantMI,const SymbolStringPtr & DependantName,MaterializingInfo & EmittedMI)1698 void JITDylib::transferEmittedNodeDependencies(
1699 MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName,
1700 MaterializingInfo &EmittedMI) {
1701 for (auto &KV : EmittedMI.UnemittedDependencies) {
1702 auto &DependencyJD = *KV.first;
1703 SymbolNameSet *UnemittedDependenciesOnDependencyJD = nullptr;
1704
1705 for (auto &DependencyName : KV.second) {
1706 auto &DependencyMI = DependencyJD.MaterializingInfos[DependencyName];
1707
1708 // Do not add self dependencies.
1709 if (&DependencyMI == &DependantMI)
1710 continue;
1711
1712 // If we haven't looked up the dependencies for DependencyJD yet, do it
1713 // now and cache the result.
1714 if (!UnemittedDependenciesOnDependencyJD)
1715 UnemittedDependenciesOnDependencyJD =
1716 &DependantMI.UnemittedDependencies[&DependencyJD];
1717
1718 DependencyMI.Dependants[this].insert(DependantName);
1719 UnemittedDependenciesOnDependencyJD->insert(DependencyName);
1720 }
1721 }
1722 }
1723
~Platform()1724 Platform::~Platform() {}
1725
lookupInitSymbols(ExecutionSession & ES,const DenseMap<JITDylib *,SymbolLookupSet> & InitSyms)1726 Expected<DenseMap<JITDylib *, SymbolMap>> Platform::lookupInitSymbols(
1727 ExecutionSession &ES,
1728 const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms) {
1729
1730 DenseMap<JITDylib *, SymbolMap> CompoundResult;
1731 Error CompoundErr = Error::success();
1732 std::mutex LookupMutex;
1733 std::condition_variable CV;
1734 uint64_t Count = InitSyms.size();
1735
1736 LLVM_DEBUG({
1737 dbgs() << "Issuing init-symbol lookup:\n";
1738 for (auto &KV : InitSyms)
1739 dbgs() << " " << KV.first->getName() << ": " << KV.second << "\n";
1740 });
1741
1742 for (auto &KV : InitSyms) {
1743 auto *JD = KV.first;
1744 auto Names = std::move(KV.second);
1745 ES.lookup(
1746 LookupKind::Static,
1747 JITDylibSearchOrder({{JD, JITDylibLookupFlags::MatchAllSymbols}}),
1748 std::move(Names), SymbolState::Ready,
1749 [&, JD](Expected<SymbolMap> Result) {
1750 {
1751 std::lock_guard<std::mutex> Lock(LookupMutex);
1752 --Count;
1753 if (Result) {
1754 assert(!CompoundResult.count(JD) &&
1755 "Duplicate JITDylib in lookup?");
1756 CompoundResult[JD] = std::move(*Result);
1757 } else
1758 CompoundErr =
1759 joinErrors(std::move(CompoundErr), Result.takeError());
1760 }
1761 CV.notify_one();
1762 },
1763 NoDependenciesToRegister);
1764 }
1765
1766 std::unique_lock<std::mutex> Lock(LookupMutex);
1767 CV.wait(Lock, [&] { return Count == 0 || CompoundErr; });
1768
1769 if (CompoundErr)
1770 return std::move(CompoundErr);
1771
1772 return std::move(CompoundResult);
1773 }
1774
ExecutionSession(std::shared_ptr<SymbolStringPool> SSP)1775 ExecutionSession::ExecutionSession(std::shared_ptr<SymbolStringPool> SSP)
1776 : SSP(SSP ? std::move(SSP) : std::make_shared<SymbolStringPool>()) {
1777 }
1778
getJITDylibByName(StringRef Name)1779 JITDylib *ExecutionSession::getJITDylibByName(StringRef Name) {
1780 return runSessionLocked([&, this]() -> JITDylib * {
1781 for (auto &JD : JDs)
1782 if (JD->getName() == Name)
1783 return JD.get();
1784 return nullptr;
1785 });
1786 }
1787
createBareJITDylib(std::string Name)1788 JITDylib &ExecutionSession::createBareJITDylib(std::string Name) {
1789 assert(!getJITDylibByName(Name) && "JITDylib with that name already exists");
1790 return runSessionLocked([&, this]() -> JITDylib & {
1791 JDs.push_back(
1792 std::shared_ptr<JITDylib>(new JITDylib(*this, std::move(Name))));
1793 return *JDs.back();
1794 });
1795 }
1796
createJITDylib(std::string Name)1797 Expected<JITDylib &> ExecutionSession::createJITDylib(std::string Name) {
1798 auto &JD = createBareJITDylib(Name);
1799 if (P)
1800 if (auto Err = P->setupJITDylib(JD))
1801 return std::move(Err);
1802 return JD;
1803 }
1804
legacyFailQuery(AsynchronousSymbolQuery & Q,Error Err)1805 void ExecutionSession::legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err) {
1806 assert(!!Err && "Error should be in failure state");
1807
1808 bool SendErrorToQuery;
1809 runSessionLocked([&]() {
1810 Q.detach();
1811 SendErrorToQuery = Q.canStillFail();
1812 });
1813
1814 if (SendErrorToQuery)
1815 Q.handleFailed(std::move(Err));
1816 else
1817 reportError(std::move(Err));
1818 }
1819
legacyLookup(LegacyAsyncLookupFunction AsyncLookup,SymbolNameSet Names,SymbolState RequiredState,RegisterDependenciesFunction RegisterDependencies)1820 Expected<SymbolMap> ExecutionSession::legacyLookup(
1821 LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names,
1822 SymbolState RequiredState,
1823 RegisterDependenciesFunction RegisterDependencies) {
1824 #if LLVM_ENABLE_THREADS
1825 // In the threaded case we use promises to return the results.
1826 std::promise<SymbolMap> PromisedResult;
1827 Error ResolutionError = Error::success();
1828 auto NotifyComplete = [&](Expected<SymbolMap> R) {
1829 if (R)
1830 PromisedResult.set_value(std::move(*R));
1831 else {
1832 ErrorAsOutParameter _(&ResolutionError);
1833 ResolutionError = R.takeError();
1834 PromisedResult.set_value(SymbolMap());
1835 }
1836 };
1837 #else
1838 SymbolMap Result;
1839 Error ResolutionError = Error::success();
1840
1841 auto NotifyComplete = [&](Expected<SymbolMap> R) {
1842 ErrorAsOutParameter _(&ResolutionError);
1843 if (R)
1844 Result = std::move(*R);
1845 else
1846 ResolutionError = R.takeError();
1847 };
1848 #endif
1849
1850 auto Query = std::make_shared<AsynchronousSymbolQuery>(
1851 SymbolLookupSet(Names), RequiredState, std::move(NotifyComplete));
1852 // FIXME: This should be run session locked along with the registration code
1853 // and error reporting below.
1854 SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names));
1855
1856 // If the query was lodged successfully then register the dependencies,
1857 // otherwise fail it with an error.
1858 if (UnresolvedSymbols.empty())
1859 RegisterDependencies(Query->QueryRegistrations);
1860 else {
1861 bool DeliverError = runSessionLocked([&]() {
1862 Query->detach();
1863 return Query->canStillFail();
1864 });
1865 auto Err = make_error<SymbolsNotFound>(std::move(UnresolvedSymbols));
1866 if (DeliverError)
1867 Query->handleFailed(std::move(Err));
1868 else
1869 reportError(std::move(Err));
1870 }
1871
1872 #if LLVM_ENABLE_THREADS
1873 auto ResultFuture = PromisedResult.get_future();
1874 auto Result = ResultFuture.get();
1875 if (ResolutionError)
1876 return std::move(ResolutionError);
1877 return std::move(Result);
1878
1879 #else
1880 if (ResolutionError)
1881 return std::move(ResolutionError);
1882
1883 return Result;
1884 #endif
1885 }
1886
lookup(LookupKind K,const JITDylibSearchOrder & SearchOrder,SymbolLookupSet Symbols,SymbolState RequiredState,SymbolsResolvedCallback NotifyComplete,RegisterDependenciesFunction RegisterDependencies)1887 void ExecutionSession::lookup(
1888 LookupKind K, const JITDylibSearchOrder &SearchOrder,
1889 SymbolLookupSet Symbols, SymbolState RequiredState,
1890 SymbolsResolvedCallback NotifyComplete,
1891 RegisterDependenciesFunction RegisterDependencies) {
1892
1893 LLVM_DEBUG({
1894 runSessionLocked([&]() {
1895 dbgs() << "Looking up " << Symbols << " in " << SearchOrder
1896 << " (required state: " << RequiredState << ")\n";
1897 });
1898 });
1899
1900 // lookup can be re-entered recursively if running on a single thread. Run any
1901 // outstanding MUs in case this query depends on them, otherwise this lookup
1902 // will starve waiting for a result from an MU that is stuck in the queue.
1903 runOutstandingMUs();
1904
1905 auto Unresolved = std::move(Symbols);
1906 std::map<JITDylib *, MaterializationUnitList> CollectedMUsMap;
1907 auto Q = std::make_shared<AsynchronousSymbolQuery>(Unresolved, RequiredState,
1908 std::move(NotifyComplete));
1909 bool QueryComplete = false;
1910
1911 auto LodgingErr = runSessionLocked([&]() -> Error {
1912 auto LodgeQuery = [&]() -> Error {
1913 for (auto &KV : SearchOrder) {
1914 assert(KV.first && "JITDylibList entries must not be null");
1915 assert(!CollectedMUsMap.count(KV.first) &&
1916 "JITDylibList should not contain duplicate entries");
1917
1918 auto &JD = *KV.first;
1919 auto JDLookupFlags = KV.second;
1920 if (auto Err = JD.lodgeQuery(CollectedMUsMap[&JD], Q, K, JDLookupFlags,
1921 Unresolved))
1922 return Err;
1923 }
1924
1925 // Strip any weakly referenced symbols that were not found.
1926 Unresolved.forEachWithRemoval(
1927 [&](const SymbolStringPtr &Name, SymbolLookupFlags Flags) {
1928 if (Flags == SymbolLookupFlags::WeaklyReferencedSymbol) {
1929 Q->dropSymbol(Name);
1930 return true;
1931 }
1932 return false;
1933 });
1934
1935 if (!Unresolved.empty())
1936 return make_error<SymbolsNotFound>(Unresolved.getSymbolNames());
1937
1938 return Error::success();
1939 };
1940
1941 if (auto Err = LodgeQuery()) {
1942 // Query failed.
1943
1944 // Disconnect the query from its dependencies.
1945 Q->detach();
1946
1947 // Replace the MUs.
1948 for (auto &KV : CollectedMUsMap)
1949 for (auto &MU : KV.second)
1950 KV.first->replace(std::move(MU));
1951
1952 return Err;
1953 }
1954
1955 // Query lodged successfully.
1956
1957 // Record whether this query is fully ready / resolved. We will use
1958 // this to call handleFullyResolved/handleFullyReady outside the session
1959 // lock.
1960 QueryComplete = Q->isComplete();
1961
1962 // Call the register dependencies function.
1963 if (RegisterDependencies && !Q->QueryRegistrations.empty())
1964 RegisterDependencies(Q->QueryRegistrations);
1965
1966 return Error::success();
1967 });
1968
1969 if (LodgingErr) {
1970 Q->handleFailed(std::move(LodgingErr));
1971 return;
1972 }
1973
1974 if (QueryComplete)
1975 Q->handleComplete();
1976
1977 // Move the MUs to the OutstandingMUs list, then materialize.
1978 {
1979 std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
1980
1981 for (auto &KV : CollectedMUsMap) {
1982 auto JD = KV.first->shared_from_this();
1983 for (auto &MU : KV.second) {
1984 auto MR = MU->createMaterializationResponsibility(JD);
1985 OutstandingMUs.push_back(std::make_pair(std::move(MU), std::move(MR)));
1986 }
1987 }
1988 }
1989
1990 runOutstandingMUs();
1991 }
1992
1993 Expected<SymbolMap>
lookup(const JITDylibSearchOrder & SearchOrder,const SymbolLookupSet & Symbols,LookupKind K,SymbolState RequiredState,RegisterDependenciesFunction RegisterDependencies)1994 ExecutionSession::lookup(const JITDylibSearchOrder &SearchOrder,
1995 const SymbolLookupSet &Symbols, LookupKind K,
1996 SymbolState RequiredState,
1997 RegisterDependenciesFunction RegisterDependencies) {
1998 #if LLVM_ENABLE_THREADS
1999 // In the threaded case we use promises to return the results.
2000 std::promise<SymbolMap> PromisedResult;
2001 Error ResolutionError = Error::success();
2002
2003 auto NotifyComplete = [&](Expected<SymbolMap> R) {
2004 if (R)
2005 PromisedResult.set_value(std::move(*R));
2006 else {
2007 ErrorAsOutParameter _(&ResolutionError);
2008 ResolutionError = R.takeError();
2009 PromisedResult.set_value(SymbolMap());
2010 }
2011 };
2012
2013 #else
2014 SymbolMap Result;
2015 Error ResolutionError = Error::success();
2016
2017 auto NotifyComplete = [&](Expected<SymbolMap> R) {
2018 ErrorAsOutParameter _(&ResolutionError);
2019 if (R)
2020 Result = std::move(*R);
2021 else
2022 ResolutionError = R.takeError();
2023 };
2024 #endif
2025
2026 // Perform the asynchronous lookup.
2027 lookup(K, SearchOrder, Symbols, RequiredState, NotifyComplete,
2028 RegisterDependencies);
2029
2030 #if LLVM_ENABLE_THREADS
2031 auto ResultFuture = PromisedResult.get_future();
2032 auto Result = ResultFuture.get();
2033
2034 if (ResolutionError)
2035 return std::move(ResolutionError);
2036
2037 return std::move(Result);
2038
2039 #else
2040 if (ResolutionError)
2041 return std::move(ResolutionError);
2042
2043 return Result;
2044 #endif
2045 }
2046
2047 Expected<JITEvaluatedSymbol>
lookup(const JITDylibSearchOrder & SearchOrder,SymbolStringPtr Name,SymbolState RequiredState)2048 ExecutionSession::lookup(const JITDylibSearchOrder &SearchOrder,
2049 SymbolStringPtr Name, SymbolState RequiredState) {
2050 SymbolLookupSet Names({Name});
2051
2052 if (auto ResultMap = lookup(SearchOrder, std::move(Names), LookupKind::Static,
2053 RequiredState, NoDependenciesToRegister)) {
2054 assert(ResultMap->size() == 1 && "Unexpected number of results");
2055 assert(ResultMap->count(Name) && "Missing result for symbol");
2056 return std::move(ResultMap->begin()->second);
2057 } else
2058 return ResultMap.takeError();
2059 }
2060
2061 Expected<JITEvaluatedSymbol>
lookup(ArrayRef<JITDylib * > SearchOrder,SymbolStringPtr Name,SymbolState RequiredState)2062 ExecutionSession::lookup(ArrayRef<JITDylib *> SearchOrder, SymbolStringPtr Name,
2063 SymbolState RequiredState) {
2064 return lookup(makeJITDylibSearchOrder(SearchOrder), Name, RequiredState);
2065 }
2066
2067 Expected<JITEvaluatedSymbol>
lookup(ArrayRef<JITDylib * > SearchOrder,StringRef Name,SymbolState RequiredState)2068 ExecutionSession::lookup(ArrayRef<JITDylib *> SearchOrder, StringRef Name,
2069 SymbolState RequiredState) {
2070 return lookup(SearchOrder, intern(Name), RequiredState);
2071 }
2072
dump(raw_ostream & OS)2073 void ExecutionSession::dump(raw_ostream &OS) {
2074 runSessionLocked([this, &OS]() {
2075 for (auto &JD : JDs)
2076 JD->dump(OS);
2077 });
2078 }
2079
runOutstandingMUs()2080 void ExecutionSession::runOutstandingMUs() {
2081 while (1) {
2082 Optional<std::pair<std::unique_ptr<MaterializationUnit>,
2083 MaterializationResponsibility>>
2084 JMU;
2085
2086 {
2087 std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
2088 if (!OutstandingMUs.empty()) {
2089 JMU.emplace(std::move(OutstandingMUs.back()));
2090 OutstandingMUs.pop_back();
2091 }
2092 }
2093
2094 if (!JMU)
2095 break;
2096
2097 assert(JMU->first && "No MU?");
2098 dispatchMaterialization(std::move(JMU->first), std::move(JMU->second));
2099 }
2100 }
2101
2102 #ifndef NDEBUG
dumpDispatchInfo(JITDylib & JD,MaterializationUnit & MU)2103 void ExecutionSession::dumpDispatchInfo(JITDylib &JD, MaterializationUnit &MU) {
2104 runSessionLocked([&]() {
2105 dbgs() << "Dispatching " << MU << " for " << JD.getName() << "\n";
2106 });
2107 }
2108 #endif // NDEBUG
2109
2110 } // End namespace orc.
2111 } // End namespace llvm.
2112