xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/JITLinkReentryTrampolines.cpp (revision 4eaff6c58ae2f130ac8d63cf2c87bbb483114876)
1f2d18a4dSLang Hames //===----- JITLinkReentryTrampolines.cpp -- JITLink-based trampoline- -----===//
2f2d18a4dSLang Hames //
3f2d18a4dSLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f2d18a4dSLang Hames // See https://llvm.org/LICENSE.txt for license information.
5f2d18a4dSLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f2d18a4dSLang Hames //
7f2d18a4dSLang Hames //===----------------------------------------------------------------------===//
8f2d18a4dSLang Hames 
9f2d18a4dSLang Hames #include "llvm/ExecutionEngine/Orc/JITLinkReentryTrampolines.h"
10f2d18a4dSLang Hames 
11f2d18a4dSLang Hames #include "llvm/ExecutionEngine/JITLink/aarch64.h"
128daf4f16SLang Hames #include "llvm/ExecutionEngine/JITLink/x86_64.h"
13f2d18a4dSLang Hames #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
14f2d18a4dSLang Hames 
15f2d18a4dSLang Hames #include <memory>
16f2d18a4dSLang Hames 
17f2d18a4dSLang Hames #define DEBUG_TYPE "orc"
18f2d18a4dSLang Hames 
19f2d18a4dSLang Hames using namespace llvm;
20f2d18a4dSLang Hames using namespace llvm::jitlink;
21f2d18a4dSLang Hames 
22f2d18a4dSLang Hames namespace {
23f2d18a4dSLang Hames constexpr StringRef ReentryFnName = "__orc_rt_reenter";
24f2d18a4dSLang Hames constexpr StringRef ReentrySectionName = "__orc_stubs";
25f2d18a4dSLang Hames } // namespace
26f2d18a4dSLang Hames 
27f2d18a4dSLang Hames namespace llvm::orc {
28f2d18a4dSLang Hames 
29f2d18a4dSLang Hames class JITLinkReentryTrampolines::TrampolineAddrScraperPlugin
30f2d18a4dSLang Hames     : public ObjectLinkingLayer::Plugin {
31f2d18a4dSLang Hames public:
32f2d18a4dSLang Hames   void modifyPassConfig(MaterializationResponsibility &MR,
33f2d18a4dSLang Hames                         jitlink::LinkGraph &G,
34f2d18a4dSLang Hames                         jitlink::PassConfiguration &Config) override {
35f2d18a4dSLang Hames     Config.PreFixupPasses.push_back(
36f2d18a4dSLang Hames         [this](LinkGraph &G) { return recordTrampolineAddrs(G); });
37f2d18a4dSLang Hames   }
38f2d18a4dSLang Hames 
39f2d18a4dSLang Hames   Error notifyFailed(MaterializationResponsibility &MR) override {
40f2d18a4dSLang Hames     return Error::success();
41f2d18a4dSLang Hames   }
42f2d18a4dSLang Hames 
43f2d18a4dSLang Hames   Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
44f2d18a4dSLang Hames     return Error::success();
45f2d18a4dSLang Hames   }
46f2d18a4dSLang Hames 
47f2d18a4dSLang Hames   void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
48f2d18a4dSLang Hames                                    ResourceKey SrcKey) override {}
49f2d18a4dSLang Hames 
50f2d18a4dSLang Hames   void registerGraph(LinkGraph &G,
51f2d18a4dSLang Hames                      std::shared_ptr<std::vector<ExecutorSymbolDef>> Addrs) {
52f2d18a4dSLang Hames     std::lock_guard<std::mutex> Lock(M);
53f2d18a4dSLang Hames     assert(!PendingAddrs.count(&G) && "Duplicate registration");
54f2d18a4dSLang Hames     PendingAddrs[&G] = std::move(Addrs);
55f2d18a4dSLang Hames   }
56f2d18a4dSLang Hames 
57f2d18a4dSLang Hames   Error recordTrampolineAddrs(LinkGraph &G) {
58f2d18a4dSLang Hames     std::shared_ptr<std::vector<ExecutorSymbolDef>> Addrs;
59f2d18a4dSLang Hames     {
60f2d18a4dSLang Hames       std::lock_guard<std::mutex> Lock(M);
61f2d18a4dSLang Hames       auto I = PendingAddrs.find(&G);
62f2d18a4dSLang Hames       if (I == PendingAddrs.end())
63f2d18a4dSLang Hames         return Error::success();
64f2d18a4dSLang Hames       Addrs = std::move(I->second);
65f2d18a4dSLang Hames       PendingAddrs.erase(I);
66f2d18a4dSLang Hames     }
67f2d18a4dSLang Hames 
68f2d18a4dSLang Hames     auto *Sec = G.findSectionByName(ReentrySectionName);
69f2d18a4dSLang Hames     assert(Sec && "Reentry graph missing reentry section");
70f2d18a4dSLang Hames     assert(!Sec->empty() && "Reentry graph is empty");
71f2d18a4dSLang Hames 
72f2d18a4dSLang Hames     for (auto *Sym : Sec->symbols())
73f2d18a4dSLang Hames       if (!Sym->hasName())
74f2d18a4dSLang Hames         Addrs->push_back({Sym->getAddress(), JITSymbolFlags()});
75f2d18a4dSLang Hames 
76f2d18a4dSLang Hames     return Error::success();
77f2d18a4dSLang Hames   }
78f2d18a4dSLang Hames 
79f2d18a4dSLang Hames private:
80f2d18a4dSLang Hames   std::mutex M;
81f2d18a4dSLang Hames   DenseMap<LinkGraph *, std::shared_ptr<std::vector<ExecutorSymbolDef>>>
82f2d18a4dSLang Hames       PendingAddrs;
83f2d18a4dSLang Hames };
84f2d18a4dSLang Hames 
85f2d18a4dSLang Hames Expected<std::unique_ptr<JITLinkReentryTrampolines>>
86f2d18a4dSLang Hames JITLinkReentryTrampolines::Create(ObjectLinkingLayer &ObjLinkingLayer) {
87f2d18a4dSLang Hames 
88f2d18a4dSLang Hames   EmitTrampolineFn EmitTrampoline;
89f2d18a4dSLang Hames 
9081c680a8SLang Hames   const auto &TT = ObjLinkingLayer.getExecutionSession().getTargetTriple();
9181c680a8SLang Hames   switch (TT.getArch()) {
92f2d18a4dSLang Hames   case Triple::aarch64:
93f2d18a4dSLang Hames     EmitTrampoline = aarch64::createAnonymousReentryTrampoline;
94f2d18a4dSLang Hames     break;
958daf4f16SLang Hames   case Triple::x86_64:
968daf4f16SLang Hames     EmitTrampoline = x86_64::createAnonymousReentryTrampoline;
978daf4f16SLang Hames     break;
98f2d18a4dSLang Hames   default:
9981c680a8SLang Hames     return make_error<StringError>("JITLinkReentryTrampolines: architecture " +
10081c680a8SLang Hames 				   TT.getArchName() + " not supported",
101f2d18a4dSLang Hames                                    inconvertibleErrorCode());
102f2d18a4dSLang Hames   }
103f2d18a4dSLang Hames 
104f2d18a4dSLang Hames   return std::make_unique<JITLinkReentryTrampolines>(ObjLinkingLayer,
105f2d18a4dSLang Hames                                                      std::move(EmitTrampoline));
106f2d18a4dSLang Hames }
107f2d18a4dSLang Hames 
108f2d18a4dSLang Hames JITLinkReentryTrampolines::JITLinkReentryTrampolines(
109f2d18a4dSLang Hames     ObjectLinkingLayer &ObjLinkingLayer, EmitTrampolineFn EmitTrampoline)
110f2d18a4dSLang Hames     : ObjLinkingLayer(ObjLinkingLayer),
111f2d18a4dSLang Hames       EmitTrampoline(std::move(EmitTrampoline)) {
112f2d18a4dSLang Hames   auto TAS = std::make_shared<TrampolineAddrScraperPlugin>();
113f2d18a4dSLang Hames   TrampolineAddrScraper = TAS.get();
114f2d18a4dSLang Hames   ObjLinkingLayer.addPlugin(std::move(TAS));
115f2d18a4dSLang Hames }
116f2d18a4dSLang Hames 
117f2d18a4dSLang Hames void JITLinkReentryTrampolines::emit(ResourceTrackerSP RT,
118f2d18a4dSLang Hames                                      size_t NumTrampolines,
119f2d18a4dSLang Hames                                      OnTrampolinesReadyFn OnTrampolinesReady) {
120f2d18a4dSLang Hames 
121f2d18a4dSLang Hames   if (NumTrampolines == 0)
122f2d18a4dSLang Hames     return OnTrampolinesReady(std::vector<ExecutorSymbolDef>());
123f2d18a4dSLang Hames 
124f2d18a4dSLang Hames   JITDylibSP JD(&RT->getJITDylib());
125f2d18a4dSLang Hames   auto &ES = ObjLinkingLayer.getExecutionSession();
126f2d18a4dSLang Hames 
127f2d18a4dSLang Hames   auto ReentryGraphSym =
128f2d18a4dSLang Hames       ES.intern(("__orc_reentry_graph_#" + Twine(++ReentryGraphIdx)).str());
129f2d18a4dSLang Hames 
130f2d18a4dSLang Hames   auto G = std::make_unique<jitlink::LinkGraph>(
131*4eaff6c5SLang Hames       (*ReentryGraphSym).str(), ES.getSymbolStringPool(), ES.getTargetTriple(),
132*4eaff6c5SLang Hames       SubtargetFeatures(), jitlink::getGenericEdgeKindName);
133f2d18a4dSLang Hames 
134f2d18a4dSLang Hames   auto &ReentryFnSym = G->addExternalSymbol(ReentryFnName, 0, false);
135f2d18a4dSLang Hames 
136f2d18a4dSLang Hames   auto &ReentrySection =
137f2d18a4dSLang Hames       G->createSection(ReentrySectionName, MemProt::Exec | MemProt::Read);
138f2d18a4dSLang Hames 
139f2d18a4dSLang Hames   for (size_t I = 0; I != NumTrampolines; ++I)
140f2d18a4dSLang Hames     EmitTrampoline(*G, ReentrySection, ReentryFnSym).setLive(true);
141f2d18a4dSLang Hames 
142f2d18a4dSLang Hames   auto &FirstBlock = **ReentrySection.blocks().begin();
143f2d18a4dSLang Hames   G->addDefinedSymbol(FirstBlock, 0, *ReentryGraphSym, FirstBlock.getSize(),
144f2d18a4dSLang Hames                       Linkage::Strong, Scope::SideEffectsOnly, true, true);
145f2d18a4dSLang Hames 
146f2d18a4dSLang Hames   auto TrampolineAddrs = std::make_shared<std::vector<ExecutorSymbolDef>>();
147f2d18a4dSLang Hames   TrampolineAddrScraper->registerGraph(*G, TrampolineAddrs);
148f2d18a4dSLang Hames 
149f2d18a4dSLang Hames   // Add Graph via object linking layer.
150f2d18a4dSLang Hames   if (auto Err = ObjLinkingLayer.add(std::move(RT), std::move(G)))
151f2d18a4dSLang Hames     return OnTrampolinesReady(std::move(Err));
152f2d18a4dSLang Hames 
153f2d18a4dSLang Hames   // Trigger graph emission.
154f2d18a4dSLang Hames   ES.lookup(
155f2d18a4dSLang Hames       LookupKind::Static, {{JD.get(), JITDylibLookupFlags::MatchAllSymbols}},
156f2d18a4dSLang Hames       SymbolLookupSet(ReentryGraphSym,
157f2d18a4dSLang Hames                       SymbolLookupFlags::WeaklyReferencedSymbol),
158f2d18a4dSLang Hames       SymbolState::Ready,
159f2d18a4dSLang Hames       [OnTrampolinesReady = std::move(OnTrampolinesReady),
160f2d18a4dSLang Hames        TrampolineAddrs =
161f2d18a4dSLang Hames            std::move(TrampolineAddrs)](Expected<SymbolMap> Result) mutable {
162f2d18a4dSLang Hames         if (Result)
163f2d18a4dSLang Hames           OnTrampolinesReady(std::move(*TrampolineAddrs));
164f2d18a4dSLang Hames         else
165f2d18a4dSLang Hames           OnTrampolinesReady(Result.takeError());
166f2d18a4dSLang Hames       },
167f2d18a4dSLang Hames       NoDependenciesToRegister);
168f2d18a4dSLang Hames }
169f2d18a4dSLang Hames 
170f2d18a4dSLang Hames Expected<std::unique_ptr<LazyReexportsManager>>
171f2d18a4dSLang Hames createJITLinkLazyReexportsManager(ObjectLinkingLayer &ObjLinkingLayer,
172f2d18a4dSLang Hames                                   RedirectableSymbolManager &RSMgr,
1732d10b7b7SLang Hames                                   JITDylib &PlatformJD,
1742d10b7b7SLang Hames                                   LazyReexportsManager::Listener *L) {
175f2d18a4dSLang Hames   auto JLT = JITLinkReentryTrampolines::Create(ObjLinkingLayer);
176f2d18a4dSLang Hames   if (!JLT)
177f2d18a4dSLang Hames     return JLT.takeError();
178f2d18a4dSLang Hames 
179f2d18a4dSLang Hames   return LazyReexportsManager::Create(
180f2d18a4dSLang Hames       [JLT = std::move(*JLT)](ResourceTrackerSP RT, size_t NumTrampolines,
181f2d18a4dSLang Hames                               LazyReexportsManager::OnTrampolinesReadyFn
182f2d18a4dSLang Hames                                   OnTrampolinesReady) mutable {
183f2d18a4dSLang Hames         JLT->emit(std::move(RT), NumTrampolines, std::move(OnTrampolinesReady));
184f2d18a4dSLang Hames       },
1852d10b7b7SLang Hames       RSMgr, PlatformJD, L);
186f2d18a4dSLang Hames }
187f2d18a4dSLang Hames 
188f2d18a4dSLang Hames } // namespace llvm::orc
189