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 uint64_t lookup(LMHandle LMH, const std::string &Name) {
82 if (uint64_t Addr = lookupOnlyIn(LMH, Name))
85 for (auto I = Handles.begin(), E = Handles.end(); I != E; ++I)
87 if (uint64_t Addr = lookupOnlyIn(I, Name))
94 uint64_t lookupOnlyIn(LMHandle LMH, const std::string &Name) {
96 if (uint64_t Addr = BaseLayer.lookupSymbolAddressIn(H, Name, false))
101 BaseLayerT &BaseLayer;
102 PseudoDylibModuleSetHandlesList Handles;
106 typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
107 typedef std::vector<BaseLayerModuleSetHandleT> BaseLayerModuleSetHandleListT;
109 struct ModuleSetInfo {
110 // Symbol lookup - just one for the whole module set.
111 std::shared_ptr<CODScopedLookup> Lookup;
113 // Logical module handles.
114 std::vector<typename CODScopedLookup::LMHandle> LMHandles;
116 // Persistent manglers - one per TU.
117 std::vector<PersistentMangler> PersistentManglers;
119 // Symbol resolution callback handlers - one per TU.
120 std::vector<std::unique_ptr<JITResolveCallbackHandler>>
121 JITResolveCallbackHandlers;
123 // List of vectors of module set handles:
124 // One vector per logical module - each vector holds the handles for the
125 // exploded modules for that logical module in the base layer.
126 BaseLayerModuleSetHandleListT BaseLayerModuleSetHandles;
128 ModuleSetInfo(std::shared_ptr<CODScopedLookup> Lookup)
129 : Lookup(std::move(Lookup)) {}
131 void releaseResources(BaseLayerT &BaseLayer) {
132 for (auto LMH : LMHandles)
133 Lookup->removeLogicalModule(LMH);
134 for (auto H : BaseLayerModuleSetHandles)
135 BaseLayer.removeModuleSet(H);
139 typedef std::list<ModuleSetInfo> ModuleSetInfoListT;
142 /// @brief Handle to a set of loaded modules.
143 typedef typename ModuleSetInfoListT::iterator ModuleSetHandleT;
145 /// @brief Convenience typedef for callback inserter.
146 typedef std::function<void(Module&, JITResolveCallbackHandler&)>
147 InsertCallbackAsmFtor;
149 /// @brief Construct a compile-on-demand layer instance.
150 CompileOnDemandLayer(BaseLayerT &BaseLayer,
151 InsertCallbackAsmFtor InsertCallbackAsm)
152 : BaseLayer(BaseLayer), InsertCallbackAsm(InsertCallbackAsm) {}
154 /// @brief Add a module to the compile-on-demand layer.
155 template <typename ModuleSetT>
156 ModuleSetHandleT addModuleSet(ModuleSetT Ms,
157 std::unique_ptr<RTDyldMemoryManager> MM) {
159 const char *JITAddrSuffix = "$orc_addr";
160 const char *JITImplSuffix = "$orc_impl";
162 // Create a symbol lookup context and ModuleSetInfo for this module set.
163 auto DylibLookup = std::make_shared<CODScopedLookup>(BaseLayer);
165 ModuleSetInfos.insert(ModuleSetInfos.end(), ModuleSetInfo(DylibLookup));
166 ModuleSetInfo &MSI = ModuleSetInfos.back();
168 // Process each of the modules in this module set. All modules share the
169 // same lookup context, but each will get its own TU lookup context.
172 // Create a TU lookup context for this module.
173 auto LMH = DylibLookup->createLogicalModule();
174 MSI.LMHandles.push_back(LMH);
176 // Create a persistent mangler for this module.
177 MSI.PersistentManglers.emplace_back(*M->getDataLayout());
179 // Make all calls to functions defined in this module indirect.
180 JITIndirections Indirections =
181 makeCallsDoubleIndirect(*M, [](const Function &) { return true; },
182 JITImplSuffix, JITAddrSuffix);
184 // Then carve up the module into a bunch of single-function modules.
185 std::vector<std::unique_ptr<Module>> ExplodedModules =
186 explode(*M, Indirections);
188 // Add a resolve-callback handler for this module to look up symbol
189 // addresses when requested via a callback.
190 MSI.JITResolveCallbackHandlers.push_back(
191 createCallbackHandlerFromJITIndirections(
192 Indirections, MSI.PersistentManglers.back(),
193 [=](StringRef S) { return DylibLookup->lookup(LMH, S); }));
195 // Insert callback asm code into the first module.
196 InsertCallbackAsm(*ExplodedModules[0],
197 *MSI.JITResolveCallbackHandlers.back());
199 // Now we need to take each of the extracted Modules and add them to
200 // base layer. Each Module will be added individually to make sure they
201 // can be compiled separately, and each will get its own lookaside
202 // memory manager with lookup functors that resolve symbols in sibling
204 for (auto &M : ExplodedModules) {
205 std::vector<std::unique_ptr<Module>> MSet;
206 MSet.push_back(std::move(M));
208 BaseLayerModuleSetHandleT H = BaseLayer.addModuleSet(
210 createLookasideRTDyldMM<SectionMemoryManager>(
211 [=](const std::string &Name) {
212 if (uint64_t Addr = DylibLookup->lookup(LMH, Name))
214 return getSymbolAddress(Name, true);
216 [=](const std::string &Name) {
217 return DylibLookup->lookup(LMH, Name);
219 DylibLookup->addToLogicalModule(LMH, H);
220 MSI.BaseLayerModuleSetHandles.push_back(H);
223 initializeFuncAddrs(*MSI.JITResolveCallbackHandlers.back(), Indirections,
224 MSI.PersistentManglers.back(), [=](StringRef S) {
225 return DylibLookup->lookup(LMH, S);
232 /// @brief Remove the module represented by the given handle.
234 /// This will remove all modules in the layers below that were derived from
235 /// the module represented by H.
236 void removeModuleSet(ModuleSetHandleT H) {
237 H->releaseResources(BaseLayer);
238 ModuleSetInfos.erase(H);
241 /// @brief Get the address of a symbol provided by this layer, or some layer
243 uint64_t getSymbolAddress(const std::string &Name, bool ExportedSymbolsOnly) {
244 return BaseLayer.getSymbolAddress(Name, ExportedSymbolsOnly);
247 /// @brief Get the address of a symbol provided by this layer, or some layer
249 uint64_t lookupSymbolAddressIn(ModuleSetHandleT H, const std::string &Name,
250 bool ExportedSymbolsOnly) {
251 BaseLayerModuleSetHandleListT &BaseLayerHandles = H->second;
252 for (auto &BH : BaseLayerHandles) {
254 BaseLayer.lookupSymbolAddressIn(BH, Name, ExportedSymbolsOnly))
261 BaseLayerT &BaseLayer;
262 InsertCallbackAsmFtor InsertCallbackAsm;
263 ModuleSetInfoListT ModuleSetInfos;
267 #endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H