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