CompileOnDemandLayer.h revision 0c7f116bb6950ef819323d855415b2f2b0aad987
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 "LambdaResolver.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ExecutionEngine/SectionMemoryManager.h"
22#include <list>
23
24namespace llvm {
25namespace orc {
26
27/// @brief Compile-on-demand layer.
28///
29///   Modules added to this layer have their calls indirected, and are then
30/// broken up into a set of single-function modules, each of which is added
31/// to the layer below in a singleton set. The lower layer can be any layer that
32/// accepts IR module sets.
33///
34/// It is expected that this layer will frequently be used on top of a
35/// LazyEmittingLayer. The combination of the two ensures that each function is
36/// compiled only when it is first called.
37template <typename BaseLayerT, typename CompileCallbackMgrT>
38class CompileOnDemandLayer {
39private:
40  /// @brief Lookup helper that provides compatibility with the classic
41  ///        static-compilation symbol resolution process.
42  ///
43  ///   The CompileOnDemand (COD) layer splits modules up into multiple
44  /// sub-modules, each held in its own llvm::Module instance, in order to
45  /// support lazy compilation. When a module that contains private symbols is
46  /// broken up symbol linkage changes may be required to enable access to
47  /// "private" data that now resides in a different llvm::Module instance. To
48  /// retain expected symbol resolution behavior for clients of the COD layer,
49  /// the CODScopedLookup class uses a two-tiered lookup system to resolve
50  /// symbols. Lookup first scans sibling modules that were split from the same
51  /// original module (logical-module scoped lookup), then scans all other
52  /// modules that have been added to the lookup scope (logical-dylib scoped
53  /// lookup).
54  class CODScopedLookup {
55  private:
56    typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
57    typedef std::vector<BaseLayerModuleSetHandleT> SiblingHandlesList;
58    typedef std::list<SiblingHandlesList> PseudoDylibModuleSetHandlesList;
59
60  public:
61    /// @brief Handle for a logical module.
62    typedef typename PseudoDylibModuleSetHandlesList::iterator LMHandle;
63
64    /// @brief Construct a scoped lookup.
65    CODScopedLookup(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {}
66
67    virtual ~CODScopedLookup() {}
68
69    /// @brief Start a new context for a single logical module.
70    LMHandle createLogicalModule() {
71      Handles.push_back(SiblingHandlesList());
72      return std::prev(Handles.end());
73    }
74
75    /// @brief Add a concrete Module's handle to the given logical Module's
76    ///        lookup scope.
77    void addToLogicalModule(LMHandle LMH, BaseLayerModuleSetHandleT H) {
78      LMH->push_back(H);
79    }
80
81    /// @brief Remove a logical Module from the CODScopedLookup entirely.
82    void removeLogicalModule(LMHandle LMH) { Handles.erase(LMH); }
83
84    /// @brief Look up a symbol in this context.
85    JITSymbol findSymbol(LMHandle LMH, const std::string &Name) {
86      if (auto Symbol = findSymbolIn(LMH, Name))
87        return Symbol;
88
89      for (auto I = Handles.begin(), E = Handles.end(); I != E; ++I)
90        if (I != LMH)
91          if (auto Symbol = findSymbolIn(I, Name))
92            return Symbol;
93
94      return nullptr;
95    }
96
97    /// @brief Find an external symbol (via the user supplied SymbolResolver).
98    virtual RuntimeDyld::SymbolInfo
99    externalLookup(const std::string &Name) const = 0;
100
101  private:
102
103    JITSymbol findSymbolIn(LMHandle LMH, const std::string &Name) {
104      for (auto H : *LMH)
105        if (auto Symbol = BaseLayer.findSymbolIn(H, Name, false))
106          return Symbol;
107      return nullptr;
108    }
109
110    BaseLayerT &BaseLayer;
111    PseudoDylibModuleSetHandlesList Handles;
112  };
113
114  template <typename ResolverPtrT>
115  class CODScopedLookupImpl : public CODScopedLookup {
116  public:
117    CODScopedLookupImpl(BaseLayerT &BaseLayer, ResolverPtrT Resolver)
118      : CODScopedLookup(BaseLayer), Resolver(std::move(Resolver)) {}
119
120    RuntimeDyld::SymbolInfo
121    externalLookup(const std::string &Name) const override {
122      return Resolver->findSymbol(Name);
123    }
124
125  private:
126    ResolverPtrT Resolver;
127  };
128
129  template <typename ResolverPtrT>
130  static std::shared_ptr<CODScopedLookup>
131  createCODScopedLookup(BaseLayerT &BaseLayer,
132                        ResolverPtrT Resolver) {
133    typedef CODScopedLookupImpl<ResolverPtrT> Impl;
134    return std::make_shared<Impl>(BaseLayer, std::move(Resolver));
135  }
136
137  typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
138  typedef std::vector<BaseLayerModuleSetHandleT> BaseLayerModuleSetHandleListT;
139
140  struct ModuleSetInfo {
141    // Symbol lookup - just one for the whole module set.
142    std::shared_ptr<CODScopedLookup> Lookup;
143
144    // Logical module handles.
145    std::vector<typename CODScopedLookup::LMHandle> LMHandles;
146
147    // List of vectors of module set handles:
148    // One vector per logical module - each vector holds the handles for the
149    // exploded modules for that logical module in the base layer.
150    BaseLayerModuleSetHandleListT BaseLayerModuleSetHandles;
151
152    ModuleSetInfo(std::shared_ptr<CODScopedLookup> Lookup)
153        : Lookup(std::move(Lookup)) {}
154
155    void releaseResources(BaseLayerT &BaseLayer) {
156      for (auto LMH : LMHandles)
157        Lookup->removeLogicalModule(LMH);
158      for (auto H : BaseLayerModuleSetHandles)
159        BaseLayer.removeModuleSet(H);
160    }
161  };
162
163  typedef std::list<ModuleSetInfo> ModuleSetInfoListT;
164
165public:
166  /// @brief Handle to a set of loaded modules.
167  typedef typename ModuleSetInfoListT::iterator ModuleSetHandleT;
168
169  /// @brief Construct a compile-on-demand layer instance.
170  CompileOnDemandLayer(BaseLayerT &BaseLayer, CompileCallbackMgrT &CallbackMgr)
171      : BaseLayer(BaseLayer), CompileCallbackMgr(CallbackMgr) {}
172
173  /// @brief Add a module to the compile-on-demand layer.
174  template <typename ModuleSetT, typename MemoryManagerPtrT,
175            typename SymbolResolverPtrT>
176  ModuleSetHandleT addModuleSet(ModuleSetT Ms,
177                                MemoryManagerPtrT MemMgr,
178                                SymbolResolverPtrT Resolver) {
179
180    assert(MemMgr == nullptr &&
181           "User supplied memory managers not supported with COD yet.");
182
183    // Create a lookup context and ModuleSetInfo for this module set.
184    // For the purposes of symbol resolution the set Ms will be treated as if
185    // the modules it contained had been linked together as a dylib.
186    auto DylibLookup = createCODScopedLookup(BaseLayer, std::move(Resolver));
187    ModuleSetHandleT H =
188        ModuleSetInfos.insert(ModuleSetInfos.end(), ModuleSetInfo(DylibLookup));
189    ModuleSetInfo &MSI = ModuleSetInfos.back();
190
191    // Process each of the modules in this module set.
192    for (auto &M : Ms)
193      partitionAndAdd(*M, MSI);
194
195    return H;
196  }
197
198  /// @brief Remove the module represented by the given handle.
199  ///
200  ///   This will remove all modules in the layers below that were derived from
201  /// the module represented by H.
202  void removeModuleSet(ModuleSetHandleT H) {
203    H->releaseResources(BaseLayer);
204    ModuleSetInfos.erase(H);
205  }
206
207  /// @brief Search for the given named symbol.
208  /// @param Name The name of the symbol to search for.
209  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
210  /// @return A handle for the given named symbol, if it exists.
211  JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
212    return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
213  }
214
215  /// @brief Get the address of a symbol provided by this layer, or some layer
216  ///        below this one.
217  JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
218                         bool ExportedSymbolsOnly) {
219
220    for (auto &BH : H->BaseLayerModuleSetHandles) {
221      if (auto Symbol = BaseLayer.findSymbolIn(BH, Name, ExportedSymbolsOnly))
222        return Symbol;
223    }
224    return nullptr;
225  }
226
227private:
228
229  void partitionAndAdd(Module &M, ModuleSetInfo &MSI) {
230    const char *AddrSuffix = "$orc_addr";
231    const char *BodySuffix = "$orc_body";
232
233    // We're going to break M up into a bunch of sub-modules, but we want
234    // internal linkage symbols to still resolve sensibly. CODScopedLookup
235    // provides the "logical module" concept to make this work, so create a
236    // new logical module for M.
237    auto DylibLookup = MSI.Lookup;
238    auto LogicalModule = DylibLookup->createLogicalModule();
239    MSI.LMHandles.push_back(LogicalModule);
240
241    // Partition M into a "globals and stubs" module, a "common symbols" module,
242    // and a list of single-function modules.
243    auto PartitionedModule = fullyPartition(M);
244    auto StubsModule = std::move(PartitionedModule.GlobalVars);
245    auto CommonsModule = std::move(PartitionedModule.Commons);
246    auto FunctionModules = std::move(PartitionedModule.Functions);
247
248    // Emit the commons stright away.
249    auto CommonHandle = addModule(std::move(CommonsModule), MSI, LogicalModule);
250    BaseLayer.emitAndFinalize(CommonHandle);
251
252    // Map of definition names to callback-info data structures. We'll use
253    // this to build the compile actions for the stubs below.
254    typedef std::map<std::string,
255                     typename CompileCallbackMgrT::CompileCallbackInfo>
256      StubInfoMap;
257    StubInfoMap StubInfos;
258
259    // Now we need to take each of the extracted Modules and add them to
260    // base layer. Each Module will be added individually to make sure they
261    // can be compiled separately, and each will get its own lookaside
262    // memory manager that will resolve within this logical module first.
263    for (auto &SubM : FunctionModules) {
264
265      // Keep track of the stubs we create for this module so that we can set
266      // their compile actions.
267      std::vector<typename StubInfoMap::iterator> NewStubInfos;
268
269      // Search for function definitions and insert stubs into the stubs
270      // module.
271      for (auto &F : *SubM) {
272        if (F.isDeclaration())
273          continue;
274
275        std::string Name = F.getName();
276        Function *Proto = StubsModule->getFunction(Name);
277        assert(Proto && "Failed to clone function decl into stubs module.");
278        auto CallbackInfo =
279          CompileCallbackMgr.getCompileCallback(Proto->getContext());
280        GlobalVariable *FunctionBodyPointer =
281          createImplPointer(*Proto->getType(), *Proto->getParent(),
282                            Name + AddrSuffix,
283                            createIRTypedAddress(*Proto->getFunctionType(),
284                                                 CallbackInfo.getAddress()));
285        makeStub(*Proto, *FunctionBodyPointer);
286
287        F.setName(Name + BodySuffix);
288        F.setVisibility(GlobalValue::HiddenVisibility);
289
290        auto KV = std::make_pair(std::move(Name), std::move(CallbackInfo));
291        NewStubInfos.push_back(StubInfos.insert(StubInfos.begin(), KV));
292      }
293
294      auto H = addModule(std::move(SubM), MSI, LogicalModule);
295
296      // Set the compile actions for this module:
297      for (auto &KVPair : NewStubInfos) {
298        std::string BodyName = Mangle(KVPair->first + BodySuffix,
299                                      M.getDataLayout());
300        auto &CCInfo = KVPair->second;
301        CCInfo.setCompileAction(
302          [=](){
303            return BaseLayer.findSymbolIn(H, BodyName, false).getAddress();
304          });
305      }
306
307    }
308
309    // Ok - we've processed all the partitioned modules. Now add the
310    // stubs/globals module and set the update actions.
311    auto StubsH =
312      addModule(std::move(StubsModule), MSI, LogicalModule);
313
314    for (auto &KVPair : StubInfos) {
315      std::string AddrName = Mangle(KVPair.first + AddrSuffix,
316                                    M.getDataLayout());
317      auto &CCInfo = KVPair.second;
318      CCInfo.setUpdateAction(
319        getLocalFPUpdater(BaseLayer, StubsH, AddrName));
320    }
321  }
322
323  // Add the given Module to the base layer using a memory manager that will
324  // perform the appropriate scoped lookup (i.e. will look first with in the
325  // module from which it was extracted, then into the set to which that module
326  // belonged, and finally externally).
327  BaseLayerModuleSetHandleT addModule(
328                               std::unique_ptr<Module> M,
329                               ModuleSetInfo &MSI,
330                               typename CODScopedLookup::LMHandle LogicalModule) {
331
332    // Add this module to the JIT with a memory manager that uses the
333    // DylibLookup to resolve symbols.
334    std::vector<std::unique_ptr<Module>> MSet;
335    MSet.push_back(std::move(M));
336
337    auto DylibLookup = MSI.Lookup;
338    auto Resolver =
339      createLambdaResolver(
340        [=](const std::string &Name) {
341          if (auto Symbol = DylibLookup->findSymbol(LogicalModule, Name))
342            return RuntimeDyld::SymbolInfo(Symbol.getAddress(),
343                                           Symbol.getFlags());
344          return DylibLookup->externalLookup(Name);
345        },
346        [=](const std::string &Name) -> RuntimeDyld::SymbolInfo {
347          if (auto Symbol = DylibLookup->findSymbol(LogicalModule, Name))
348            return RuntimeDyld::SymbolInfo(Symbol.getAddress(),
349                                           Symbol.getFlags());
350          return nullptr;
351        });
352
353    BaseLayerModuleSetHandleT H =
354      BaseLayer.addModuleSet(std::move(MSet),
355                             make_unique<SectionMemoryManager>(),
356                             std::move(Resolver));
357    // Add this module to the logical module lookup.
358    DylibLookup->addToLogicalModule(LogicalModule, H);
359    MSI.BaseLayerModuleSetHandles.push_back(H);
360
361    return H;
362  }
363
364  static std::string Mangle(StringRef Name, const DataLayout &DL) {
365    Mangler M(&DL);
366    std::string MangledName;
367    {
368      raw_string_ostream MangledNameStream(MangledName);
369      M.getNameWithPrefix(MangledNameStream, Name);
370    }
371    return MangledName;
372  }
373
374  BaseLayerT &BaseLayer;
375  CompileCallbackMgrT &CompileCallbackMgr;
376  ModuleSetInfoListT ModuleSetInfos;
377};
378
379} // End namespace orc.
380} // End namespace llvm.
381
382#endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
383