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