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