]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/include/llvm/ExecutionEngine/Orc/Core.h
Merge lld trunk r351319, resolve conflicts, and update FREEBSD-Xlist.
[FreeBSD/FreeBSD.git] / contrib / llvm / include / llvm / ExecutionEngine / Orc / Core.h
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;
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   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   JITDylib &getTargetJITDylib() const { return JD; }
170
171   /// Returns the VModuleKey for this instance.
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.
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:
254   MaterializationUnit(SymbolFlagsMap InitalSymbolFlags, VModuleKey K)
255       : SymbolFlags(std::move(InitalSymbolFlags)), K(std::move(K)) {}
256
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.
264   const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
265
266   /// Called by materialization dispatchers (see
267   /// ExecutionSession::DispatchMaterializationFunction) to trigger
268   /// materialization of this MaterializationUnit.
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.
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;
339   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.
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.
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.
513   const std::string &getName() const { return JITDylibName; }
514
515   /// Get a reference to the ExecutionSession for this JITDylib.
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.
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 {
620     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.
715   SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
716
717   /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession.
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.
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.
742   void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */
743   }
744
745   /// Set the error reporter function.
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.
754   void reportError(Error Err) { ReportError(std::move(Err)); }
755
756   /// Set the materialization dispatch function.
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.
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:
846   static void logErrorsToStdErr(Error Err) {
847     logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
848   }
849
850   static void
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>
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>
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