[Orc] Add a JITSymbol class to the Orc APIs, refactor APIs, update clients.
[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 "llvm/ExecutionEngine/SectionMemoryManager.h"
22 #include <list>
23
24 namespace llvm {
25
26 /// @brief Compile-on-demand layer.
27 ///
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.
32 ///
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 {
37 public:
38   /// @brief Lookup helper that provides compatibility with the classic
39   ///        static-compilation symbol resolution process.
40   ///
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
51   /// lookup).
52   class CODScopedLookup {
53   private:
54     typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
55     typedef std::vector<BaseLayerModuleSetHandleT> SiblingHandlesList;
56     typedef std::list<SiblingHandlesList> PseudoDylibModuleSetHandlesList;
57
58   public:
59     /// @brief Handle for a logical module.
60     typedef typename PseudoDylibModuleSetHandlesList::iterator LMHandle;
61
62     /// @brief Construct a scoped lookup.
63     CODScopedLookup(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {}
64
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());
69     }
70
71     /// @brief Add a concrete Module's handle to the given logical Module's
72     ///        lookup scope.
73     void addToLogicalModule(LMHandle LMH, BaseLayerModuleSetHandleT H) {
74       LMH->push_back(H);
75     }
76
77     /// @brief Remove a logical Module from the CODScopedLookup entirely.
78     void removeLogicalModule(LMHandle LMH) { Handles.erase(LMH); }
79
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))
83         return Symbol;
84
85       for (auto I = Handles.begin(), E = Handles.end(); I != E; ++I)
86         if (I != LMH)
87           if (auto Symbol = findSymbolIn(I, Name))
88             return Symbol;
89
90       return nullptr;
91     }
92
93   private:
94
95     JITSymbol findSymbolIn(LMHandle LMH, const std::string &Name) {
96       for (auto H : *LMH)
97         if (auto Symbol = BaseLayer.findSymbolIn(H, Name, false))
98           return Symbol;
99       return nullptr;
100     }
101
102     BaseLayerT &BaseLayer;
103     PseudoDylibModuleSetHandlesList Handles;
104   };
105
106 private:
107   typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
108   typedef std::vector<BaseLayerModuleSetHandleT> BaseLayerModuleSetHandleListT;
109
110   struct ModuleSetInfo {
111     // Symbol lookup - just one for the whole module set.
112     std::shared_ptr<CODScopedLookup> Lookup;
113
114     // Logical module handles.
115     std::vector<typename CODScopedLookup::LMHandle> LMHandles;
116
117     // Persistent manglers - one per TU.
118     std::vector<PersistentMangler> PersistentManglers;
119
120     // Symbol resolution callback handlers - one per TU.
121     std::vector<std::unique_ptr<JITResolveCallbackHandler>>
122         JITResolveCallbackHandlers;
123
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;
128
129     ModuleSetInfo(std::shared_ptr<CODScopedLookup> Lookup)
130         : Lookup(std::move(Lookup)) {}
131
132     void releaseResources(BaseLayerT &BaseLayer) {
133       for (auto LMH : LMHandles)
134         Lookup->removeLogicalModule(LMH);
135       for (auto H : BaseLayerModuleSetHandles)
136         BaseLayer.removeModuleSet(H);
137     }
138   };
139
140   typedef std::list<ModuleSetInfo> ModuleSetInfoListT;
141
142 public:
143   /// @brief Handle to a set of loaded modules.
144   typedef typename ModuleSetInfoListT::iterator ModuleSetHandleT;
145
146   /// @brief Convenience typedef for callback inserter.
147   typedef std::function<void(Module&, JITResolveCallbackHandler&)>
148     InsertCallbackAsmFtor;
149
150   /// @brief Construct a compile-on-demand layer instance.
151   CompileOnDemandLayer(BaseLayerT &BaseLayer,
152                        InsertCallbackAsmFtor InsertCallbackAsm)
153     : BaseLayer(BaseLayer), InsertCallbackAsm(InsertCallbackAsm) {}
154
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) {
159
160     const char *JITAddrSuffix = "$orc_addr";
161     const char *JITImplSuffix = "$orc_impl";
162
163     // Create a symbol lookup context and ModuleSetInfo for this module set.
164     auto DylibLookup = std::make_shared<CODScopedLookup>(BaseLayer);
165     ModuleSetHandleT H =
166         ModuleSetInfos.insert(ModuleSetInfos.end(), ModuleSetInfo(DylibLookup));
167     ModuleSetInfo &MSI = ModuleSetInfos.back();
168
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.
171     for (auto &M : Ms) {
172
173       // Create a TU lookup context for this module.
174       auto LMH = DylibLookup->createLogicalModule();
175       MSI.LMHandles.push_back(LMH);
176
177       // Create a persistent mangler for this module.
178       MSI.PersistentManglers.emplace_back(*M->getDataLayout());
179
180       // Make all calls to functions defined in this module indirect.
181       JITIndirections Indirections =
182           makeCallsDoubleIndirect(*M, [](const Function &) { return true; },
183                                   JITImplSuffix, JITAddrSuffix);
184
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);
188
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(),
194               [=](StringRef S) {
195                 return DylibLookup->findSymbol(LMH, S).getAddress();
196               }));
197
198       // Insert callback asm code into the first module.
199       InsertCallbackAsm(*ExplodedModules[0],
200                         *MSI.JITResolveCallbackHandlers.back());
201
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
206       // modules first.OA
207       for (auto &M : ExplodedModules) {
208         std::vector<std::unique_ptr<Module>> MSet;
209         MSet.push_back(std::move(M));
210
211         BaseLayerModuleSetHandleT H = BaseLayer.addModuleSet(
212             std::move(MSet),
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();
218                 },
219                 [=](const std::string &Name) {
220                   return DylibLookup->findSymbol(LMH, Name).getAddress();
221                 }));
222         DylibLookup->addToLogicalModule(LMH, H);
223         MSI.BaseLayerModuleSetHandles.push_back(H);
224       }
225
226       initializeFuncAddrs(*MSI.JITResolveCallbackHandlers.back(), Indirections,
227                           MSI.PersistentManglers.back(), [=](StringRef S) {
228                             return DylibLookup->findSymbol(LMH, S).getAddress();
229                           });
230     }
231
232     return H;
233   }
234
235   /// @brief Remove the module represented by the given handle.
236   ///
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);
242   }
243
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);
250   }
251
252   /// @brief Get the address of a symbol provided by this layer, or some layer
253   ///        below this one.
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))
259         return Symbol;
260     }
261     return nullptr;
262   }
263
264 private:
265   BaseLayerT &BaseLayer;
266   InsertCallbackAsmFtor InsertCallbackAsm;
267   ModuleSetInfoListT ModuleSetInfos;
268 };
269 }
270
271 #endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H