Home | History | Annotate | Line # | Download | only in Orc
      1 //===------ LazyReexports.h -- Utilities for lazy reexports -----*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // Lazy re-exports are similar to normal re-exports, except that for callable
     10 // symbols the definitions are replaced with trampolines that will look up and
     11 // call through to the re-exported symbol at runtime. This can be used to
     12 // enable lazy compilation.
     13 //
     14 //===----------------------------------------------------------------------===//
     15 
     16 #ifndef LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H
     17 #define LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H
     18 
     19 #include "llvm/ADT/STLExtras.h"
     20 #include "llvm/ExecutionEngine/Orc/Core.h"
     21 #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
     22 #include "llvm/ExecutionEngine/Orc/Speculation.h"
     23 
     24 namespace llvm {
     25 
     26 class Triple;
     27 
     28 namespace orc {
     29 
     30 /// Manages a set of 'lazy call-through' trampolines. These are compiler
     31 /// re-entry trampolines that are pre-bound to look up a given symbol in a given
     32 /// JITDylib, then jump to that address. Since compilation of symbols is
     33 /// triggered on first lookup, these call-through trampolines can be used to
     34 /// implement lazy compilation.
     35 ///
     36 /// The easiest way to construct these call-throughs is using the lazyReexport
     37 /// function.
     38 class LazyCallThroughManager {
     39 public:
     40   using NotifyResolvedFunction =
     41       unique_function<Error(JITTargetAddress ResolvedAddr)>;
     42 
     43   LazyCallThroughManager(ExecutionSession &ES,
     44                          JITTargetAddress ErrorHandlerAddr, TrampolinePool *TP);
     45 
     46   // Return a free call-through trampoline and bind it to look up and call
     47   // through to the given symbol.
     48   Expected<JITTargetAddress>
     49   getCallThroughTrampoline(JITDylib &SourceJD, SymbolStringPtr SymbolName,
     50                            NotifyResolvedFunction NotifyResolved);
     51 
     52   void resolveTrampolineLandingAddress(
     53       JITTargetAddress TrampolineAddr,
     54       TrampolinePool::NotifyLandingResolvedFunction NotifyLandingResolved);
     55 
     56   virtual ~LazyCallThroughManager() = default;
     57 
     58 protected:
     59   using NotifyLandingResolvedFunction =
     60       TrampolinePool::NotifyLandingResolvedFunction;
     61 
     62   struct ReexportsEntry {
     63     JITDylib *SourceJD;
     64     SymbolStringPtr SymbolName;
     65   };
     66 
     67   JITTargetAddress reportCallThroughError(Error Err);
     68   Expected<ReexportsEntry> findReexport(JITTargetAddress TrampolineAddr);
     69   Error notifyResolved(JITTargetAddress TrampolineAddr,
     70                        JITTargetAddress ResolvedAddr);
     71   void setTrampolinePool(TrampolinePool &TP) { this->TP = &TP; }
     72 
     73 private:
     74   using ReexportsMap = std::map<JITTargetAddress, ReexportsEntry>;
     75 
     76   using NotifiersMap = std::map<JITTargetAddress, NotifyResolvedFunction>;
     77 
     78   std::mutex LCTMMutex;
     79   ExecutionSession &ES;
     80   JITTargetAddress ErrorHandlerAddr;
     81   TrampolinePool *TP = nullptr;
     82   ReexportsMap Reexports;
     83   NotifiersMap Notifiers;
     84 };
     85 
     86 /// A lazy call-through manager that builds trampolines in the current process.
     87 class LocalLazyCallThroughManager : public LazyCallThroughManager {
     88 private:
     89   using NotifyTargetResolved = unique_function<void(JITTargetAddress)>;
     90 
     91   LocalLazyCallThroughManager(ExecutionSession &ES,
     92                               JITTargetAddress ErrorHandlerAddr)
     93       : LazyCallThroughManager(ES, ErrorHandlerAddr, nullptr) {}
     94 
     95   template <typename ORCABI> Error init() {
     96     auto TP = LocalTrampolinePool<ORCABI>::Create(
     97         [this](JITTargetAddress TrampolineAddr,
     98                TrampolinePool::NotifyLandingResolvedFunction
     99                    NotifyLandingResolved) {
    100           resolveTrampolineLandingAddress(TrampolineAddr,
    101                                           std::move(NotifyLandingResolved));
    102         });
    103 
    104     if (!TP)
    105       return TP.takeError();
    106 
    107     this->TP = std::move(*TP);
    108     setTrampolinePool(*this->TP);
    109     return Error::success();
    110   }
    111 
    112   std::unique_ptr<TrampolinePool> TP;
    113 
    114 public:
    115   /// Create a LocalLazyCallThroughManager using the given ABI. See
    116   /// createLocalLazyCallThroughManager.
    117   template <typename ORCABI>
    118   static Expected<std::unique_ptr<LocalLazyCallThroughManager>>
    119   Create(ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr) {
    120     auto LLCTM = std::unique_ptr<LocalLazyCallThroughManager>(
    121         new LocalLazyCallThroughManager(ES, ErrorHandlerAddr));
    122 
    123     if (auto Err = LLCTM->init<ORCABI>())
    124       return std::move(Err);
    125 
    126     return std::move(LLCTM);
    127   }
    128 };
    129 
    130 /// Create a LocalLazyCallThroughManager from the given triple and execution
    131 /// session.
    132 Expected<std::unique_ptr<LazyCallThroughManager>>
    133 createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES,
    134                                   JITTargetAddress ErrorHandlerAddr);
    135 
    136 /// A materialization unit that builds lazy re-exports. These are callable
    137 /// entry points that call through to the given symbols.
    138 /// Unlike a 'true' re-export, the address of the lazy re-export will not
    139 /// match the address of the re-exported symbol, but calling it will behave
    140 /// the same as calling the re-exported symbol.
    141 class LazyReexportsMaterializationUnit : public MaterializationUnit {
    142 public:
    143   LazyReexportsMaterializationUnit(LazyCallThroughManager &LCTManager,
    144                                    IndirectStubsManager &ISManager,
    145                                    JITDylib &SourceJD,
    146                                    SymbolAliasMap CallableAliases,
    147                                    ImplSymbolMap *SrcJDLoc);
    148 
    149   StringRef getName() const override;
    150 
    151 private:
    152   void materialize(std::unique_ptr<MaterializationResponsibility> R) override;
    153   void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
    154   static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
    155 
    156   LazyCallThroughManager &LCTManager;
    157   IndirectStubsManager &ISManager;
    158   JITDylib &SourceJD;
    159   SymbolAliasMap CallableAliases;
    160   ImplSymbolMap *AliaseeTable;
    161 };
    162 
    163 /// Define lazy-reexports based on the given SymbolAliasMap. Each lazy re-export
    164 /// is a callable symbol that will look up and dispatch to the given aliasee on
    165 /// first call. All subsequent calls will go directly to the aliasee.
    166 inline std::unique_ptr<LazyReexportsMaterializationUnit>
    167 lazyReexports(LazyCallThroughManager &LCTManager,
    168               IndirectStubsManager &ISManager, JITDylib &SourceJD,
    169               SymbolAliasMap CallableAliases,
    170               ImplSymbolMap *SrcJDLoc = nullptr) {
    171   return std::make_unique<LazyReexportsMaterializationUnit>(
    172       LCTManager, ISManager, SourceJD, std::move(CallableAliases), SrcJDLoc);
    173 }
    174 
    175 } // End namespace orc
    176 } // End namespace llvm
    177 
    178 #endif // LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H
    179