1 //===- CompileOnDemandLayer.h - Compile each function on demand -*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // JIT layer for breaking up modules and inserting callbacks to allow
11 // individual functions to be compiled on demand.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
16 #define LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
18 #include "IndirectionUtils.h"
19 #include "LookasideRTDyldMM.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
26 /// @brief Compile-on-demand layer.
28 /// Modules added to this layer have their calls indirected, and are then
29 /// broken up into a set of single-function modules, each of which is added
30 /// to the layer below in a singleton set. The lower layer can be any layer that
31 /// accepts IR module sets.
33 /// It is expected that this layer will frequently be used on top of a
34 /// LazyEmittingLayer. The combination of the two ensures that each function is
35 /// compiled only when it is first called.
36 template <typename BaseLayerT> class CompileOnDemandLayer {
38 /// @brief Lookup helper that provides compatibility with the classic
39 /// static-compilation symbol resolution process.
41 /// The CompileOnDemand (COD) layer splits modules up into multiple
42 /// sub-modules, each held in its own llvm::Module instance, in order to
43 /// support lazy compilation. When a module that contains private symbols is
44 /// broken up symbol linkage changes may be required to enable access to
45 /// "private" data that now resides in a different llvm::Module instance. To
46 /// retain expected symbol resolution behavior for clients of the COD layer,
47 /// the CODScopedLookup class uses a two-tiered lookup system to resolve
48 /// symbols. Lookup first scans sibling modules that were split from the same
49 /// original module (logical-module scoped lookup), then scans all other
50 /// modules that have been added to the lookup scope (logical-dylib scoped
52 class CODScopedLookup {
54 typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
55 typedef std::vector<BaseLayerModuleSetHandleT> SiblingHandlesList;
56 typedef std::list<SiblingHandlesList> PseudoDylibModuleSetHandlesList;
59 /// @brief Handle for a logical module.
60 typedef typename PseudoDylibModuleSetHandlesList::iterator LMHandle;
62 /// @brief Construct a scoped lookup.
63 CODScopedLookup(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {}
65 /// @brief Start a new context for a single logical module.
66 LMHandle createLogicalModule() {
67 Handles.push_back(SiblingHandlesList());
68 return std::prev(Handles.end());
71 /// @brief Add a concrete Module's handle to the given logical Module's
73 void addToLogicalModule(LMHandle LMH, BaseLayerModuleSetHandleT H) {
77 /// @brief Remove a logical Module from the CODScopedLookup entirely.
78 void removeLogicalModule(LMHandle LMH) { Handles.erase(LMH); }
80 /// @brief Look up a symbol in this context.
81 JITSymbol findSymbol(LMHandle LMH, const std::string &Name) {
82 if (auto Symbol = findSymbolIn(LMH, Name))
85 for (auto I = Handles.begin(), E = Handles.end(); I != E; ++I)
87 if (auto Symbol = findSymbolIn(I, Name))
95 JITSymbol findSymbolIn(LMHandle LMH, const std::string &Name) {
97 if (auto Symbol = BaseLayer.findSymbolIn(H, Name, false))
102 BaseLayerT &BaseLayer;
103 PseudoDylibModuleSetHandlesList Handles;
107 typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
108 typedef std::vector<BaseLayerModuleSetHandleT> BaseLayerModuleSetHandleListT;
110 struct ModuleSetInfo {
111 // Symbol lookup - just one for the whole module set.
112 std::shared_ptr<CODScopedLookup> Lookup;
114 // Logical module handles.
115 std::vector<typename CODScopedLookup::LMHandle> LMHandles;
117 // Persistent manglers - one per TU.
118 std::vector<PersistentMangler> PersistentManglers;
120 // Symbol resolution callback handlers - one per TU.
121 std::vector<std::unique_ptr<JITResolveCallbackHandler>>
122 JITResolveCallbackHandlers;
124 // List of vectors of module set handles:
125 // One vector per logical module - each vector holds the handles for the
126 // exploded modules for that logical module in the base layer.
127 BaseLayerModuleSetHandleListT BaseLayerModuleSetHandles;
129 ModuleSetInfo(std::shared_ptr<CODScopedLookup> Lookup)
130 : Lookup(std::move(Lookup)) {}
132 void releaseResources(BaseLayerT &BaseLayer) {
133 for (auto LMH : LMHandles)
134 Lookup->removeLogicalModule(LMH);
135 for (auto H : BaseLayerModuleSetHandles)
136 BaseLayer.removeModuleSet(H);
140 typedef std::list<ModuleSetInfo> ModuleSetInfoListT;
143 /// @brief Handle to a set of loaded modules.
144 typedef typename ModuleSetInfoListT::iterator ModuleSetHandleT;
146 /// @brief Convenience typedef for callback inserter.
147 typedef std::function<void(Module&, JITResolveCallbackHandler&)>
148 InsertCallbackAsmFtor;
150 /// @brief Construct a compile-on-demand layer instance.
151 CompileOnDemandLayer(BaseLayerT &BaseLayer,
152 InsertCallbackAsmFtor InsertCallbackAsm)
153 : BaseLayer(BaseLayer), InsertCallbackAsm(InsertCallbackAsm) {}
155 /// @brief Add a module to the compile-on-demand layer.
156 template <typename ModuleSetT>
157 ModuleSetHandleT addModuleSet(ModuleSetT Ms,
158 std::unique_ptr<RTDyldMemoryManager> MM) {
160 const char *JITAddrSuffix = "$orc_addr";
161 const char *JITImplSuffix = "$orc_impl";
163 // Create a symbol lookup context and ModuleSetInfo for this module set.
164 auto DylibLookup = std::make_shared<CODScopedLookup>(BaseLayer);
166 ModuleSetInfos.insert(ModuleSetInfos.end(), ModuleSetInfo(DylibLookup));
167 ModuleSetInfo &MSI = ModuleSetInfos.back();
169 // Process each of the modules in this module set. All modules share the
170 // same lookup context, but each will get its own TU lookup context.
173 // Create a TU lookup context for this module.
174 auto LMH = DylibLookup->createLogicalModule();
175 MSI.LMHandles.push_back(LMH);
177 // Create a persistent mangler for this module.
178 MSI.PersistentManglers.emplace_back(*M->getDataLayout());
180 // Make all calls to functions defined in this module indirect.
181 JITIndirections Indirections =
182 makeCallsDoubleIndirect(*M, [](const Function &) { return true; },
183 JITImplSuffix, JITAddrSuffix);
185 // Then carve up the module into a bunch of single-function modules.
186 std::vector<std::unique_ptr<Module>> ExplodedModules =
187 explode(*M, Indirections);
189 // Add a resolve-callback handler for this module to look up symbol
190 // addresses when requested via a callback.
191 MSI.JITResolveCallbackHandlers.push_back(
192 createCallbackHandlerFromJITIndirections(
193 Indirections, MSI.PersistentManglers.back(),
195 return DylibLookup->findSymbol(LMH, S).getAddress();
198 // Insert callback asm code into the first module.
199 InsertCallbackAsm(*ExplodedModules[0],
200 *MSI.JITResolveCallbackHandlers.back());
202 // Now we need to take each of the extracted Modules and add them to
203 // base layer. Each Module will be added individually to make sure they
204 // can be compiled separately, and each will get its own lookaside
205 // memory manager with lookup functors that resolve symbols in sibling
207 for (auto &M : ExplodedModules) {
208 std::vector<std::unique_ptr<Module>> MSet;
209 MSet.push_back(std::move(M));
211 BaseLayerModuleSetHandleT H = BaseLayer.addModuleSet(
213 createLookasideRTDyldMM<SectionMemoryManager>(
214 [=](const std::string &Name) {
215 if (auto Symbol = DylibLookup->findSymbol(LMH, Name))
216 return Symbol.getAddress();
217 return findSymbol(Name, true).getAddress();
219 [=](const std::string &Name) {
220 return DylibLookup->findSymbol(LMH, Name).getAddress();
222 DylibLookup->addToLogicalModule(LMH, H);
223 MSI.BaseLayerModuleSetHandles.push_back(H);
226 initializeFuncAddrs(*MSI.JITResolveCallbackHandlers.back(), Indirections,
227 MSI.PersistentManglers.back(), [=](StringRef S) {
228 return DylibLookup->findSymbol(LMH, S).getAddress();
235 /// @brief Remove the module represented by the given handle.
237 /// This will remove all modules in the layers below that were derived from
238 /// the module represented by H.
239 void removeModuleSet(ModuleSetHandleT H) {
240 H->releaseResources(BaseLayer);
241 ModuleSetInfos.erase(H);
244 /// @brief Search for the given named symbol.
245 /// @param Name The name of the symbol to search for.
246 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
247 /// @return A handle for the given named symbol, if it exists.
248 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
249 return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
252 /// @brief Get the address of a symbol provided by this layer, or some layer
254 JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
255 bool ExportedSymbolsOnly) {
256 BaseLayerModuleSetHandleListT &BaseLayerHandles = H->second;
257 for (auto &BH : BaseLayerHandles) {
258 if (auto Symbol = BaseLayer.findSymbolIn(BH, Name, ExportedSymbolsOnly))
265 BaseLayerT &BaseLayer;
266 InsertCallbackAsmFtor InsertCallbackAsm;
267 ModuleSetInfoListT ModuleSetInfos;
271 #endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H