• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
22 #include <list>
23 #include <map>
24 #include <memory>
25 #include <set>
26 #include <vector>
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 VSO;
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 = std::set<SymbolStringPtr>;
45 
46 /// Render a SymbolNameSet to an ostream.
47 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols);
48 
49 /// A map from symbol names (as SymbolStringPtrs) to JITSymbols
50 ///        (address/flags pairs).
51 using SymbolMap = std::map<SymbolStringPtr, JITEvaluatedSymbol>;
52 
53 /// Render a SymbolMap to an ostream.
54 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols);
55 
56 /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
57 using SymbolFlagsMap = std::map<SymbolStringPtr, JITSymbolFlags>;
58 
59 /// Render a SymbolMap to an ostream.
60 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &Symbols);
61 
62 /// A base class for materialization failures that allows the failing
63 ///        symbols to be obtained for logging.
64 using SymbolDependenceMap = std::map<VSO *, SymbolNameSet>;
65 
66 /// Render a SymbolDependendeMap.
67 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps);
68 
69 /// A list of VSO pointers.
70 using VSOList = std::vector<VSO *>;
71 
72 /// Render a VSOList.
73 raw_ostream &operator<<(raw_ostream &OS, const VSOList &VSOs);
74 
75 /// Callback to notify client that symbols have been resolved.
76 using SymbolsResolvedCallback = std::function<void(Expected<SymbolMap>)>;
77 
78 /// Callback to notify client that symbols are ready for execution.
79 using SymbolsReadyCallback = std::function<void(Error)>;
80 
81 /// Callback to register the dependencies for a given query.
82 using RegisterDependenciesFunction =
83     std::function<void(const SymbolDependenceMap &)>;
84 
85 /// This can be used as the value for a RegisterDependenciesFunction if there
86 /// are no dependants to register with.
87 extern RegisterDependenciesFunction NoDependenciesToRegister;
88 
89 /// Used to notify a VSO that the given set of symbols failed to materialize.
90 class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
91 public:
92   static char ID;
93 
94   FailedToMaterialize(SymbolNameSet Symbols);
95   std::error_code convertToErrorCode() const override;
96   void log(raw_ostream &OS) const override;
getSymbols()97   const SymbolNameSet &getSymbols() const { return Symbols; }
98 
99 private:
100   SymbolNameSet Symbols;
101 };
102 
103 /// Used to notify clients when symbols can not be found during a lookup.
104 class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
105 public:
106   static char ID;
107 
108   SymbolsNotFound(SymbolNameSet Symbols);
109   std::error_code convertToErrorCode() const override;
110   void log(raw_ostream &OS) const override;
getSymbols()111   const SymbolNameSet &getSymbols() const { return Symbols; }
112 
113 private:
114   SymbolNameSet Symbols;
115 };
116 
117 /// Tracks responsibility for materialization, and mediates interactions between
118 /// MaterializationUnits and VSOs.
119 ///
120 /// An instance of this class is passed to MaterializationUnits when their
121 /// materialize method is called. It allows MaterializationUnits to resolve and
122 /// finalize symbols, or abandon materialization by notifying any unmaterialized
123 /// symbols of an error.
124 class MaterializationResponsibility {
125   friend class MaterializationUnit;
126 public:
127   MaterializationResponsibility(MaterializationResponsibility &&) = default;
128   MaterializationResponsibility &
129   operator=(MaterializationResponsibility &&) = delete;
130 
131   /// Destruct a MaterializationResponsibility instance. In debug mode
132   ///        this asserts that all symbols being tracked have been either
133   ///        finalized or notified of an error.
134   ~MaterializationResponsibility();
135 
136   /// Returns the target VSO that these symbols are being materialized
137   ///        into.
getTargetVSO()138   VSO &getTargetVSO() const { return V; }
139 
140   /// Returns the symbol flags map for this responsibility instance.
getSymbols()141   SymbolFlagsMap getSymbols() { return SymbolFlags; }
142 
143   /// Returns the names of any symbols covered by this
144   /// MaterializationResponsibility object that have queries pending. This
145   /// information can be used to return responsibility for unrequested symbols
146   /// back to the VSO via the delegate method.
147   SymbolNameSet getRequestedSymbols();
148 
149   /// Resolves the given symbols. Individual calls to this method may
150   ///        resolve a subset of the symbols, but all symbols must have been
151   ///        resolved prior to calling finalize.
152   void resolve(const SymbolMap &Symbols);
153 
154   /// Finalizes all symbols tracked by this instance.
155   void finalize();
156 
157   /// Adds new symbols to the VSO and this responsibility instance.
158   ///        VSO entries start out in the materializing state.
159   ///
160   ///   This method can be used by materialization units that want to add
161   /// additional symbols at materialization time (e.g. stubs, compile
162   /// callbacks, metadata).
163   Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
164 
165   /// Notify all unfinalized symbols that an error has occurred.
166   /// This will remove all symbols covered by this MaterializationResponsibilty
167   /// from V, and send an error to any queries waiting on these symbols.
168   void failMaterialization();
169 
170   /// Transfers responsibility to the given MaterializationUnit for all
171   /// symbols defined by that MaterializationUnit. This allows
172   /// materializers to break up work based on run-time information (e.g.
173   /// by introspecting which symbols have actually been looked up and
174   /// materializing only those).
175   void replace(std::unique_ptr<MaterializationUnit> MU);
176 
177   /// Delegates responsibility for the given symbols to the returned
178   /// materialization responsibility. Useful for breaking up work between
179   /// threads, or different kinds of materialization processes.
180   MaterializationResponsibility delegate(const SymbolNameSet &Symbols);
181 
182   void addDependencies(const SymbolStringPtr &Name,
183                        const SymbolDependenceMap &Dependencies);
184 
185   /// Add dependencies that apply to all symbols covered by this instance.
186   void addDependenciesForAll(const SymbolDependenceMap &Dependencies);
187 
188 private:
189   /// Create a MaterializationResponsibility for the given VSO and
190   ///        initial symbols.
191   MaterializationResponsibility(VSO &V, SymbolFlagsMap SymbolFlags);
192 
193   VSO &V;
194   SymbolFlagsMap SymbolFlags;
195 };
196 
197 /// A MaterializationUnit represents a set of symbol definitions that can
198 ///        be materialized as a group, or individually discarded (when
199 ///        overriding definitions are encountered).
200 ///
201 /// MaterializationUnits are used when providing lazy definitions of symbols to
202 /// VSOs. The VSO will call materialize when the address of a symbol is
203 /// requested via the lookup method. The VSO will call discard if a stronger
204 /// definition is added or already present.
205 class MaterializationUnit {
206 public:
MaterializationUnit(SymbolFlagsMap InitalSymbolFlags)207   MaterializationUnit(SymbolFlagsMap InitalSymbolFlags)
208       : SymbolFlags(std::move(InitalSymbolFlags)) {}
209 
~MaterializationUnit()210   virtual ~MaterializationUnit() {}
211 
212   /// Return the set of symbols that this source provides.
getSymbols()213   const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
214 
215   /// Called by materialization dispatchers (see
216   /// ExecutionSession::DispatchMaterializationFunction) to trigger
217   /// materialization of this MaterializationUnit.
doMaterialize(VSO & V)218   void doMaterialize(VSO &V) {
219     materialize(MaterializationResponsibility(V, std::move(SymbolFlags)));
220   }
221 
222   /// Called by VSOs to notify MaterializationUnits that the given symbol has
223   /// been overridden.
doDiscard(const VSO & V,SymbolStringPtr Name)224   void doDiscard(const VSO &V, SymbolStringPtr Name) {
225     SymbolFlags.erase(Name);
226     discard(V, std::move(Name));
227   }
228 
229 protected:
230   SymbolFlagsMap SymbolFlags;
231 
232 private:
233   virtual void anchor();
234 
235   /// Implementations of this method should materialize all symbols
236   ///        in the materialzation unit, except for those that have been
237   ///        previously discarded.
238   virtual void materialize(MaterializationResponsibility R) = 0;
239 
240   /// Implementations of this method should discard the given symbol
241   ///        from the source (e.g. if the source is an LLVM IR Module and the
242   ///        symbol is a function, delete the function body or mark it available
243   ///        externally).
244   virtual void discard(const VSO &V, SymbolStringPtr Name) = 0;
245 };
246 
247 using MaterializationUnitList =
248     std::vector<std::unique_ptr<MaterializationUnit>>;
249 
250 /// A MaterializationUnit implementation for pre-existing absolute symbols.
251 ///
252 /// All symbols will be resolved and marked ready as soon as the unit is
253 /// materialized.
254 class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
255 public:
256   AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols);
257 
258 private:
259   void materialize(MaterializationResponsibility R) override;
260   void discard(const VSO &V, SymbolStringPtr Name) override;
261   static SymbolFlagsMap extractFlags(const SymbolMap &Symbols);
262 
263   SymbolMap Symbols;
264 };
265 
266 /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
267 /// Useful for inserting absolute symbols into a VSO. E.g.:
268 /// \code{.cpp}
269 ///   VSO &V = ...;
270 ///   SymbolStringPtr Foo = ...;
271 ///   JITEvaluatedSymbol FooSym = ...;
272 ///   if (auto Err = V.define(absoluteSymbols({{Foo, FooSym}})))
273 ///     return Err;
274 /// \endcode
275 ///
276 inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit>
absoluteSymbols(SymbolMap Symbols)277 absoluteSymbols(SymbolMap Symbols) {
278   return llvm::make_unique<AbsoluteSymbolsMaterializationUnit>(
279       std::move(Symbols));
280 }
281 
282 struct SymbolAliasMapEntry {
283   SymbolAliasMapEntry() = default;
SymbolAliasMapEntrySymbolAliasMapEntry284   SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
285       : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {}
286 
287   SymbolStringPtr Aliasee;
288   JITSymbolFlags AliasFlags;
289 };
290 
291 /// A map of Symbols to (Symbol, Flags) pairs.
292 using SymbolAliasMap = std::map<SymbolStringPtr, SymbolAliasMapEntry>;
293 
294 /// A materialization unit for symbol aliases. Allows existing symbols to be
295 /// aliased with alternate flags.
296 class ReExportsMaterializationUnit : public MaterializationUnit {
297 public:
298   /// SourceVSO is allowed to be nullptr, in which case the source VSO is
299   /// taken to be whatever VSO these definitions are materialized in. This
300   /// is useful for defining aliases within a VSO.
301   ///
302   /// Note: Care must be taken that no sets of aliases form a cycle, as such
303   ///       a cycle will result in a deadlock when any symbol in the cycle is
304   ///       resolved.
305   ReExportsMaterializationUnit(VSO *SourceVSO, SymbolAliasMap Aliases);
306 
307 private:
308   void materialize(MaterializationResponsibility R) override;
309   void discard(const VSO &V, SymbolStringPtr Name) override;
310   static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
311 
312   VSO *SourceVSO = nullptr;
313   SymbolAliasMap Aliases;
314 };
315 
316 /// Create a ReExportsMaterializationUnit with the given aliases.
317 /// Useful for defining symbol aliases.: E.g., given a VSO V containing symbols
318 /// "foo" and "bar", we can define aliases "baz" (for "foo") and "qux" (for
319 /// "bar") with:
320 /// \code{.cpp}
321 ///   SymbolStringPtr Baz = ...;
322 ///   SymbolStringPtr Qux = ...;
323 ///   if (auto Err = V.define(symbolAliases({
324 ///       {Baz, { Foo, JITSymbolFlags::Exported }},
325 ///       {Qux, { Bar, JITSymbolFlags::Weak }}}))
326 ///     return Err;
327 /// \endcode
328 inline std::unique_ptr<ReExportsMaterializationUnit>
symbolAliases(SymbolAliasMap Aliases)329 symbolAliases(SymbolAliasMap Aliases) {
330   return llvm::make_unique<ReExportsMaterializationUnit>(nullptr,
331                                                          std::move(Aliases));
332 }
333 
334 /// Create a materialization unit for re-exporting symbols from another VSO
335 /// with alternative names/flags.
336 inline std::unique_ptr<ReExportsMaterializationUnit>
reexports(VSO & SourceV,SymbolAliasMap Aliases)337 reexports(VSO &SourceV, SymbolAliasMap Aliases) {
338   return llvm::make_unique<ReExportsMaterializationUnit>(&SourceV,
339                                                          std::move(Aliases));
340 }
341 
342 /// Build a SymbolAliasMap for the common case where you want to re-export
343 /// symbols from another VSO with the same linkage/flags.
344 Expected<SymbolAliasMap>
345 buildSimpleReexportsAliasMap(VSO &SourceV, const SymbolNameSet &Symbols);
346 
347 /// Base utilities for ExecutionSession.
348 class ExecutionSessionBase {
349   // FIXME: Remove this when we remove the old ORC layers.
350   friend class VSO;
351 
352 public:
353   /// For reporting errors.
354   using ErrorReporter = std::function<void(Error)>;
355 
356   /// For dispatching MaterializationUnit::materialize calls.
357   using DispatchMaterializationFunction =
358       std::function<void(VSO &V, std::unique_ptr<MaterializationUnit> MU)>;
359 
360   /// Construct an ExecutionSessionBase.
361   ///
362   /// SymbolStringPools may be shared between ExecutionSessions.
363   ExecutionSessionBase(std::shared_ptr<SymbolStringPool> SSP = nullptr)
364       : SSP(SSP ? std::move(SSP) : std::make_shared<SymbolStringPool>()) {}
365 
366   /// Returns the SymbolStringPool for this ExecutionSession.
getSymbolStringPool()367   SymbolStringPool &getSymbolStringPool() const { return *SSP; }
368 
369   /// Run the given lambda with the session mutex locked.
370   template <typename Func> auto runSessionLocked(Func &&F) -> decltype(F()) {
371     std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
372     return F();
373   }
374 
375   /// Set the error reporter function.
setErrorReporter(ErrorReporter ReportError)376   ExecutionSessionBase &setErrorReporter(ErrorReporter ReportError) {
377     this->ReportError = std::move(ReportError);
378     return *this;
379   }
380 
381   /// Set the materialization dispatch function.
setDispatchMaterialization(DispatchMaterializationFunction DispatchMaterialization)382   ExecutionSessionBase &setDispatchMaterialization(
383       DispatchMaterializationFunction DispatchMaterialization) {
384     this->DispatchMaterialization = std::move(DispatchMaterialization);
385     return *this;
386   }
387 
388   /// Report a error for this execution session.
389   ///
390   /// Unhandled errors can be sent here to log them.
reportError(Error Err)391   void reportError(Error Err) { ReportError(std::move(Err)); }
392 
393   /// Allocate a module key for a new module to add to the JIT.
allocateVModule()394   VModuleKey allocateVModule() { return ++LastKey; }
395 
396   /// Return a module key to the ExecutionSession so that it can be
397   ///        re-used. This should only be done once all resources associated
398   ///        with the original key have been released.
releaseVModule(VModuleKey Key)399   void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */
400   }
401 
402   void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err);
403 
404   using LegacyAsyncLookupFunction = std::function<SymbolNameSet(
405       std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>;
406 
407   /// A legacy lookup function for JITSymbolResolverAdapter.
408   /// Do not use -- this will be removed soon.
409   Expected<SymbolMap>
410   legacyLookup(ExecutionSessionBase &ES, LegacyAsyncLookupFunction AsyncLookup,
411                SymbolNameSet Names, bool WaiUntilReady,
412                RegisterDependenciesFunction RegisterDependencies);
413 
414   /// Search the given VSO list for the given symbols.
415   ///
416   ///
417   /// The OnResolve callback will be called once all requested symbols are
418   /// resolved, or if an error occurs prior to resolution.
419   ///
420   /// The OnReady callback will be called once all requested symbols are ready,
421   /// or if an error occurs after resolution but before all symbols are ready.
422   ///
423   /// If all symbols are found, the RegisterDependencies function will be called
424   /// while the session lock is held. This gives clients a chance to register
425   /// dependencies for on the queried symbols for any symbols they are
426   /// materializing (if a MaterializationResponsibility instance is present,
427   /// this can be implemented by calling
428   /// MaterializationResponsibility::addDependencies). If there are no
429   /// dependenant symbols for this query (e.g. it is being made by a top level
430   /// client to get an address to call) then the value NoDependenciesToRegister
431   /// can be used.
432   void lookup(const VSOList &VSOs, const SymbolNameSet &Symbols,
433               SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady,
434               RegisterDependenciesFunction RegisterDependencies);
435 
436   /// Blocking version of lookup above. Returns the resolved symbol map.
437   /// If WaitUntilReady is true (the default), will not return until all
438   /// requested symbols are ready (or an error occurs). If WaitUntilReady is
439   /// false, will return as soon as all requested symbols are resolved,
440   /// or an error occurs. If WaitUntilReady is false and an error occurs
441   /// after resolution, the function will return a success value, but the
442   /// error will be reported via reportErrors.
443   Expected<SymbolMap> lookup(const VSOList &VSOs, const SymbolNameSet &Symbols,
444                              RegisterDependenciesFunction RegisterDependencies,
445                              bool WaitUntilReady = true);
446 
447   /// Materialize the given unit.
dispatchMaterialization(VSO & V,std::unique_ptr<MaterializationUnit> MU)448   void dispatchMaterialization(VSO &V,
449                                std::unique_ptr<MaterializationUnit> MU) {
450     DispatchMaterialization(V, std::move(MU));
451   }
452 
453 private:
logErrorsToStdErr(Error Err)454   static void logErrorsToStdErr(Error Err) {
455     logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
456   }
457 
458   static void
materializeOnCurrentThread(VSO & V,std::unique_ptr<MaterializationUnit> MU)459   materializeOnCurrentThread(VSO &V, std::unique_ptr<MaterializationUnit> MU) {
460     MU->doMaterialize(V);
461   }
462 
463   void runOutstandingMUs();
464 
465   mutable std::recursive_mutex SessionMutex;
466   std::shared_ptr<SymbolStringPool> SSP;
467   VModuleKey LastKey = 0;
468   ErrorReporter ReportError = logErrorsToStdErr;
469   DispatchMaterializationFunction DispatchMaterialization =
470       materializeOnCurrentThread;
471 
472   // FIXME: Remove this (and runOutstandingMUs) once the linking layer works
473   //        with callbacks from asynchronous queries.
474   mutable std::recursive_mutex OutstandingMUsMutex;
475   std::vector<std::pair<VSO *, std::unique_ptr<MaterializationUnit>>>
476       OutstandingMUs;
477 };
478 
479 /// A symbol query that returns results via a callback when results are
480 ///        ready.
481 ///
482 /// makes a callback when all symbols are available.
483 class AsynchronousSymbolQuery {
484   friend class ExecutionSessionBase;
485   friend class VSO;
486 
487 public:
488 
489   /// Create a query for the given symbols, notify-resolved and
490   ///        notify-ready callbacks.
491   AsynchronousSymbolQuery(const SymbolNameSet &Symbols,
492                           SymbolsResolvedCallback NotifySymbolsResolved,
493                           SymbolsReadyCallback NotifySymbolsReady);
494 
495   /// Set the resolved symbol information for the given symbol name.
496   void resolve(const SymbolStringPtr &Name, JITEvaluatedSymbol Sym);
497 
498   /// Returns true if all symbols covered by this query have been
499   ///        resolved.
isFullyResolved()500   bool isFullyResolved() const { return NotYetResolvedCount == 0; }
501 
502   /// Call the NotifySymbolsResolved callback.
503   ///
504   /// This should only be called if all symbols covered by the query have been
505   /// resolved.
506   void handleFullyResolved();
507 
508   /// Notify the query that a requested symbol is ready for execution.
509   void notifySymbolReady();
510 
511   /// Returns true if all symbols covered by this query are ready.
isFullyReady()512   bool isFullyReady() const { return NotYetReadyCount == 0; }
513 
514   /// Calls the NotifySymbolsReady callback.
515   ///
516   /// This should only be called if all symbols covered by this query are ready.
517   void handleFullyReady();
518 
519 private:
520   void addQueryDependence(VSO &V, SymbolStringPtr Name);
521 
522   void removeQueryDependence(VSO &V, const SymbolStringPtr &Name);
523 
524   bool canStillFail();
525 
526   void handleFailed(Error Err);
527 
528   void detach();
529 
530   SymbolsResolvedCallback NotifySymbolsResolved;
531   SymbolsReadyCallback NotifySymbolsReady;
532   SymbolDependenceMap QueryRegistrations;
533   SymbolMap ResolvedSymbols;
534   size_t NotYetResolvedCount;
535   size_t NotYetReadyCount;
536 };
537 
538 /// A symbol table that supports asynchoronous symbol queries.
539 ///
540 /// Represents a virtual shared object. Instances can not be copied or moved, so
541 /// their addresses may be used as keys for resource management.
542 /// VSO state changes must be made via an ExecutionSession to guarantee that
543 /// they are synchronized with respect to other VSO operations.
544 class VSO {
545   friend class AsynchronousSymbolQuery;
546   friend class ExecutionSession;
547   friend class ExecutionSessionBase;
548   friend class MaterializationResponsibility;
549 public:
550   using FallbackDefinitionGeneratorFunction =
551       std::function<SymbolNameSet(VSO &Parent, const SymbolNameSet &Names)>;
552 
553   using AsynchronousSymbolQuerySet =
554       std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
555 
556   VSO(const VSO &) = delete;
557   VSO &operator=(const VSO &) = delete;
558   VSO(VSO &&) = delete;
559   VSO &operator=(VSO &&) = delete;
560 
561   /// Get the name for this VSO.
getName()562   const std::string &getName() const { return VSOName; }
563 
564   /// Get a reference to the ExecutionSession for this VSO.
getExecutionSession()565   ExecutionSessionBase &getExecutionSession() const { return ES; }
566 
567   /// Set a fallback defenition generator. If set, lookup and lookupFlags will
568   /// pass the unresolved symbols set to the fallback definition generator,
569   /// allowing it to add a new definition to the VSO.
setFallbackDefinitionGenerator(FallbackDefinitionGeneratorFunction FallbackDefinitionGenerator)570   void setFallbackDefinitionGenerator(
571       FallbackDefinitionGeneratorFunction FallbackDefinitionGenerator) {
572     this->FallbackDefinitionGenerator = std::move(FallbackDefinitionGenerator);
573   }
574 
575   /// Set the search order to be used when fixing up definitions in VSO.
576   /// This will replace the previous search order, and apply to any symbol
577   /// resolutions made for definitions in this VSO after the call to
578   /// setSearchOrder (even if the definition itself was added before the
579   /// call).
580   ///
581   /// If SearchThisVSOFirst is set, which by default it is, then this VSO will
582   /// add itself to the beginning of the SearchOrder (Clients should *not*
583   /// put this VSO in the list in this case, to avoid redundant lookups).
584   ///
585   /// If SearchThisVSOFirst is false then the search order will be used as
586   /// given. The main motivation for this feature is to support deliberate
587   /// shadowing of symbols in this VSO by a facade VSO. For example, the
588   /// facade may resolve function names to stubs, and the stubs may compile
589   /// lazily by looking up symbols in this dylib. Adding the facade dylib
590   /// as the first in the search order (instead of this dylib) ensures that
591   /// definitions within this dylib resolve to the lazy-compiling stubs,
592   /// rather than immediately materializing the definitions in this dylib.
593   void setSearchOrder(VSOList NewSearchOrder, bool SearchThisVSOFirst = true);
594 
595   /// Add the given VSO to the search order for definitions in this VSO.
596   void addToSearchOrder(VSO &V);
597 
598   /// Replace OldV with NewV in the search order if OldV is present. Otherwise
599   /// this operation is a no-op.
600   void replaceInSearchOrder(VSO &OldV, VSO &NewV);
601 
602   /// Remove the given VSO from the search order for this VSO if it is
603   /// present. Otherwise this operation is a no-op.
604   void removeFromSearchOrder(VSO &V);
605 
606   /// Do something with the search order (run under the session lock).
607   template <typename Func>
608   auto withSearchOrderDo(Func &&F)
609       -> decltype(F(std::declval<const VSOList &>())) {
610     return ES.runSessionLocked([&]() { return F(SearchOrder); });
611   }
612 
613   /// Define all symbols provided by the materialization unit to be part
614   ///        of the given VSO.
615   template <typename UniquePtrToMaterializationUnit>
616   typename std::enable_if<
617       std::is_convertible<
618           typename std::decay<UniquePtrToMaterializationUnit>::type,
619           std::unique_ptr<MaterializationUnit>>::value,
620       Error>::type
define(UniquePtrToMaterializationUnit && MU)621   define(UniquePtrToMaterializationUnit &&MU) {
622     return ES.runSessionLocked([&, this]() -> Error {
623       assert(MU && "Can't define with a null MU");
624 
625       if (auto Err = defineImpl(*MU))
626         return Err;
627 
628       /// defineImpl succeeded.
629       auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
630       for (auto &KV : UMI->MU->getSymbols())
631         UnmaterializedInfos[KV.first] = UMI;
632 
633       return Error::success();
634     });
635   }
636 
637   /// Search the given VSO for the symbols in Symbols. If found, store
638   ///        the flags for each symbol in Flags. Returns any unresolved symbols.
639   SymbolFlagsMap lookupFlags(const SymbolNameSet &Names);
640 
641   /// Dump current VSO state to OS.
642   void dump(raw_ostream &OS);
643 
644   /// FIXME: Remove this when we remove the old ORC layers.
645   /// Search the given VSOs in order for the symbols in Symbols. Results
646   ///        (once they become available) will be returned via the given Query.
647   ///
648   /// If any symbol is not found then the unresolved symbols will be returned,
649   /// and the query will not be applied. The Query is not failed and can be
650   /// re-used in a subsequent lookup once the symbols have been added, or
651   /// manually failed.
652   SymbolNameSet legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
653                              SymbolNameSet Names);
654 
655 private:
656   using AsynchronousSymbolQueryList =
657       std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
658 
659   struct UnmaterializedInfo {
UnmaterializedInfoUnmaterializedInfo660     UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU)
661         : MU(std::move(MU)) {}
662 
663     std::unique_ptr<MaterializationUnit> MU;
664   };
665 
666   using UnmaterializedInfosMap =
667       std::map<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
668 
669   struct MaterializingInfo {
670     AsynchronousSymbolQueryList PendingQueries;
671     SymbolDependenceMap Dependants;
672     SymbolDependenceMap UnfinalizedDependencies;
673     bool IsFinalized = false;
674   };
675 
676   using MaterializingInfosMap = std::map<SymbolStringPtr, MaterializingInfo>;
677 
678   using LookupImplActionFlags = enum {
679     None = 0,
680     NotifyFullyResolved = 1 << 0U,
681     NotifyFullyReady = 1 << 1U,
682     LLVM_MARK_AS_BITMASK_ENUM(NotifyFullyReady)
683   };
684 
685   VSO(ExecutionSessionBase &ES, std::string Name);
686 
687   Error defineImpl(MaterializationUnit &MU);
688 
689   SymbolNameSet lookupFlagsImpl(SymbolFlagsMap &Flags,
690                                 const SymbolNameSet &Names);
691 
692   void lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
693                   SymbolNameSet &Unresolved, MaterializationUnitList &MUs);
694 
695   void lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
696                       SymbolNameSet &Unresolved, MaterializationUnitList &MUs);
697 
698   LookupImplActionFlags
699   lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
700              std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
701              SymbolNameSet &Unresolved);
702 
703   void detachQueryHelper(AsynchronousSymbolQuery &Q,
704                          const SymbolNameSet &QuerySymbols);
705 
706   void transferFinalizedNodeDependencies(MaterializingInfo &DependantMI,
707                                          const SymbolStringPtr &DependantName,
708                                          MaterializingInfo &FinalizedMI);
709 
710   Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
711 
712   void replace(std::unique_ptr<MaterializationUnit> MU);
713 
714   SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags);
715 
716   void addDependencies(const SymbolStringPtr &Name,
717                        const SymbolDependenceMap &Dependants);
718 
719   void resolve(const SymbolMap &Resolved);
720 
721   void finalize(const SymbolFlagsMap &Finalized);
722 
723   void notifyFailed(const SymbolNameSet &FailedSymbols);
724 
725   ExecutionSessionBase &ES;
726   std::string VSOName;
727   SymbolMap Symbols;
728   UnmaterializedInfosMap UnmaterializedInfos;
729   MaterializingInfosMap MaterializingInfos;
730   FallbackDefinitionGeneratorFunction FallbackDefinitionGenerator;
731   VSOList SearchOrder;
732 };
733 
734 /// An ExecutionSession represents a running JIT program.
735 class ExecutionSession : public ExecutionSessionBase {
736 public:
737   using ErrorReporter = std::function<void(Error)>;
738 
739   using DispatchMaterializationFunction =
740       std::function<void(VSO &V, std::unique_ptr<MaterializationUnit> MU)>;
741 
742   /// Construct an ExecutionEngine.
743   ///
744   /// SymbolStringPools may be shared between ExecutionSessions.
745   ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr)
ExecutionSessionBase(std::move (SSP))746       : ExecutionSessionBase(std::move(SSP)) {}
747 
748   /// Add a new VSO to this ExecutionSession.
749   VSO &createVSO(std::string Name);
750 
751 private:
752   std::vector<std::unique_ptr<VSO>> VSOs;
753 };
754 
755 /// Look up the given names in the given VSOs.
756 /// VSOs will be searched in order and no VSO pointer may be null.
757 /// All symbols must be found within the given VSOs or an error
758 /// will be returned.
759 Expected<SymbolMap> lookup(const VSOList &VSOs, SymbolNameSet Names);
760 
761 /// Look up a symbol by searching a list of VSOs.
762 Expected<JITEvaluatedSymbol> lookup(const VSOList &VSOs, SymbolStringPtr Name);
763 
764 /// Mangles symbol names then uniques them in the context of an
765 /// ExecutionSession.
766 class MangleAndInterner {
767 public:
768   MangleAndInterner(ExecutionSessionBase &ES, const DataLayout &DL);
769   SymbolStringPtr operator()(StringRef Name);
770 
771 private:
772   ExecutionSessionBase &ES;
773   const DataLayout &DL;
774 };
775 
776 } // End namespace orc
777 } // End namespace llvm
778 
779 #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H
780