llvm.org GIT mirror llvm / bb60b65
[ORC] Rewrite the VSO symbol table yet again. Update related utilities. VSOs now track dependencies for materializing symbols. Each symbol must have its dependencies registered with the VSO prior to finalization. Usually this will involve registering the dependencies returned in AsynchronousSymbolQuery::ResolutionResults for queries made while linking the symbols being materialized. Queries against symbols are notified that a symbol is ready once it and all of its transitive dependencies are finalized, allowing compilation work to be broken up and moved between threads without queries returning until their symbols fully safe to access / execute. Related utilities (VSO, MaterializationUnit, MaterializationResponsibility) are updated to support dependence tracking and more explicitly track responsibility for symbols from the point of definition until they are finalized. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@332541 91177308-0d34-0410-b5e6-96231b3b80d8 Lang Hames 1 year, 2 months ago
19 changed file(s) with 1662 addition(s) and 1073 deletion(s). Raw diff Collapse all Expand all
4747 public:
4848 KaleidoscopeJIT()
4949 : Resolver(createLegacyLookupResolver(
50 ES,
5051 [this](const std::string &Name) -> JITSymbol {
5152 if (auto Sym = CompileLayer.findSymbol(Name, false))
5253 return Sym;
5757 public:
5858 KaleidoscopeJIT()
5959 : Resolver(createLegacyLookupResolver(
60 ES,
6061 [this](const std::string &Name) -> JITSymbol {
6162 if (auto Sym = OptimizeLayer.findSymbol(Name, false))
6263 return Sym;
9797
9898 // Build a resolver and associate it with the new key.
9999 Resolvers[K] = createLegacyLookupResolver(
100 ES,
100101 [this](const std::string &Name) -> JITSymbol {
101102 if (auto Sym = CompileLayer.findSymbol(Name, false))
102103 return Sym;
9090 public:
9191 KaleidoscopeJIT()
9292 : Resolver(createLegacyLookupResolver(
93 ES,
9394 [this](const std::string &Name) -> JITSymbol {
9495 if (auto Sym = IndirectStubsMgr->findStub(Name, false))
9596 return Sym;
9696 public:
9797 KaleidoscopeJIT(MyRemote &Remote)
9898 : Resolver(createLegacyLookupResolver(
99 ES,
99100 [this](const std::string &Name) -> JITSymbol {
100101 if (auto Sym = IndirectStubsMgr->findStub(Name, false))
101102 return Sym;
4444
4545 KaleidoscopeJIT()
4646 : Resolver(createLegacyLookupResolver(
47 ES,
4748 [this](const std::string &Name) {
4849 return ObjectLayer.findSymbol(Name, true);
4950 },
172172
173173 /// Return the flags for this symbol.
174174 JITSymbolFlags getFlags() const { return Flags; }
175
176 /// Set the flags for this symbol.
177 void setFlags(JITSymbolFlags Flags) { this->Flags = std::move(Flags); }
175178
176179 private:
177180 JITTargetAddress Address = 0;
489489 return LD.BackingResolver->lookupFlags(SymbolFlags,
490490 *NotFoundViaLegacyLookup);
491491 },
492 [&LD, LegacyLookup](std::shared_ptr Query,
493 SymbolNameSet Symbols) {
492 [this, &LD,
493 LegacyLookup](std::shared_ptr Query,
494 SymbolNameSet Symbols) {
494495 auto NotFoundViaLegacyLookup =
495 lookupWithLegacyFn(*Query, Symbols, LegacyLookup);
496 lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
496497 return LD.BackingResolver->lookup(Query, NotFoundViaLegacyLookup);
497498 });
498499
646647 return LD.BackingResolver->lookupFlags(SymbolFlags,
647648 *NotFoundViaLegacyLookup);
648649 },
649 [&LD, LegacyLookup](std::shared_ptr Q,
650 SymbolNameSet Symbols) {
650 [this, &LD, LegacyLookup](std::shared_ptr Q,
651 SymbolNameSet Symbols) {
651652 auto NotFoundViaLegacyLookup =
652 lookupWithLegacyFn(*Q, Symbols, LegacyLookup);
653 lookupWithLegacyFn(ES, *Q, Symbols, LegacyLookup);
653654 return LD.BackingResolver->lookup(Q,
654655 std::move(NotFoundViaLegacyLookup));
655656 });
2626 namespace orc {
2727
2828 // Forward declare some classes.
29 class AsynchronousSymbolQuery;
30 class ExecutionSession;
31 class MaterializationUnit;
32 class MaterializationResponsibility;
2933 class VSO;
3034
3135 /// VModuleKey provides a unique identifier (allocated and managed by
5458
5559 /// A base class for materialization failures that allows the failing
5660 /// symbols to be obtained for logging.
61 using SymbolDependenceMap = std::map;
62
63 /// Render a SymbolDependendeMap.
64 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps);
65
66 /// A base class for materialization failures that allows the failing
67 /// symbols to be obtained for logging.
5768 class FailedToMaterialize : public ErrorInfo {
5869 public:
5970 static char ID;
8899
89100 private:
90101 SymbolNameSet Symbols;
102 };
103
104 /// Tracks responsibility for materialization, and mediates interactions between
105 /// MaterializationUnits and VSOs.
106 ///
107 /// An instance of this class is passed to MaterializationUnits when their
108 /// materialize method is called. It allows MaterializationUnits to resolve and
109 /// finalize symbols, or abandon materialization by notifying any unmaterialized
110 /// symbols of an error.
111 class MaterializationResponsibility {
112 public:
113 /// Create a MaterializationResponsibility for the given VSO and
114 /// initial symbols.
115 MaterializationResponsibility(VSO &V, SymbolFlagsMap SymbolFlags);
116
117 MaterializationResponsibility(MaterializationResponsibility &&) = default;
118 MaterializationResponsibility &
119 operator=(MaterializationResponsibility &&) = default;
120
121 /// Destruct a MaterializationResponsibility instance. In debug mode
122 /// this asserts that all symbols being tracked have been either
123 /// finalized or notified of an error.
124 ~MaterializationResponsibility();
125
126 /// Returns the target VSO that these symbols are being materialized
127 /// into.
128 const VSO &getTargetVSO() const { return V; }
129
130 /// Resolves the given symbols. Individual calls to this method may
131 /// resolve a subset of the symbols, but all symbols must have been
132 /// resolved prior to calling finalize.
133 void resolve(const SymbolMap &Symbols);
134
135 /// Finalizes all symbols tracked by this instance.
136 void finalize();
137
138 /// Adds new symbols to the VSO and this responsibility instance.
139 /// VSO entries start out in the materializing state.
140 ///
141 /// This method can be used by materialization units that want to add
142 /// additional symbols at materialization time (e.g. stubs, compile
143 /// callbacks, metadata).
144 Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
145
146 /// Notify all unfinalized symbols that an error has occurred.
147 /// This will remove all symbols covered by this MaterializationResponsibilty
148 /// from V, and send an error to any queries waiting on these symbols.
149 void failMaterialization(std::function GenerateError);
150
151 /// Transfers responsibility to the given MaterializationUnit for all
152 /// symbols defined by that MaterializationUnit. This allows
153 /// materializers to break up work based on run-time information (e.g.
154 /// by introspecting which symbols have actually been looked up and
155 /// materializing only those).
156 void delegate(std::unique_ptr MU);
157
158 /// Add dependencies for the symbols in this dylib.
159 void addDependencies(const SymbolDependenceMap &Dependencies);
160
161 private:
162 VSO &V;
163 SymbolFlagsMap SymbolFlags;
164 };
165
166 /// A MaterializationUnit represents a set of symbol definitions that can
167 /// be materialized as a group, or individually discarded (when
168 /// overriding definitions are encountered).
169 ///
170 /// MaterializationUnits are used when providing lazy definitions of symbols to
171 /// VSOs. The VSO will call materialize when the address of a symbol is
172 /// requested via the lookup method. The VSO will call discard if a stronger
173 /// definition is added or already present.
174 class MaterializationUnit {
175 public:
176 MaterializationUnit(SymbolFlagsMap SymbolFlags)
177 : SymbolFlags(std::move(SymbolFlags)) {}
178
179 virtual ~MaterializationUnit() {}
180
181 /// Return the set of symbols that this source provides.
182 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
183
184 /// Called by materialization dispatchers (see
185 /// ExecutionSession::DispatchMaterializationFunction) to trigger
186 /// materialization of this MaterializationUnit.
187 void doMaterialize(VSO &V) {
188 materialize(MaterializationResponsibility(V, std::move(SymbolFlags)));
189 }
190
191 /// Called by VSOs to notify MaterializationUnits that the given symbol has
192 /// been overridden.
193 void doDiscard(const VSO &V, SymbolStringPtr Name) {
194 SymbolFlags.erase(Name);
195 discard(V, std::move(Name));
196 }
197
198 private:
199 virtual void anchor();
200
201 /// Implementations of this method should materialize all symbols
202 /// in the materialzation unit, except for those that have been
203 /// previously discarded.
204 virtual void materialize(MaterializationResponsibility R) = 0;
205
206 /// Implementations of this method should discard the given symbol
207 /// from the source (e.g. if the source is an LLVM IR Module and the
208 /// symbol is a function, delete the function body or mark it available
209 /// externally).
210 virtual void discard(const VSO &V, SymbolStringPtr Name) = 0;
211
212 SymbolFlagsMap SymbolFlags;
213 };
214
215 /// A MaterializationUnit implementation for pre-existing absolute symbols.
216 ///
217 /// All symbols will be resolved and marked ready as soon as the unit is
218 /// materialized.
219 class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
220 public:
221 AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols);
222
223 private:
224 void materialize(MaterializationResponsibility R) override;
225 void discard(const VSO &V, SymbolStringPtr Name) override;
226 static SymbolFlagsMap extractFlags(const SymbolMap &Symbols);
227
228 SymbolMap Symbols;
229 };
230
231 /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
232 /// Useful for inserting absolute symbols into a VSO. E.g.:
233 /// \code{.cpp}
234 /// VSO &V = ...;
235 /// SymbolStringPtr Foo = ...;
236 /// JITEvaluatedSymbol FooSym = ...;
237 /// if (auto Err = V.define(absoluteSymbols({{Foo, FooSym}})))
238 /// return Err;
239 /// \endcode
240 ///
241 inline std::unique_ptr
242 absoluteSymbols(SymbolMap Symbols) {
243 return llvm::make_unique(
244 std::move(Symbols));
245 }
246
247 /// Base utilities for ExecutionSession.
248 class ExecutionSessionBase {
249 public:
250 /// For reporting errors.
251 using ErrorReporter = std::function;
252
253 /// For dispatching MaterializationUnit::materialize calls.
254 using DispatchMaterializationFunction =
255 std::function MU)>;
256
257 /// Construct an ExecutionSessionBase.
258 ///
259 /// SymbolStringPools may be shared between ExecutionSessions.
260 ExecutionSessionBase(std::shared_ptr SSP = nullptr)
261 : SSP(SSP ? std::move(SSP) : std::make_shared()) {}
262
263 /// Returns the SymbolStringPool for this ExecutionSession.
264 SymbolStringPool &getSymbolStringPool() const { return *SSP; }
265
266 /// Run the given lambda with the session mutex locked.
267 template auto runSessionLocked(Func &&F) -> decltype(F()) {
268 std::lock_guard Lock(SessionMutex);
269 return F();
270 }
271
272 /// Set the error reporter function.
273 ExecutionSessionBase &setErrorReporter(ErrorReporter ReportError) {
274 this->ReportError = std::move(ReportError);
275 return *this;
276 }
277
278 /// Set the materialization dispatch function.
279 ExecutionSessionBase &setDispatchMaterialization(
280 DispatchMaterializationFunction DispatchMaterialization) {
281 this->DispatchMaterialization = std::move(DispatchMaterialization);
282 return *this;
283 }
284
285 /// Report a error for this execution session.
286 ///
287 /// Unhandled errors can be sent here to log them.
288 void reportError(Error Err) { ReportError(std::move(Err)); }
289
290 /// Allocate a module key for a new module to add to the JIT.
291 VModuleKey allocateVModule() { return ++LastKey; }
292
293 /// Return a module key to the ExecutionSession so that it can be
294 /// re-used. This should only be done once all resources associated
295 /// with the original key have been released.
296 void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */
297 }
298
299 /// Cause the given query to fail with the given Error.
300 ///
301 /// This should only be used by legacy APIs and will be deprecated in the
302 /// future.
303 void failQuery(AsynchronousSymbolQuery &Q, Error Err);
304
305 /// Materialize the given unit.
306 void dispatchMaterialization(VSO &V,
307 std::unique_ptr MU) {
308 DispatchMaterialization(V, std::move(MU));
309 }
310
311 private:
312 static void logErrorsToStdErr(Error Err) {
313 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
314 }
315
316 static void
317 materializeOnCurrentThread(VSO &V, std::unique_ptr MU) {
318 MU->doMaterialize(V);
319 }
320
321 mutable std::recursive_mutex SessionMutex;
322 std::shared_ptr SSP;
323 VModuleKey LastKey = 0;
324 ErrorReporter ReportError = logErrorsToStdErr;
325 DispatchMaterializationFunction DispatchMaterialization =
326 materializeOnCurrentThread;
91327 };
92328
93329 /// A symbol query that returns results via a callback when results are
95331 ///
96332 /// makes a callback when all symbols are available.
97333 class AsynchronousSymbolQuery {
98 public:
334 friend class ExecutionSessionBase;
335 friend class VSO;
336
337 public:
338 class ResolutionResult {
339 public:
340 ResolutionResult(SymbolMap Symbols, const SymbolDependenceMap &Dependencies)
341 : Symbols(std::move(Symbols)), Dependencies(Dependencies) {}
342
343 SymbolMap Symbols;
344 const SymbolDependenceMap &Dependencies;
345 };
346
99347 /// Callback to notify client that symbols have been resolved.
100 using SymbolsResolvedCallback = std::function)>;
348 using SymbolsResolvedCallback =
349 std::function)>;
101350
102351 /// Callback to notify client that symbols are ready for execution.
103352 using SymbolsReadyCallback = std::function;
108357 SymbolsResolvedCallback NotifySymbolsResolved,
109358 SymbolsReadyCallback NotifySymbolsReady);
110359
111 /// Notify client that the query failed.
112 ///
113 /// If the notify-resolved callback has not been made yet, then it is called
114 /// with the given error, and the notify-finalized callback is never made.
115 ///
116 /// If the notify-resolved callback has already been made then then the
117 /// notify-finalized callback is called with the given error.
118 ///
119 /// It is illegal to call setFailed after both callbacks have been made.
120 void notifyMaterializationFailed(Error Err);
121
122360 /// Set the resolved symbol information for the given symbol name.
123 ///
124 /// If this symbol was the last one not resolved, this will trigger a call to
125 /// the notify-finalized callback passing the completed sybol map.
126 void resolve(SymbolStringPtr Name, JITEvaluatedSymbol Sym);
361 void resolve(const SymbolStringPtr &Name, JITEvaluatedSymbol Sym);
362
363 /// Returns true if all symbols covered by this query have been
364 /// resolved.
365 bool isFullyResolved() const { return NotYetResolvedCount == 0; }
366
367 /// Call the NotifySymbolsResolved callback.
368 ///
369 /// This should only be called if all symbols covered by the query have been
370 /// resolved.
371 void handleFullyResolved();
127372
128373 /// Notify the query that a requested symbol is ready for execution.
129 ///
130 /// This decrements the query's internal count of not-yet-ready symbols. If
131 /// this call to notifySymbolFinalized sets the counter to zero, it will call
132 /// the notify-finalized callback with Error::success as the value.
133 void finalizeSymbol();
134
135 private:
136 SymbolMap Symbols;
137 size_t OutstandingResolutions = 0;
138 size_t OutstandingFinalizations = 0;
374 void notifySymbolReady();
375
376 /// Returns true if all symbols covered by this query are ready.
377 bool isFullyReady() const { return NotYetReadyCount == 0; }
378
379 /// Calls the NotifySymbolsReady callback.
380 ///
381 /// This should only be called if all symbols covered by this query are ready.
382 void handleFullyReady();
383
384 private:
385 void addQueryDependence(VSO &V, SymbolStringPtr Name);
386
387 void removeQueryDependence(VSO &V, const SymbolStringPtr &Name);
388
389 void handleFailed(Error Err);
390
391 void detach();
392
139393 SymbolsResolvedCallback NotifySymbolsResolved;
140394 SymbolsReadyCallback NotifySymbolsReady;
395 SymbolDependenceMap QueryRegistrations;
396 SymbolMap ResolvedSymbols;
397 size_t NotYetResolvedCount;
398 size_t NotYetReadyCount;
141399 };
142400
143401 /// SymbolResolver is a composable interface for looking up symbol flags
205463 std::forward(LookupFlags), std::forward(Lookup));
206464 }
207465
208 /// Tracks responsibility for materialization.
466 /// A symbol table that supports asynchoronous symbol queries.
209467 ///
210 /// An instance of this class is passed to MaterializationUnits when their
211 /// materialize method is called. It allows MaterializationUnits to resolve and
212 /// finalize symbols, or abandon materialization by notifying any unmaterialized
213 /// symbols of an error.
214 class MaterializationResponsibility {
215 public:
216 /// Create a MaterializationResponsibility for the given VSO and
217 /// initial symbols.
218 MaterializationResponsibility(VSO &V, SymbolFlagsMap SymbolFlags);
219
220 MaterializationResponsibility(MaterializationResponsibility &&) = default;
221 MaterializationResponsibility &
222 operator=(MaterializationResponsibility &&) = default;
223
224 /// Destruct a MaterializationResponsibility instance. In debug mode
225 /// this asserts that all symbols being tracked have been either
226 /// finalized or notified of an error.
227 ~MaterializationResponsibility();
228
229 /// Returns the target VSO that these symbols are being materialized
230 /// into.
231 const VSO &getTargetVSO() const { return V; }
232
233 /// Resolves the given symbols. Individual calls to this method may
234 /// resolve a subset of the symbols, but all symbols must have been
235 /// resolved prior to calling finalize.
236 void resolve(const SymbolMap &Symbols);
237
238 /// Finalizes all symbols tracked by this instance.
239 void finalize();
240
241 /// Notify all unfinalized symbols that an error has occurred.
242 /// This method should be called if materialization of any symbol is
243 /// abandoned.
244 void notifyMaterializationFailed();
245
246 /// Transfers responsibility for the given symbols to a new
247 /// MaterializationResponsibility class. This is useful if a
248 /// MaterializationUnit wants to transfer responsibility for a subset
249 /// of symbols to another MaterializationUnit or utility.
250 MaterializationResponsibility delegate(SymbolNameSet Symbols);
251
252 private:
253 VSO &V;
254 SymbolFlagsMap SymbolFlags;
255 };
256
257 /// A MaterializationUnit represents a set of symbol definitions that can
258 /// be materialized as a group, or individually discarded (when
259 /// overriding definitions are encountered).
260 ///
261 /// MaterializationUnits are used when providing lazy definitions of symbols to
262 /// VSOs. The VSO will call materialize when the address of a symbol is
263 /// requested via the lookup method. The VSO will call discard if a stronger
264 /// definition is added or already present.
265 class MaterializationUnit {
266 public:
267 virtual ~MaterializationUnit() {}
268
269 /// Return the set of symbols that this source provides.
270 virtual SymbolFlagsMap getSymbols() = 0;
271
272 /// Implementations of this method should materialize all symbols
273 /// in the materialzation unit, except for those that have been
274 /// previously discarded.
275 virtual void materialize(MaterializationResponsibility R) = 0;
276
277 /// Implementations of this method should discard the given symbol
278 /// from the source (e.g. if the source is an LLVM IR Module and the
279 /// symbol is a function, delete the function body or mark it available
280 /// externally).
281 virtual void discard(const VSO &V, SymbolStringPtr Name) = 0;
282
283 private:
284 virtual void anchor();
285 };
286
287 /// Represents a dynamic linkage unit in a JIT process.
288 ///
289 /// VSO acts as a symbol table (symbol definitions can be set and the dylib
290 /// queried to find symbol addresses) and as a key for tracking resources
291 /// (since a VSO's address is fixed).
468 /// Represents a virtual shared object. Instances can not be copied or moved, so
469 /// their addresses may be used as keys for resource management.
470 /// VSO state changes must be made via an ExecutionSession to guarantee that
471 /// they are synchronized with respect to other VSO operations.
292472 class VSO {
473 friend class AsynchronousSymbolQuery;
293474 friend class ExecutionSession;
294 friend class MaterializationResponsibility;
295
296 public:
297 enum RelativeLinkageStrength {
298 NewDefinitionIsStronger,
299 DuplicateDefinition,
300 ExistingDefinitionIsStronger
301 };
302
303 using SetDefinitionsResult =
304 std::map;
305
306 struct Materializer {
307 public:
308 Materializer(std::unique_ptr MU,
309 MaterializationResponsibility R);
310 void operator()();
311
312 private:
313 std::unique_ptr MU;
314 MaterializationResponsibility R;
315 };
316
317 using MaterializerList = std::vector;
318
319 struct LookupResult {
320 MaterializerList Materializers;
321 SymbolNameSet UnresolvedSymbols;
322 };
323
324 VSO() = default;
475 public:
476 using AsynchronousSymbolQuerySet =
477 std::set>;
478
479 using MaterializationUnitList =
480 std::vector>;
481
482 using VSOList = std::vector;
325483
326484 VSO(const VSO &) = delete;
327485 VSO &operator=(const VSO &) = delete;
328486 VSO(VSO &&) = delete;
329487 VSO &operator=(VSO &&) = delete;
330488
331 /// Compare new linkage with existing linkage.
332 static RelativeLinkageStrength
333 compareLinkage(Optional OldFlags, JITSymbolFlags NewFlags);
334
335 /// Compare new linkage with an existing symbol's linkage.
336 RelativeLinkageStrength compareLinkage(SymbolStringPtr Name,
337 JITSymbolFlags NewFlags) const;
338
339 /// Adds the given symbols to the mapping as resolved, finalized
340 /// symbols.
341 ///
342 /// FIXME: We can take this by const-ref once symbol-based laziness is
343 /// removed.
344 Error define(SymbolMap NewSymbols);
345
346 /// Adds the given symbols to the mapping as lazy symbols.
347 Error defineLazy(std::unique_ptr Source);
348
349 /// Look up the flags for the given symbols.
350 ///
351 /// Returns the flags for the give symbols, together with the set of symbols
352 /// not found.
353 SymbolNameSet lookupFlags(SymbolFlagsMap &Flags, SymbolNameSet Symbols);
354
355 /// Apply the given query to the given symbols in this VSO.
356 ///
357 /// For symbols in this VSO that have already been materialized, their address
358 /// will be set in the query immediately.
359 ///
360 /// For symbols in this VSO that have not been materialized, the query will be
361 /// recorded and the source for those symbols (plus the set of symbols to be
362 /// materialized by that source) will be returned as the MaterializationWork
363 /// field of the LookupResult.
364 ///
365 /// Any symbols not found in this VSO will be returned in the
366 /// UnresolvedSymbols field of the LookupResult.
367 LookupResult lookup(std::shared_ptr Query,
368 SymbolNameSet Symbols);
369
370 private:
371 /// Add the given symbol/address mappings to the dylib, but do not
372 /// mark the symbols as finalized yet.
373 void resolve(const SymbolMap &SymbolValues);
489 /// Get the name for this VSO.
490 const std::string &getName() const { return VSOName; }
491
492 /// Get a reference to the ExecutionSession for this VSO.
493 ExecutionSessionBase &getExecutionSession() const { return ES; }
494
495 /// Define all symbols provided by the materialization unit to be part
496 /// of the given VSO.
497 template
498 typename std::enable_if<
499 std::is_convertible<
500 typename std::decay::type,
501 std::unique_ptr>::value,
502 Error>::type
503 define(UniquePtrToMaterializationUnit &&MU) {
504 return ES.runSessionLocked([&, this]() -> Error {
505 assert(MU && "Can't define with a null MU");
506
507 if (auto Err = defineImpl(*MU))
508 return Err;
509
510 /// defineImpl succeeded.
511 auto UMI = std::make_shared(std::move(MU));
512 for (auto &KV : UMI->MU->getSymbols())
513 UnmaterializedInfos[KV.first] = UMI;
514
515 return Error::success();
516 });
517 }
518
519 /// Define a set of symbols already in the materializing state.
520 Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
521
522 /// Replace the definition of a set of materializing symbols with a new
523 /// MaterializationUnit.
524 ///
525 /// All symbols being replaced must be in the materializing state. If any
526 /// symbol being replaced has pending queries then the MU will be returned
527 /// for materialization. Otherwise it will be stored in the VSO and all
528 /// symbols covered by MU moved back to the lazy state.
529 void replace(std::unique_ptr MU);
530
531 /// Record dependencies between symbols in this VSO and symbols in
532 /// other VSOs.
533 void addDependencies(const SymbolFlagsMap &Dependents,
534 const SymbolDependenceMap &Dependencies);
535
536 /// Resolve the given symbols.
537 ///
538 /// Returns the list of queries that become fully resolved as a consequence of
539 /// this operation.
540 void resolve(const SymbolMap &Resolved);
374541
375542 /// Finalize the given symbols.
376 void finalize(const SymbolNameSet &SymbolsToFinalize);
377
378 /// Notify the VSO that the given symbols failed to materialized.
379 void notifyMaterializationFailed(const SymbolNameSet &Names);
380
381 class UnmaterializedInfo {
382 public:
383 UnmaterializedInfo(std::unique_ptr MU);
384 void discard(VSO &V, SymbolStringPtr Name);
543 ///
544 /// Returns the list of queries that become fully ready as a consequence of
545 /// this operation.
546 void finalize(const SymbolFlagsMap &Finalized);
547
548 /// Fail to materialize the given symbols.
549 ///
550 /// Returns the list of queries that fail as a consequence.
551 void notifyFailed(const SymbolFlagsMap &Failed,
552 std::function GenerateError);
553
554 /// Search the given VSO for the symbols in Symbols. If found, store
555 /// the flags for each symbol in Flags. Returns any unresolved symbols.
556 SymbolNameSet lookupFlags(SymbolFlagsMap &Flags, const SymbolNameSet &Names);
557
558 /// Search the given VSOs in order for the symbols in Symbols. Results
559 /// (once they become available) will be returned via the given Query.
560 ///
561 /// If any symbol is not found then the unresolved symbols will be returned,
562 /// and the query will not be applied. The Query is not failed and can be
563 /// re-used in a subsequent lookup once the symbols have been added, or
564 /// manually failed.
565 SymbolNameSet lookup(std::shared_ptr Q,
566 SymbolNameSet Names);
567
568 /// Dump current VSO state to OS.
569 void dump(raw_ostream &OS);
570
571 private:
572 using AsynchronousSymbolQueryList =
573 std::vector>;
574
575 struct UnmaterializedInfo {
576 UnmaterializedInfo(std::unique_ptr MU)
577 : MU(std::move(MU)) {}
385578
386579 std::unique_ptr MU;
387 SymbolFlagsMap Symbols;
388580 };
389581
390 using UnmaterializedInfoList = std::list;
391
392 using UnmaterializedInfoIterator = UnmaterializedInfoList::iterator;
393
394 class MaterializingInfo {
395 public:
396 using QueryList = std::vector>;
397
398 QueryList PendingResolution;
399 QueryList PendingFinalization;
582 using UnmaterializedInfosMap =
583 std::map>;
584
585 struct MaterializingInfo {
586 AsynchronousSymbolQueryList PendingQueries;
587 SymbolDependenceMap Dependants;
588 SymbolDependenceMap UnfinalizedDependencies;
589 bool IsFinalized = false;
400590 };
401591
402 using MaterializingInfoMap = std::map;
403
404 using MaterializingInfoIterator = MaterializingInfoMap::iterator;
405
406 class SymbolTableEntry {
407 public:
408 SymbolTableEntry(JITSymbolFlags SymbolFlags,
409 UnmaterializedInfoIterator UnmaterializedInfoItr);
410 SymbolTableEntry(JITSymbolFlags SymbolFlags);
411 SymbolTableEntry(JITEvaluatedSymbol Sym);
412 SymbolTableEntry(SymbolTableEntry &&Other);
413 SymbolTableEntry &operator=(SymbolTableEntry &&Other);
414 ~SymbolTableEntry();
415
416 // Change definition due to override. Only usable prior to materialization.
417 void replaceWith(VSO &V, SymbolStringPtr Name, JITEvaluatedSymbol Sym);
418
419 // Change definition due to override. Only usable prior to materialization.
420 void replaceWith(VSO &V, SymbolStringPtr Name, JITSymbolFlags Flags,
421 UnmaterializedInfoIterator NewUMII);
422
423 // Abandon old definition and move to materializing state.
424 // There is no need to call notifyMaterializing after this.
425 void replaceMaterializing(VSO &V, SymbolStringPtr Name,
426 JITSymbolFlags NewFlags);
427
428 // Notify this entry that it is being materialized.
429 void notifyMaterializing();
430
431 // Move entry to resolved state.
432 void resolve(VSO &V, JITEvaluatedSymbol Sym);
433
434 // Move entry to finalized state.
435 void finalize();
436
437 JITSymbolFlags Flags;
438
439 union {
440 JITTargetAddress Address;
441 UnmaterializedInfoIterator UMII;
442 };
443
444 private:
445 void destroy();
446 };
447
448 std::map Symbols;
449 UnmaterializedInfoList UnmaterializedInfos;
450 MaterializingInfoMap MaterializingInfos;
592 using MaterializingInfosMap = std::map;
593
594 VSO(ExecutionSessionBase &ES, std::string Name)
595 : ES(ES), VSOName(std::move(Name)) {}
596
597 ExecutionSessionBase &ES;
598 std::string VSOName;
599 SymbolMap Symbols;
600 UnmaterializedInfosMap UnmaterializedInfos;
601 MaterializingInfosMap MaterializingInfos;
602
603 Error defineImpl(MaterializationUnit &MU);
604
605 void detachQueryHelper(AsynchronousSymbolQuery &Q,
606 const SymbolNameSet &QuerySymbols);
607
608 void transferFinalizedNodeDependencies(MaterializingInfo &DependantMI,
609 const SymbolStringPtr &DependantName,
610 MaterializingInfo &FinalizedMI);
451611 };
452612
453613 /// An ExecutionSession represents a running JIT program.
454 class ExecutionSession {
614 class ExecutionSession : public ExecutionSessionBase {
455615 public:
456616 using ErrorReporter = std::function;
617
618 using DispatchMaterializationFunction =
619 std::function MU)>;
457620
458621 /// Construct an ExecutionEngine.
459622 ///
460623 /// SymbolStringPools may be shared between ExecutionSessions.
461624 ExecutionSession(std::shared_ptr SSP = nullptr)
462 : SSP(SSP ? std::move(SSP) : std::make_shared()) {}
463
464 /// Returns the SymbolStringPool for this ExecutionSession.
465 SymbolStringPool &getSymbolStringPool() const { return *SSP; }
466
467 /// Set the error reporter function.
468 void setErrorReporter(ErrorReporter ReportError) {
469 this->ReportError = std::move(ReportError);
470 }
471
472 /// Report a error for this execution session.
473 ///
474 /// Unhandled errors can be sent here to log them.
475 void reportError(Error Err) { ReportError(std::move(Err)); }
476
477 /// Allocate a module key for a new module to add to the JIT.
478 VModuleKey allocateVModule() { return ++LastKey; }
479
480 /// Return a module key to the ExecutionSession so that it can be
481 /// re-used. This should only be done once all resources associated
482 //// with the original key have been released.
483 void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */ }
484
485 public:
486 static void logErrorsToStdErr(Error Err);
487
488 std::shared_ptr SSP;
489 VModuleKey LastKey = 0;
490 ErrorReporter ReportError = logErrorsToStdErr;
491 };
492
493 /// Runs Materializers on the current thread and reports errors to the given
494 /// ExecutionSession.
495 class MaterializeOnCurrentThread {
496 public:
497 void operator()(VSO::Materializer M) { M(); }
498 };
499
500 /// Materialization function object wrapper for the lookup method.
501 using MaterializationDispatcher = std::function;
502
503 /// Look up a set of symbols by searching a list of VSOs.
625 : ExecutionSessionBase(std::move(SSP)) {}
626
627 /// Add a new VSO to this ExecutionSession.
628 VSO &createVSO(std::string Name);
629
630 private:
631 std::vector> VSOs;
632 };
633
634 /// Look up the given names in the given VSOs.
635 /// VSOs will be searched in order and no VSO pointer may be null.
636 /// All symbols must be found within the given VSOs or an error
637 /// will be returned.
504638 ///
505 /// All VSOs in the list should be non-null.
639 /// If this lookup is being performed on behalf of a
640 /// MaterializationResponsibility then it must be passed in as R
641 /// (in order to record the symbol dependencies).
642 /// If this lookup is not being performed on behalf of a
643 /// MaterializationResponsibility then R should be left null.
506644 Expected lookup(const std::vector &VSOs, SymbolNameSet Names,
507 MaterializationDispatcher DispatchMaterialization);
645 MaterializationResponsibility *R);
508646
509647 /// Look up a symbol by searching a list of VSOs.
510 Expected
511 lookup(const std::vector VSOs, SymbolStringPtr Name,
512 MaterializationDispatcher DispatchMaterialization);
648 Expected lookup(const std::vector VSOs,
649 SymbolStringPtr Name,
650 MaterializationResponsibility *R);
513651
514652 } // End namespace orc
515653 } // End namespace llvm
2121
2222 class JITSymbolResolverAdapter : public JITSymbolResolver {
2323 public:
24 JITSymbolResolverAdapter(ExecutionSession &ES, SymbolResolver &R);
24 JITSymbolResolverAdapter(ExecutionSession &ES, SymbolResolver &R,
25 MaterializationResponsibility *MR);
2526 Expected lookupFlags(const LookupSet &Symbols) override;
2627 Expected lookup(const LookupSet &Symbols) override;
2728
2930 ExecutionSession &ES;
3031 std::set ResolvedStrings;
3132 SymbolResolver &R;
33 MaterializationResponsibility *MR;
3234 };
3335
3436 /// Use the given legacy-style FindSymbol function (i.e. a function that
6769 ///
6870 /// Useful for implementing lookup bodies that query legacy resolvers.
6971 template
70 SymbolNameSet lookupWithLegacyFn(AsynchronousSymbolQuery &Query,
71 const SymbolNameSet &Symbols,
72 FindSymbolFn FindSymbol) {
72 SymbolNameSet
73 lookupWithLegacyFn(ExecutionSession &ES, AsynchronousSymbolQuery &Query,
74 const SymbolNameSet &Symbols, FindSymbolFn FindSymbol) {
7375 SymbolNameSet SymbolsNotFound;
76 bool NewSymbolsResolved = false;
7477
7578 for (auto &S : Symbols) {
7679 if (JITSymbol Sym = FindSymbol(*S)) {
7780 if (auto Addr = Sym.getAddress()) {
7881 Query.resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
79 Query.finalizeSymbol();
82 Query.notifySymbolReady();
83 NewSymbolsResolved = true;
8084 } else {
81 Query.notifyMaterializationFailed(Addr.takeError());
85 ES.failQuery(Query, Addr.takeError());
8286 return SymbolNameSet();
8387 }
8488 } else if (auto Err = Sym.takeError()) {
85 Query.notifyMaterializationFailed(std::move(Err));
89 ES.failQuery(Query, std::move(Err));
8690 return SymbolNameSet();
8791 } else
8892 SymbolsNotFound.insert(S);
8993 }
94
95 if (NewSymbolsResolved && Query.isFullyResolved())
96 Query.handleFullyResolved();
97
98 if (NewSymbolsResolved && Query.isFullyReady())
99 Query.handleFullyReady();
90100
91101 return SymbolsNotFound;
92102 }
98108 public:
99109 using ErrorReporter = std::function;
100110
101 LegacyLookupFnResolver(LegacyLookupFn LegacyLookup, ErrorReporter ReportError)
102 : LegacyLookup(std::move(LegacyLookup)),
111 LegacyLookupFnResolver(ExecutionSession &ES, LegacyLookupFn LegacyLookup,
112 ErrorReporter ReportError)
113 : ES(ES), LegacyLookup(std::move(LegacyLookup)),
103114 ReportError(std::move(ReportError)) {}
104115
105116 SymbolNameSet lookupFlags(SymbolFlagsMap &Flags,
115126
116127 SymbolNameSet lookup(std::shared_ptr Query,
117128 SymbolNameSet Symbols) final {
118 return lookupWithLegacyFn(*Query, Symbols, LegacyLookup);
129 return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
119130 }
120131
121132 private:
133 ExecutionSession &ES;
122134 LegacyLookupFn LegacyLookup;
123135 ErrorReporter ReportError;
124136 };
125137
126138 template
127139 std::shared_ptr>
128 createLegacyLookupResolver(LegacyLookupFn LegacyLookup,
140 createLegacyLookupResolver(ExecutionSession &ES, LegacyLookupFn LegacyLookup,
129141 std::function ErrorReporter) {
130142 return std::make_shared>(
131 std::move(LegacyLookup), std::move(ErrorReporter));
143 ES, std::move(LegacyLookup), std::move(ErrorReporter));
132144 }
133145
134146 } // End namespace orc
123123 Error finalize() override {
124124 assert(PFC && "mapSectionAddress called on finalized LinkedObject");
125125
126 JITSymbolResolverAdapter ResolverAdapter(PFC->Parent.ES, *PFC->Resolver);
126 JITSymbolResolverAdapter ResolverAdapter(PFC->Parent.ES, *PFC->Resolver,
127 nullptr);
127128 PFC->RTDyld = llvm::make_unique(*MemMgr, ResolverAdapter);
128129 PFC->RTDyld->setProcessAllSections(PFC->ProcessAllSections);
129130
7575
7676 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags) {
7777 OS << "{";
78 if (SymbolFlags.empty()) {
78 if (!SymbolFlags.empty()) {
7979 OS << " {\"" << *SymbolFlags.begin()->first
8080 << "\": " << SymbolFlags.begin()->second << "}";
8181 for (auto &KV :
8686 return OS;
8787 }
8888
89 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps) {
90 OS << "{";
91 if (!Deps.empty()) {
92 OS << " { " << Deps.begin()->first->getName() << ": "
93 << Deps.begin()->second << " }";
94 for (auto &KV : make_range(std::next(Deps.begin()), Deps.end()))
95 OS << ", { " << KV.first->getName() << ": " << KV.second << " }";
96 }
97 OS << " }";
98 return OS;
99 }
100
89101 FailedToResolve::FailedToResolve(SymbolNameSet Symbols)
90102 : Symbols(std::move(Symbols)) {
91103 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
110122
111123 void FailedToFinalize::log(raw_ostream &OS) const {
112124 OS << "Failed to finalize symbols: " << Symbols;
125 }
126
127 void ExecutionSessionBase::failQuery(AsynchronousSymbolQuery &Q, Error Err) {
128 runSessionLocked([&]() -> void {
129 Q.detach();
130 Q.handleFailed(std::move(Err));
131 });
113132 }
114133
115134 AsynchronousSymbolQuery::AsynchronousSymbolQuery(
117136 SymbolsReadyCallback NotifySymbolsReady)
118137 : NotifySymbolsResolved(std::move(NotifySymbolsResolved)),
119138 NotifySymbolsReady(std::move(NotifySymbolsReady)) {
120 assert(this->NotifySymbolsResolved &&
121 "Symbols resolved callback must be set");
122 assert(this->NotifySymbolsReady && "Symbols ready callback must be set");
123 OutstandingResolutions = OutstandingFinalizations = Symbols.size();
124 }
125
126 void AsynchronousSymbolQuery::notifyMaterializationFailed(Error Err) {
127 if (OutstandingResolutions != 0)
139 NotYetResolvedCount = NotYetReadyCount = Symbols.size();
140
141 for (auto &S : Symbols)
142 ResolvedSymbols[S] = nullptr;
143 }
144
145 void AsynchronousSymbolQuery::resolve(const SymbolStringPtr &Name,
146 JITEvaluatedSymbol Sym) {
147 auto I = ResolvedSymbols.find(Name);
148 assert(I != ResolvedSymbols.end() &&
149 "Resolving symbol outside the requested set");
150 assert(I->second.getAddress() == 0 && "Redundantly resolving symbol Name");
151 I->second = std::move(Sym);
152 --NotYetResolvedCount;
153 }
154
155 void AsynchronousSymbolQuery::handleFullyResolved() {
156 assert(NotYetResolvedCount == 0 && "Not fully resolved?");
157 assert(NotifySymbolsResolved &&
158 "NotifySymbolsResolved already called or error occurred");
159 NotifySymbolsResolved(
160 ResolutionResult(std::move(ResolvedSymbols), QueryRegistrations));
161 NotifySymbolsResolved = SymbolsResolvedCallback();
162 }
163
164 void AsynchronousSymbolQuery::notifySymbolReady() {
165 assert(NotYetReadyCount != 0 && "All symbols already finalized");
166 --NotYetReadyCount;
167 }
168
169 void AsynchronousSymbolQuery::handleFullyReady() {
170 assert(QueryRegistrations.empty() &&
171 "Query is still registered with some symbols");
172 assert(!NotifySymbolsResolved && "Resolution not applied yet");
173 NotifySymbolsReady(Error::success());
174 NotifySymbolsReady = SymbolsReadyCallback();
175 }
176
177 void AsynchronousSymbolQuery::handleFailed(Error Err) {
178 assert(QueryRegistrations.empty() && ResolvedSymbols.empty() &&
179 NotYetResolvedCount == 0 && NotYetReadyCount == 0 &&
180 "Query should already have been abandoned");
181 if (NotifySymbolsResolved)
128182 NotifySymbolsResolved(std::move(Err));
129 else if (OutstandingFinalizations != 0)
183 else {
184 assert(NotifySymbolsReady && "Failed after both callbacks issued?");
130185 NotifySymbolsReady(std::move(Err));
131 else
132 consumeError(std::move(Err));
133 OutstandingResolutions = OutstandingFinalizations = 0;
134 }
135
136 void AsynchronousSymbolQuery::resolve(SymbolStringPtr Name,
137 JITEvaluatedSymbol Sym) {
138 // If OutstandingResolutions is zero we must have errored out already. Just
139 // ignore this.
140 if (OutstandingResolutions == 0)
141 return;
142
143 assert(!Symbols.count(Name) && "Symbol has already been assigned an address");
144 Symbols.insert(std::make_pair(std::move(Name), std::move(Sym)));
145 --OutstandingResolutions;
146 if (OutstandingResolutions == 0)
147 NotifySymbolsResolved(std::move(Symbols));
148 }
149
150 void AsynchronousSymbolQuery::finalizeSymbol() {
151 // If OutstandingFinalizations is zero we must have errored out already. Just
152 // ignore this.
153 if (OutstandingFinalizations == 0)
154 return;
155
156 assert(OutstandingFinalizations > 0 && "All symbols already finalized");
157 --OutstandingFinalizations;
158 if (OutstandingFinalizations == 0)
159 NotifySymbolsReady(Error::success());
186 NotifySymbolsReady = SymbolsReadyCallback();
187 }
188 }
189
190 void AsynchronousSymbolQuery::addQueryDependence(VSO &V, SymbolStringPtr Name) {
191 bool Added = QueryRegistrations[&V].insert(std::move(Name)).second;
192 (void)Added;
193 assert(Added && "Duplicate dependence notification?");
194 }
195
196 void AsynchronousSymbolQuery::removeQueryDependence(
197 VSO &V, const SymbolStringPtr &Name) {
198 auto QRI = QueryRegistrations.find(&V);
199 assert(QRI != QueryRegistrations.end() && "No dependencies registered for V");
200 assert(QRI->second.count(Name) && "No dependency on Name in V");
201 QRI->second.erase(Name);
202 if (QRI->second.empty())
203 QueryRegistrations.erase(QRI);
204 }
205
206 void AsynchronousSymbolQuery::detach() {
207 ResolvedSymbols.clear();
208 NotYetResolvedCount = 0;
209 NotYetReadyCount = 0;
210 for (auto &KV : QueryRegistrations)
211 KV.first->detachQueryHelper(*this, KV.second);
212 QueryRegistrations.clear();
160213 }
161214
162215 MaterializationResponsibility::MaterializationResponsibility(
163216 VSO &V, SymbolFlagsMap SymbolFlags)
164217 : V(V), SymbolFlags(std::move(SymbolFlags)) {
165218 assert(!this->SymbolFlags.empty() && "Materializing nothing?");
219
220 for (auto &KV : this->SymbolFlags)
221 KV.second |= JITSymbolFlags::Materializing;
166222 }
167223
168224 MaterializationResponsibility::~MaterializationResponsibility() {
171227 }
172228
173229 void MaterializationResponsibility::resolve(const SymbolMap &Symbols) {
174 #ifndef NDEBUG
175230 for (auto &KV : Symbols) {
176231 auto I = SymbolFlags.find(KV.first);
177232 assert(I != SymbolFlags.end() &&
178233 "Resolving symbol outside this responsibility set");
234 assert(I->second.isMaterializing() && "Duplicate resolution");
235 I->second &= ~JITSymbolFlags::Materializing;
179236 assert(KV.second.getFlags() == I->second &&
180237 "Resolving symbol with incorrect flags");
181238 }
182 #endif
239
183240 V.resolve(Symbols);
184241 }
185242
186243 void MaterializationResponsibility::finalize() {
187 SymbolNameSet SymbolNames;
244 #ifndef NDEBUG
188245 for (auto &KV : SymbolFlags)
189 SymbolNames.insert(KV.first);
246 assert(!KV.second.isMaterializing() &&
247 "Failed to resolve symbol before finalization");
248 #endif // NDEBUG
249
250 V.finalize(SymbolFlags);
190251 SymbolFlags.clear();
191 V.finalize(SymbolNames);
192 }
193
194 void MaterializationResponsibility::notifyMaterializationFailed() {
195 SymbolNameSet SymbolNames;
196 for (auto &KV : SymbolFlags)
197 SymbolNames.insert(KV.first);
252 }
253
254 Error MaterializationResponsibility::defineMaterializing(
255 const SymbolFlagsMap &NewSymbolFlags) {
256 // Add the given symbols to this responsibility object.
257 // It's ok if we hit a duplicate here: In that case the new version will be
258 // discarded, and the VSO::defineMaterializing method will return a duplicate
259 // symbol error.
260 for (auto &KV : NewSymbolFlags) {
261 auto I = SymbolFlags.insert(KV).first;
262 I->second |= JITSymbolFlags::Materializing;
263 }
264
265 return V.defineMaterializing(NewSymbolFlags);
266 }
267
268 void MaterializationResponsibility::failMaterialization(
269 std::function GenerateError) {
270 V.notifyFailed(SymbolFlags, std::move(GenerateError));
198271 SymbolFlags.clear();
199 V.notifyMaterializationFailed(SymbolNames);
200 }
201
202 MaterializationResponsibility
203 MaterializationResponsibility::delegate(SymbolNameSet Symbols) {
204 SymbolFlagsMap ExtractedFlags;
205
206 for (auto &S : Symbols) {
207 auto I = SymbolFlags.find(S);
208 ExtractedFlags.insert(*I);
209 SymbolFlags.erase(I);
210 }
211
212 return MaterializationResponsibility(V, std::move(ExtractedFlags));
213 }
214
215 VSO::Materializer::Materializer(std::unique_ptr MU,
216 MaterializationResponsibility R)
217 : MU(std::move(MU)), R(std::move(R)) {}
218
219 void VSO::Materializer::operator()() { MU->materialize(std::move(R)); }
220
221 VSO::UnmaterializedInfo::UnmaterializedInfo(
222 std::unique_ptr MU)
223 : MU(std::move(MU)), Symbols(this->MU->getSymbols()) {}
224
225 void VSO::UnmaterializedInfo::discard(VSO &V, SymbolStringPtr Name) {
226 assert(MU && "No materializer attached");
227 MU->discard(V, Name);
228 auto I = Symbols.find(Name);
229 assert(I != Symbols.end() && "Symbol not found in this MU");
230 Symbols.erase(I);
231 }
232
233 VSO::SymbolTableEntry::SymbolTableEntry(JITSymbolFlags Flags,
234 UnmaterializedInfoIterator UMII)
235 : Flags(Flags), UMII(std::move(UMII)) {
236 // We *don't* expect isLazy to be set here. That's for the VSO to do.
237 assert(!Flags.isLazy() && "Initial flags include lazy?");
238 assert(!Flags.isMaterializing() && "Initial flags include materializing");
239 this->Flags |= JITSymbolFlags::Lazy;
240 }
241
242 VSO::SymbolTableEntry::SymbolTableEntry(JITSymbolFlags Flags)
243 : Flags(Flags), Address(0) {
244 // We *don't* expect isMaterializing to be set here. That's for the VSO to do.
245 assert(!Flags.isLazy() && "Initial flags include lazy?");
246 assert(!Flags.isMaterializing() && "Initial flags include materializing");
247 this->Flags |= JITSymbolFlags::Materializing;
248 }
249
250 VSO::SymbolTableEntry::SymbolTableEntry(JITEvaluatedSymbol Sym)
251 : Flags(Sym.getFlags()), Address(Sym.getAddress()) {
252 assert(!Flags.isLazy() && !Flags.isMaterializing() &&
253 "This constructor is for final symbols only");
254 }
255
256 VSO::SymbolTableEntry::SymbolTableEntry(SymbolTableEntry &&Other)
257 : Flags(Other.Flags), Address(0) {
258 if (this->Flags.isLazy())
259 UMII = std::move(Other.UMII);
260 else
261 Address = Other.Address;
262 }
263
264 VSO::SymbolTableEntry &VSO::SymbolTableEntry::
265 operator=(SymbolTableEntry &&Other) {
266 destroy();
267 Flags = std::move(Other.Flags);
268 if (Other.Flags.isLazy()) {
269 UMII = std::move(Other.UMII);
270 } else
271 Address = Other.Address;
272 return *this;
273 }
274
275 VSO::SymbolTableEntry::~SymbolTableEntry() { destroy(); }
276
277 void VSO::SymbolTableEntry::replaceWith(VSO &V, SymbolStringPtr Name,
278 JITEvaluatedSymbol Sym) {
279 assert(!Flags.isMaterializing() &&
280 "Attempting to replace definition during materialization?");
281 if (Flags.isLazy()) {
282 UMII->discard(V, Name);
283 if (UMII->Symbols.empty())
284 V.UnmaterializedInfos.erase(UMII);
285 }
286 destroy();
287 Flags = Sym.getFlags();
288 Address = Sym.getAddress();
289 }
290
291 void VSO::SymbolTableEntry::replaceWith(VSO &V, SymbolStringPtr Name,
292 JITSymbolFlags NewFlags,
293 UnmaterializedInfoIterator NewUMII) {
294 assert(!Flags.isMaterializing() &&
295 "Attempting to replace definition during materialization?");
296 if (Flags.isLazy()) {
297 UMII->discard(V, Name);
298 if (UMII->Symbols.empty())
299 V.UnmaterializedInfos.erase(UMII);
300 }
301 destroy();
302 Flags = NewFlags;
303 UMII = std::move(NewUMII);
304 }
305
306 void VSO::SymbolTableEntry::replaceMaterializing(VSO &V, SymbolStringPtr Name,
307 JITSymbolFlags NewFlags) {
308 assert(!NewFlags.isWeak() &&
309 "Can't define a lazy symbol in materializing mode");
310 assert(!NewFlags.isLazy() && !NewFlags.isMaterializing() &&
311 "Flags should not be in lazy or materializing state");
312 if (Flags.isLazy()) {
313 UMII->discard(V, Name);
314 if (UMII->Symbols.empty())
315 V.UnmaterializedInfos.erase(UMII);
316 }
317 destroy();
318 Flags = NewFlags;
319 Flags |= JITSymbolFlags::Materializing;
320 Address = 0;
321 }
322
323 void VSO::SymbolTableEntry::notifyMaterializing() {
324 assert(Flags.isLazy() && "Can only start materializing from lazy state");
325 UMII.~UnmaterializedInfoIterator();
326 Flags &= ~JITSymbolFlags::Lazy;
327 Flags |= JITSymbolFlags::Materializing;
328 Address = 0;
329 }
330
331 void VSO::SymbolTableEntry::resolve(VSO &V, JITEvaluatedSymbol Sym) {
332 assert(!Flags.isLazy() && Flags.isMaterializing() &&
333 "Can only resolve in materializing state");
334 Flags = Sym.getFlags();
335 Flags |= JITSymbolFlags::Materializing;
336 Address = Sym.getAddress();
337 assert(Address != 0 && "Can not resolve to null");
338 }
339
340 void VSO::SymbolTableEntry::finalize() {
341 assert(Address != 0 && "Cannot finalize with null address");
342 assert(Flags.isMaterializing() && !Flags.isLazy() &&
343 "Symbol should be in materializing state");
344 Flags &= ~JITSymbolFlags::Materializing;
345 }
346
347 void VSO::SymbolTableEntry::destroy() {
348 if (Flags.isLazy())
349 UMII.~UnmaterializedInfoIterator();
350 }
351
352 VSO::RelativeLinkageStrength VSO::compareLinkage(Optional Old,
353 JITSymbolFlags New) {
354 if (Old == None)
355 return llvm::orc::VSO::NewDefinitionIsStronger;
356
357 if (Old->isStrong()) {
358 if (New.isStrong())
359 return llvm::orc::VSO::DuplicateDefinition;
360 else
361 return llvm::orc::VSO::ExistingDefinitionIsStronger;
362 } else {
363 if (New.isStrong())
364 return llvm::orc::VSO::NewDefinitionIsStronger;
365 else
366 return llvm::orc::VSO::ExistingDefinitionIsStronger;
367 }
368 }
369
370 VSO::RelativeLinkageStrength
371 VSO::compareLinkage(SymbolStringPtr Name, JITSymbolFlags NewFlags) const {
372 auto I = Symbols.find(Name);
373 return compareLinkage(
374 I == Symbols.end() ? None : Optional(I->second.Flags),
375 NewFlags);
376 }
377
378 Error VSO::define(SymbolMap NewSymbols) {
379 Error Err = Error::success();
380 for (auto &KV : NewSymbols) {
381 auto I = Symbols.find(KV.first);
382 auto LinkageResult = compareLinkage(
383 I == Symbols.end() ? None : Optional(I->second.Flags),
384 KV.second.getFlags());
385
386 // Silently discard weaker definitions.
387 if (LinkageResult == ExistingDefinitionIsStronger)
388 continue;
389
390 // Report duplicate definition errors.
391 if (LinkageResult == DuplicateDefinition) {
392 Err = joinErrors(std::move(Err),
393 make_error(*KV.first));
394 continue;
395 }
396
397 if (I != Symbols.end())
398 I->second.replaceWith(*this, I->first, KV.second);
399 else
400 Symbols.insert(std::make_pair(KV.first, std::move(KV.second)));
401 }
402 return Err;
403 }
404
405 Error VSO::defineLazy(std::unique_ptr MU) {
406 auto UMII = UnmaterializedInfos.insert(UnmaterializedInfos.end(),
407 UnmaterializedInfo(std::move(MU)));
408
409 Error Err = Error::success();
410 for (auto &KV : UMII->Symbols) {
411 auto I = Symbols.find(KV.first);
412
413 assert((I == Symbols.end() ||
414 !I->second.Flags.isMaterializing()) &&
415 "Attempt to replace materializing symbol definition");
416
417 auto LinkageResult = compareLinkage(
418 I == Symbols.end() ? None : Optional(I->second.Flags),
419 KV.second);
420
421 // Discard weaker definitions.
422 if (LinkageResult == ExistingDefinitionIsStronger) {
423 UMII->discard(*this, KV.first);
424 continue;
425 }
426
427 // Report duplicate definition errors.
428 if (LinkageResult == DuplicateDefinition) {
429 Err = joinErrors(std::move(Err),
430 make_error(*KV.first));
431 // Duplicate definitions are discarded, so remove the duplicates from
432 // materializer.
433 UMII->discard(*this, KV.first);
434 continue;
435 }
436
437 // Existing definition was weaker. Replace it.
438 if (I != Symbols.end())
439 I->second.replaceWith(*this, KV.first, KV.second, UMII);
440 else
441 Symbols.insert(
442 std::make_pair(KV.first, SymbolTableEntry(KV.second, UMII)));
443 }
444
445 if (UMII->Symbols.empty())
446 UnmaterializedInfos.erase(UMII);
447
448 return Err;
449 }
450
451 SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags, SymbolNameSet Names) {
452
453 for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) {
454 auto Tmp = I++;
455 auto SymI = Symbols.find(*Tmp);
456
457 // If the symbol isn't in this dylib then just continue.
458 if (SymI == Symbols.end())
459 continue;
460
461 Names.erase(Tmp);
462
463 Flags[SymI->first] =
464 JITSymbolFlags::stripTransientFlags(SymI->second.Flags);
465 }
466
467 return Names;
468 }
469
470 VSO::LookupResult VSO::lookup(std::shared_ptr Query,
471 SymbolNameSet Names) {
472 MaterializerList Materializers;
473
474 for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) {
475 auto Tmp = I++;
476 auto SymI = Symbols.find(*Tmp);
477
478 // If the symbol isn't in this dylib then just continue.
479 if (SymI == Symbols.end())
480 continue;
481
482 // The symbol is in the VSO. Erase it from Names and proceed.
483 Names.erase(Tmp);
484
485 // If this symbol has not been materialized yet grab its materializer,
486 // move all of its sibling symbols to the materializing state, and
487 // delete its unmaterialized info.
488 if (SymI->second.Flags.isLazy()) {
489 assert(SymI->second.UMII->MU &&
490 "Lazy symbol has no materializer attached");
491 auto MU = std::move(SymI->second.UMII->MU);
492 auto SymbolFlags = std::move(SymI->second.UMII->Symbols);
493 UnmaterializedInfos.erase(SymI->second.UMII);
494
495 for (auto &KV : SymbolFlags) {
496 auto SiblingI = Symbols.find(KV.first);
497 MaterializingInfos.insert(
498 std::make_pair(SiblingI->first, MaterializingInfo()));
499 SiblingI->second.notifyMaterializing();
272 }
273
274 void MaterializationResponsibility::delegate(
275 std::unique_ptr MU) {
276 for (auto &KV : MU->getSymbols())
277 SymbolFlags.erase(KV.first);
278
279 V.replace(std::move(MU));
280 }
281
282 void MaterializationResponsibility::addDependencies(
283 const SymbolDependenceMap &Dependencies) {
284 V.addDependencies(SymbolFlags, Dependencies);
285 }
286
287 AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit(
288 SymbolMap Symbols)
289 : MaterializationUnit(extractFlags(Symbols)), Symbols(std::move(Symbols)) {}
290
291 void AbsoluteSymbolsMaterializationUnit::materialize(
292 MaterializationResponsibility R) {
293 R.resolve(Symbols);
294 R.finalize();
295 }
296
297 void AbsoluteSymbolsMaterializationUnit::discard(const VSO &V,
298 SymbolStringPtr Name) {
299 assert(Symbols.count(Name) && "Symbol is not part of this MU");
300 Symbols.erase(Name);
301 }
302
303 SymbolFlagsMap
304 AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) {
305 SymbolFlagsMap Flags;
306 for (const auto &KV : Symbols)
307 Flags[KV.first] = KV.second.getFlags();
308 return Flags;
309 }
310
311 Error VSO::defineMaterializing(const SymbolFlagsMap &SymbolFlags) {
312 return ES.runSessionLocked([&]() -> Error {
313 std::vector AddedSyms;
314
315 for (auto &KV : SymbolFlags) {
316 SymbolMap::iterator EntryItr;
317 bool Added;
318
319 auto NewFlags = KV.second;
320 NewFlags |= JITSymbolFlags::Materializing;
321
322 std::tie(EntryItr, Added) = Symbols.insert(
323 std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags)));
324
325 if (Added)
326 AddedSyms.push_back(EntryItr);
327 else {
328 // Remove any symbols already added.
329 for (auto &SI : AddedSyms)
330 Symbols.erase(SI);
331
332 // FIXME: Return all duplicates.
333 return make_error(*KV.first);
500334 }
501
502 Materializers.push_back(Materializer(
503 std::move(MU),
504 MaterializationResponsibility(*this, std::move(SymbolFlags))));
505 }
506
507 // If this symbol already has a fully materialized value, just use it.
508 if (!SymI->second.Flags.isMaterializing()) {
509 Query->resolve(SymI->first, JITEvaluatedSymbol(SymI->second.Address,
510 SymI->second.Flags));
511 Query->finalizeSymbol();
512 continue;
513 }
514
515 // If this symbol is materializing, then get (or create) its
516 // MaterializingInfo struct and appaend the query.
517 auto J = MaterializingInfos.find(SymI->first);
518 assert(J != MaterializingInfos.end() && "Missing MaterializingInfo");
519
520 if (SymI->second.Address) {
521 auto Sym = JITEvaluatedSymbol(SymI->second.Address, SymI->second.Flags);
522 Query->resolve(SymI->first, Sym);
523 assert(J->second.PendingResolution.empty() &&
524 "Queries still pending resolution on resolved symbol?");
525 J->second.PendingFinalization.push_back(Query);
526 } else {
527 assert(J->second.PendingFinalization.empty() &&
528 "Queries pendiing finalization on unresolved symbol?");
529 J->second.PendingResolution.push_back(Query);
530 }
531 }
532
533 return {std::move(Materializers), std::move(Names)};
534 }
535
536 void VSO::resolve(const SymbolMap &SymbolValues) {
537 for (auto &KV : SymbolValues) {
538 auto I = Symbols.find(KV.first);
539 assert(I != Symbols.end() && "Resolving symbol not present in this dylib");
540 I->second.resolve(*this, KV.second);
541
542 auto J = MaterializingInfos.find(KV.first);
543 if (J == MaterializingInfos.end())
544 continue;
545
546 assert(J->second.PendingFinalization.empty() &&
547 "Queries already pending finalization?");
548 for (auto &Q : J->second.PendingResolution)
549 Q->resolve(KV.first, KV.second);
550 J->second.PendingFinalization = std::move(J->second.PendingResolution);
551 J->second.PendingResolution = MaterializingInfo::QueryList();
552 }
553 }
554
555 void VSO::notifyMaterializationFailed(const SymbolNameSet &Names) {
556 assert(!Names.empty() && "Failed to materialize empty set?");
557
558 std::map, SymbolNameSet>
559 ResolutionFailures;
560 std::map, SymbolNameSet>
561 FinalizationFailures;
562
563 for (auto &S : Names) {
564 auto I = Symbols.find(S);
565 assert(I != Symbols.end() && "Symbol not present in this VSO");
566
567 auto J = MaterializingInfos.find(S);
568 if (J != MaterializingInfos.end()) {
569 if (J->second.PendingFinalization.empty()) {
570 for (auto &Q : J->second.PendingResolution)
571 ResolutionFailures[Q].insert(S);
572 } else {
573 for (auto &Q : J->second.PendingFinalization)
574 FinalizationFailures[Q].insert(S);
335 }
336
337 return Error::success();
338 });
339 }
340
341 void VSO::replace(std::unique_ptr MU) {
342 assert(MU != nullptr && "Can not replace with a null MaterializationUnit");
343
344 auto MustRunMU =
345 ES.runSessionLocked([&, this]() -> std::unique_ptr {
346
347 #ifndef NDEBUG
348 for (auto &KV : MU->getSymbols()) {
349 auto SymI = Symbols.find(KV.first);
350 assert(SymI != Symbols.end() && "Replacing unknown symbol");
351 assert(!SymI->second.getFlags().isLazy() &&
352 SymI->second.getFlags().isMaterializing() &&
353 "Can not replace symbol that is not materializing");
354 assert(UnmaterializedInfos.count(KV.first) == 0 &&
355 "Symbol being replaced should have no UnmaterializedInfo");
356 assert(MaterializingInfos.count(KV.first) &&
357 "Symbol being replaced should have a MaterializingInfo");
358 }
359 #endif // NDEBUG
360
361 // If any symbol has pending queries against it then we need to
362 // materialize MU immediately.
363 for (auto &KV : MU->getSymbols())
364 if (!MaterializingInfos[KV.first].PendingQueries.empty())
365 return std::move(MU);
366
367 // Otherwise, make MU responsible for all the symbols.
368 auto UMI = std::make_shared(std::move(MU));
369 for (auto &KV : UMI->MU->getSymbols()) {
370 assert(!KV.second.isLazy() &&
371 "Lazy flag should be managed internally.");
372 assert(!KV.second.isMaterializing() &&
373 "Materializing flags should be managed internally.");
374
375 auto SymI = Symbols.find(KV.first);
376 SymI->second.getFlags() = KV.second;
377 SymI->second.getFlags() |= JITSymbolFlags::Lazy;
378 UnmaterializedInfos[KV.first] = UMI;
379 }
380
381 return nullptr;
382 });
383
384 if (MustRunMU)
385 ES.dispatchMaterialization(*this, std::move(MustRunMU));
386 }
387
388 void VSO::addDependencies(const SymbolFlagsMap &Dependants,
389 const SymbolDependenceMap &Dependencies) {
390 ES.runSessionLocked([&, this]() {
391 for (auto &KV : Dependants) {
392 const auto &Name = KV.first;
393 assert(Symbols.count(Name) && "Name not in symbol table");
394 assert((Symbols[Name].getFlags().isLazy() ||
395 Symbols[Name].getFlags().isMaterializing()) &&
396 "Symbol is not lazy or materializing");
397
398 auto &MI = MaterializingInfos[Name];
399 assert(!MI.IsFinalized && "Can not add dependencies to finalized symbol");
400
401 for (auto &KV : Dependencies) {
402 assert(KV.first && "Null VSO in dependency?");
403 auto &OtherVSO = *KV.first;
404 auto &DepsOnOtherVSO = MI.UnfinalizedDependencies[&OtherVSO];
405
406 for (auto &OtherSymbol : KV.second) {
407 auto &OtherMI = OtherVSO.MaterializingInfos[OtherSymbol];
408
409 if (OtherMI.IsFinalized)
410 transferFinalizedNodeDependencies(MI, Name, OtherMI);
411 else {
412 OtherMI.Dependants[this].insert(Name);
413 DepsOnOtherVSO.insert(OtherSymbol);
414 }
415 }
575416 }
576 MaterializingInfos.erase(J);
577 }
578 Symbols.erase(I);
579 }
580
581 for (auto &KV : ResolutionFailures)
582 KV.first->notifyMaterializationFailed(
583 make_error(std::move(KV.second)));
584
585 for (auto &KV : FinalizationFailures)
586 KV.first->notifyMaterializationFailed(
587 make_error(std::move(KV.second)));
588 }
589
590 void VSO::finalize(const SymbolNameSet &SymbolsToFinalize) {
591 for (auto &S : SymbolsToFinalize) {
592 auto I = Symbols.find(S);
593 assert(I != Symbols.end() && "Finalizing symbol not present in this dylib");
594
595 auto J = MaterializingInfos.find(S);
596 if (J != MaterializingInfos.end()) {
597 assert(J->second.PendingResolution.empty() &&
598 "Queries still pending resolution?");
599 for (auto &Q : J->second.PendingFinalization)
600 Q->finalizeSymbol();
601 MaterializingInfos.erase(J);
602 }
603 I->second.finalize();
604 }
417 }
418 });
419 }
420
421 void VSO::resolve(const SymbolMap &Resolved) {
422 auto FullyResolvedQueries = ES.runSessionLocked([&, this]() {
423 AsynchronousSymbolQuerySet FullyResolvedQueries;
424 for (const auto &KV : Resolved) {
425 auto &Name = KV.first;
426 auto Sym = KV.second;
427
428 assert(!Sym.getFlags().isLazy() && !Sym.getFlags().isMaterializing() &&
429 "Materializing flags should be managed internally");
430
431 auto I = Symbols.find(Name);
432
433 assert(I != Symbols.end() && "Symbol not found");
434 assert(!I->second.getFlags().isLazy() &&
435 I->second.getFlags().isMaterializing() &&
436 "Symbol should be materializing");
437 assert(I->second.getAddress() == 0 && "Symbol has already been resolved");
438
439 assert(Sym.getFlags() ==
440 JITSymbolFlags::stripTransientFlags(I->second.getFlags()) &&
441 "Resolved flags should match the declared flags");
442
443 // Once resolved, symbols can never be weak.
444 Sym.getFlags() = static_cast(
445 Sym.getFlags() & ~JITSymbolFlags::Weak);
446 I->second = Sym;
447
448 auto &MI = MaterializingInfos[Name];
449 for (auto &Q : MI.PendingQueries) {
450 Q->resolve(Name, Sym);
451 if (Q->isFullyResolved())
452 FullyResolvedQueries.insert(Q);
453 }
454 }
455
456 return FullyResolvedQueries;
457 });
458
459 for (auto &Q : FullyResolvedQueries) {
460 assert(Q->isFullyResolved() && "Q not fully resolved");
461 Q->handleFullyResolved();
462 }
463 }
464
465 void VSO::finalize(const SymbolFlagsMap &Finalized) {
466 auto FullyReadyQueries = ES.runSessionLocked([&, this]() {
467 AsynchronousSymbolQuerySet ReadyQueries;
468
469 for (const auto &KV : Finalized) {
470 const auto &Name = KV.first;
471
472 auto MII = MaterializingInfos.find(Name);
473 assert(MII != MaterializingInfos.end() &&
474 "Missing MaterializingInfo entry");
475
476 auto &MI = MII->second;
477
478 // For each dependant, transfer this node's unfinalized dependencies to
479 // it. If the dependant node is fully finalized then notify any pending
480 // queries.
481 for (auto &KV : MI.Dependants) {
482 auto &DependantVSO = *KV.first;
483 for (auto &DependantName : KV.second) {
484 auto DependantMII =
485 DependantVSO.MaterializingInfos.find(DependantName);
486 assert(DependantMII != DependantVSO.MaterializingInfos.end() &&
487 "Dependant should have MaterializingInfo");
488
489 auto &DependantMI = DependantMII->second;
490
491 // Remove the dependant's dependency on this node.
492 assert(DependantMI.UnfinalizedDependencies[this].count(Name) &&
493 "Dependant does not count this symbol as a dependency?");
494 DependantMI.UnfinalizedDependencies[this].erase(Name);
495 if (DependantMI.UnfinalizedDependencies[this].empty())
496 DependantMI.UnfinalizedDependencies.erase(this);
497
498 // Transfer unfinalized dependencies from this node to the dependant.
499 DependantVSO.transferFinalizedNodeDependencies(DependantMI,
500 DependantName, MI);
501
502 // If the dependant is finalized and this node was the last of its
503 // unfinalized dependencies then notify any pending queries on the
504 // dependant node.
505 if (DependantMI.IsFinalized &&
506 DependantMI.UnfinalizedDependencies.empty()) {
507 assert(DependantMI.Dependants.empty() &&
508 "Dependants should be empty by now");
509 for (auto &Q : DependantMI.PendingQueries) {
510 Q->notifySymbolReady();
511 if (Q->isFullyReady())
512 ReadyQueries.insert(Q);
513 Q->removeQueryDependence(DependantVSO, DependantName);
514 }
515
516 // If this dependant node was fully finalized we can erase its
517 // MaterializingInfo and update its materializing state.
518 assert(DependantVSO.Symbols.count(DependantName) &&
519 "Dependant has no entry in the Symbols table");
520 DependantVSO.Symbols[DependantName].getFlags() &=
521 JITSymbolFlags::Materializing;
522 DependantVSO.MaterializingInfos.erase(DependantMII);
523 }
524 }
525 }
526 MI.Dependants.clear();
527 MI.IsFinalized = true;
528
529 if (MI.UnfinalizedDependencies.empty()) {
530 for (auto &Q : MI.PendingQueries) {
531 Q->notifySymbolReady();
532 if (Q->isFullyReady())
533 ReadyQueries.insert(Q);
534 Q->removeQueryDependence(*this, Name);
535 }
536 assert(Symbols.count(Name) &&
537 "Symbol has no entry in the Symbols table");
538 Symbols[Name].getFlags() &= ~JITSymbolFlags::Materializing;
539 MaterializingInfos.erase(MII);
540 }
541 }
542
543 return ReadyQueries;
544 });
545
546 for (auto &Q : FullyReadyQueries) {
547 assert(Q->isFullyReady() && "Q is not fully ready");
548 Q->handleFullyReady();
549 }
550 }
551
552 void VSO::notifyFailed(const SymbolFlagsMap &Failed,
553 std::function GenerateError) {
554 auto FailedQueriesToNotify = ES.runSessionLocked([&, this]() {
555 AsynchronousSymbolQuerySet FailedQueries;
556
557 for (auto &KV : Failed) {
558 const auto &Name = KV.first;
559
560 auto I = Symbols.find(Name);
561 assert(I != Symbols.end() && "Symbol not present in this VSO");
562 Symbols.erase(I);
563
564 auto MII = MaterializingInfos.find(Name);
565
566 // If we have not created a MaterializingInfo for this symbol yet then
567 // there is nobody to notify.
568 if (MII == MaterializingInfos.end())
569 continue;
570
571 // Copy all the queries to the FailedQueries list, then abandon them.
572 // This has to be a copy, and the copy has to come before the abandon
573 // operation: Each Q.detach() call will reach back into this
574 // PendingQueries list to remove Q.
575 for (auto &Q : MII->second.PendingQueries)
576 FailedQueries.insert(Q);
577
578 for (auto &Q : FailedQueries)
579 Q->detach();
580
581 assert(MII->second.PendingQueries.empty() &&
582 "Queries remain after symbol was failed");
583
584 MaterializingInfos.erase(MII);
585 }
586
587 return FailedQueries;
588 });
589
590 for (auto &Q : FailedQueriesToNotify)
591 Q->handleFailed(GenerateError());
592 }
593
594 SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags,
595 const SymbolNameSet &Names) {
596 return ES.runSessionLocked([&, this]() {
597 SymbolNameSet Unresolved;
598
599 for (auto &Name : Names) {
600 auto I = Symbols.find(Name);
601 if (I == Symbols.end()) {
602 Unresolved.insert(Name);
603 continue;
604 }
605
606 assert(!Flags.count(Name) && "Symbol already present in Flags map");
607 Flags[Name] = JITSymbolFlags::stripTransientFlags(I->second.getFlags());
608 }
609
610 return Unresolved;
611 });
612 }
613
614 SymbolNameSet VSO::lookup(std::shared_ptr Q,
615 SymbolNameSet Names) {
616 SymbolNameSet Unresolved = std::move(Names);
617 std::vector> MUs;
618
619 ES.runSessionLocked([&, this]() {
620 for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) {
621 auto TmpI = I++;
622 auto Name = *TmpI;
623
624 // Search for the name in Symbols. Skip it if not found.
625 auto SymI = Symbols.find(Name);
626 if (SymI == Symbols.end())
627 continue;
628
629 // If we found Name in V, remove it frome the Unresolved set and add it
630 // to the dependencies set.
631 Unresolved.erase(TmpI);
632
633 // If the symbol has an address then resolve it.
634 if (SymI->second.getAddress() != 0)
635 Q->resolve(Name, SymI->second);
636
637 // If the symbol is lazy, get the MaterialiaztionUnit for it.
638 if (SymI->second.getFlags().isLazy()) {
639 assert(SymI->second.getAddress() == 0 &&
640 "Lazy symbol should not have a resolved address");
641 assert(!SymI->second.getFlags().isMaterializing() &&
642 "Materializing and lazy should not both be set");
643 auto UMII = UnmaterializedInfos.find(Name);
644 assert(UMII != UnmaterializedInfos.end() &&
645 "Lazy symbol should have UnmaterializedInfo");
646 auto MU = std::move(UMII->second->MU);
647 assert(MU != nullptr && "Materializer should not be null");
648
649 // Kick all symbols associated with this MaterializationUnit into
650 // materializing state.
651 for (auto &KV : MU->getSymbols()) {
652 auto SymK = Symbols.find(KV.first);
653 auto Flags = SymK->second.getFlags();
654 Flags &= ~JITSymbolFlags::Lazy;
655 Flags |= JITSymbolFlags::Materializing;
656 SymK->second.setFlags(Flags);
657 UnmaterializedInfos.erase(KV.first);
658 }
659
660 // Add MU to the list of MaterializationUnits to be materialized.
661 MUs.push_back(std::move(MU));
662 } else if (!SymI->second.getFlags().isMaterializing()) {
663 // The symbol is neither lazy nor materializing. Finalize it and
664 // continue.
665 Q->notifySymbolReady();
666 continue;
667 }
668
669 // Add the query to the PendingQueries list.
670 assert(SymI->second.getFlags().isMaterializing() &&
671 "By this line the symbol should be materializing");
672 auto &MI = MaterializingInfos[Name];
673 MI.PendingQueries.push_back(Q);
674 Q->addQueryDependence(*this, Name);
675 }
676 });
677
678 if (Q->isFullyResolved())
679 Q->handleFullyResolved();
680
681 if (Q->isFullyReady())
682 Q->handleFullyReady();
683
684 // Dispatch any required MaterializationUnits for materialization.
685 for (auto &MU : MUs)
686 ES.dispatchMaterialization(*this, std::move(MU));
687
688 return Unresolved;
689 }
690
691 void VSO::dump(raw_ostream &OS) {
692 ES.runSessionLocked([&, this]() {
693 OS << "VSO \"" << VSOName
694 << "\" (ES: " << format("0x%016x", reinterpret_cast(&ES))
695 << "):\n"
696 << "Symbol table:\n";
697
698 for (auto &KV : Symbols) {
699 OS << " \"" << *KV.first << "\": " << KV.second.getAddress();
700 if (KV.second.getFlags().isLazy() ||
701 KV.second.getFlags().isMaterializing()) {
702 OS << " (";
703 if (KV.second.getFlags().isLazy()) {
704 auto I = UnmaterializedInfos.find(KV.first);
705 assert(I != UnmaterializedInfos.end() &&
706 "Lazy symbol should have UnmaterializedInfo");
707 OS << " Lazy (MU=" << I->second->MU.get() << ")";
708 }
709 if (KV.second.getFlags().isMaterializing())
710 OS << " Materializing";
711 OS << " )\n";
712 } else
713 OS << "\n";
714 }
715
716 if (!MaterializingInfos.empty())
717 OS << " MaterializingInfos entries:\n";
718 for (auto &KV : MaterializingInfos) {
719 OS << " \"" << *KV.first << "\":\n"
720 << " IsFinalized = " << (KV.second.IsFinalized ? "true" : "false")
721 << "\n"
722 << " " << KV.second.PendingQueries.size() << " pending queries.\n"
723 << " Dependants:\n";
724 for (auto &KV2 : KV.second.Dependants)
725 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n";
726 OS << " Unfinalized Dependencies:\n";
727 for (auto &KV2 : KV.second.UnfinalizedDependencies)
728 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n";
729 }
730 });
731 }
732
733 Error VSO::defineImpl(MaterializationUnit &MU) {
734 SymbolNameSet Duplicates;
735 SymbolNameSet MUDefsOverridden;
736 std::vector ExistingDefsOverridden;
737 for (auto &KV : MU.getSymbols()) {
738 assert(!KV.second.isLazy() && "Lazy flag should be managed internally.");
739 assert(!KV.second.isMaterializing() &&
740 "Materializing flags should be managed internally.");
741
742 SymbolMap::iterator EntryItr;
743 bool Added;
744
745 auto NewFlags = KV.second;
746 NewFlags |= JITSymbolFlags::Lazy;
747
748 std::tie(EntryItr, Added) = Symbols.insert(
749 std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags)));
750
751 if (!Added) {
752 if (KV.second.isStrong()) {
753 if (EntryItr->second.getFlags().isStrong())
754 Duplicates.insert(KV.first);
755 else
756 ExistingDefsOverridden.push_back(EntryItr);
757 } else
758 MUDefsOverridden.insert(KV.first);
759 }
760 }
761
762 if (!Duplicates.empty()) {
763 // We need to remove the symbols we added.
764 for (auto &KV : MU.getSymbols()) {
765 if (Duplicates.count(KV.first) || Duplicates.count(KV.first))
766 continue;
767
768 bool Found = false;
769 for (const auto &I : ExistingDefsOverridden)
770 if (I->first == KV.first)
771 Found = true;
772
773 if (!Found)
774 Symbols.erase(KV.first);
775 }
776
777 // FIXME: Return all duplicates.
778 return make_error(**Duplicates.begin());
779 }
780
781 // Update flags on existing defs and call discard on their materializers.
782 for (auto &ExistingDefItr : ExistingDefsOverridden) {
783 assert(ExistingDefItr->second.getFlags().isLazy() &&
784 !ExistingDefItr->second.getFlags().isMaterializing() &&
785 "Overridden existing def should be in the Lazy state");
786
787 ExistingDefItr->second.getFlags() &= ~JITSymbolFlags::Weak;
788
789 auto UMII = UnmaterializedInfos.find(ExistingDefItr->first);
790 assert(UMII != UnmaterializedInfos.end() &&
791 "Overridden existing def should have an UnmaterializedInfo");
792
793 UMII->second->MU->doDiscard(*this, ExistingDefItr->first);
794 }
795
796 // Discard overridden symbols povided by MU.
797 for (auto &Sym : MUDefsOverridden)
798 MU.doDiscard(*this, Sym);
799
800 return Error::success();
801 }
802
803 void VSO::detachQueryHelper(AsynchronousSymbolQuery &Q,
804 const SymbolNameSet &QuerySymbols) {
805 for (auto &QuerySymbol : QuerySymbols) {
806 assert(MaterializingInfos.count(QuerySymbol) &&
807 "QuerySymbol does not have MaterializingInfo");
808 auto &MI = MaterializingInfos[QuerySymbol];
809
810 auto IdenticalQuery =
811 [&](const std::shared_ptr &R) {
812 return R.get() == &Q;
813 };
814
815 auto I = std::find_if(MI.PendingQueries.begin(), MI.PendingQueries.end(),
816 IdenticalQuery);
817 assert(I != MI.PendingQueries.end() &&
818 "Query Q should be in the PendingQueries list for QuerySymbol");
819 MI.PendingQueries.erase(I);
820 }
821 }
822
823 void VSO::transferFinalizedNodeDependencies(
824 MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName,
825 MaterializingInfo &FinalizedMI) {
826 for (auto &KV : FinalizedMI.UnfinalizedDependencies) {
827 auto &DependencyVSO = *KV.first;
828 SymbolNameSet *UnfinalizedDependenciesOnDependencyVSO = nullptr;
829
830 for (auto &DependencyName : KV.second) {
831 auto &DependencyMI = DependencyVSO.MaterializingInfos[DependencyName];
832
833 // Do not add self dependencies.
834 if (&DependencyMI == &DependantMI)
835 continue;
836
837 // If we haven't looked up the dependencies for DependencyVSO yet, do it
838 // now and cache the result.
839 if (!UnfinalizedDependenciesOnDependencyVSO)
840 UnfinalizedDependenciesOnDependencyVSO =
841 &DependantMI.UnfinalizedDependencies[&DependencyVSO];
842
843 DependencyMI.Dependants[this].insert(DependantName);
844 UnfinalizedDependenciesOnDependencyVSO->insert(DependencyName);
845 }
846 }
847 }
848
849 VSO &ExecutionSession::createVSO(std::string Name) {
850 return runSessionLocked([&, this]() -> VSO & {
851 VSOs.push_back(std::unique_ptr(new VSO(*this, std::move(Name))));
852 return *VSOs.back();
853 });
605854 }
606855
607856 Expected lookup(const std::vector &VSOs, SymbolNameSet Names,
608 MaterializationDispatcher DispatchMaterialization) {
857 MaterializationResponsibility *R) {
609858 #if LLVM_ENABLE_THREADS
610859 // In the threaded case we use promises to return the results.
611860 std::promise PromisedResult;
613862 Error ResolutionError = Error::success();
614863 std::promise PromisedReady;
615864 Error ReadyError = Error::success();
616 auto OnResolve = [&](Expected Result) {
617 if (Result)
618 PromisedResult.set_value(std::move(*Result));
619 else {
620 {
621 ErrorAsOutParameter _(&ResolutionError);
622 std::lock_guard Lock(ErrMutex);
623 ResolutionError = Result.takeError();
624 }
625 PromisedResult.set_value(SymbolMap());
626 }
627 };
865 auto OnResolve =
866 [&](Expected Result) {
867 if (Result) {
868 if (R)
869 R->addDependencies(Result->Dependencies);
870 PromisedResult.set_value(std::move(Result->Symbols));
871 } else {
872 {
873 ErrorAsOutParameter _(&ResolutionError);
874 std::lock_guard Lock(ErrMutex);
875 ResolutionError = Result.takeError();
876 }
877 PromisedResult.set_value(SymbolMap());
878 }
879 };
628880 auto OnReady = [&](Error Err) {
629881 if (Err) {
630882 ErrorAsOutParameter _(&ReadyError);
638890 Error ResolutionError = Error::success();
639891 Error ReadyError = Error::success();
640892
641 auto OnResolve = [&](Expected<SymbolMap> R) {
893 auto OnResolve = [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
642894 ErrorAsOutParameter _(&ResolutionError);
643 if (R)
644 Result = std::move(*R);
645 else
646 ResolutionError = R.takeError();
895 if (RR) {
896 if (R)
897 R->addDependencies(RR->Dependencies);
898 Result = std::move(RR->Symbols);
899 } else
900 ResolutionError = RR.takeError();
647901 };
648902 auto OnReady = [&](Error Err) {
649903 ErrorAsOutParameter _(&ReadyError);
657911 SymbolNameSet UnresolvedSymbols(std::move(Names));
658912
659913 for (auto *V : VSOs) {
660
914 assert(V && "VSO pointers in VSOs list should be non-null");
661915 if (UnresolvedSymbols.empty())
662916 break;
663
664 assert(V && "VSO pointers in VSOs list should be non-null");
665 auto LR = V->lookup(Query, UnresolvedSymbols);
666 UnresolvedSymbols = std::move(LR.UnresolvedSymbols);
667
668 for (auto &M : LR.Materializers)
669 DispatchMaterialization(std::move(M));
670 }
917 UnresolvedSymbols = V->lookup(Query, UnresolvedSymbols);
918 }
919
920 // FIXME: Error out if there are remaining unresolved symbols.
671921
672922 #if LLVM_ENABLE_THREADS
673923 auto ResultFuture = PromisedResult.get_future();
708958 }
709959
710960 /// Look up a symbol by searching a list of VSOs.
711 Expected
712 lookup(const std::vector VSOs, SymbolStringPtr Name,
713 MaterializationDispatcher DispatchMaterialization) {
961 Expected lookup(const std::vector VSOs,
962 SymbolStringPtr Name,
963 MaterializationResponsibility *R) {
714964 SymbolNameSet Names({Name});
715 if (auto ResultMap =
716 lookup(VSOs, std::move(Names), std::move(DispatchMaterialization))) {
965 if (auto ResultMap = lookup(VSOs, std::move(Names), R)) {
717966 assert(ResultMap->size() == 1 && "Unexpected number of results");
718967 assert(ResultMap->count(Name) && "Missing result for symbol");
719 return ResultMap->begin()->second;
968 return std::move(ResultMap->begin()->second);
720969 } else
721970 return ResultMap.takeError();
722971 }
723972
724 void ExecutionSession::logErrorsToStdErr(Error Err) {
725 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
726 }
727
728973 } // End namespace orc.
729974 } // End namespace llvm.
1111 namespace llvm {
1212 namespace orc {
1313
14 JITSymbolResolverAdapter::JITSymbolResolverAdapter(ExecutionSession &ES,
15 SymbolResolver &R)
16 : ES(ES), R(R) {}
14 JITSymbolResolverAdapter::JITSymbolResolverAdapter(
15 ExecutionSession &ES, SymbolResolver &R, MaterializationResponsibility *MR)
16 : ES(ES), R(R), MR(MR) {}
1717
1818 Expected
1919 JITSymbolResolverAdapter::lookup(const LookupSet &Symbols) {
2424 for (auto &S : Symbols)
2525 InternedSymbols.insert(ES.getSymbolStringPool().intern(S));
2626
27 auto OnResolve = [&](Expected R) {
28 if (R) {
29 for (auto &KV : *R) {
30 ResolvedStrings.insert(KV.first);
31 Result[*KV.first] = KV.second;
32 }
33 } else
34 Err = joinErrors(std::move(Err), R.takeError());
35 };
27 auto OnResolve =
28 [&, this](Expected RR) {
29 if (RR) {
30 // If this lookup was attached to a MaterializationResponsibility then
31 // record the dependencies.
32 if (MR)
33 MR->addDependencies(RR->Dependencies);
3634
37 auto OnReady = [](Error Err) {
38 // FIXME: Report error to ExecutionSession.
39 logAllUnhandledErrors(std::move(Err), errs(),
40 "legacy resolver received on-ready error:\n");
41 };
35 for (auto &KV : RR->Symbols) {
36 ResolvedStrings.insert(KV.first);
37 Result[*KV.first] = KV.second;
38 }
39 } else
40 Err = joinErrors(std::move(Err), RR.takeError());
41 };
42
43 auto OnReady = [this](Error Err) { ES.reportError(std::move(Err)); };
4244
4345 auto Query = std::make_shared(InternedSymbols,
4446 OnResolve, OnReady);
4547
46 auto UnresolvedSymbols = R.lookup(std::move(Query), InternedSymbols);
48 auto UnresolvedSymbols = R.lookup(Query, InternedSymbols);
4749
4850 if (!UnresolvedSymbols.empty()) {
4951 std::string ErrorMsg = "Unresolved symbols: ";
154154 if (auto Addr = Sym.getAddress())
155155 Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
156156 else {
157 Query->notifyMaterializationFailed(Addr.takeError());
157 Stack.ES.failQuery(*Query, Addr.takeError());
158158 return orc::SymbolNameSet();
159159 }
160160 } else if (auto Err = Sym.takeError()) {
161 Query->notifyMaterializationFailed(std::move(Err));
161 Stack.ES.failQuery(*Query, std::move(Err));
162162 return orc::SymbolNameSet();
163163 } else
164164 UnresolvedSymbols.insert(S);
165165 }
166
167 if (Query->isFullyResolved())
168 Query->handleFullyResolved();
166169
167170 return UnresolvedSymbols;
168171 }
170170 SymbolNameSet lookup(std::shared_ptr Query,
171171 SymbolNameSet Symbols) override {
172172 SymbolNameSet UnresolvedSymbols;
173 bool NewSymbolsResolved = false;
173174
174175 for (auto &S : Symbols) {
175176 if (auto Sym = M.findMangledSymbol(*S)) {
176 if (auto Addr = Sym.getAddress())
177 if (auto Addr = Sym.getAddress()) {
177178 Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
178 else {
179 Query->notifyMaterializationFailed(Addr.takeError());
179 NewSymbolsResolved = true;
180 } else {
181 M.ES.failQuery(*Query, Addr.takeError());
180182 return SymbolNameSet();
181183 }
182184 } else if (auto Err = Sym.takeError()) {
183 Query->notifyMaterializationFailed(std::move(Err));
185 M.ES.failQuery(*Query, std::move(Err));
184186 return SymbolNameSet();
185187 } else {
186188 if (auto Sym2 = M.ClientResolver->findSymbol(*S)) {
187 if (auto Addr = Sym2.getAddress())
189 if (auto Addr = Sym2.getAddress()) {
188190 Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym2.getFlags()));
189 else {
190 Query->notifyMaterializationFailed(Addr.takeError());
191 NewSymbolsResolved = true;
192 } else {
193 M.ES.failQuery(*Query, Addr.takeError());
191194 return SymbolNameSet();
192195 }
193196 } else if (auto Err = Sym2.takeError()) {
194 Query->notifyMaterializationFailed(std::move(Err));
197 M.ES.failQuery(*Query, std::move(Err));
195198 return SymbolNameSet();
196199 } else
197200 UnresolvedSymbols.insert(S);
198201 }
199202 }
203
204 if (NewSymbolsResolved && Query->isFullyResolved())
205 Query->handleFullyResolved();
200206
201207 return UnresolvedSymbols;
202208 }
173173 }
174174 return std::move(*NotFoundViaLegacyLookup);
175175 },
176 [LegacyLookup](std::shared_ptr Query,
176 [this,
177 LegacyLookup](std::shared_ptr Query,
177178 orc::SymbolNameSet Symbols) {
178 return lookupWithLegacyFn(*Query, Symbols, LegacyLookup);
179 return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
179180 });
180181
181182 // Add the module to the JIT.
2121
2222 class SimpleMaterializationUnit : public MaterializationUnit {
2323 public:
24 using GetSymbolsFunction = std::function;
2524 using MaterializeFunction =
2625 std::function;
2726 using DiscardFunction = std::function;
2827 using DestructorFunction = std::function;
2928
3029 SimpleMaterializationUnit(
31 GetSymbolsFunction GetSymbols, MaterializeFunction Materialize,
32 DiscardFunction Discard,
30 SymbolFlagsMap SymbolFlags, MaterializeFunction Materialize,
31 DiscardFunction Discard = DiscardFunction(),
3332 DestructorFunction Destructor = DestructorFunction())
34 : GetSymbols(std::move(GetSymbols)), Materialize(std::move(Materialize)),
35 Discard(std::move(Discard)), Destructor(std::move(Destructor)) {}
33 : MaterializationUnit(std::move(SymbolFlags)),
34 Materialize(std::move(Materialize)), Discard(std::move(Discard)),
35 Destructor(std::move(Destructor)) {}
3636
3737 ~SimpleMaterializationUnit() override {
3838 if (Destructor)
3939 Destructor();
4040 }
4141
42 SymbolFlagsMap getSymbols() override { return GetSymbols(); }
43
4442 void materialize(MaterializationResponsibility R) override {
4543 Materialize(std::move(R));
4644 }
4745
4846 void discard(const VSO &V, SymbolStringPtr Name) override {
49 Discard(V, std::move(Name));
47 if (Discard)
48 Discard(V, std::move(Name));
49 else
50 llvm_unreachable("Discard not supported");
5051 }
5152
5253 private:
53 GetSymbolsFunction GetSymbols;
5454 MaterializeFunction Materialize;
5555 DiscardFunction Discard;
5656 DestructorFunction Destructor;
6464
6565 bool OnResolutionRun = false;
6666 bool OnReadyRun = false;
67 auto OnResolution = [&](Expected Result) {
68 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
69 auto I = Result->find(Foo);
70 EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
71 EXPECT_EQ(I->second.getAddress(), FakeAddr)
72 << "Resolution returned incorrect result";
73 OnResolutionRun = true;
74 };
67 auto OnResolution =
68 [&](Expected Result) {
69 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
70 auto &Resolved = Result->Symbols;
71 auto I = Resolved.find(Foo);
72 EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition";
73 EXPECT_EQ(I->second.getAddress(), FakeAddr)
74 << "Resolution returned incorrect result";
75 OnResolutionRun = true;
76 };
7577 auto OnReady = [&](Error Err) {
7678 cantFail(std::move(Err));
7779 OnReadyRun = true;
8183
8284 Q.resolve(Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported));
8385
86 EXPECT_TRUE(Q.isFullyResolved()) << "Expected query to be fully resolved";
87
88 if (!Q.isFullyResolved())
89 return;
90
91 Q.handleFullyResolved();
92
8493 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
8594 EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
8695 }
8796
88 TEST(CoreAPIsTest, AsynchronousSymbolQueryResolutionErrorOnly) {
89 SymbolStringPool SP;
90 auto Foo = SP.intern("foo");
97 TEST(CoreAPIsTest, ExecutionSessionFailQuery) {
98 ExecutionSession ES;
99 auto Foo = ES.getSymbolStringPool().intern("foo");
91100 SymbolNameSet Names({Foo});
92101
93102 bool OnResolutionRun = false;
94103 bool OnReadyRun = false;
95104
96 auto OnResolution = [&](Expected Result) {
97 EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success";
98 auto Msg = toString(Result.takeError());
99 EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result";
100 OnResolutionRun = true;
101 };
105 auto OnResolution =
106 [&](Expected Result) {
107 EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success";
108 auto Msg = toString(Result.takeError());
109 EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result";
110 OnResolutionRun = true;
111 };
102112 auto OnReady = [&](Error Err) {
103113 cantFail(std::move(Err));
104114 OnReadyRun = true;
106116
107117 AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
108118
109 Q.notifyMaterializationFailed(
110 make_error("xyz", inconvertibleErrorCode()));
119 ES.failQuery(Q, make_error("xyz", inconvertibleErrorCode()));
111120
112121 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
113122 EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
114123 }
115124
116125 TEST(CoreAPIsTest, SimpleAsynchronousSymbolQueryAgainstVSO) {
117 SymbolStringPool SP;
118 auto Foo = SP.intern("foo");
126 ExecutionSession ES;
127 auto Foo = ES.getSymbolStringPool().intern("foo");
119128 constexpr JITTargetAddress FakeAddr = 0xdeadbeef;
120129 SymbolNameSet Names({Foo});
121130
122131 bool OnResolutionRun = false;
123132 bool OnReadyRun = false;
124133
125 auto OnResolution = [&](Expected Result) {
126 EXPECT_TRUE(!!Result) << "Query unexpectedly returned error";
127 auto I = Result->find(Foo);
128 EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
129 EXPECT_EQ(I->second.getAddress(), FakeAddr)
130 << "Resolution returned incorrect result";
131 OnResolutionRun = true;
132 };
134 auto OnResolution =
135 [&](Expected Result) {
136 EXPECT_TRUE(!!Result) << "Query unexpectedly returned error";
137 auto &Resolved = Result->Symbols;
138 auto I = Resolved.find(Foo);
139 EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition";
140 EXPECT_EQ(I->second.getAddress(), FakeAddr)
141 << "Resolution returned incorrect result";
142 OnResolutionRun = true;
143 };
133144
134145 auto OnReady = [&](Error Err) {
135146 cantFail(std::move(Err));
138149
139150 auto Q =
140151 std::make_shared(Names, OnResolution, OnReady);
141 VSO V;
142
143 SymbolMap Defs;
144 Defs[Foo] = JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported);
145 cantFail(V.define(std::move(Defs)));
152 auto &V = ES.createVSO("V");
153
154 auto Defs = absoluteSymbols(
155 {{Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported)}});
156 cantFail(V.define(Defs));
157 assert(Defs == nullptr && "Defs should have been accepted");
146158 V.lookup(Q, Names);
147159
148160 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
154166 // Test that lookupFlags works on a predefined symbol, and does not trigger
155167 // materialization of a lazy symbol.
156168
157 SymbolStringPool SP;
158 auto Foo = SP.intern("foo");
159 auto Bar = SP.intern("bar");
160 auto Baz = SP.intern("baz");
169 ExecutionSession ES;
170 auto Foo = ES.getSymbolStringPool().intern("foo");
171 auto Bar = ES.getSymbolStringPool().intern("bar");
172 auto Baz = ES.getSymbolStringPool().intern("baz");
161173
162174 JITSymbolFlags FooFlags = JITSymbolFlags::Exported;
163175 JITSymbolFlags BarFlags = static_cast(
164176 JITSymbolFlags::Exported | JITSymbolFlags::Weak);
165177
166 VSO V;
178 VSO &V = ES.createVSO("V");
167179
168180 auto MU = llvm::make_unique(
169 [=]() {
170 return SymbolFlagsMap({{Bar, BarFlags}});
171 },
181 SymbolFlagsMap({{Bar, BarFlags}}),
172182 [](MaterializationResponsibility R) {
173183 llvm_unreachable("Symbol materialized on flags lookup");
174 },
175 [](const VSO &V, SymbolStringPtr Name) {
176 llvm_unreachable("Symbol finalized on flags lookup");
177 });
178
179 SymbolMap InitialDefs;
180 InitialDefs[Foo] = JITEvaluatedSymbol(0xdeadbeef, FooFlags);
181 cantFail(V.define(std::move(InitialDefs)));
182
183 cantFail(V.defineLazy(std::move(MU)));
184 });
185
186 cantFail(V.define(
187 absoluteSymbols({{Foo, JITEvaluatedSymbol(0xdeadbeef, FooFlags)}})));
188 cantFail(V.define(std::move(MU)));
184189
185190 SymbolNameSet Names({Foo, Bar, Baz});
186191
198203 EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar";
199204 }
200205
206 TEST(CoreAPIsTest, TestCircularDependenceInOneVSO) {
207
208 ExecutionSession ES;
209
210 auto &V = ES.createVSO("V");
211
212 // Create three symbols: Foo, Bar and Baz.
213 auto Foo = ES.getSymbolStringPool().intern("foo");
214 auto FooFlags = JITSymbolFlags::Exported;
215 auto FooSym = JITEvaluatedSymbol(1U, FooFlags);
216
217 auto Bar = ES.getSymbolStringPool().intern("bar");
218 auto BarFlags = JITSymbolFlags::Exported;
219 auto BarSym = JITEvaluatedSymbol(2U, BarFlags);
220
221 auto Baz = ES.getSymbolStringPool().intern("baz");
222 auto BazFlags = JITSymbolFlags::Exported;
223 auto BazSym = JITEvaluatedSymbol(3U, BazFlags);
224
225 // Create three MaterializationResponsibility objects: one for each symbol
226 // (these are optional because MaterializationResponsibility does not have
227 // a default constructor).
228 Optional FooR;
229 Optional BarR;
230 Optional BazR;
231
232 // Create a MaterializationUnit for each symbol that moves the
233 // MaterializationResponsibility into one of the locals above.
234 auto FooMU = llvm::make_unique(
235 SymbolFlagsMap({{Foo, FooFlags}}),
236 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); });
237
238 auto BarMU = llvm::make_unique(
239 SymbolFlagsMap({{Bar, BarFlags}}),
240 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); });
241
242 auto BazMU = llvm::make_unique(
243 SymbolFlagsMap({{Baz, BazFlags}}),
244 [&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); });
245
246 // Define the symbols.
247 cantFail(V.define(FooMU));
248 cantFail(V.define(BarMU));
249 cantFail(V.define(BazMU));
250
251 // Query each of the symbols to trigger materialization.
252 bool FooResolved = false;
253 bool FooReady = false;
254 auto FooQ = std::make_shared(
255 SymbolNameSet({Foo}),
256 [&](Expected RR) {
257 cantFail(std::move(RR));
258 FooResolved = true;
259 },
260 [&](Error Err) {
261 cantFail(std::move(Err));
262 FooReady = true;
263 });
264 {
265 auto Unresolved = V.lookup(FooQ, {Foo});
266 EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Foo\"";
267 }
268
269 bool BarResolved = false;
270 bool BarReady = false;
271 auto BarQ = std::make_shared(
272 SymbolNameSet({Bar}),
273 [&](Expected RR) {
274 cantFail(std::move(RR));
275 BarResolved = true;
276 },
277 [&](Error Err) {
278 cantFail(std::move(Err));
279 BarReady = true;
280 });
281 {
282 auto Unresolved = V.lookup(BarQ, {Bar});
283 EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Bar\"";
284 }
285
286 bool BazResolved = false;
287 bool BazReady = false;
288 auto BazQ = std::make_shared(
289 SymbolNameSet({Baz}),
290 [&](Expected RR) {
291 cantFail(std::move(RR));
292 BazResolved = true;
293 },
294 [&](Error Err) {
295 cantFail(std::move(Err));
296 BazReady = true;
297 });
298 {
299 auto Unresolved = V.lookup(BazQ, {Baz});
300 EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Baz\"";
301 }
302
303 FooR->addDependencies({{&V, SymbolNameSet({Bar})}});
304 BarR->addDependencies({{&V, SymbolNameSet({Baz})}});
305 BazR->addDependencies({{&V, SymbolNameSet({Foo})}});
306
307 EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet";
308 EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet";
309 EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet";
310
311 FooR->resolve({{Foo, FooSym}});
312 BarR->resolve({{Bar, BarSym}});
313 BazR->resolve({{Baz, BazSym}});
314
315 EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now";
316 EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now";
317 EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now";
318
319 EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet";
320 EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet";
321 EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet";
322
323 FooR->finalize();
324 BarR->finalize();
325
326 // Verify that nothing is ready until the circular dependence is resolved.
327
328 EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready";
329 EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready";
330 EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready";
331
332 BazR->finalize();
333
334 // Verify that everything becomes ready once the circular dependence resolved.
335 EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now";
336 EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now";
337 EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now";
338 }
339
201340 TEST(CoreAPIsTest, DropMaterializerWhenEmpty) {
202 SymbolStringPool SP;
203 auto Foo = SP.intern("foo");
204 auto Bar = SP.intern("bar");
341 ExecutionSession ES;
342 auto Foo = ES.getSymbolStringPool().intern("foo");
343 auto Bar = ES.getSymbolStringPool().intern("bar");
205344
206345 bool DestructorRun = false;
207346
208347 auto MU = llvm::make_unique(
209 [=]() {
210 return SymbolFlagsMap(
211 {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}});
212 },
348 SymbolFlagsMap(
349 {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}),
213350 [](MaterializationResponsibility R) {
214351 llvm_unreachable("Unexpected call to materialize");
215352 },
219356 },
220357 [&]() { DestructorRun = true; });
221358
222 VSO V;
223
224 cantFail(V.defineLazy(std::move(MU)));
359 auto &V = ES.createVSO("V");
360
361 cantFail(V.define(MU));
225362
226363 auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported);
227364 auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported);
228 cantFail(V.define(SymbolMap({{Foo, FooSym}})));
365 cantFail(V.define(absoluteSymbols({{Foo, FooSym}})));
229366
230367 EXPECT_FALSE(DestructorRun)
231368 << "MaterializationUnit should not have been destroyed yet";
232369
233 cantFail(V.define(SymbolMap({{Bar, BarSym}})));
370 cantFail(V.define(absoluteSymbols({{Bar, BarSym}})));
234371
235372 EXPECT_TRUE(DestructorRun)
236373 << "MaterializationUnit should have been destroyed";
241378 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
242379 constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
243380
244 SymbolStringPool SP;
245 auto Foo = SP.intern("foo");
246 auto Bar = SP.intern("bar");
381 ExecutionSession ES;
382 auto Foo = ES.getSymbolStringPool().intern("foo");
383 auto Bar = ES.getSymbolStringPool().intern("bar");
247384
248385 bool FooMaterialized = false;
249386 bool BarDiscarded = false;
250387
251 VSO V;
388 auto &V = ES.createVSO("V");
252389
253390 auto MU = llvm::make_unique(
254 [=]() {
255 return SymbolFlagsMap(
256 {{Foo, JITSymbolFlags::Exported},
257 {Bar, static_cast(
258 JITSymbolFlags::Exported | JITSymbolFlags::Weak)}});
259 },
391 SymbolFlagsMap(
392 {{Foo, JITSymbolFlags::Exported},
393 {Bar, static_cast(
394 JITSymbolFlags::Exported | JITSymbolFlags::Weak)}}),
260395 [&](MaterializationResponsibility R) {
261396 assert(BarDiscarded && "Bar should have been discarded by this point");
262397 SymbolMap SymbolsToResolve;
271406 BarDiscarded = true;
272407 });
273408
274 cantFail(V.defineLazy(std::move(MU)));
275
276 SymbolMap BarOverride;
277 BarOverride[Bar] = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
278 cantFail(V.define(std::move(BarOverride)));
409 cantFail(V.define(MU));
410
411 ;
412 cantFail(V.define(absoluteSymbols(
413 {{Bar, JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported)}})));
279414
280415 SymbolNameSet Names({Foo});
281416
282417 bool OnResolutionRun = false;
283418 bool OnReadyRun = false;
284419
285 auto OnResolution = [&](Expected Result) {
286 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
287 auto I = Result->find(Foo);
288 EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
289 EXPECT_EQ(I->second.getAddress(), FakeFooAddr)
290 << "Resolution returned incorrect result";
291 OnResolutionRun = true;
292 };
420 auto OnResolution =
421 [&](Expected Result) {
422 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
423 auto I = Result->Symbols.find(Foo);
424 EXPECT_NE(I, Result->Symbols.end())
425 << "Could not find symbol definition";
426 EXPECT_EQ(I->second.getAddress(), FakeFooAddr)
427 << "Resolution returned incorrect result";
428 OnResolutionRun = true;
429 };
293430
294431 auto OnReady = [&](Error Err) {
295432 cantFail(std::move(Err));
299436 auto Q =
300437 std::make_shared(Names, OnResolution, OnReady);
301438
302 auto LR = V.lookup(std::move(Q), Names);
303
304 for (auto &M : LR.Materializers)
305 M();
306
307 EXPECT_TRUE(LR.UnresolvedSymbols.empty()) << "Could not find Foo in dylib";
439 auto Unresolved = V.lookup(std::move(Q), Names);
440
441 EXPECT_TRUE(Unresolved.empty()) << "Could not find Foo in dylib";
308442 EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
309443 EXPECT_TRUE(BarDiscarded) << "Bar was not discarded";
310444 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
311445 EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
312446 }
313447
448 TEST(CoreAPIsTest, DefineMaterializingSymbol) {
449 ExecutionSession ES;
450 auto Foo = ES.getSymbolStringPool().intern("foo");
451 auto Bar = ES.getSymbolStringPool().intern("bar");
452
453 auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported);
454 auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported);
455
456 bool ExpectNoMoreMaterialization = false;
457 ES.setDispatchMaterialization(
458 [&](VSO &V, std::unique_ptr MU) {
459 if (ExpectNoMoreMaterialization)
460 ADD_FAILURE() << "Unexpected materialization";
461 MU->doMaterialize(V);
462 });
463
464 auto MU = llvm::make_unique(
465 SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
466 [&](MaterializationResponsibility R) {
467 cantFail(
468 R.defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}})));
469 R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}));
470 R.finalize();
471 });
472
473 auto &V = ES.createVSO("V");
474 cantFail(V.define(MU));
475
476 auto OnResolution1 =
477 [&](Expected Result) {
478 cantFail(std::move(Result));
479 };
480
481 auto OnReady1 = [](Error Err) { cantFail(std::move(Err)); };
482
483 auto Q1 = std::make_shared(SymbolNameSet({Foo}),
484 OnResolution1, OnReady1);
485
486 V.lookup(std::move(Q1), {Foo});
487
488 bool BarResolved = false;
489 auto OnResolution2 =
490 [&](Expected Result) {
491 auto R = cantFail(std::move(Result));
492 EXPECT_EQ(R.Symbols.size(), 1U) << "Expected to resolve one symbol";
493 EXPECT_EQ(R.Symbols.count(Bar), 1U) << "Expected to resolve 'Bar'";
494 EXPECT_EQ(R.Symbols[Bar].getAddress(), BarSym.getAddress())
495 << "Expected Bar == BarSym";
496 BarResolved = true;
497 };
498
499 auto OnReady2 = [](Error Err) { cantFail(std::move(Err)); };
500
501 auto Q2 = std::make_shared(SymbolNameSet({Bar}),
502 OnResolution2, OnReady2);
503
504 ExpectNoMoreMaterialization = true;
505 V.lookup(std::move(Q2), {Bar});
506
507 EXPECT_TRUE(BarResolved) << "Bar should have been resolved";
508 }
509
314510 TEST(CoreAPIsTest, FailResolution) {
315 SymbolStringPool SP;
316 auto Foo = SP.intern("foo");
317 auto Bar = SP.intern("bar");
511 ExecutionSession ES;
512 auto Foo = ES.getSymbolStringPool().intern("foo");
513 auto Bar = ES.getSymbolStringPool().intern("bar");
318514
319515 SymbolNameSet Names({Foo, Bar});
320516
321517 auto MU = llvm::make_unique(
322 [=]() {
323 return SymbolFlagsMap(
324 {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}});
325 },
326 [&](MaterializationResponsibility R) { R.notifyMaterializationFailed(); },
327 [&](const VSO &V, SymbolStringPtr Name) {
328 llvm_unreachable("Unexpected call to discard");
329 });
330
331 VSO V;
332
333 cantFail(V.defineLazy(std::move(MU)));
334
335 auto OnResolution = [&](Expected Result) {
518 SymbolFlagsMap(
519 {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}),
520 [&](MaterializationResponsibility R) {
521 R.failMaterialization(
522 [&]() { return make_error(Names); });
523 });
524
525 auto &V = ES.createVSO("V");
526
527 cantFail(V.define(MU));
528
529 auto OnResolution = [&](Expected
530 Result) {
336531 handleAllErrors(Result.takeError(),
337532 [&](FailedToResolve &F) {
338533 EXPECT_EQ(F.getSymbols(), Names)
358553 auto Q =
359554 std::make_shared(Names, OnResolution, OnReady);
360555
361 auto LR = V.lookup(std::move(Q), Names);
362 for (auto &M : LR.Materializers)
363 M();
556 V.lookup(std::move(Q), Names);
364557 }
365558
366559 TEST(CoreAPIsTest, FailFinalization) {
367 SymbolStringPool SP;
368 auto Foo = SP.intern("foo");
369 auto Bar = SP.intern("bar");
560 ExecutionSession ES;
561 auto Foo = ES.getSymbolStringPool().intern("foo");
562 auto Bar = ES.getSymbolStringPool().intern("bar");
370563
371564 SymbolNameSet Names({Foo, Bar});
372565
373566 auto MU = llvm::make_unique(
374 [=]() {
375 return SymbolFlagsMap(
376 {{Foo, JITSymbolFlags::Exported}, {Bar, JITSymbolFlags::Exported}});
377 },
567 SymbolFlagsMap(
568 {{Foo, JITSymbolFlags::Exported}, {Bar, JITSymbolFlags::Exported}}),
378569 [&](MaterializationResponsibility R) {
379570 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
380571 constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
382573 auto FooSym = JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
383574 auto BarSym = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
384575 R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}));
385 R.notifyMaterializationFailed();
386 },
387 [&](const VSO &V, SymbolStringPtr Name) {
388 llvm_unreachable("Unexpected call to discard");
389 });
390
391 VSO V;
392
393 cantFail(V.defineLazy(std::move(MU)));
394
395 auto OnResolution = [](Expected Result) {
396 cantFail(std::move(Result));
397 };
576 R.failMaterialization(
577 [&]() { return make_error(Names); });
578 });
579
580 auto &V = ES.createVSO("V");
581
582 cantFail(V.define(MU));
583
584 auto OnResolution =
585 [](Expected Result) {
586 cantFail(std::move(Result));
587 };
398588
399589 auto OnReady = [&](Error Err) {
400590 handleAllErrors(std::move(Err),
417607 auto Q =
418608 std::make_shared(Names, OnResolution, OnReady);
419609
420 auto LR = V.lookup(std::move(Q), Names);
421 for (auto &M : LR.Materializers)
422 M();
610 V.lookup(std::move(Q), Names);
423611 }
424612
425613 TEST(CoreAPIsTest, TestLambdaSymbolResolver) {
426614 JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
427615 JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported);
428616
429 SymbolStringPool SP;
430 auto Foo = SP.intern("foo");
431 auto Bar = SP.intern("bar");
432 auto Baz = SP.intern("baz");
433
434 VSO V;
435 cantFail(V.define({{Foo, FooSym}, {Bar, BarSym}}));
617 ExecutionSession ES;
618
619 auto Foo = ES.getSymbolStringPool().intern("foo");
620 auto Bar = ES.getSymbolStringPool().intern("bar");
621 auto Baz = ES.getSymbolStringPool().intern("baz");
622
623 auto &V = ES.createVSO("V");
624 cantFail(V.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}})));
436625
437626 auto Resolver = createSymbolResolver(
438627 [&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) {
439628 return V.lookupFlags(SymbolFlags, Symbols);
440629 },
441630 [&](std::shared_ptr Q, SymbolNameSet Symbols) {
442 auto LR = V.lookup(std::move(Q), Symbols);
443 assert(LR.Materializers.empty() &&
444 "Test generated unexpected materialization work?");
445 return std::move(LR.UnresolvedSymbols);
631 return V.lookup(std::move(Q), Symbols);
446632 });
447633
448634 SymbolNameSet Symbols({Foo, Bar, Baz});
465651
466652 bool OnResolvedRun = false;
467653
468 auto OnResolved = [&](Expected Result) {
469 OnResolvedRun = true;
470 EXPECT_TRUE(!!Result) << "Unexpected error";
471 EXPECT_EQ(Result->size(), 2U) << "Unexpected number of resolved symbols";
472 EXPECT_EQ(Result->count(Foo), 1U) << "Missing lookup result for foo";
473 EXPECT_EQ(Result->count(Bar), 1U) << "Missing lookup result for bar";
474 EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress())
475 << "Incorrect address for foo";
476 EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress())
477 << "Incorrect address for bar";
478 };
654 auto OnResolved =
655 [&](Expected Result) {
656 OnResolvedRun = true;
657 EXPECT_TRUE(!!Result) << "Unexpected error";
658 EXPECT_EQ(Result->Symbols.size(), 2U)
659 << "Unexpected number of resolved symbols";
660 EXPECT_EQ(Result->Symbols.count(Foo), 1U)
661 << "Missing lookup result for foo";
662 EXPECT_EQ(Result->Symbols.count(Bar), 1U)
663 << "Missing lookup result for bar";
664 EXPECT_EQ(Result->Symbols[Foo].getAddress(), FooSym.getAddress())
665 << "Incorrect address for foo";
666 EXPECT_EQ(Result->Symbols[Bar].getAddress(), BarSym.getAddress())
667 << "Incorrect address for bar";
668 };
479669 auto OnReady = [&](Error Err) {
480670 EXPECT_FALSE(!!Err) << "Finalization should never fail in this test";
481671 };
497687 auto Foo = ES.getSymbolStringPool().intern("foo");
498688
499689 auto MU = llvm::make_unique(
500 [=]() {
501 return SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}});
502 },
690 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
503691 [&](MaterializationResponsibility R) {
504692 R.resolve({{Foo, FooSym}});
505693 R.finalize();
506 },
507 [](const VSO &V, SymbolStringPtr Name) {
508 llvm_unreachable("Not expecting finalization");
509 });
510
511 VSO V;
512
513 cantFail(V.defineLazy(std::move(MU)));
514
515 auto FooLookupResult =
516 cantFail(lookup({&V}, Foo, MaterializeOnCurrentThread()));
694 });
695
696 auto &V = ES.createVSO("V");
697
698 cantFail(V.define(MU));
699
700 auto FooLookupResult = cantFail(lookup({&V}, Foo, nullptr));
517701
518702 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
519703 << "lookup returned an incorrect address";
527711 JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported);
528712
529713 ExecutionSession ES(std::make_shared());
530 auto Foo = ES.getSymbolStringPool().intern("foo");
531
532 auto MU = llvm::make_unique(
533 [=]() {
534 return SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}});
535 },
536 [&](MaterializationResponsibility R) {
537 R.resolve({{Foo, FooSym}});
538 R.finalize();
539 },
540 [](const VSO &V, SymbolStringPtr Name) {
541 llvm_unreachable("Not expecting finalization");
542 });
543
544 VSO V;
545
546 cantFail(V.defineLazy(std::move(MU)));
547714
548715 std::thread MaterializationThread;
549 auto MaterializeOnNewThread = [&](VSO::Materializer M) {
550 // FIXME: Use move capture once we move to C++14.
551 auto SharedM = std::make_shared(std::move(M));
552 MaterializationThread = std::thread([SharedM]() { (*SharedM)(); });
553 };
554
555 auto FooLookupResult =
556 cantFail(lookup({&V}, Foo, MaterializeOnNewThread));
716 ES.setDispatchMaterialization(
717 [&](VSO &V, std::unique_ptr MU) {
718 auto SharedMU = std::shared_ptr(std::move(MU));
719 MaterializationThread =
720 std::thread([SharedMU, &V]() { SharedMU->doMaterialize(V); });
721 });
722 auto Foo = ES.getSymbolStringPool().intern("foo");
723
724 auto &V = ES.createVSO("V");
725 cantFail(V.define(absoluteSymbols({{Foo, FooSym}})));
726
727 auto FooLookupResult = cantFail(lookup({&V}, Foo, nullptr));
557728
558729 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
559730 << "lookup returned an incorrect address";
2020 ExecutionSession ES(std::make_shared());
2121 auto Foo = ES.getSymbolStringPool().intern("foo");
2222
23 VSO V;
24 SymbolMap Defs;
23 auto &V = ES.createVSO("V");
2524 JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
26 Defs[Foo] = FooSym;
27 cantFail(V.define(std::move(Defs)));
25 cantFail(V.define(absoluteSymbols({{Foo, FooSym}})));
2826
2927 auto LookupFlags = [&](SymbolFlagsMap &SymbolFlags,
3028 const SymbolNameSet &Names) {
3331
3432 auto Lookup = [&](std::shared_ptr Query,
3533 SymbolNameSet Symbols) {
36 auto R = V.lookup(std::move(Query), Symbols);
37 EXPECT_TRUE(R.Materializers.empty())
38 << "Query resulted in unexpected materialization work";
39 return std::move(R.UnresolvedSymbols);
34 return V.lookup(std::move(Query), Symbols);
4035 };
4136
4237 auto UnderlyingResolver =
4338 createSymbolResolver(std::move(LookupFlags), std::move(Lookup));
44 JITSymbolResolverAdapter Resolver(ES, *UnderlyingResolver);
39 JITSymbolResolverAdapter Resolver(ES, *UnderlyingResolver, nullptr);
4540
4641 JITSymbolResolver::LookupSet Names{StringRef("foo")};
4742
8984 return nullptr;
9085 };
9186
92 SymbolStringPool SP;
93 auto Foo = SP.intern("foo");
94 auto Bar = SP.intern("bar");
95 auto Baz = SP.intern("baz");
87 ExecutionSession ES;
88 auto Foo = ES.getSymbolStringPool().intern("foo");
89 auto Bar = ES.getSymbolStringPool().intern("bar");
90 auto Baz = ES.getSymbolStringPool().intern("baz");
9691
9792 SymbolNameSet Symbols({Foo, Bar, Baz});
9893
114109
115110 bool OnResolvedRun = false;
116111 bool OnReadyRun = false;
117 auto OnResolved = [&](Expected Result) {
118 OnResolvedRun = true;
119 EXPECT_TRUE(!!Result) << "lookuWithLegacy failed to resolve";
120 EXPECT_EQ(Result->size(), 2U) << "Wrong number of symbols resolved";
121 EXPECT_EQ(Result->count(Foo), 1U) << "Result for foo missing";
122 EXPECT_EQ(Result->count(Bar), 1U) << "Result for bar missing";
123 EXPECT_EQ((*Result)[Foo].getAddress(), FooAddr) << "Wrong address for foo";
124 EXPECT_EQ((*Result)[Foo].getFlags(), FooFlags) << "Wrong flags for foo";
125 EXPECT_EQ((*Result)[Bar].getAddress(), BarAddr) << "Wrong address for bar";
126 EXPECT_EQ((*Result)[Bar].getFlags(), BarFlags) << "Wrong flags for bar";
127 };
112 auto OnResolved =
113 [&](Expected Result) {
114 OnResolvedRun = true;
115 EXPECT_TRUE(!!Result) << "lookuWithLegacy failed to resolve";
116
117 auto &Resolved = Result->Symbols;
118 EXPECT_EQ(Resolved.size(), 2U) << "Wrong number of symbols resolved";
119 EXPECT_EQ(Resolved.count(Foo), 1U) << "Result for foo missing";
120 EXPECT_EQ(Resolved.count(Bar), 1U) << "Result for bar missing";
121 EXPECT_EQ(Resolved[Foo].getAddress(), FooAddr)
122 << "Wrong address for foo";
123 EXPECT_EQ(Resolved[Foo].getFlags(), FooFlags) << "Wrong flags for foo";
124 EXPECT_EQ(Resolved[Bar].getAddress(), BarAddr)
125 << "Wrong address for bar";
126 EXPECT_EQ(Resolved[Bar].getFlags(), BarFlags) << "Wrong flags for bar";
127 };
128128 auto OnReady = [&](Error Err) {
129129 EXPECT_FALSE(!!Err) << "Finalization unexpectedly failed";
130130 OnReadyRun = true;
131131 };
132132
133133 AsynchronousSymbolQuery Q({Foo, Bar}, OnResolved, OnReady);
134 auto Unresolved = lookupWithLegacyFn(Q, Symbols, LegacyLookup);
134 auto Unresolved = lookupWithLegacyFn(ES, Q, Symbols, LegacyLookup);
135135
136136 EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run";
137137 EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
189189 },
190190 [&](std::shared_ptr Query,
191191 const SymbolNameSet &Symbols) {
192 return lookupWithLegacyFn(*Query, Symbols, LegacyLookup);
192 return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
193193 });
194194
195195 cantFail(ObjLayer.addObject(K2, std::move(Obj2)));