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*, bool) pairs.
58 using JITDylibSearchList = std::vector<std::pair<JITDylib *, bool>>;
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 JITDylibSearchList.
89 raw_ostream &operator<<(raw_ostream &OS, const JITDylibSearchList &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;
getSymbols()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;
getSymbols()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;
getSymbols()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   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.
getTargetJITDylib()169   JITDylib &getTargetJITDylib() const { return JD; }
170 
171   /// Returns the VModuleKey for this instance.
getVModuleKey()172   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.
getSymbols()178   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:
MaterializationUnit(SymbolFlagsMap InitalSymbolFlags,VModuleKey K)254   MaterializationUnit(SymbolFlagsMap InitalSymbolFlags, VModuleKey K)
255       : SymbolFlags(std::move(InitalSymbolFlags)), K(std::move(K)) {}
256 
~MaterializationUnit()257   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.
getSymbols()264   const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
265 
266   /// Called by materialization dispatchers (see
267   /// ExecutionSession::DispatchMaterializationFunction) to trigger
268   /// materialization of this MaterializationUnit.
doMaterialize(JITDylib & JD)269   void doMaterialize(JITDylib &JD) {
270     materialize(MaterializationResponsibility(JD, std::move(SymbolFlags),
271                                               std::move(K)));
272   }
273 
274   /// Called by JITDylibs to notify MaterializationUnits that the given symbol
275   /// has been overridden.
doDiscard(const JITDylib & JD,const SymbolStringPtr & Name)276   void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) {
277     SymbolFlags.erase(Name);
278     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       std::move(Symbols), std::move(K));
335 }
336 
337 struct SymbolAliasMapEntry {
338   SymbolAliasMapEntry() = default;
SymbolAliasMapEntrySymbolAliasMapEntry339   SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
340       : 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 (and
355   /// MatchNonExported has no effect). This is useful for defining aliases
356   /// within a JITDylib.
357   ///
358   /// Note: Care must be taken that no sets of aliases form a cycle, as such
359   ///       a cycle will result in a deadlock when any symbol in the cycle is
360   ///       resolved.
361   ReExportsMaterializationUnit(JITDylib *SourceJD, bool MatchNonExported,
362                                SymbolAliasMap Aliases, VModuleKey K);
363 
364   StringRef getName() const override;
365 
366 private:
367   void materialize(MaterializationResponsibility R) override;
368   void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
369   static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
370 
371   JITDylib *SourceJD = nullptr;
372   bool MatchNonExported = false;
373   SymbolAliasMap Aliases;
374 };
375 
376 /// Create a ReExportsMaterializationUnit with the given aliases.
377 /// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing
378 /// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux"
379 /// (for "bar") with: \code{.cpp}
380 ///   SymbolStringPtr Baz = ...;
381 ///   SymbolStringPtr Qux = ...;
382 ///   if (auto Err = JD.define(symbolAliases({
383 ///       {Baz, { Foo, JITSymbolFlags::Exported }},
384 ///       {Qux, { Bar, JITSymbolFlags::Weak }}}))
385 ///     return Err;
386 /// \endcode
387 inline std::unique_ptr<ReExportsMaterializationUnit>
388 symbolAliases(SymbolAliasMap Aliases, VModuleKey K = VModuleKey()) {
389   return llvm::make_unique<ReExportsMaterializationUnit>(
390       nullptr, true, std::move(Aliases), std::move(K));
391 }
392 
393 /// Create a materialization unit for re-exporting symbols from another JITDylib
394 /// with alternative names/flags.
395 /// If MatchNonExported is true then non-exported symbols from SourceJD can be
396 /// re-exported. If it is false, attempts to re-export a non-exported symbol
397 /// will result in a "symbol not found" error.
398 inline std::unique_ptr<ReExportsMaterializationUnit>
399 reexports(JITDylib &SourceJD, SymbolAliasMap Aliases,
400           bool MatchNonExported = false, VModuleKey K = VModuleKey()) {
401   return llvm::make_unique<ReExportsMaterializationUnit>(
402       &SourceJD, MatchNonExported, std::move(Aliases), std::move(K));
403 }
404 
405 /// Build a SymbolAliasMap for the common case where you want to re-export
406 /// symbols from another JITDylib with the same linkage/flags.
407 Expected<SymbolAliasMap>
408 buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols);
409 
410 /// ReexportsGenerator can be used with JITDylib::setGenerator to automatically
411 /// re-export a subset of the source JITDylib's symbols in the target.
412 class ReexportsGenerator {
413 public:
414   using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
415 
416   /// Create a reexports generator. If an Allow predicate is passed, only
417   /// symbols for which the predicate returns true will be reexported. If no
418   /// Allow predicate is passed, all symbols will be exported.
419   ReexportsGenerator(JITDylib &SourceJD, bool MatchNonExported = false,
420                      SymbolPredicate Allow = SymbolPredicate());
421 
422   SymbolNameSet operator()(JITDylib &JD, const SymbolNameSet &Names);
423 
424 private:
425   JITDylib &SourceJD;
426   bool MatchNonExported = false;
427   SymbolPredicate Allow;
428 };
429 
430 /// A symbol query that returns results via a callback when results are
431 ///        ready.
432 ///
433 /// makes a callback when all symbols are available.
434 class AsynchronousSymbolQuery {
435   friend class ExecutionSession;
436   friend class JITDylib;
437   friend class JITSymbolResolverAdapter;
438 
439 public:
440 
441   /// Create a query for the given symbols, notify-resolved and
442   ///        notify-ready callbacks.
443   AsynchronousSymbolQuery(const SymbolNameSet &Symbols,
444                           SymbolsResolvedCallback NotifySymbolsResolved,
445                           SymbolsReadyCallback NotifySymbolsReady);
446 
447   /// Set the resolved symbol information for the given symbol name.
448   void resolve(const SymbolStringPtr &Name, JITEvaluatedSymbol Sym);
449 
450   /// Returns true if all symbols covered by this query have been
451   ///        resolved.
isFullyResolved()452   bool isFullyResolved() const { return NotYetResolvedCount == 0; }
453 
454   /// Call the NotifySymbolsResolved callback.
455   ///
456   /// This should only be called if all symbols covered by the query have been
457   /// resolved.
458   void handleFullyResolved();
459 
460   /// Notify the query that a requested symbol is ready for execution.
461   void notifySymbolReady();
462 
463   /// Returns true if all symbols covered by this query are ready.
isFullyReady()464   bool isFullyReady() const { return NotYetReadyCount == 0; }
465 
466   /// Calls the NotifySymbolsReady callback.
467   ///
468   /// This should only be called if all symbols covered by this query are ready.
469   void handleFullyReady();
470 
471 private:
472   void addQueryDependence(JITDylib &JD, SymbolStringPtr Name);
473 
474   void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name);
475 
476   bool canStillFail();
477 
478   void handleFailed(Error Err);
479 
480   void detach();
481 
482   SymbolsResolvedCallback NotifySymbolsResolved;
483   SymbolsReadyCallback NotifySymbolsReady;
484   SymbolDependenceMap QueryRegistrations;
485   SymbolMap ResolvedSymbols;
486   size_t NotYetResolvedCount;
487   size_t NotYetReadyCount;
488 };
489 
490 /// A symbol table that supports asynchoronous symbol queries.
491 ///
492 /// Represents a virtual shared object. Instances can not be copied or moved, so
493 /// their addresses may be used as keys for resource management.
494 /// JITDylib state changes must be made via an ExecutionSession to guarantee
495 /// that they are synchronized with respect to other JITDylib operations.
496 class JITDylib {
497   friend class AsynchronousSymbolQuery;
498   friend class ExecutionSession;
499   friend class MaterializationResponsibility;
500 public:
501   using GeneratorFunction = std::function<SymbolNameSet(
502       JITDylib &Parent, const SymbolNameSet &Names)>;
503 
504   using AsynchronousSymbolQuerySet =
505     std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
506 
507   JITDylib(const JITDylib &) = delete;
508   JITDylib &operator=(const JITDylib &) = delete;
509   JITDylib(JITDylib &&) = delete;
510   JITDylib &operator=(JITDylib &&) = delete;
511 
512   /// Get the name for this JITDylib.
getName()513   const std::string &getName() const { return JITDylibName; }
514 
515   /// Get a reference to the ExecutionSession for this JITDylib.
getExecutionSession()516   ExecutionSession &getExecutionSession() const { return ES; }
517 
518   /// Set a definition generator. If set, whenever a symbol fails to resolve
519   /// within this JITDylib, lookup and lookupFlags will pass the unresolved
520   /// symbols set to the definition generator. The generator can optionally
521   /// add a definition for the unresolved symbols to the dylib.
setGenerator(GeneratorFunction DefGenerator)522   void setGenerator(GeneratorFunction DefGenerator) {
523     this->DefGenerator = std::move(DefGenerator);
524   }
525 
526   /// Set the search order to be used when fixing up definitions in JITDylib.
527   /// This will replace the previous search order, and apply to any symbol
528   /// resolutions made for definitions in this JITDylib after the call to
529   /// setSearchOrder (even if the definition itself was added before the
530   /// call).
531   ///
532   /// If SearchThisJITDylibFirst is set, which by default it is, then this
533   /// JITDylib will add itself to the beginning of the SearchOrder (Clients
534   /// should *not* put this JITDylib in the list in this case, to avoid
535   /// redundant lookups).
536   ///
537   /// If SearchThisJITDylibFirst is false then the search order will be used as
538   /// given. The main motivation for this feature is to support deliberate
539   /// shadowing of symbols in this JITDylib by a facade JITDylib. For example,
540   /// the facade may resolve function names to stubs, and the stubs may compile
541   /// lazily by looking up symbols in this dylib. Adding the facade dylib
542   /// as the first in the search order (instead of this dylib) ensures that
543   /// definitions within this dylib resolve to the lazy-compiling stubs,
544   /// rather than immediately materializing the definitions in this dylib.
545   void setSearchOrder(JITDylibSearchList NewSearchOrder,
546                       bool SearchThisJITDylibFirst = true,
547                       bool MatchNonExportedInThisDylib = true);
548 
549   /// Add the given JITDylib to the search order for definitions in this
550   /// JITDylib.
551   void addToSearchOrder(JITDylib &JD, bool MatcNonExported = false);
552 
553   /// Replace OldJD with NewJD in the search order if OldJD is present.
554   /// Otherwise this operation is a no-op.
555   void replaceInSearchOrder(JITDylib &OldJD, JITDylib &NewJD,
556                             bool MatchNonExported = false);
557 
558   /// Remove the given JITDylib from the search order for this JITDylib if it is
559   /// present. Otherwise this operation is a no-op.
560   void removeFromSearchOrder(JITDylib &JD);
561 
562   /// Do something with the search order (run under the session lock).
563   template <typename Func>
564   auto withSearchOrderDo(Func &&F)
565       -> decltype(F(std::declval<const JITDylibSearchList &>()));
566 
567   /// Define all symbols provided by the materialization unit to be part of this
568   /// JITDylib.
569   ///
570   /// This overload always takes ownership of the MaterializationUnit. If any
571   /// errors occur, the MaterializationUnit consumed.
572   template <typename MaterializationUnitType>
573   Error define(std::unique_ptr<MaterializationUnitType> &&MU);
574 
575   /// Define all symbols provided by the materialization unit to be part of this
576   /// JITDylib.
577   ///
578   /// This overload only takes ownership of the MaterializationUnit no error is
579   /// generated. If an error occurs, ownership remains with the caller. This
580   /// may allow the caller to modify the MaterializationUnit to correct the
581   /// issue, then re-call define.
582   template <typename MaterializationUnitType>
583   Error define(std::unique_ptr<MaterializationUnitType> &MU);
584 
585   /// Tries to remove the given symbols.
586   ///
587   /// If any symbols are not defined in this JITDylib this method will return
588   /// a SymbolsNotFound error covering the missing symbols.
589   ///
590   /// If all symbols are found but some symbols are in the process of being
591   /// materialized this method will return a SymbolsCouldNotBeRemoved error.
592   ///
593   /// On success, all symbols are removed. On failure, the JITDylib state is
594   /// left unmodified (no symbols are removed).
595   Error remove(const SymbolNameSet &Names);
596 
597   /// Search the given JITDylib for the symbols in Symbols. If found, store
598   ///        the flags for each symbol in Flags. Returns any unresolved symbols.
599   SymbolFlagsMap lookupFlags(const SymbolNameSet &Names);
600 
601   /// Dump current JITDylib state to OS.
602   void dump(raw_ostream &OS);
603 
604   /// FIXME: Remove this when we remove the old ORC layers.
605   /// Search the given JITDylibs in order for the symbols in Symbols. Results
606   ///        (once they become available) will be returned via the given Query.
607   ///
608   /// If any symbol is not found then the unresolved symbols will be returned,
609   /// and the query will not be applied. The Query is not failed and can be
610   /// re-used in a subsequent lookup once the symbols have been added, or
611   /// manually failed.
612   SymbolNameSet legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
613                              SymbolNameSet Names);
614 
615 private:
616   using AsynchronousSymbolQueryList =
617       std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
618 
619   struct UnmaterializedInfo {
UnmaterializedInfoUnmaterializedInfo620     UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU)
621         : MU(std::move(MU)) {}
622 
623     std::unique_ptr<MaterializationUnit> MU;
624   };
625 
626   using UnmaterializedInfosMap =
627       DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
628 
629   struct MaterializingInfo {
630     AsynchronousSymbolQueryList PendingQueries;
631     SymbolDependenceMap Dependants;
632     SymbolDependenceMap UnemittedDependencies;
633     bool IsEmitted = false;
634   };
635 
636   using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>;
637 
638   using LookupImplActionFlags = enum {
639     None = 0,
640     NotifyFullyResolved = 1 << 0U,
641     NotifyFullyReady = 1 << 1U,
642     LLVM_MARK_AS_BITMASK_ENUM(NotifyFullyReady)
643   };
644 
645   JITDylib(ExecutionSession &ES, std::string Name);
646 
647   Error defineImpl(MaterializationUnit &MU);
648 
649   SymbolNameSet lookupFlagsImpl(SymbolFlagsMap &Flags,
650                                 const SymbolNameSet &Names);
651 
652   void lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
653                   SymbolNameSet &Unresolved, bool MatchNonExported,
654                   MaterializationUnitList &MUs);
655 
656   void lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
657                       SymbolNameSet &Unresolved, bool MatchNonExported,
658                       MaterializationUnitList &MUs);
659 
660   LookupImplActionFlags
661   lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
662              std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
663              SymbolNameSet &Unresolved);
664 
665   void detachQueryHelper(AsynchronousSymbolQuery &Q,
666                          const SymbolNameSet &QuerySymbols);
667 
668   void transferEmittedNodeDependencies(MaterializingInfo &DependantMI,
669                                        const SymbolStringPtr &DependantName,
670                                        MaterializingInfo &EmittedMI);
671 
672   Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
673 
674   void replace(std::unique_ptr<MaterializationUnit> MU);
675 
676   SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const;
677 
678   void addDependencies(const SymbolStringPtr &Name,
679                        const SymbolDependenceMap &Dependants);
680 
681   void resolve(const SymbolMap &Resolved);
682 
683   void emit(const SymbolFlagsMap &Emitted);
684 
685   void notifyFailed(const SymbolNameSet &FailedSymbols);
686 
687   ExecutionSession &ES;
688   std::string JITDylibName;
689   SymbolMap Symbols;
690   UnmaterializedInfosMap UnmaterializedInfos;
691   MaterializingInfosMap MaterializingInfos;
692   GeneratorFunction DefGenerator;
693   JITDylibSearchList SearchOrder;
694 };
695 
696 /// An ExecutionSession represents a running JIT program.
697 class ExecutionSession {
698   // FIXME: Remove this when we remove the old ORC layers.
699   friend class JITDylib;
700 
701 public:
702   /// For reporting errors.
703   using ErrorReporter = std::function<void(Error)>;
704 
705   /// For dispatching MaterializationUnit::materialize calls.
706   using DispatchMaterializationFunction = std::function<void(
707       JITDylib &JD, std::unique_ptr<MaterializationUnit> MU)>;
708 
709   /// Construct an ExecutionSession.
710   ///
711   /// SymbolStringPools may be shared between ExecutionSessions.
712   ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr);
713 
714   /// Add a symbol name to the SymbolStringPool and return a pointer to it.
intern(StringRef SymName)715   SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
716 
717   /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession.
getSymbolStringPool()718   std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
719 
720   /// Run the given lambda with the session mutex locked.
721   template <typename Func> auto runSessionLocked(Func &&F) -> decltype(F()) {
722     std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
723     return F();
724   }
725 
726   /// Get the "main" JITDylib, which is created automatically on construction of
727   /// the ExecutionSession.
728   JITDylib &getMainJITDylib();
729 
730   /// Add a new JITDylib to this ExecutionSession.
731   JITDylib &createJITDylib(std::string Name,
732                            bool AddToMainDylibSearchOrder = true);
733 
734   /// Allocate a module key for a new module to add to the JIT.
allocateVModule()735   VModuleKey allocateVModule() {
736     return runSessionLocked([this]() { return ++LastKey; });
737   }
738 
739   /// Return a module key to the ExecutionSession so that it can be
740   ///        re-used. This should only be done once all resources associated
741   ///        with the original key have been released.
releaseVModule(VModuleKey Key)742   void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */
743   }
744 
745   /// Set the error reporter function.
setErrorReporter(ErrorReporter ReportError)746   ExecutionSession &setErrorReporter(ErrorReporter ReportError) {
747     this->ReportError = std::move(ReportError);
748     return *this;
749   }
750 
751   /// Report a error for this execution session.
752   ///
753   /// Unhandled errors can be sent here to log them.
reportError(Error Err)754   void reportError(Error Err) { ReportError(std::move(Err)); }
755 
756   /// Set the materialization dispatch function.
setDispatchMaterialization(DispatchMaterializationFunction DispatchMaterialization)757   ExecutionSession &setDispatchMaterialization(
758       DispatchMaterializationFunction DispatchMaterialization) {
759     this->DispatchMaterialization = std::move(DispatchMaterialization);
760     return *this;
761   }
762 
763   void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err);
764 
765   using LegacyAsyncLookupFunction = std::function<SymbolNameSet(
766       std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>;
767 
768   /// A legacy lookup function for JITSymbolResolverAdapter.
769   /// Do not use -- this will be removed soon.
770   Expected<SymbolMap>
771   legacyLookup(LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names,
772                bool WaiUntilReady,
773                RegisterDependenciesFunction RegisterDependencies);
774 
775   /// Search the given JITDylib list for the given symbols.
776   ///
777   /// SearchOrder lists the JITDylibs to search. For each dylib, the associated
778   /// boolean indicates whether the search should match against non-exported
779   /// (hidden visibility) symbols in that dylib (true means match against
780   /// non-exported symbols, false means do not match).
781   ///
782   /// The OnResolve callback will be called once all requested symbols are
783   /// resolved, or if an error occurs prior to resolution.
784   ///
785   /// The OnReady callback will be called once all requested symbols are ready,
786   /// or if an error occurs after resolution but before all symbols are ready.
787   ///
788   /// If all symbols are found, the RegisterDependencies function will be called
789   /// while the session lock is held. This gives clients a chance to register
790   /// dependencies for on the queried symbols for any symbols they are
791   /// materializing (if a MaterializationResponsibility instance is present,
792   /// this can be implemented by calling
793   /// MaterializationResponsibility::addDependencies). If there are no
794   /// dependenant symbols for this query (e.g. it is being made by a top level
795   /// client to get an address to call) then the value NoDependenciesToRegister
796   /// can be used.
797   void lookup(const JITDylibSearchList &SearchOrder, SymbolNameSet Symbols,
798               SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady,
799               RegisterDependenciesFunction RegisterDependencies);
800 
801   /// Blocking version of lookup above. Returns the resolved symbol map.
802   /// If WaitUntilReady is true (the default), will not return until all
803   /// requested symbols are ready (or an error occurs). If WaitUntilReady is
804   /// false, will return as soon as all requested symbols are resolved,
805   /// or an error occurs. If WaitUntilReady is false and an error occurs
806   /// after resolution, the function will return a success value, but the
807   /// error will be reported via reportErrors.
808   Expected<SymbolMap> lookup(const JITDylibSearchList &SearchOrder,
809                              const SymbolNameSet &Symbols,
810                              RegisterDependenciesFunction RegisterDependencies =
811                                  NoDependenciesToRegister,
812                              bool WaitUntilReady = true);
813 
814   /// Convenience version of blocking lookup.
815   /// Searches each of the JITDylibs in the search order in turn for the given
816   /// symbol.
817   Expected<JITEvaluatedSymbol> lookup(const JITDylibSearchList &SearchOrder,
818                                       SymbolStringPtr Symbol);
819 
820   /// Convenience version of blocking lookup.
821   /// Searches each of the JITDylibs in the search order in turn for the given
822   /// symbol. The search will not find non-exported symbols.
823   Expected<JITEvaluatedSymbol> lookup(ArrayRef<JITDylib *> SearchOrder,
824                                       SymbolStringPtr Symbol);
825 
826   /// Convenience version of blocking lookup.
827   /// Searches each of the JITDylibs in the search order in turn for the given
828   /// symbol. The search will not find non-exported symbols.
829   Expected<JITEvaluatedSymbol> lookup(ArrayRef<JITDylib *> SearchOrder,
830                                       StringRef Symbol);
831 
832   /// Materialize the given unit.
dispatchMaterialization(JITDylib & JD,std::unique_ptr<MaterializationUnit> MU)833   void dispatchMaterialization(JITDylib &JD,
834                                std::unique_ptr<MaterializationUnit> MU) {
835     LLVM_DEBUG(runSessionLocked([&]() {
836                  dbgs() << "Compiling, for " << JD.getName() << ", " << *MU
837                         << "\n";
838                }););
839     DispatchMaterialization(JD, std::move(MU));
840   }
841 
842   /// Dump the state of all the JITDylibs in this session.
843   void dump(raw_ostream &OS);
844 
845 private:
logErrorsToStdErr(Error Err)846   static void logErrorsToStdErr(Error Err) {
847     logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
848   }
849 
850   static void
materializeOnCurrentThread(JITDylib & JD,std::unique_ptr<MaterializationUnit> MU)851   materializeOnCurrentThread(JITDylib &JD,
852                              std::unique_ptr<MaterializationUnit> MU) {
853     MU->doMaterialize(JD);
854   }
855 
856   void runOutstandingMUs();
857 
858   mutable std::recursive_mutex SessionMutex;
859   std::shared_ptr<SymbolStringPool> SSP;
860   VModuleKey LastKey = 0;
861   ErrorReporter ReportError = logErrorsToStdErr;
862   DispatchMaterializationFunction DispatchMaterialization =
863       materializeOnCurrentThread;
864 
865   std::vector<std::unique_ptr<JITDylib>> JDs;
866 
867   // FIXME: Remove this (and runOutstandingMUs) once the linking layer works
868   //        with callbacks from asynchronous queries.
869   mutable std::recursive_mutex OutstandingMUsMutex;
870   std::vector<std::pair<JITDylib *, std::unique_ptr<MaterializationUnit>>>
871       OutstandingMUs;
872 };
873 
874 template <typename Func>
875 auto JITDylib::withSearchOrderDo(Func &&F)
876     -> decltype(F(std::declval<const JITDylibSearchList &>())) {
877   return ES.runSessionLocked([&]() { return F(SearchOrder); });
878 }
879 
880 template <typename MaterializationUnitType>
define(std::unique_ptr<MaterializationUnitType> && MU)881 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU) {
882   assert(MU && "Can not define with a null MU");
883   return ES.runSessionLocked([&, this]() -> Error {
884     if (auto Err = defineImpl(*MU))
885       return Err;
886 
887     /// defineImpl succeeded.
888     auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
889     for (auto &KV : UMI->MU->getSymbols())
890       UnmaterializedInfos[KV.first] = UMI;
891 
892     return Error::success();
893   });
894 }
895 
896 template <typename MaterializationUnitType>
define(std::unique_ptr<MaterializationUnitType> & MU)897 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU) {
898   assert(MU && "Can not define with a null MU");
899 
900   return ES.runSessionLocked([&, this]() -> Error {
901     if (auto Err = defineImpl(*MU))
902       return Err;
903 
904     /// defineImpl succeeded.
905     auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
906     for (auto &KV : UMI->MU->getSymbols())
907       UnmaterializedInfos[KV.first] = UMI;
908 
909     return Error::success();
910   });
911 }
912 
913 /// Mangles symbol names then uniques them in the context of an
914 /// ExecutionSession.
915 class MangleAndInterner {
916 public:
917   MangleAndInterner(ExecutionSession &ES, const DataLayout &DL);
918   SymbolStringPtr operator()(StringRef Name);
919 
920 private:
921   ExecutionSession &ES;
922   const DataLayout &DL;
923 };
924 
925 } // End namespace orc
926 } // End namespace llvm
927 
928 #undef DEBUG_TYPE // "orc"
929 
930 #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H
931