LazyReexports.h 6.8 KB

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