Home | History | Annotate | Download | only in Orc
      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;
     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;
    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.
    138   VSO &getTargetVSO() const { return V; }
    139 
    140   /// Returns the symbol flags map for this responsibility instance.
    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:
    207   MaterializationUnit(SymbolFlagsMap InitalSymbolFlags)
    208       : SymbolFlags(std::move(InitalSymbolFlags)) {}
    209 
    210   virtual ~MaterializationUnit() {}
    211 
    212   /// Return the set of symbols that this source provides.
    213   const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
    214 
    215   /// Called by materialization dispatchers (see
    216   /// ExecutionSession::DispatchMaterializationFunction) to trigger
    217   /// materialization of this MaterializationUnit.
    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.
    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>
    277 absoluteSymbols(SymbolMap Symbols) {
    278   return llvm::make_unique<AbsoluteSymbolsMaterializationUnit>(
    279       std::move(Symbols));
    280 }
    281 
    282 struct SymbolAliasMapEntry {
    283   SymbolAliasMapEntry() = default;
    284   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>
    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>
    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.
    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.
    376   ExecutionSessionBase &setErrorReporter(ErrorReporter ReportError) {
    377     this->ReportError = std::move(ReportError);
    378     return *this;
    379   }
    380 
    381   /// Set the materialization dispatch function.
    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.
    391   void reportError(Error Err) { ReportError(std::move(Err)); }
    392 
    393   /// Allocate a module key for a new module to add to the JIT.
    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.
    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.
    448   void dispatchMaterialization(VSO &V,
    449                                std::unique_ptr<MaterializationUnit> MU) {
    450     DispatchMaterialization(V, std::move(MU));
    451   }
    452 
    453 private:
    454   static void logErrorsToStdErr(Error Err) {
    455     logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
    456   }
    457 
    458   static void
    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.
    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.
    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.
    562   const std::string &getName() const { return VSOName; }
    563 
    564   /// Get a reference to the ExecutionSession for this VSO.
    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.
    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
    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 {
    660     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)
    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