//===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Contains core ORC APIs. // //===----------------------------------------------------------------------===// #ifndef LLVM_EXECUTIONENGINE_ORC_CORE_H #define LLVM_EXECUTIONENGINE_ORC_CORE_H #include "llvm/ADT/BitmaskEnum.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" #include "llvm/IR/Module.h" #include #include #include #include #include namespace llvm { namespace orc { // Forward declare some classes. class AsynchronousSymbolQuery; class ExecutionSession; class MaterializationUnit; class MaterializationResponsibility; class VSO; /// VModuleKey provides a unique identifier (allocated and managed by /// ExecutionSessions) for a module added to the JIT. using VModuleKey = uint64_t; /// A set of symbol names (represented by SymbolStringPtrs for // efficiency). using SymbolNameSet = std::set; /// Render a SymbolNameSet to an ostream. raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols); /// A map from symbol names (as SymbolStringPtrs) to JITSymbols /// (address/flags pairs). using SymbolMap = std::map; /// Render a SymbolMap to an ostream. raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols); /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags. using SymbolFlagsMap = std::map; /// Render a SymbolMap to an ostream. raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &Symbols); /// A base class for materialization failures that allows the failing /// symbols to be obtained for logging. using SymbolDependenceMap = std::map; /// Render a SymbolDependendeMap. raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps); /// A list of VSO pointers. using VSOList = std::vector; /// Render a VSOList. raw_ostream &operator<<(raw_ostream &OS, const VSOList &VSOs); /// Callback to notify client that symbols have been resolved. using SymbolsResolvedCallback = std::function)>; /// Callback to notify client that symbols are ready for execution. using SymbolsReadyCallback = std::function; /// Callback to register the dependencies for a given query. using RegisterDependenciesFunction = std::function; /// This can be used as the value for a RegisterDependenciesFunction if there /// are no dependants to register with. extern RegisterDependenciesFunction NoDependenciesToRegister; /// Used to notify a VSO that the given set of symbols failed to materialize. class FailedToMaterialize : public ErrorInfo { public: static char ID; FailedToMaterialize(SymbolNameSet Symbols); std::error_code convertToErrorCode() const override; void log(raw_ostream &OS) const override; const SymbolNameSet &getSymbols() const { return Symbols; } private: SymbolNameSet Symbols; }; /// Used to notify clients when symbols can not be found during a lookup. class SymbolsNotFound : public ErrorInfo { public: static char ID; SymbolsNotFound(SymbolNameSet Symbols); std::error_code convertToErrorCode() const override; void log(raw_ostream &OS) const override; const SymbolNameSet &getSymbols() const { return Symbols; } private: SymbolNameSet Symbols; }; /// Tracks responsibility for materialization, and mediates interactions between /// MaterializationUnits and VSOs. /// /// An instance of this class is passed to MaterializationUnits when their /// materialize method is called. It allows MaterializationUnits to resolve and /// finalize symbols, or abandon materialization by notifying any unmaterialized /// symbols of an error. class MaterializationResponsibility { friend class MaterializationUnit; public: MaterializationResponsibility(MaterializationResponsibility &&) = default; MaterializationResponsibility & operator=(MaterializationResponsibility &&) = default; /// Destruct a MaterializationResponsibility instance. In debug mode /// this asserts that all symbols being tracked have been either /// finalized or notified of an error. ~MaterializationResponsibility(); /// Returns the target VSO that these symbols are being materialized /// into. VSO &getTargetVSO() const { return V; } /// Returns the symbol flags map for this responsibility instance. SymbolFlagsMap getSymbols() { return SymbolFlags; } /// Returns the names of any symbols covered by this /// MaterializationResponsibility object that have queries pending. This /// information can be used to return responsibility for unrequested symbols /// back to the VSO via the delegate method. SymbolNameSet getRequestedSymbols(); /// Resolves the given symbols. Individual calls to this method may /// resolve a subset of the symbols, but all symbols must have been /// resolved prior to calling finalize. void resolve(const SymbolMap &Symbols); /// Finalizes all symbols tracked by this instance. void finalize(); /// Adds new symbols to the VSO and this responsibility instance. /// VSO entries start out in the materializing state. /// /// This method can be used by materialization units that want to add /// additional symbols at materialization time (e.g. stubs, compile /// callbacks, metadata). Error defineMaterializing(const SymbolFlagsMap &SymbolFlags); /// Notify all unfinalized symbols that an error has occurred. /// This will remove all symbols covered by this MaterializationResponsibilty /// from V, and send an error to any queries waiting on these symbols. void failMaterialization(); /// Transfers responsibility to the given MaterializationUnit for all /// symbols defined by that MaterializationUnit. This allows /// materializers to break up work based on run-time information (e.g. /// by introspecting which symbols have actually been looked up and /// materializing only those). void replace(std::unique_ptr MU); /// Delegates responsibility for the given symbols to the returned /// materialization responsibility. Useful for breaking up work between /// threads, or different kinds of materialization processes. MaterializationResponsibility delegate(const SymbolNameSet &Symbols); void addDependencies(const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies); /// Add dependencies that apply to all symbols covered by this instance. void addDependenciesForAll(const SymbolDependenceMap &Dependencies); private: /// Create a MaterializationResponsibility for the given VSO and /// initial symbols. MaterializationResponsibility(VSO &V, SymbolFlagsMap SymbolFlags); VSO &V; SymbolFlagsMap SymbolFlags; }; /// A MaterializationUnit represents a set of symbol definitions that can /// be materialized as a group, or individually discarded (when /// overriding definitions are encountered). /// /// MaterializationUnits are used when providing lazy definitions of symbols to /// VSOs. The VSO will call materialize when the address of a symbol is /// requested via the lookup method. The VSO will call discard if a stronger /// definition is added or already present. class MaterializationUnit { public: MaterializationUnit(SymbolFlagsMap InitalSymbolFlags) : SymbolFlags(std::move(InitalSymbolFlags)) {} virtual ~MaterializationUnit() {} /// Return the set of symbols that this source provides. const SymbolFlagsMap &getSymbols() const { return SymbolFlags; } /// Called by materialization dispatchers (see /// ExecutionSession::DispatchMaterializationFunction) to trigger /// materialization of this MaterializationUnit. void doMaterialize(VSO &V) { materialize(MaterializationResponsibility(V, std::move(SymbolFlags))); } /// Called by VSOs to notify MaterializationUnits that the given symbol has /// been overridden. void doDiscard(const VSO &V, SymbolStringPtr Name) { SymbolFlags.erase(Name); discard(V, std::move(Name)); } protected: SymbolFlagsMap SymbolFlags; private: virtual void anchor(); /// Implementations of this method should materialize all symbols /// in the materialzation unit, except for those that have been /// previously discarded. virtual void materialize(MaterializationResponsibility R) = 0; /// Implementations of this method should discard the given symbol /// from the source (e.g. if the source is an LLVM IR Module and the /// symbol is a function, delete the function body or mark it available /// externally). virtual void discard(const VSO &V, SymbolStringPtr Name) = 0; }; using MaterializationUnitList = std::vector>; /// A MaterializationUnit implementation for pre-existing absolute symbols. /// /// All symbols will be resolved and marked ready as soon as the unit is /// materialized. class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit { public: AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols); private: void materialize(MaterializationResponsibility R) override; void discard(const VSO &V, SymbolStringPtr Name) override; static SymbolFlagsMap extractFlags(const SymbolMap &Symbols); SymbolMap Symbols; }; /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols. /// Useful for inserting absolute symbols into a VSO. E.g.: /// \code{.cpp} /// VSO &V = ...; /// SymbolStringPtr Foo = ...; /// JITEvaluatedSymbol FooSym = ...; /// if (auto Err = V.define(absoluteSymbols({{Foo, FooSym}}))) /// return Err; /// \endcode /// inline std::unique_ptr absoluteSymbols(SymbolMap Symbols) { return llvm::make_unique( std::move(Symbols)); } struct SymbolAliasMapEntry { SymbolAliasMapEntry() = default; SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags) : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {} SymbolStringPtr Aliasee; JITSymbolFlags AliasFlags; }; /// A map of Symbols to (Symbol, Flags) pairs. using SymbolAliasMap = std::map; /// A materialization unit for symbol aliases. Allows existing symbols to be /// aliased with alternate flags. class ReExportsMaterializationUnit : public MaterializationUnit { public: /// SourceVSO is allowed to be nullptr, in which case the source VSO is /// taken to be whatever VSO these definitions are materialized in. This /// is useful for defining aliases within a VSO. /// /// Note: Care must be taken that no sets of aliases form a cycle, as such /// a cycle will result in a deadlock when any symbol in the cycle is /// resolved. ReExportsMaterializationUnit(VSO *SourceVSO, SymbolAliasMap Aliases); private: void materialize(MaterializationResponsibility R) override; void discard(const VSO &V, SymbolStringPtr Name) override; static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases); VSO *SourceVSO = nullptr; SymbolAliasMap Aliases; }; /// Create a ReExportsMaterializationUnit with the given aliases. /// Useful for defining symbol aliases.: E.g., given a VSO V containing symbols /// "foo" and "bar", we can define aliases "baz" (for "foo") and "qux" (for /// "bar") with: /// \code{.cpp} /// SymbolStringPtr Baz = ...; /// SymbolStringPtr Qux = ...; /// if (auto Err = V.define(symbolAliases({ /// {Baz, { Foo, JITSymbolFlags::Exported }}, /// {Qux, { Bar, JITSymbolFlags::Weak }}})) /// return Err; /// \endcode inline std::unique_ptr symbolAliases(SymbolAliasMap Aliases) { return llvm::make_unique(nullptr, std::move(Aliases)); } /// Create a materialization unit for re-exporting symbols from another VSO /// with alternative names/flags. inline std::unique_ptr reexports(VSO &SourceV, SymbolAliasMap Aliases) { return llvm::make_unique(&SourceV, std::move(Aliases)); } /// Build a SymbolAliasMap for the common case where you want to re-export /// symbols from another VSO with the same linkage/flags. Expected buildSimpleReexportsAliasMap(VSO &SourceV, const SymbolNameSet &Symbols); /// Base utilities for ExecutionSession. class ExecutionSessionBase { // FIXME: Remove this when we remove the old ORC layers. friend class VSO; public: /// For reporting errors. using ErrorReporter = std::function; /// For dispatching MaterializationUnit::materialize calls. using DispatchMaterializationFunction = std::function MU)>; /// Construct an ExecutionSessionBase. /// /// SymbolStringPools may be shared between ExecutionSessions. ExecutionSessionBase(std::shared_ptr SSP = nullptr) : SSP(SSP ? std::move(SSP) : std::make_shared()) {} /// Returns the SymbolStringPool for this ExecutionSession. SymbolStringPool &getSymbolStringPool() const { return *SSP; } /// Run the given lambda with the session mutex locked. template auto runSessionLocked(Func &&F) -> decltype(F()) { std::lock_guard Lock(SessionMutex); return F(); } /// Set the error reporter function. ExecutionSessionBase &setErrorReporter(ErrorReporter ReportError) { this->ReportError = std::move(ReportError); return *this; } /// Set the materialization dispatch function. ExecutionSessionBase &setDispatchMaterialization( DispatchMaterializationFunction DispatchMaterialization) { this->DispatchMaterialization = std::move(DispatchMaterialization); return *this; } /// Report a error for this execution session. /// /// Unhandled errors can be sent here to log them. void reportError(Error Err) { ReportError(std::move(Err)); } /// Allocate a module key for a new module to add to the JIT. VModuleKey allocateVModule() { return ++LastKey; } /// Return a module key to the ExecutionSession so that it can be /// re-used. This should only be done once all resources associated /// with the original key have been released. void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */ } void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err); using LegacyAsyncLookupFunction = std::function Q, SymbolNameSet Names)>; /// A legacy lookup function for JITSymbolResolverAdapter. /// Do not use -- this will be removed soon. Expected legacyLookup(ExecutionSessionBase &ES, LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names, bool WaiUntilReady, RegisterDependenciesFunction RegisterDependencies); /// Search the given VSO list for the given symbols. /// /// /// The OnResolve callback will be called once all requested symbols are /// resolved, or if an error occurs prior to resolution. /// /// The OnReady callback will be called once all requested symbols are ready, /// or if an error occurs after resolution but before all symbols are ready. /// /// If all symbols are found, the RegisterDependencies function will be called /// while the session lock is held. This gives clients a chance to register /// dependencies for on the queried symbols for any symbols they are /// materializing (if a MaterializationResponsibility instance is present, /// this can be implemented by calling /// MaterializationResponsibility::addDependencies). If there are no /// dependenant symbols for this query (e.g. it is being made by a top level /// client to get an address to call) then the value NoDependenciesToRegister /// can be used. void lookup(const VSOList &VSOs, const SymbolNameSet &Symbols, SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady, RegisterDependenciesFunction RegisterDependencies); /// Blocking version of lookup above. Returns the resolved symbol map. /// If WaitUntilReady is true (the default), will not return until all /// requested symbols are ready (or an error occurs). If WaitUntilReady is /// false, will return as soon as all requested symbols are resolved, /// or an error occurs. If WaitUntilReady is false and an error occurs /// after resolution, the function will return a success value, but the /// error will be reported via reportErrors. Expected lookup(const VSOList &VSOs, const SymbolNameSet &Symbols, RegisterDependenciesFunction RegisterDependencies, bool WaitUntilReady = true); /// Materialize the given unit. void dispatchMaterialization(VSO &V, std::unique_ptr MU) { DispatchMaterialization(V, std::move(MU)); } private: static void logErrorsToStdErr(Error Err) { logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: "); } static void materializeOnCurrentThread(VSO &V, std::unique_ptr MU) { MU->doMaterialize(V); } void runOutstandingMUs(); mutable std::recursive_mutex SessionMutex; std::shared_ptr SSP; VModuleKey LastKey = 0; ErrorReporter ReportError = logErrorsToStdErr; DispatchMaterializationFunction DispatchMaterialization = materializeOnCurrentThread; // FIXME: Remove this (and runOutstandingMUs) once the linking layer works // with callbacks from asynchronous queries. mutable std::recursive_mutex OutstandingMUsMutex; std::vector>> OutstandingMUs; }; /// A symbol query that returns results via a callback when results are /// ready. /// /// makes a callback when all symbols are available. class AsynchronousSymbolQuery { friend class ExecutionSessionBase; friend class VSO; public: /// Create a query for the given symbols, notify-resolved and /// notify-ready callbacks. AsynchronousSymbolQuery(const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved, SymbolsReadyCallback NotifySymbolsReady); /// Set the resolved symbol information for the given symbol name. void resolve(const SymbolStringPtr &Name, JITEvaluatedSymbol Sym); /// Returns true if all symbols covered by this query have been /// resolved. bool isFullyResolved() const { return NotYetResolvedCount == 0; } /// Call the NotifySymbolsResolved callback. /// /// This should only be called if all symbols covered by the query have been /// resolved. void handleFullyResolved(); /// Notify the query that a requested symbol is ready for execution. void notifySymbolReady(); /// Returns true if all symbols covered by this query are ready. bool isFullyReady() const { return NotYetReadyCount == 0; } /// Calls the NotifySymbolsReady callback. /// /// This should only be called if all symbols covered by this query are ready. void handleFullyReady(); private: void addQueryDependence(VSO &V, SymbolStringPtr Name); void removeQueryDependence(VSO &V, const SymbolStringPtr &Name); bool canStillFail(); void handleFailed(Error Err); void detach(); SymbolsResolvedCallback NotifySymbolsResolved; SymbolsReadyCallback NotifySymbolsReady; SymbolDependenceMap QueryRegistrations; SymbolMap ResolvedSymbols; size_t NotYetResolvedCount; size_t NotYetReadyCount; }; /// A symbol table that supports asynchoronous symbol queries. /// /// Represents a virtual shared object. Instances can not be copied or moved, so /// their addresses may be used as keys for resource management. /// VSO state changes must be made via an ExecutionSession to guarantee that /// they are synchronized with respect to other VSO operations. class VSO { friend class AsynchronousSymbolQuery; friend class ExecutionSession; friend class ExecutionSessionBase; friend class MaterializationResponsibility; public: using FallbackDefinitionGeneratorFunction = std::function; using AsynchronousSymbolQuerySet = std::set>; VSO(const VSO &) = delete; VSO &operator=(const VSO &) = delete; VSO(VSO &&) = delete; VSO &operator=(VSO &&) = delete; /// Get the name for this VSO. const std::string &getName() const { return VSOName; } /// Get a reference to the ExecutionSession for this VSO. ExecutionSessionBase &getExecutionSession() const { return ES; } /// Set a fallback defenition generator. If set, lookup and lookupFlags will /// pass the unresolved symbols set to the fallback definition generator, /// allowing it to add a new definition to the VSO. void setFallbackDefinitionGenerator( FallbackDefinitionGeneratorFunction FallbackDefinitionGenerator) { this->FallbackDefinitionGenerator = std::move(FallbackDefinitionGenerator); } /// Set the search order to be used when fixing up definitions in VSO. /// This will replace the previous search order, and apply to any symbol /// resolutions made for definitions in this VSO after the call to /// setSearchOrder (even if the definition itself was added before the /// call). /// /// If SearchThisVSOFirst is set, which by default it is, then this VSO will /// add itself to the beginning of the SearchOrder (Clients should *not* /// put this VSO in the list in this case, to avoid redundant lookups). /// /// If SearchThisVSOFirst is false then the search order will be used as /// given. The main motivation for this feature is to support deliberate /// shadowing of symbols in this VSO by a facade VSO. For example, the /// facade may resolve function names to stubs, and the stubs may compile /// lazily by looking up symbols in this dylib. Adding the facade dylib /// as the first in the search order (instead of this dylib) ensures that /// definitions within this dylib resolve to the lazy-compiling stubs, /// rather than immediately materializing the definitions in this dylib. void setSearchOrder(VSOList NewSearchOrder, bool SearchThisVSOFirst = true); /// Add the given VSO to the search order for definitions in this VSO. void addToSearchOrder(VSO &V); /// Replace OldV with NewV in the search order if OldV is present. Otherwise /// this operation is a no-op. void replaceInSearchOrder(VSO &OldV, VSO &NewV); /// Remove the given VSO from the search order for this VSO if it is /// present. Otherwise this operation is a no-op. void removeFromSearchOrder(VSO &V); /// Do something with the search order (run under the session lock). template auto withSearchOrderDo(Func &&F) -> decltype(F(std::declval())) { return ES.runSessionLocked([&]() { return F(SearchOrder); }); } /// Define all symbols provided by the materialization unit to be part /// of the given VSO. template typename std::enable_if< std::is_convertible< typename std::decay::type, std::unique_ptr>::value, Error>::type define(UniquePtrToMaterializationUnit &&MU) { return ES.runSessionLocked([&, this]() -> Error { assert(MU && "Can't define with a null MU"); if (auto Err = defineImpl(*MU)) return Err; /// defineImpl succeeded. auto UMI = std::make_shared(std::move(MU)); for (auto &KV : UMI->MU->getSymbols()) UnmaterializedInfos[KV.first] = UMI; return Error::success(); }); } /// Search the given VSO for the symbols in Symbols. If found, store /// the flags for each symbol in Flags. Returns any unresolved symbols. SymbolFlagsMap lookupFlags(const SymbolNameSet &Names); /// Dump current VSO state to OS. void dump(raw_ostream &OS); /// FIXME: Remove this when we remove the old ORC layers. /// Search the given VSOs in order for the symbols in Symbols. Results /// (once they become available) will be returned via the given Query. /// /// If any symbol is not found then the unresolved symbols will be returned, /// and the query will not be applied. The Query is not failed and can be /// re-used in a subsequent lookup once the symbols have been added, or /// manually failed. SymbolNameSet legacyLookup(std::shared_ptr Q, SymbolNameSet Names); private: using AsynchronousSymbolQueryList = std::vector>; struct UnmaterializedInfo { UnmaterializedInfo(std::unique_ptr MU) : MU(std::move(MU)) {} std::unique_ptr MU; }; using UnmaterializedInfosMap = std::map>; struct MaterializingInfo { AsynchronousSymbolQueryList PendingQueries; SymbolDependenceMap Dependants; SymbolDependenceMap UnfinalizedDependencies; bool IsFinalized = false; }; using MaterializingInfosMap = std::map; using LookupImplActionFlags = enum { None = 0, NotifyFullyResolved = 1 << 0U, NotifyFullyReady = 1 << 1U, LLVM_MARK_AS_BITMASK_ENUM(NotifyFullyReady) }; VSO(ExecutionSessionBase &ES, std::string Name); Error defineImpl(MaterializationUnit &MU); SymbolNameSet lookupFlagsImpl(SymbolFlagsMap &Flags, const SymbolNameSet &Names); void lodgeQuery(std::shared_ptr &Q, SymbolNameSet &Unresolved, MaterializationUnitList &MUs); void lodgeQueryImpl(std::shared_ptr &Q, SymbolNameSet &Unresolved, MaterializationUnitList &MUs); LookupImplActionFlags lookupImpl(std::shared_ptr &Q, std::vector> &MUs, SymbolNameSet &Unresolved); void detachQueryHelper(AsynchronousSymbolQuery &Q, const SymbolNameSet &QuerySymbols); void transferFinalizedNodeDependencies(MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName, MaterializingInfo &FinalizedMI); Error defineMaterializing(const SymbolFlagsMap &SymbolFlags); void replace(std::unique_ptr MU); SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags); void addDependencies(const SymbolStringPtr &Name, const SymbolDependenceMap &Dependants); void resolve(const SymbolMap &Resolved); void finalize(const SymbolFlagsMap &Finalized); void notifyFailed(const SymbolNameSet &FailedSymbols); ExecutionSessionBase &ES; std::string VSOName; SymbolMap Symbols; UnmaterializedInfosMap UnmaterializedInfos; MaterializingInfosMap MaterializingInfos; FallbackDefinitionGeneratorFunction FallbackDefinitionGenerator; VSOList SearchOrder; }; /// An ExecutionSession represents a running JIT program. class ExecutionSession : public ExecutionSessionBase { public: using ErrorReporter = std::function; using DispatchMaterializationFunction = std::function MU)>; /// Construct an ExecutionEngine. /// /// SymbolStringPools may be shared between ExecutionSessions. ExecutionSession(std::shared_ptr SSP = nullptr) : ExecutionSessionBase(std::move(SSP)) {} /// Add a new VSO to this ExecutionSession. VSO &createVSO(std::string Name); private: std::vector> VSOs; }; /// Look up the given names in the given VSOs. /// VSOs will be searched in order and no VSO pointer may be null. /// All symbols must be found within the given VSOs or an error /// will be returned. Expected lookup(const VSOList &VSOs, SymbolNameSet Names); /// Look up a symbol by searching a list of VSOs. Expected lookup(const VSOList &VSOs, SymbolStringPtr Name); /// Mangles symbol names then uniques them in the context of an /// ExecutionSession. class MangleAndInterner { public: MangleAndInterner(ExecutionSessionBase &ES, const DataLayout &DL); SymbolStringPtr operator()(StringRef Name); private: ExecutionSessionBase &ES; const DataLayout &DL; }; } // End namespace orc } // End namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H