Line data Source code
1 : //===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- C++ -*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // Contains core ORC APIs.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #ifndef LLVM_EXECUTIONENGINE_ORC_CORE_H
15 : #define LLVM_EXECUTIONENGINE_ORC_CORE_H
16 :
17 : #include "llvm/ADT/BitmaskEnum.h"
18 : #include "llvm/ExecutionEngine/JITSymbol.h"
19 : #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
20 : #include "llvm/IR/Module.h"
21 : #include "llvm/Support/Debug.h"
22 :
23 : #include <memory>
24 : #include <vector>
25 :
26 : #define DEBUG_TYPE "orc"
27 :
28 : namespace llvm {
29 : namespace orc {
30 :
31 : // Forward declare some classes.
32 : class AsynchronousSymbolQuery;
33 : class ExecutionSession;
34 : class MaterializationUnit;
35 : class MaterializationResponsibility;
36 : class JITDylib;
37 :
38 : /// VModuleKey provides a unique identifier (allocated and managed by
39 : /// ExecutionSessions) for a module added to the JIT.
40 : using VModuleKey = uint64_t;
41 :
42 : /// A set of symbol names (represented by SymbolStringPtrs for
43 : // efficiency).
44 : using SymbolNameSet = DenseSet<SymbolStringPtr>;
45 :
46 : /// A map from symbol names (as SymbolStringPtrs) to JITSymbols
47 : /// (address/flags pairs).
48 : using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>;
49 :
50 : /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
51 : using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>;
52 :
53 : /// A base class for materialization failures that allows the failing
54 : /// symbols to be obtained for logging.
55 : using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>;
56 :
57 : /// A list of JITDylib pointers.
58 : using JITDylibList = std::vector<JITDylib *>;
59 :
60 : /// Render a SymbolStringPtr.
61 : raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPtr &Sym);
62 :
63 : /// Render a SymbolNameSet.
64 : raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols);
65 :
66 : /// Render a SymbolFlagsMap entry.
67 : raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap::value_type &KV);
68 :
69 : /// Render a SymbolMap entry.
70 : raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV);
71 :
72 : /// Render a SymbolFlagsMap.
73 : raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags);
74 :
75 : /// Render a SymbolMap.
76 : raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols);
77 :
78 : /// Render a SymbolDependenceMap entry.
79 : raw_ostream &operator<<(raw_ostream &OS,
80 : const SymbolDependenceMap::value_type &KV);
81 :
82 : /// Render a SymbolDependendeMap.
83 : raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps);
84 :
85 : /// Render a MaterializationUnit.
86 : raw_ostream &operator<<(raw_ostream &OS, const MaterializationUnit &MU);
87 :
88 : /// Render a JITDylibList.
89 : raw_ostream &operator<<(raw_ostream &OS, const JITDylibList &JDs);
90 :
91 : /// Callback to notify client that symbols have been resolved.
92 : using SymbolsResolvedCallback = std::function<void(Expected<SymbolMap>)>;
93 :
94 : /// Callback to notify client that symbols are ready for execution.
95 : using SymbolsReadyCallback = std::function<void(Error)>;
96 :
97 : /// Callback to register the dependencies for a given query.
98 : using RegisterDependenciesFunction =
99 : std::function<void(const SymbolDependenceMap &)>;
100 :
101 : /// This can be used as the value for a RegisterDependenciesFunction if there
102 : /// are no dependants to register with.
103 : extern RegisterDependenciesFunction NoDependenciesToRegister;
104 :
105 : /// Used to notify a JITDylib that the given set of symbols failed to
106 : /// materialize.
107 : class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
108 : public:
109 : static char ID;
110 :
111 : FailedToMaterialize(SymbolNameSet Symbols);
112 : std::error_code convertToErrorCode() const override;
113 : void log(raw_ostream &OS) const override;
114 : const SymbolNameSet &getSymbols() const { return Symbols; }
115 :
116 : private:
117 : SymbolNameSet Symbols;
118 : };
119 :
120 : /// Used to notify clients when symbols can not be found during a lookup.
121 : class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
122 : public:
123 : static char ID;
124 :
125 : SymbolsNotFound(SymbolNameSet Symbols);
126 : std::error_code convertToErrorCode() const override;
127 : void log(raw_ostream &OS) const override;
128 : const SymbolNameSet &getSymbols() const { return Symbols; }
129 :
130 : private:
131 : SymbolNameSet Symbols;
132 : };
133 :
134 : /// Used to notify clients that a set of symbols could not be removed.
135 : class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> {
136 : public:
137 : static char ID;
138 :
139 : SymbolsCouldNotBeRemoved(SymbolNameSet Symbols);
140 : std::error_code convertToErrorCode() const override;
141 : void log(raw_ostream &OS) const override;
142 : const SymbolNameSet &getSymbols() const { return Symbols; }
143 :
144 : private:
145 : SymbolNameSet Symbols;
146 : };
147 :
148 : /// Tracks responsibility for materialization, and mediates interactions between
149 : /// MaterializationUnits and JDs.
150 : ///
151 : /// An instance of this class is passed to MaterializationUnits when their
152 : /// materialize method is called. It allows MaterializationUnits to resolve and
153 : /// emit symbols, or abandon materialization by notifying any unmaterialized
154 : /// symbols of an error.
155 : class MaterializationResponsibility {
156 : friend class MaterializationUnit;
157 : public:
158 362 : MaterializationResponsibility(MaterializationResponsibility &&) = default;
159 : MaterializationResponsibility &
160 : operator=(MaterializationResponsibility &&) = delete;
161 :
162 : /// Destruct a MaterializationResponsibility instance. In debug mode
163 : /// this asserts that all symbols being tracked have been either
164 : /// emitted or notified of an error.
165 : ~MaterializationResponsibility();
166 :
167 : /// Returns the target JITDylib that these symbols are being materialized
168 : /// into.
169 0 : JITDylib &getTargetJITDylib() const { return JD; }
170 :
171 : /// Returns the VModuleKey for this instance.
172 0 : VModuleKey getVModuleKey() const { return K; }
173 :
174 : /// Returns the symbol flags map for this responsibility instance.
175 : /// Note: The returned flags may have transient flags (Lazy, Materializing)
176 : /// set. These should be stripped with JITSymbolFlags::stripTransientFlags
177 : /// before using.
178 35 : const SymbolFlagsMap &getSymbols() { return SymbolFlags; }
179 :
180 : /// Returns the names of any symbols covered by this
181 : /// MaterializationResponsibility object that have queries pending. This
182 : /// information can be used to return responsibility for unrequested symbols
183 : /// back to the JITDylib via the delegate method.
184 : SymbolNameSet getRequestedSymbols() const;
185 :
186 : /// Notifies the target JITDylib that the given symbols have been resolved.
187 : /// This will update the given symbols' addresses in the JITDylib, and notify
188 : /// any pending queries on the given symbols of their resolution. The given
189 : /// symbols must be ones covered by this MaterializationResponsibility
190 : /// instance. Individual calls to this method may resolve a subset of the
191 : /// symbols, but all symbols must have been resolved prior to calling emit.
192 : void resolve(const SymbolMap &Symbols);
193 :
194 : /// Notifies the target JITDylib (and any pending queries on that JITDylib)
195 : /// that all symbols covered by this MaterializationResponsibility instance
196 : /// have been emitted.
197 : void emit();
198 :
199 : /// Adds new symbols to the JITDylib and this responsibility instance.
200 : /// JITDylib entries start out in the materializing state.
201 : ///
202 : /// This method can be used by materialization units that want to add
203 : /// additional symbols at materialization time (e.g. stubs, compile
204 : /// callbacks, metadata).
205 : Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
206 :
207 : /// Notify all not-yet-emitted covered by this MaterializationResponsibility
208 : /// instance that an error has occurred.
209 : /// This will remove all symbols covered by this MaterializationResponsibilty
210 : /// from the target JITDylib, and send an error to any queries waiting on
211 : /// these symbols.
212 : void failMaterialization();
213 :
214 : /// Transfers responsibility to the given MaterializationUnit for all
215 : /// symbols defined by that MaterializationUnit. This allows
216 : /// materializers to break up work based on run-time information (e.g.
217 : /// by introspecting which symbols have actually been looked up and
218 : /// materializing only those).
219 : void replace(std::unique_ptr<MaterializationUnit> MU);
220 :
221 : /// Delegates responsibility for the given symbols to the returned
222 : /// materialization responsibility. Useful for breaking up work between
223 : /// threads, or different kinds of materialization processes.
224 : MaterializationResponsibility delegate(const SymbolNameSet &Symbols,
225 : VModuleKey NewKey = VModuleKey());
226 :
227 : void addDependencies(const SymbolStringPtr &Name,
228 : const SymbolDependenceMap &Dependencies);
229 :
230 : /// Add dependencies that apply to all symbols covered by this instance.
231 : void addDependenciesForAll(const SymbolDependenceMap &Dependencies);
232 :
233 : private:
234 : /// Create a MaterializationResponsibility for the given JITDylib and
235 : /// initial symbols.
236 : MaterializationResponsibility(JITDylib &JD, SymbolFlagsMap SymbolFlags,
237 : VModuleKey K);
238 :
239 : JITDylib &JD;
240 : SymbolFlagsMap SymbolFlags;
241 : VModuleKey K;
242 : };
243 :
244 : /// A MaterializationUnit represents a set of symbol definitions that can
245 : /// be materialized as a group, or individually discarded (when
246 : /// overriding definitions are encountered).
247 : ///
248 : /// MaterializationUnits are used when providing lazy definitions of symbols to
249 : /// JITDylibs. The JITDylib will call materialize when the address of a symbol
250 : /// is requested via the lookup method. The JITDylib will call discard if a
251 : /// stronger definition is added or already present.
252 : class MaterializationUnit {
253 : public:
254 : MaterializationUnit(SymbolFlagsMap InitalSymbolFlags, VModuleKey K)
255 314 : : SymbolFlags(std::move(InitalSymbolFlags)), K(std::move(K)) {}
256 :
257 22 : virtual ~MaterializationUnit() {}
258 :
259 : /// Return the name of this materialization unit. Useful for debugging
260 : /// output.
261 : virtual StringRef getName() const = 0;
262 :
263 : /// Return the set of symbols that this source provides.
264 251 : const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
265 :
266 : /// Called by materialization dispatchers (see
267 : /// ExecutionSession::DispatchMaterializationFunction) to trigger
268 : /// materialization of this MaterializationUnit.
269 107 : void doMaterialize(JITDylib &JD) {
270 107 : materialize(MaterializationResponsibility(JD, std::move(SymbolFlags),
271 107 : std::move(K)));
272 107 : }
273 :
274 : /// Called by JITDylibs to notify MaterializationUnits that the given symbol
275 : /// has been overridden.
276 : void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) {
277 7 : SymbolFlags.erase(Name);
278 7 : discard(JD, std::move(Name));
279 : }
280 :
281 : protected:
282 : SymbolFlagsMap SymbolFlags;
283 : VModuleKey K;
284 :
285 : private:
286 : virtual void anchor();
287 :
288 : /// Implementations of this method should materialize all symbols
289 : /// in the materialzation unit, except for those that have been
290 : /// previously discarded.
291 : virtual void materialize(MaterializationResponsibility R) = 0;
292 :
293 : /// Implementations of this method should discard the given symbol
294 : /// from the source (e.g. if the source is an LLVM IR Module and the
295 : /// symbol is a function, delete the function body or mark it available
296 : /// externally).
297 : virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0;
298 : };
299 :
300 : using MaterializationUnitList =
301 : std::vector<std::unique_ptr<MaterializationUnit>>;
302 :
303 : /// A MaterializationUnit implementation for pre-existing absolute symbols.
304 : ///
305 : /// All symbols will be resolved and marked ready as soon as the unit is
306 : /// materialized.
307 : class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
308 : public:
309 : AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols, VModuleKey K);
310 :
311 : StringRef getName() const override;
312 :
313 : private:
314 : void materialize(MaterializationResponsibility R) override;
315 : void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
316 : static SymbolFlagsMap extractFlags(const SymbolMap &Symbols);
317 :
318 : SymbolMap Symbols;
319 : };
320 :
321 : /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
322 : /// Useful for inserting absolute symbols into a JITDylib. E.g.:
323 : /// \code{.cpp}
324 : /// JITDylib &JD = ...;
325 : /// SymbolStringPtr Foo = ...;
326 : /// JITEvaluatedSymbol FooSym = ...;
327 : /// if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}})))
328 : /// return Err;
329 : /// \endcode
330 : ///
331 : inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit>
332 : absoluteSymbols(SymbolMap Symbols, VModuleKey K = VModuleKey()) {
333 : return llvm::make_unique<AbsoluteSymbolsMaterializationUnit>(
334 33 : std::move(Symbols), std::move(K));
335 : }
336 :
337 117 : struct SymbolAliasMapEntry {
338 : SymbolAliasMapEntry() = default;
339 : SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
340 14 : : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {}
341 :
342 : SymbolStringPtr Aliasee;
343 : JITSymbolFlags AliasFlags;
344 : };
345 :
346 : /// A map of Symbols to (Symbol, Flags) pairs.
347 : using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>;
348 :
349 : /// A materialization unit for symbol aliases. Allows existing symbols to be
350 : /// aliased with alternate flags.
351 : class ReExportsMaterializationUnit : public MaterializationUnit {
352 : public:
353 : /// SourceJD is allowed to be nullptr, in which case the source JITDylib is
354 : /// taken to be whatever JITDylib these definitions are materialized in. This
355 : /// is useful for defining aliases within a JITDylib.
356 : ///
357 : /// Note: Care must be taken that no sets of aliases form a cycle, as such
358 : /// a cycle will result in a deadlock when any symbol in the cycle is
359 : /// resolved.
360 : ReExportsMaterializationUnit(JITDylib *SourceJD, SymbolAliasMap Aliases,
361 : VModuleKey K);
362 :
363 : StringRef getName() const override;
364 :
365 : private:
366 : void materialize(MaterializationResponsibility R) override;
367 : void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
368 : static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
369 :
370 : JITDylib *SourceJD = nullptr;
371 : SymbolAliasMap Aliases;
372 : };
373 :
374 : /// Create a ReExportsMaterializationUnit with the given aliases.
375 : /// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing
376 : /// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux"
377 : /// (for "bar") with: \code{.cpp}
378 : /// SymbolStringPtr Baz = ...;
379 : /// SymbolStringPtr Qux = ...;
380 : /// if (auto Err = JD.define(symbolAliases({
381 : /// {Baz, { Foo, JITSymbolFlags::Exported }},
382 : /// {Qux, { Bar, JITSymbolFlags::Weak }}}))
383 : /// return Err;
384 : /// \endcode
385 : inline std::unique_ptr<ReExportsMaterializationUnit>
386 : symbolAliases(SymbolAliasMap Aliases, VModuleKey K = VModuleKey()) {
387 : return llvm::make_unique<ReExportsMaterializationUnit>(
388 2 : nullptr, std::move(Aliases), std::move(K));
389 : }
390 :
391 : /// Create a materialization unit for re-exporting symbols from another JITDylib
392 : /// with alternative names/flags.
393 : inline std::unique_ptr<ReExportsMaterializationUnit>
394 : reexports(JITDylib &SourceJD, SymbolAliasMap Aliases,
395 : VModuleKey K = VModuleKey()) {
396 : return llvm::make_unique<ReExportsMaterializationUnit>(
397 18 : &SourceJD, std::move(Aliases), std::move(K));
398 : }
399 :
400 : /// Build a SymbolAliasMap for the common case where you want to re-export
401 : /// symbols from another JITDylib with the same linkage/flags.
402 : Expected<SymbolAliasMap>
403 : buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols);
404 :
405 : /// ReexportsGenerator can be used with JITDylib::setGenerator to automatically
406 : /// re-export a subset of the source JITDylib's symbols in the target.
407 0 : class ReexportsGenerator {
408 : public:
409 : using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
410 :
411 : /// Create a reexports generator. If an Allow predicate is passed, only
412 : /// symbols for which the predicate returns true will be reexported. If no
413 : /// Allow predicate is passed, all symbols will be exported.
414 : ReexportsGenerator(JITDylib &SourceJD,
415 : SymbolPredicate Allow = SymbolPredicate());
416 :
417 : SymbolNameSet operator()(JITDylib &JD, const SymbolNameSet &Names);
418 :
419 : private:
420 : JITDylib &SourceJD;
421 : SymbolPredicate Allow;
422 : };
423 :
424 : /// A symbol query that returns results via a callback when results are
425 : /// ready.
426 : ///
427 : /// makes a callback when all symbols are available.
428 : class AsynchronousSymbolQuery {
429 : friend class ExecutionSession;
430 : friend class JITDylib;
431 : friend class JITSymbolResolverAdapter;
432 :
433 : public:
434 :
435 : /// Create a query for the given symbols, notify-resolved and
436 : /// notify-ready callbacks.
437 : AsynchronousSymbolQuery(const SymbolNameSet &Symbols,
438 : SymbolsResolvedCallback NotifySymbolsResolved,
439 : SymbolsReadyCallback NotifySymbolsReady);
440 :
441 : /// Set the resolved symbol information for the given symbol name.
442 : void resolve(const SymbolStringPtr &Name, JITEvaluatedSymbol Sym);
443 :
444 : /// Returns true if all symbols covered by this query have been
445 : /// resolved.
446 0 : bool isFullyResolved() const { return NotYetResolvedCount == 0; }
447 :
448 : /// Call the NotifySymbolsResolved callback.
449 : ///
450 : /// This should only be called if all symbols covered by the query have been
451 : /// resolved.
452 : void handleFullyResolved();
453 :
454 : /// Notify the query that a requested symbol is ready for execution.
455 : void notifySymbolReady();
456 :
457 : /// Returns true if all symbols covered by this query are ready.
458 0 : bool isFullyReady() const { return NotYetReadyCount == 0; }
459 :
460 : /// Calls the NotifySymbolsReady callback.
461 : ///
462 : /// This should only be called if all symbols covered by this query are ready.
463 : void handleFullyReady();
464 :
465 : private:
466 : void addQueryDependence(JITDylib &JD, SymbolStringPtr Name);
467 :
468 : void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name);
469 :
470 : bool canStillFail();
471 :
472 : void handleFailed(Error Err);
473 :
474 : void detach();
475 :
476 : SymbolsResolvedCallback NotifySymbolsResolved;
477 : SymbolsReadyCallback NotifySymbolsReady;
478 : SymbolDependenceMap QueryRegistrations;
479 : SymbolMap ResolvedSymbols;
480 : size_t NotYetResolvedCount;
481 : size_t NotYetReadyCount;
482 : };
483 :
484 : /// A symbol table that supports asynchoronous symbol queries.
485 : ///
486 : /// Represents a virtual shared object. Instances can not be copied or moved, so
487 : /// their addresses may be used as keys for resource management.
488 : /// JITDylib state changes must be made via an ExecutionSession to guarantee
489 : /// that they are synchronized with respect to other JITDylib operations.
490 : class JITDylib {
491 : friend class AsynchronousSymbolQuery;
492 : friend class ExecutionSession;
493 : friend class MaterializationResponsibility;
494 : public:
495 : using GeneratorFunction = std::function<SymbolNameSet(
496 : JITDylib &Parent, const SymbolNameSet &Names)>;
497 :
498 : using AsynchronousSymbolQuerySet =
499 : std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
500 :
501 : JITDylib(const JITDylib &) = delete;
502 : JITDylib &operator=(const JITDylib &) = delete;
503 : JITDylib(JITDylib &&) = delete;
504 : JITDylib &operator=(JITDylib &&) = delete;
505 :
506 : /// Get the name for this JITDylib.
507 12 : const std::string &getName() const { return JITDylibName; }
508 :
509 : /// Get a reference to the ExecutionSession for this JITDylib.
510 0 : ExecutionSession &getExecutionSession() const { return ES; }
511 :
512 : /// Set a definition generator. If set, whenever a symbol fails to resolve
513 : /// within this JITDylib, lookup and lookupFlags will pass the unresolved
514 : /// symbols set to the definition generator. The generator can optionally
515 : /// add a definition for the unresolved symbols to the dylib.
516 : void setGenerator(GeneratorFunction DefGenerator) {
517 15 : this->DefGenerator = std::move(DefGenerator);
518 : }
519 :
520 : /// Set the search order to be used when fixing up definitions in JITDylib.
521 : /// This will replace the previous search order, and apply to any symbol
522 : /// resolutions made for definitions in this JITDylib after the call to
523 : /// setSearchOrder (even if the definition itself was added before the
524 : /// call).
525 : ///
526 : /// If SearchThisJITDylibFirst is set, which by default it is, then this
527 : /// JITDylib will add itself to the beginning of the SearchOrder (Clients
528 : /// should *not* put this JITDylib in the list in this case, to avoid
529 : /// redundant lookups).
530 : ///
531 : /// If SearchThisJITDylibFirst is false then the search order will be used as
532 : /// given. The main motivation for this feature is to support deliberate
533 : /// shadowing of symbols in this JITDylib by a facade JITDylib. For example,
534 : /// the facade may resolve function names to stubs, and the stubs may compile
535 : /// lazily by looking up symbols in this dylib. Adding the facade dylib
536 : /// as the first in the search order (instead of this dylib) ensures that
537 : /// definitions within this dylib resolve to the lazy-compiling stubs,
538 : /// rather than immediately materializing the definitions in this dylib.
539 : void setSearchOrder(JITDylibList NewSearchOrder,
540 : bool SearchThisJITDylibFirst = true);
541 :
542 : /// Add the given JITDylib to the search order for definitions in this
543 : /// JITDylib.
544 : void addToSearchOrder(JITDylib &JD);
545 :
546 : /// Replace OldJD with NewJD in the search order if OldJD is present.
547 : /// Otherwise this operation is a no-op.
548 : void replaceInSearchOrder(JITDylib &OldJD, JITDylib &NewJD);
549 :
550 : /// Remove the given JITDylib from the search order for this JITDylib if it is
551 : /// present. Otherwise this operation is a no-op.
552 : void removeFromSearchOrder(JITDylib &JD);
553 :
554 : /// Do something with the search order (run under the session lock).
555 : template <typename Func>
556 : auto withSearchOrderDo(Func &&F)
557 : -> decltype(F(std::declval<const JITDylibList &>()));
558 :
559 : /// Define all symbols provided by the materialization unit to be part of this
560 : /// JITDylib.
561 : ///
562 : /// This overload always takes ownership of the MaterializationUnit. If any
563 : /// errors occur, the MaterializationUnit consumed.
564 : template <typename MaterializationUnitType>
565 : Error define(std::unique_ptr<MaterializationUnitType> &&MU);
566 :
567 : /// Define all symbols provided by the materialization unit to be part of this
568 : /// JITDylib.
569 : ///
570 : /// This overload only takes ownership of the MaterializationUnit no error is
571 : /// generated. If an error occurs, ownership remains with the caller. This
572 : /// may allow the caller to modify the MaterializationUnit to correct the
573 : /// issue, then re-call define.
574 : template <typename MaterializationUnitType>
575 : Error define(std::unique_ptr<MaterializationUnitType> &MU);
576 :
577 : /// Tries to remove the given symbols.
578 : ///
579 : /// If any symbols are not defined in this JITDylib this method will return
580 : /// a SymbolsNotFound error covering the missing symbols.
581 : ///
582 : /// If all symbols are found but some symbols are in the process of being
583 : /// materialized this method will return a SymbolsCouldNotBeRemoved error.
584 : ///
585 : /// On success, all symbols are removed. On failure, the JITDylib state is
586 : /// left unmodified (no symbols are removed).
587 : Error remove(const SymbolNameSet &Names);
588 :
589 : /// Search the given JITDylib for the symbols in Symbols. If found, store
590 : /// the flags for each symbol in Flags. Returns any unresolved symbols.
591 : SymbolFlagsMap lookupFlags(const SymbolNameSet &Names);
592 :
593 : /// Dump current JITDylib state to OS.
594 : void dump(raw_ostream &OS);
595 :
596 : /// FIXME: Remove this when we remove the old ORC layers.
597 : /// Search the given JITDylibs in order for the symbols in Symbols. Results
598 : /// (once they become available) will be returned via the given Query.
599 : ///
600 : /// If any symbol is not found then the unresolved symbols will be returned,
601 : /// and the query will not be applied. The Query is not failed and can be
602 : /// re-used in a subsequent lookup once the symbols have been added, or
603 : /// manually failed.
604 : SymbolNameSet legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
605 : SymbolNameSet Names);
606 :
607 : private:
608 : using AsynchronousSymbolQueryList =
609 : std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
610 :
611 141 : struct UnmaterializedInfo {
612 : UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU)
613 : : MU(std::move(MU)) {}
614 :
615 : std::unique_ptr<MaterializationUnit> MU;
616 : };
617 :
618 : using UnmaterializedInfosMap =
619 : DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
620 :
621 : struct MaterializingInfo {
622 : AsynchronousSymbolQueryList PendingQueries;
623 : SymbolDependenceMap Dependants;
624 : SymbolDependenceMap UnemittedDependencies;
625 : bool IsEmitted = false;
626 : };
627 :
628 : using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>;
629 :
630 : using LookupImplActionFlags = enum {
631 : None = 0,
632 : NotifyFullyResolved = 1 << 0U,
633 : NotifyFullyReady = 1 << 1U,
634 : LLVM_MARK_AS_BITMASK_ENUM(NotifyFullyReady)
635 : };
636 :
637 : JITDylib(ExecutionSession &ES, std::string Name);
638 :
639 : Error defineImpl(MaterializationUnit &MU);
640 :
641 : SymbolNameSet lookupFlagsImpl(SymbolFlagsMap &Flags,
642 : const SymbolNameSet &Names);
643 :
644 : void lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
645 : SymbolNameSet &Unresolved, JITDylib *MatchNonExportedInJD,
646 : bool MatchNonExported, MaterializationUnitList &MUs);
647 :
648 : void lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
649 : SymbolNameSet &Unresolved, JITDylib *MatchNonExportedInJD,
650 : bool MatchNonExported, MaterializationUnitList &MUs);
651 :
652 : LookupImplActionFlags
653 : lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
654 : std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
655 : SymbolNameSet &Unresolved);
656 :
657 : void detachQueryHelper(AsynchronousSymbolQuery &Q,
658 : const SymbolNameSet &QuerySymbols);
659 :
660 : void transferEmittedNodeDependencies(MaterializingInfo &DependantMI,
661 : const SymbolStringPtr &DependantName,
662 : MaterializingInfo &EmittedMI);
663 :
664 : Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
665 :
666 : void replace(std::unique_ptr<MaterializationUnit> MU);
667 :
668 : SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const;
669 :
670 : void addDependencies(const SymbolStringPtr &Name,
671 : const SymbolDependenceMap &Dependants);
672 :
673 : void resolve(const SymbolMap &Resolved);
674 :
675 : void emit(const SymbolFlagsMap &Emitted);
676 :
677 : void notifyFailed(const SymbolNameSet &FailedSymbols);
678 :
679 : ExecutionSession &ES;
680 : std::string JITDylibName;
681 : SymbolMap Symbols;
682 : UnmaterializedInfosMap UnmaterializedInfos;
683 : MaterializingInfosMap MaterializingInfos;
684 : GeneratorFunction DefGenerator;
685 : JITDylibList SearchOrder;
686 : };
687 :
688 : /// An ExecutionSession represents a running JIT program.
689 : class ExecutionSession {
690 : // FIXME: Remove this when we remove the old ORC layers.
691 : friend class JITDylib;
692 :
693 : public:
694 : /// For reporting errors.
695 : using ErrorReporter = std::function<void(Error)>;
696 :
697 : /// For dispatching MaterializationUnit::materialize calls.
698 : using DispatchMaterializationFunction = std::function<void(
699 : JITDylib &JD, std::unique_ptr<MaterializationUnit> MU)>;
700 :
701 : /// Construct an ExecutionSession.
702 : ///
703 : /// SymbolStringPools may be shared between ExecutionSessions.
704 : ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr);
705 :
706 : /// Add a symbol name to the SymbolStringPool and return a pointer to it.
707 319 : SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
708 :
709 : /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession.
710 : std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
711 :
712 : /// Run the given lambda with the session mutex locked.
713 420 : template <typename Func> auto runSessionLocked(Func &&F) -> decltype(F()) {
714 807 : std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
715 691 : return F();
716 : }
717 0 :
718 0 : /// Get the "main" JITDylib, which is created automatically on construction of
719 0 : /// the ExecutionSession.
720 : JITDylib &getMainJITDylib();
721 1 :
722 1 : /// Add a new JITDylib to this ExecutionSession.
723 1 : JITDylib &createJITDylib(std::string Name,
724 : bool AddToMainDylibSearchOrder = true);
725 0 :
726 0 : /// Allocate a module key for a new module to add to the JIT.
727 0 : VModuleKey allocateVModule() {
728 131 : return runSessionLocked([this]() { return ++LastKey; });
729 4 : }
730 4 :
731 4 : /// Return a module key to the ExecutionSession so that it can be
732 : /// re-used. This should only be done once all resources associated
733 3 : /// with the original key have been released.
734 3 : void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */
735 3 : }
736 :
737 0 : /// Set the error reporter function.
738 0 : ExecutionSession &setErrorReporter(ErrorReporter ReportError) {
739 24 : this->ReportError = std::move(ReportError);
740 : return *this;
741 61 : }
742 61 :
743 61 : /// Report a error for this execution session.
744 : ///
745 12 : /// Unhandled errors can be sent here to log them.
746 66 : void reportError(Error Err) { ReportError(std::move(Err)); }
747 12 :
748 : /// Set the materialization dispatch function.
749 1 : ExecutionSession &setDispatchMaterialization(
750 1 : DispatchMaterializationFunction DispatchMaterialization) {
751 4 : this->DispatchMaterialization = std::move(DispatchMaterialization);
752 : return *this;
753 95 : }
754 95 :
755 95 : void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err);
756 :
757 95 : using LegacyAsyncLookupFunction = std::function<SymbolNameSet(
758 95 : std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>;
759 95 :
760 : /// A legacy lookup function for JITSymbolResolverAdapter.
761 52 : /// Do not use -- this will be removed soon.
762 52 : Expected<SymbolMap>
763 52 : legacyLookup(LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names,
764 : bool WaiUntilReady,
765 61 : RegisterDependenciesFunction RegisterDependencies);
766 61 :
767 61 : /// Search the given JITDylib list for the given symbols.
768 : ///
769 7 : ///
770 7 : /// The OnResolve callback will be called once all requested symbols are
771 7 : /// resolved, or if an error occurs prior to resolution.
772 : ///
773 : /// The OnReady callback will be called once all requested symbols are ready,
774 : /// or if an error occurs after resolution but before all symbols are ready.
775 : ///
776 : /// If all symbols are found, the RegisterDependencies function will be called
777 : /// while the session lock is held. This gives clients a chance to register
778 : /// dependencies for on the queried symbols for any symbols they are
779 : /// materializing (if a MaterializationResponsibility instance is present,
780 : /// this can be implemented by calling
781 : /// MaterializationResponsibility::addDependencies). If there are no
782 : /// dependenant symbols for this query (e.g. it is being made by a top level
783 : /// client to get an address to call) then the value NoDependenciesToRegister
784 : /// can be used.
785 : ///
786 : /// If the MatchNonExportedInJD pointer is non-null, then the lookup will find
787 : /// non-exported symbols defined in the JITDylib pointed to by
788 : /// MatchNonExportedInJD.
789 : /// If MatchNonExported is true the lookup will find non-exported symbols in
790 : /// any JITDylib (setting MatchNonExportedInJD is redundant in such cases).
791 : /// If MatchNonExported is false and MatchNonExportedInJD is null,
792 : /// non-exported symbols will never be found.
793 : void lookup(const JITDylibList &JDs, SymbolNameSet Symbols,
794 : SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady,
795 : RegisterDependenciesFunction RegisterDependencies,
796 : JITDylib *MatchNonExportedInJD = nullptr,
797 : bool MatchNonExported = false);
798 :
799 : /// Blocking version of lookup above. Returns the resolved symbol map.
800 : /// If WaitUntilReady is true (the default), will not return until all
801 : /// requested symbols are ready (or an error occurs). If WaitUntilReady is
802 9 : /// false, will return as soon as all requested symbols are resolved,
803 : /// or an error occurs. If WaitUntilReady is false and an error occurs
804 : /// after resolution, the function will return a success value, but the
805 : /// error will be reported via reportErrors.
806 : Expected<SymbolMap> lookup(const JITDylibList &JDs,
807 : const SymbolNameSet &Symbols,
808 : RegisterDependenciesFunction RegisterDependencies =
809 : NoDependenciesToRegister,
810 : bool WaitUntilReady = true,
811 : JITDylib *MatchNonExportedInJD = nullptr,
812 : bool MatchNonExported = false);
813 :
814 : /// Convenience version of blocking lookup.
815 : /// Performs a single-symbol lookup.
816 : Expected<JITEvaluatedSymbol> lookup(const JITDylibList &JDs,
817 : SymbolStringPtr Symbol,
818 : bool MatchNonExported = false);
819 :
820 : /// Convenience version of blocking lookup.
821 : /// Performs a single-symbol lookup, auto-interning the given symbol name.
822 : Expected<JITEvaluatedSymbol> lookup(const JITDylibList &JDs, StringRef Symbol,
823 : bool MatchNonExported = false);
824 :
825 : /// Materialize the given unit.
826 : void dispatchMaterialization(JITDylib &JD,
827 : std::unique_ptr<MaterializationUnit> MU) {
828 : LLVM_DEBUG(runSessionLocked([&]() {
829 : dbgs() << "Compiling, for " << JD.getName() << ", " << *MU
830 : << "\n";
831 : }););
832 : DispatchMaterialization(JD, std::move(MU));
833 : }
834 :
835 : /// Dump the state of all the JITDylibs in this session.
836 : void dump(raw_ostream &OS);
837 :
838 : private:
839 : static void logErrorsToStdErr(Error Err) {
840 : logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
841 : }
842 :
843 : static void
844 : materializeOnCurrentThread(JITDylib &JD,
845 : std::unique_ptr<MaterializationUnit> MU) {
846 : MU->doMaterialize(JD);
847 : }
848 :
849 : void runOutstandingMUs();
850 :
851 : mutable std::recursive_mutex SessionMutex;
852 : std::shared_ptr<SymbolStringPool> SSP;
853 : VModuleKey LastKey = 0;
854 : ErrorReporter ReportError = logErrorsToStdErr;
855 : DispatchMaterializationFunction DispatchMaterialization =
856 : materializeOnCurrentThread;
857 :
858 : std::vector<std::unique_ptr<JITDylib>> JDs;
859 :
860 : // FIXME: Remove this (and runOutstandingMUs) once the linking layer works
861 : // with callbacks from asynchronous queries.
862 : mutable std::recursive_mutex OutstandingMUsMutex;
863 : std::vector<std::pair<JITDylib *, std::unique_ptr<MaterializationUnit>>>
864 : OutstandingMUs;
865 : };
866 :
867 : template <typename Func>
868 : auto JITDylib::withSearchOrderDo(Func &&F)
869 : -> decltype(F(std::declval<const JITDylibList &>())) {
870 52 : return ES.runSessionLocked([&]() { return F(SearchOrder); });
871 : }
872 :
873 : template <typename MaterializationUnitType>
874 77 : Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU) {
875 : assert(MU && "Can not define with a null MU");
876 79 : return ES.runSessionLocked([&, this]() -> Error {
877 : if (auto Err = defineImpl(*MU))
878 : return Err;
879 :
880 : /// defineImpl succeeded.
881 : auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
882 107 : for (auto &KV : UMI->MU->getSymbols())
883 : UnmaterializedInfos[KV.first] = UMI;
884 :
885 : return Error::success();
886 79 : });
887 : }
888 111 :
889 107 : template <typename MaterializationUnitType>
890 4 : Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU) {
891 : assert(MU && "Can not define with a null MU");
892 :
893 : return ES.runSessionLocked([&, this]() -> Error {
894 : if (auto Err = defineImpl(*MU))
895 63 : return Err;
896 63 :
897 63 : /// defineImpl succeeded.
898 : auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
899 : for (auto &KV : UMI->MU->getSymbols())
900 102 : UnmaterializedInfos[KV.first] = UMI;
901 :
902 116 : return Error::success();
903 98 : });
904 18 : }
905 :
906 : /// Mangles symbol names then uniques them in the context of an
907 : /// ExecutionSession.
908 : class MangleAndInterner {
909 : public:
910 : MangleAndInterner(ExecutionSession &ES, const DataLayout &DL);
911 : SymbolStringPtr operator()(StringRef Name);
912 :
913 : private:
914 18 : ExecutionSession &ES;
915 : const DataLayout &DL;
916 5 : };
917 :
918 5 : } // End namespace orc
919 : } // End namespace llvm
920 :
921 : #undef DEBUG_TYPE // "orc"
922 :
923 : #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H
|