79e8306cfd975ea6cc2b74b4274236a22eb94758
[oota-llvm.git] / include / llvm / ExecutionEngine / Orc / CompileOnDemandLayer.h
1 //===- CompileOnDemandLayer.h - Compile each function on demand -*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // JIT layer for breaking up modules and inserting callbacks to allow
11 // individual functions to be compiled on demand.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
16 #define LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
17
18 #include "IndirectionUtils.h"
19 #include "LookasideRTDyldMM.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include <list>
22
23 namespace llvm {
24
25 /// @brief Compile-on-demand layer.
26 ///
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.
31 ///
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 {
36 public:
37   /// @brief Lookup helper that provides compatibility with the classic
38   ///        static-compilation symbol resolution process.
39   ///
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
50   /// lookup).
51   class CODScopedLookup {
52   private:
53     typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
54     typedef std::vector<BaseLayerModuleSetHandleT> SiblingHandlesList;
55     typedef std::list<SiblingHandlesList> PseudoDylibModuleSetHandlesList;
56
57   public:
58     /// @brief Handle for a logical module.
59     typedef typename PseudoDylibModuleSetHandlesList::iterator LMHandle;
60
61     /// @brief Construct a scoped lookup.
62     CODScopedLookup(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {}
63
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());
68     }
69
70     /// @brief Add a concrete Module's handle to the given logical Module's
71     ///        lookup scope.
72     void addToLogicalModule(LMHandle LMH, BaseLayerModuleSetHandleT H) {
73       LMH->push_back(H);
74     }
75
76     /// @brief Remove a logical Module from the CODScopedLookup entirely.
77     void removeLogicalModule(LMHandle LMH) { Handles.erase(LMH); }
78
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))
82         return Addr;
83
84       for (auto I = Handles.begin(), E = Handles.end(); I != E; ++I)
85         if (I != LMH)
86           if (uint64_t Addr = lookupOnlyIn(I, Name))
87             return Addr;
88
89       return 0;
90     }
91
92   private:
93     uint64_t lookupOnlyIn(LMHandle LMH, const std::string &Name) {
94       for (auto H : *LMH)
95         if (uint64_t Addr = BaseLayer.lookupSymbolAddressIn(H, Name, false))
96           return Addr;
97       return 0;
98     }
99
100     BaseLayerT &BaseLayer;
101     PseudoDylibModuleSetHandlesList Handles;
102   };
103
104 private:
105   typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
106   typedef std::vector<BaseLayerModuleSetHandleT> BaseLayerModuleSetHandleListT;
107
108   struct ModuleSetInfo {
109     // Symbol lookup - just one for the whole module set.
110     std::shared_ptr<CODScopedLookup> Lookup;
111
112     // Logical module handles.
113     std::vector<typename CODScopedLookup::LMHandle> LMHandles;
114
115     // Persistent manglers - one per TU.
116     std::vector<PersistentMangler> PersistentManglers;
117
118     // Symbol resolution callback handlers - one per TU.
119     std::vector<std::unique_ptr<JITResolveCallbackHandler>>
120         JITResolveCallbackHandlers;
121
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;
126
127     ModuleSetInfo(std::shared_ptr<CODScopedLookup> Lookup)
128         : Lookup(std::move(Lookup)) {}
129
130     void releaseResources(BaseLayerT &BaseLayer) {
131       for (auto LMH : LMHandles)
132         Lookup->removeLogicalModule(LMH);
133       for (auto H : BaseLayerModuleSetHandles)
134         BaseLayer.removeModuleSet(H);
135     }
136   };
137
138   typedef std::list<ModuleSetInfo> ModuleSetInfoListT;
139
140 public:
141   /// @brief Handle to a set of loaded modules.
142   typedef typename ModuleSetInfoListT::iterator ModuleSetHandleT;
143
144   /// @brief Convenience typedef for callback inserter.
145   typedef std::function<void(Module&, JITResolveCallbackHandler&)>
146     InsertCallbackAsmFtor;
147
148   /// @brief Construct a compile-on-demand layer instance.
149   CompileOnDemandLayer(BaseLayerT &BaseLayer,
150                        InsertCallbackAsmFtor InsertCallbackAsm)
151     : BaseLayer(BaseLayer), InsertCallbackAsm(InsertCallbackAsm) {}
152
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) {
157
158     const char *JITAddrSuffix = "$orc_addr";
159     const char *JITImplSuffix = "$orc_impl";
160
161     // Create a symbol lookup context and ModuleSetInfo for this module set.
162     auto DylibLookup = std::make_shared<CODScopedLookup>(BaseLayer);
163     ModuleSetHandleT H =
164         ModuleSetInfos.insert(ModuleSetInfos.end(), ModuleSetInfo(DylibLookup));
165     ModuleSetInfo &MSI = ModuleSetInfos.back();
166
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.
169     for (auto &M : Ms) {
170
171       // Create a TU lookup context for this module.
172       auto LMH = DylibLookup->createLogicalModule();
173       MSI.LMHandles.push_back(LMH);
174
175       // Create a persistent mangler for this module.
176       MSI.PersistentManglers.emplace_back(*M->getDataLayout());
177
178       // Make all calls to functions defined in this module indirect.
179       JITIndirections Indirections =
180           makeCallsDoubleIndirect(*M, [](const Function &) { return true; },
181                                   JITImplSuffix, JITAddrSuffix);
182
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);
186
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); }));
193
194       // Insert callback asm code into the first module.
195       InsertCallbackAsm(*ExplodedModules[0],
196                         *MSI.JITResolveCallbackHandlers.back());
197
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
202       // modules first.OA
203       for (auto &M : ExplodedModules) {
204         std::vector<std::unique_ptr<Module>> MSet;
205         MSet.push_back(std::move(M));
206
207         BaseLayerModuleSetHandleT H = BaseLayer.addModuleSet(
208             std::move(MSet),
209             createLookasideRTDyldMM<SectionMemoryManager>(
210                 [=](const std::string &Name) {
211                   if (uint64_t Addr = DylibLookup->lookup(LMH, Name))
212                     return Addr;
213                   return getSymbolAddress(Name, true);
214                 },
215                 [=](const std::string &Name) {
216                   return DylibLookup->lookup(LMH, Name);
217                 }));
218         DylibLookup->addToLogicalModule(LMH, H);
219         MSI.BaseLayerModuleSetHandles.push_back(H);
220       }
221
222       initializeFuncAddrs(*MSI.JITResolveCallbackHandlers.back(), Indirections,
223                           MSI.PersistentManglers.back(), [=](StringRef S) {
224                             return DylibLookup->lookup(LMH, S);
225                           });
226     }
227
228     return H;
229   }
230
231   /// @brief Remove the module represented by the given handle.
232   ///
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);
238   }
239
240   /// @brief Get the address of a symbol provided by this layer, or some layer
241   ///        below this one.
242   uint64_t getSymbolAddress(const std::string &Name, bool ExportedSymbolsOnly) {
243     return BaseLayer.getSymbolAddress(Name, ExportedSymbolsOnly);
244   }
245
246   /// @brief Get the address of a symbol provided by this layer, or some layer
247   ///        below this one.
248   uint64_t lookupSymbolAddressIn(ModuleSetHandleT H, const std::string &Name,
249                                  bool ExportedSymbolsOnly) {
250     BaseLayerModuleSetHandleListT &BaseLayerHandles = H->second;
251     for (auto &BH : BaseLayerHandles) {
252       if (uint64_t Addr =
253             BaseLayer.lookupSymbolAddressIn(BH, Name, ExportedSymbolsOnly))
254         return Addr;
255     }
256     return 0;
257   }
258
259 private:
260   BaseLayerT &BaseLayer;
261   InsertCallbackAsmFtor InsertCallbackAsm;
262   ModuleSetInfoListT ModuleSetInfos;
263 };
264 }
265
266 #endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H