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"
22 /// @brief Compile-on-demand layer.
24 /// Modules added to this layer have their calls indirected, and are then
25 /// broken up into a set of single-function modules, each of which is added
26 /// to the layer below in a singleton set. The lower layer can be any layer that
27 /// accepts IR module sets.
29 /// It is expected that this layer will frequently be used on top of a
30 /// LazyEmittingLayer. The combination of the two ensures that each function is
31 /// compiled only when it is first called.
32 template <typename BaseLayerT> class CompileOnDemandLayer {
34 /// @brief Lookup helper that provides compatibility with the classic
35 /// static-compilation symbol resolution process.
37 /// The CompileOnDemand (COD) layer splits modules up into multiple
38 /// sub-modules, each held in its own llvm::Module instance, in order to
39 /// support lazy compilation. When a module that contains private symbols is
40 /// broken up symbol linkage changes may be required to enable access to
41 /// "private" data that now resides in a different llvm::Module instance. To
42 /// retain expected symbol resolution behavior for clients of the COD layer,
43 /// the CODScopedLookup class uses a two-tiered lookup system to resolve
44 /// symbols. Lookup first scans sibling modules that were split from the same
45 /// original module (logical-module scoped lookup), then scans all other
46 /// modules that have been added to the lookup scope (logical-dylib scoped
48 class CODScopedLookup {
50 typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
51 typedef std::vector<BaseLayerModuleSetHandleT> SiblingHandlesList;
52 typedef std::list<SiblingHandlesList> PseudoDylibModuleSetHandlesList;
55 /// @brief Handle for a logical module.
56 typedef typename PseudoDylibModuleSetHandlesList::iterator LMHandle;
58 /// @brief Construct a scoped lookup.
59 CODScopedLookup(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {}
61 /// @brief Start a new context for a single logical module.
62 LMHandle createLogicalModule() {
63 Handles.push_back(SiblingHandlesList());
64 return std::prev(Handles.end());
67 /// @brief Add a concrete Module's handle to the given logical Module's
69 void addToLogicalModule(LMHandle LMH, BaseLayerModuleSetHandleT H) {
73 /// @brief Remove a logical Module from the CODScopedLookup entirely.
74 void removeLogicalModule(LMHandle LMH) { Handles.erase(LMH); }
76 /// @brief Look up a symbol in this context.
77 uint64_t lookup(LMHandle LMH, const std::string &Name) {
78 if (uint64_t Addr = lookupOnlyIn(LMH, Name))
81 for (auto I = Handles.begin(), E = Handles.end(); I != E; ++I)
83 if (uint64_t Addr = lookupOnlyIn(I, Name))
90 uint64_t lookupOnlyIn(LMHandle LMH, const std::string &Name) {
92 if (uint64_t Addr = BaseLayer.lookupSymbolAddressIn(H, Name, false))
97 BaseLayerT &BaseLayer;
98 PseudoDylibModuleSetHandlesList Handles;
102 typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
103 typedef std::vector<BaseLayerModuleSetHandleT> BaseLayerModuleSetHandleListT;
105 struct ModuleSetInfo {
106 // Symbol lookup - just one for the whole module set.
107 std::shared_ptr<CODScopedLookup> Lookup;
109 // Logical module handles.
110 std::vector<typename CODScopedLookup::LMHandle> LMHandles;
112 // Persistent manglers - one per TU.
113 std::vector<PersistentMangler> PersistentManglers;
115 // Symbol resolution callback handlers - one per TU.
116 std::vector<std::unique_ptr<JITResolveCallbackHandler>>
117 JITResolveCallbackHandlers;
119 // List of vectors of module set handles:
120 // One vector per logical module - each vector holds the handles for the
121 // exploded modules for that logical module in the base layer.
122 BaseLayerModuleSetHandleListT BaseLayerModuleSetHandles;
124 ModuleSetInfo(std::shared_ptr<CODScopedLookup> Lookup)
125 : Lookup(std::move(Lookup)) {}
127 void releaseResources(BaseLayerT &BaseLayer) {
128 for (auto LMH : LMHandles)
129 Lookup->removeLogicalModule(LMH);
130 for (auto H : BaseLayerModuleSetHandles)
131 BaseLayer.removeModuleSet(H);
135 typedef std::list<ModuleSetInfo> ModuleSetInfoListT;
138 /// @brief Handle to a set of loaded modules.
139 typedef typename ModuleSetInfoListT::iterator ModuleSetHandleT;
141 /// @brief Convenience typedef for callback inserter.
142 typedef std::function<void(Module&, JITResolveCallbackHandler&)>
143 InsertCallbackAsmFtor;
145 /// @brief Construct a compile-on-demand layer instance.
146 CompileOnDemandLayer(BaseLayerT &BaseLayer,
147 InsertCallbackAsmFtor InsertCallbackAsm)
148 : BaseLayer(BaseLayer), InsertCallbackAsm(InsertCallbackAsm) {}
150 /// @brief Add a module to the compile-on-demand layer.
151 template <typename ModuleSetT>
152 ModuleSetHandleT addModuleSet(ModuleSetT Ms,
153 std::unique_ptr<RTDyldMemoryManager> MM) {
155 const char *JITAddrSuffix = "$orc_addr";
156 const char *JITImplSuffix = "$orc_impl";
158 // Create a symbol lookup context and ModuleSetInfo for this module set.
159 auto DylibLookup = std::make_shared<CODScopedLookup>(BaseLayer);
161 ModuleSetInfos.insert(ModuleSetInfos.end(), ModuleSetInfo(DylibLookup));
162 ModuleSetInfo &MSI = ModuleSetInfos.back();
164 // Process each of the modules in this module set. All modules share the
165 // same lookup context, but each will get its own TU lookup context.
168 // Create a TU lookup context for this module.
169 auto LMH = DylibLookup->createLogicalModule();
170 MSI.LMHandles.push_back(LMH);
172 // Create a persistent mangler for this module.
173 MSI.PersistentManglers.emplace_back(*M->getDataLayout());
175 // Make all calls to functions defined in this module indirect.
176 JITIndirections Indirections =
177 makeCallsDoubleIndirect(*M, [](const Function &) { return true; },
178 JITImplSuffix, JITAddrSuffix);
180 // Then carve up the module into a bunch of single-function modules.
181 std::vector<std::unique_ptr<Module>> ExplodedModules =
182 explode(*M, Indirections);
184 // Add a resolve-callback handler for this module to look up symbol
185 // addresses when requested via a callback.
186 MSI.JITResolveCallbackHandlers.push_back(
187 createCallbackHandlerFromJITIndirections(
188 Indirections, MSI.PersistentManglers.back(),
189 [=](StringRef S) { return DylibLookup->lookup(LMH, S); }));
191 // Insert callback asm code into the first module.
192 InsertCallbackAsm(*ExplodedModules[0],
193 *MSI.JITResolveCallbackHandlers.back());
195 // Now we need to take each of the extracted Modules and add them to
196 // base layer. Each Module will be added individually to make sure they
197 // can be compiled separately, and each will get its own lookaside
198 // memory manager with lookup functors that resolve symbols in sibling
200 for (auto &M : ExplodedModules) {
201 std::vector<std::unique_ptr<Module>> MSet;
202 MSet.push_back(std::move(M));
204 BaseLayerModuleSetHandleT H = BaseLayer.addModuleSet(
206 createLookasideRTDyldMM<SectionMemoryManager>(
207 [=](const std::string &Name) {
208 if (uint64_t Addr = DylibLookup->lookup(LMH, Name))
210 return getSymbolAddress(Name, true);
212 [=](const std::string &Name) {
213 return DylibLookup->lookup(LMH, Name);
215 DylibLookup->addToLogicalModule(LMH, H);
216 MSI.BaseLayerModuleSetHandles.push_back(H);
219 initializeFuncAddrs(*MSI.JITResolveCallbackHandlers.back(), Indirections,
220 MSI.PersistentManglers.back(), [=](StringRef S) {
221 return DylibLookup->lookup(LMH, S);
228 /// @brief Remove the module represented by the given handle.
230 /// This will remove all modules in the layers below that were derived from
231 /// the module represented by H.
232 void removeModuleSet(ModuleSetHandleT H) {
233 H->releaseResources(BaseLayer);
234 ModuleSetInfos.erase(H);
237 /// @brief Get the address of a symbol provided by this layer, or some layer
239 uint64_t getSymbolAddress(const std::string &Name, bool ExportedSymbolsOnly) {
240 return BaseLayer.getSymbolAddress(Name, ExportedSymbolsOnly);
243 /// @brief Get the address of a symbol provided by this layer, or some layer
245 uint64_t lookupSymbolAddressIn(ModuleSetHandleT H, const std::string &Name,
246 bool ExportedSymbolsOnly) {
247 BaseLayerModuleSetHandleListT &BaseLayerHandles = H->second;
248 for (auto &BH : BaseLayerHandles) {
250 BaseLayer.lookupSymbolAddressIn(BH, Name, ExportedSymbolsOnly))
257 BaseLayerT &BaseLayer;
258 InsertCallbackAsmFtor InsertCallbackAsm;
259 ModuleSetInfoListT ModuleSetInfos;
263 #endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H