LazyReexports.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. //===---------- LazyReexports.cpp - Utilities for lazy reexports ----------===//
  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. #include "llvm/ExecutionEngine/Orc/LazyReexports.h"
  9. #include "llvm/ADT/Triple.h"
  10. #include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
  11. #define DEBUG_TYPE "orc"
  12. namespace llvm {
  13. namespace orc {
  14. LazyCallThroughManager::LazyCallThroughManager(
  15. ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr, TrampolinePool *TP)
  16. : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(TP) {}
  17. Expected<JITTargetAddress> LazyCallThroughManager::getCallThroughTrampoline(
  18. JITDylib &SourceJD, SymbolStringPtr SymbolName,
  19. NotifyResolvedFunction NotifyResolved) {
  20. assert(TP && "TrampolinePool not set");
  21. std::lock_guard<std::mutex> Lock(LCTMMutex);
  22. auto Trampoline = TP->getTrampoline();
  23. if (!Trampoline)
  24. return Trampoline.takeError();
  25. Reexports[*Trampoline] = ReexportsEntry{&SourceJD, std::move(SymbolName)};
  26. Notifiers[*Trampoline] = std::move(NotifyResolved);
  27. return *Trampoline;
  28. }
  29. JITTargetAddress LazyCallThroughManager::reportCallThroughError(Error Err) {
  30. ES.reportError(std::move(Err));
  31. return ErrorHandlerAddr;
  32. }
  33. Expected<LazyCallThroughManager::ReexportsEntry>
  34. LazyCallThroughManager::findReexport(JITTargetAddress TrampolineAddr) {
  35. std::lock_guard<std::mutex> Lock(LCTMMutex);
  36. auto I = Reexports.find(TrampolineAddr);
  37. if (I == Reexports.end())
  38. return createStringError(inconvertibleErrorCode(),
  39. "Missing reexport for trampoline address %p",
  40. TrampolineAddr);
  41. return I->second;
  42. }
  43. Error LazyCallThroughManager::notifyResolved(JITTargetAddress TrampolineAddr,
  44. JITTargetAddress ResolvedAddr) {
  45. NotifyResolvedFunction NotifyResolved;
  46. {
  47. std::lock_guard<std::mutex> Lock(LCTMMutex);
  48. auto I = Notifiers.find(TrampolineAddr);
  49. if (I != Notifiers.end()) {
  50. NotifyResolved = std::move(I->second);
  51. Notifiers.erase(I);
  52. }
  53. }
  54. return NotifyResolved ? NotifyResolved(ResolvedAddr) : Error::success();
  55. }
  56. void LazyCallThroughManager::resolveTrampolineLandingAddress(
  57. JITTargetAddress TrampolineAddr,
  58. NotifyLandingResolvedFunction NotifyLandingResolved) {
  59. auto Entry = findReexport(TrampolineAddr);
  60. if (!Entry)
  61. return NotifyLandingResolved(reportCallThroughError(Entry.takeError()));
  62. // Declaring SLS and the callback outside of the call to ES.lookup is a
  63. // workaround to fix build failures on AIX and on z/OS platforms.
  64. SymbolLookupSet SLS({Entry->SymbolName});
  65. auto Callback = [this, TrampolineAddr, SymbolName = Entry->SymbolName,
  66. NotifyLandingResolved = std::move(NotifyLandingResolved)](
  67. Expected<SymbolMap> Result) mutable {
  68. if (Result) {
  69. assert(Result->size() == 1 && "Unexpected result size");
  70. assert(Result->count(SymbolName) && "Unexpected result value");
  71. JITTargetAddress LandingAddr = (*Result)[SymbolName].getAddress();
  72. if (auto Err = notifyResolved(TrampolineAddr, LandingAddr))
  73. NotifyLandingResolved(reportCallThroughError(std::move(Err)));
  74. else
  75. NotifyLandingResolved(LandingAddr);
  76. } else {
  77. NotifyLandingResolved(reportCallThroughError(Result.takeError()));
  78. }
  79. };
  80. ES.lookup(LookupKind::Static,
  81. makeJITDylibSearchOrder(Entry->SourceJD,
  82. JITDylibLookupFlags::MatchAllSymbols),
  83. std::move(SLS), SymbolState::Ready, std::move(Callback),
  84. NoDependenciesToRegister);
  85. }
  86. Expected<std::unique_ptr<LazyCallThroughManager>>
  87. createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES,
  88. JITTargetAddress ErrorHandlerAddr) {
  89. switch (T.getArch()) {
  90. default:
  91. return make_error<StringError>(
  92. std::string("No callback manager available for ") + T.str(),
  93. inconvertibleErrorCode());
  94. case Triple::aarch64:
  95. case Triple::aarch64_32:
  96. return LocalLazyCallThroughManager::Create<OrcAArch64>(ES,
  97. ErrorHandlerAddr);
  98. case Triple::x86:
  99. return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr);
  100. case Triple::loongarch64:
  101. return LocalLazyCallThroughManager::Create<OrcLoongArch64>(
  102. ES, ErrorHandlerAddr);
  103. case Triple::mips:
  104. return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES,
  105. ErrorHandlerAddr);
  106. case Triple::mipsel:
  107. return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES,
  108. ErrorHandlerAddr);
  109. case Triple::mips64:
  110. case Triple::mips64el:
  111. return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr);
  112. case Triple::riscv64:
  113. return LocalLazyCallThroughManager::Create<OrcRiscv64>(ES,
  114. ErrorHandlerAddr);
  115. case Triple::x86_64:
  116. if (T.getOS() == Triple::OSType::Win32)
  117. return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>(
  118. ES, ErrorHandlerAddr);
  119. else
  120. return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>(
  121. ES, ErrorHandlerAddr);
  122. }
  123. }
  124. LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit(
  125. LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager,
  126. JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc)
  127. : MaterializationUnit(extractFlags(CallableAliases)),
  128. LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD),
  129. CallableAliases(std::move(CallableAliases)), AliaseeTable(SrcJDLoc) {}
  130. StringRef LazyReexportsMaterializationUnit::getName() const {
  131. return "<Lazy Reexports>";
  132. }
  133. void LazyReexportsMaterializationUnit::materialize(
  134. std::unique_ptr<MaterializationResponsibility> R) {
  135. auto RequestedSymbols = R->getRequestedSymbols();
  136. SymbolAliasMap RequestedAliases;
  137. for (auto &RequestedSymbol : RequestedSymbols) {
  138. auto I = CallableAliases.find(RequestedSymbol);
  139. assert(I != CallableAliases.end() && "Symbol not found in alias map?");
  140. RequestedAliases[I->first] = std::move(I->second);
  141. CallableAliases.erase(I);
  142. }
  143. if (!CallableAliases.empty())
  144. if (auto Err = R->replace(lazyReexports(LCTManager, ISManager, SourceJD,
  145. std::move(CallableAliases),
  146. AliaseeTable))) {
  147. R->getExecutionSession().reportError(std::move(Err));
  148. R->failMaterialization();
  149. return;
  150. }
  151. IndirectStubsManager::StubInitsMap StubInits;
  152. for (auto &Alias : RequestedAliases) {
  153. auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline(
  154. SourceJD, Alias.second.Aliasee,
  155. [&ISManager = this->ISManager,
  156. StubSym = Alias.first](JITTargetAddress ResolvedAddr) -> Error {
  157. return ISManager.updatePointer(*StubSym, ResolvedAddr);
  158. });
  159. if (!CallThroughTrampoline) {
  160. SourceJD.getExecutionSession().reportError(
  161. CallThroughTrampoline.takeError());
  162. R->failMaterialization();
  163. return;
  164. }
  165. StubInits[*Alias.first] =
  166. std::make_pair(*CallThroughTrampoline, Alias.second.AliasFlags);
  167. }
  168. if (AliaseeTable != nullptr && !RequestedAliases.empty())
  169. AliaseeTable->trackImpls(RequestedAliases, &SourceJD);
  170. if (auto Err = ISManager.createStubs(StubInits)) {
  171. SourceJD.getExecutionSession().reportError(std::move(Err));
  172. R->failMaterialization();
  173. return;
  174. }
  175. SymbolMap Stubs;
  176. for (auto &Alias : RequestedAliases)
  177. Stubs[Alias.first] = ISManager.findStub(*Alias.first, false);
  178. // No registered dependencies, so these calls cannot fail.
  179. cantFail(R->notifyResolved(Stubs));
  180. cantFail(R->notifyEmitted());
  181. }
  182. void LazyReexportsMaterializationUnit::discard(const JITDylib &JD,
  183. const SymbolStringPtr &Name) {
  184. assert(CallableAliases.count(Name) &&
  185. "Symbol not covered by this MaterializationUnit");
  186. CallableAliases.erase(Name);
  187. }
  188. MaterializationUnit::Interface
  189. LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
  190. SymbolFlagsMap SymbolFlags;
  191. for (auto &KV : Aliases) {
  192. assert(KV.second.AliasFlags.isCallable() &&
  193. "Lazy re-exports must be callable symbols");
  194. SymbolFlags[KV.first] = KV.second.AliasFlags;
  195. }
  196. return MaterializationUnit::Interface(std::move(SymbolFlags), nullptr);
  197. }
  198. } // End namespace orc.
  199. } // End namespace llvm.