CompileOnDemandLayer.h revision 288943
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 "LogicalDylib.h"
21#include "llvm/ADT/STLExtras.h"
22#include "llvm/ExecutionEngine/SectionMemoryManager.h"
23#include "llvm/Transforms/Utils/Cloning.h"
24#include <list>
25#include <set>
26
27#include "llvm/Support/Debug.h"
28
29namespace llvm {
30namespace orc {
31
32/// @brief Compile-on-demand layer.
33///
34///   When a module is added to this layer a stub is created for each of its
35/// function definitions. The stubs and other global values are immediately
36/// added to the layer below. When a stub is called it triggers the extraction
37/// of the function body from the original module. The extracted body is then
38/// compiled and executed.
39template <typename BaseLayerT, typename CompileCallbackMgrT,
40          typename PartitioningFtor =
41            std::function<std::set<Function*>(Function&)>>
42class CompileOnDemandLayer {
43private:
44
45  // Utility class for MapValue. Only materializes declarations for global
46  // variables.
47  class GlobalDeclMaterializer : public ValueMaterializer {
48  public:
49    typedef std::set<const Function*> StubSet;
50
51    GlobalDeclMaterializer(Module &Dst, const StubSet *StubsToClone = nullptr)
52        : Dst(Dst), StubsToClone(StubsToClone) {}
53
54    Value* materializeValueFor(Value *V) final {
55      if (auto *GV = dyn_cast<GlobalVariable>(V))
56        return cloneGlobalVariableDecl(Dst, *GV);
57      else if (auto *F = dyn_cast<Function>(V)) {
58        auto *ClonedF = cloneFunctionDecl(Dst, *F);
59        if (StubsToClone && StubsToClone->count(F)) {
60          GlobalVariable *FnBodyPtr =
61            createImplPointer(*ClonedF->getType(), *ClonedF->getParent(),
62                              ClonedF->getName() + "$orc_addr", nullptr);
63          makeStub(*ClonedF, *FnBodyPtr);
64          ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage);
65          ClonedF->addFnAttr(Attribute::AlwaysInline);
66        }
67        return ClonedF;
68      }
69      // Else.
70      return nullptr;
71    }
72  private:
73    Module &Dst;
74    const StubSet *StubsToClone;
75  };
76
77  typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
78
79  struct LogicalModuleResources {
80    std::shared_ptr<Module> SourceModule;
81    std::set<const Function*> StubsToClone;
82  };
83
84  struct LogicalDylibResources {
85    typedef std::function<RuntimeDyld::SymbolInfo(const std::string&)>
86      SymbolResolverFtor;
87    SymbolResolverFtor ExternalSymbolResolver;
88    PartitioningFtor Partitioner;
89  };
90
91  typedef LogicalDylib<BaseLayerT, LogicalModuleResources,
92                       LogicalDylibResources> CODLogicalDylib;
93
94  typedef typename CODLogicalDylib::LogicalModuleHandle LogicalModuleHandle;
95  typedef std::list<CODLogicalDylib> LogicalDylibList;
96
97public:
98  /// @brief Handle to a set of loaded modules.
99  typedef typename LogicalDylibList::iterator ModuleSetHandleT;
100
101  /// @brief Construct a compile-on-demand layer instance.
102  CompileOnDemandLayer(BaseLayerT &BaseLayer, CompileCallbackMgrT &CallbackMgr,
103                       bool CloneStubsIntoPartitions)
104      : BaseLayer(BaseLayer), CompileCallbackMgr(CallbackMgr),
105        CloneStubsIntoPartitions(CloneStubsIntoPartitions) {}
106
107  /// @brief Add a module to the compile-on-demand layer.
108  template <typename ModuleSetT, typename MemoryManagerPtrT,
109            typename SymbolResolverPtrT>
110  ModuleSetHandleT addModuleSet(ModuleSetT Ms,
111                                MemoryManagerPtrT MemMgr,
112                                SymbolResolverPtrT Resolver) {
113
114    assert(MemMgr == nullptr &&
115           "User supplied memory managers not supported with COD yet.");
116
117    LogicalDylibs.push_back(CODLogicalDylib(BaseLayer));
118    auto &LDResources = LogicalDylibs.back().getDylibResources();
119
120    LDResources.ExternalSymbolResolver =
121      [Resolver](const std::string &Name) {
122        return Resolver->findSymbol(Name);
123      };
124
125    LDResources.Partitioner =
126      [](Function &F) {
127        std::set<Function*> Partition;
128        Partition.insert(&F);
129        return Partition;
130      };
131
132    // Process each of the modules in this module set.
133    for (auto &M : Ms)
134      addLogicalModule(LogicalDylibs.back(),
135                       std::shared_ptr<Module>(std::move(M)));
136
137    return std::prev(LogicalDylibs.end());
138  }
139
140  /// @brief Remove the module represented by the given handle.
141  ///
142  ///   This will remove all modules in the layers below that were derived from
143  /// the module represented by H.
144  void removeModuleSet(ModuleSetHandleT H) {
145    LogicalDylibs.erase(H);
146  }
147
148  /// @brief Search for the given named symbol.
149  /// @param Name The name of the symbol to search for.
150  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
151  /// @return A handle for the given named symbol, if it exists.
152  JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
153    return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
154  }
155
156  /// @brief Get the address of a symbol provided by this layer, or some layer
157  ///        below this one.
158  JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
159                         bool ExportedSymbolsOnly) {
160    return H->findSymbol(Name, ExportedSymbolsOnly);
161  }
162
163private:
164
165  void addLogicalModule(CODLogicalDylib &LD, std::shared_ptr<Module> SrcM) {
166
167    // Bump the linkage and rename any anonymous/privote members in SrcM to
168    // ensure that everything will resolve properly after we partition SrcM.
169    makeAllSymbolsExternallyAccessible(*SrcM);
170
171    // Create a logical module handle for SrcM within the logical dylib.
172    auto LMH = LD.createLogicalModule();
173    auto &LMResources =  LD.getLogicalModuleResources(LMH);
174    LMResources.SourceModule = SrcM;
175
176    // Create the GVs-and-stubs module.
177    auto GVsAndStubsM = llvm::make_unique<Module>(
178                          (SrcM->getName() + ".globals_and_stubs").str(),
179                          SrcM->getContext());
180    GVsAndStubsM->setDataLayout(SrcM->getDataLayout());
181    ValueToValueMapTy VMap;
182
183    // Process module and create stubs.
184    // We create the stubs before copying the global variables as we know the
185    // stubs won't refer to any globals (they only refer to their implementation
186    // pointer) so there's no ordering/value-mapping issues.
187    for (auto &F : *SrcM) {
188
189      // Skip declarations.
190      if (F.isDeclaration())
191        continue;
192
193      // Record all functions defined by this module.
194      if (CloneStubsIntoPartitions)
195        LMResources.StubsToClone.insert(&F);
196
197      // For each definition: create a callback, a stub, and a function body
198      // pointer. Initialize the function body pointer to point at the callback,
199      // and set the callback to compile the function body.
200      auto CCInfo = CompileCallbackMgr.getCompileCallback(SrcM->getContext());
201      Function *StubF = cloneFunctionDecl(*GVsAndStubsM, F, &VMap);
202      GlobalVariable *FnBodyPtr =
203        createImplPointer(*StubF->getType(), *StubF->getParent(),
204                          StubF->getName() + "$orc_addr",
205                          createIRTypedAddress(*StubF->getFunctionType(),
206                                               CCInfo.getAddress()));
207      makeStub(*StubF, *FnBodyPtr);
208      CCInfo.setCompileAction(
209        [this, &LD, LMH, &F]() {
210          return this->extractAndCompile(LD, LMH, F);
211        });
212    }
213
214    // Now clone the global variable declarations.
215    GlobalDeclMaterializer GDMat(*GVsAndStubsM);
216    for (auto &GV : SrcM->globals())
217      if (!GV.isDeclaration())
218        cloneGlobalVariableDecl(*GVsAndStubsM, GV, &VMap);
219
220    // Then clone the initializers.
221    for (auto &GV : SrcM->globals())
222      if (!GV.isDeclaration())
223        moveGlobalVariableInitializer(GV, VMap, &GDMat);
224
225    // Build a resolver for the stubs module and add it to the base layer.
226    auto GVsAndStubsResolver = createLambdaResolver(
227        [&LD](const std::string &Name) {
228          return LD.getDylibResources().ExternalSymbolResolver(Name);
229        },
230        [](const std::string &Name) {
231          return RuntimeDyld::SymbolInfo(nullptr);
232        });
233
234    std::vector<std::unique_ptr<Module>> GVsAndStubsMSet;
235    GVsAndStubsMSet.push_back(std::move(GVsAndStubsM));
236    auto GVsAndStubsH =
237      BaseLayer.addModuleSet(std::move(GVsAndStubsMSet),
238                             llvm::make_unique<SectionMemoryManager>(),
239                             std::move(GVsAndStubsResolver));
240    LD.addToLogicalModule(LMH, GVsAndStubsH);
241  }
242
243  static std::string Mangle(StringRef Name, const DataLayout &DL) {
244    std::string MangledName;
245    {
246      raw_string_ostream MangledNameStream(MangledName);
247      Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
248    }
249    return MangledName;
250  }
251
252  TargetAddress extractAndCompile(CODLogicalDylib &LD,
253                                  LogicalModuleHandle LMH,
254                                  Function &F) {
255    Module &SrcM = *LD.getLogicalModuleResources(LMH).SourceModule;
256
257    // If F is a declaration we must already have compiled it.
258    if (F.isDeclaration())
259      return 0;
260
261    // Grab the name of the function being called here.
262    std::string CalledFnName = Mangle(F.getName(), SrcM.getDataLayout());
263
264    auto Partition = LD.getDylibResources().Partitioner(F);
265    auto PartitionH = emitPartition(LD, LMH, Partition);
266
267    TargetAddress CalledAddr = 0;
268    for (auto *SubF : Partition) {
269      std::string FName = SubF->getName();
270      auto FnBodySym =
271        BaseLayer.findSymbolIn(PartitionH, Mangle(FName, SrcM.getDataLayout()),
272                               false);
273      auto FnPtrSym =
274        BaseLayer.findSymbolIn(*LD.moduleHandlesBegin(LMH),
275                               Mangle(FName + "$orc_addr",
276                                      SrcM.getDataLayout()),
277                               false);
278      assert(FnBodySym && "Couldn't find function body.");
279      assert(FnPtrSym && "Couldn't find function body pointer.");
280
281      TargetAddress FnBodyAddr = FnBodySym.getAddress();
282      void *FnPtrAddr = reinterpret_cast<void*>(
283          static_cast<uintptr_t>(FnPtrSym.getAddress()));
284
285      // If this is the function we're calling record the address so we can
286      // return it from this function.
287      if (SubF == &F)
288        CalledAddr = FnBodyAddr;
289
290      memcpy(FnPtrAddr, &FnBodyAddr, sizeof(uintptr_t));
291    }
292
293    return CalledAddr;
294  }
295
296  template <typename PartitionT>
297  BaseLayerModuleSetHandleT emitPartition(CODLogicalDylib &LD,
298                                          LogicalModuleHandle LMH,
299                                          const PartitionT &Partition) {
300    auto &LMResources = LD.getLogicalModuleResources(LMH);
301    Module &SrcM = *LMResources.SourceModule;
302
303    // Create the module.
304    std::string NewName = SrcM.getName();
305    for (auto *F : Partition) {
306      NewName += ".";
307      NewName += F->getName();
308    }
309
310    auto M = llvm::make_unique<Module>(NewName, SrcM.getContext());
311    M->setDataLayout(SrcM.getDataLayout());
312    ValueToValueMapTy VMap;
313    GlobalDeclMaterializer GDM(*M, &LMResources.StubsToClone);
314
315    // Create decls in the new module.
316    for (auto *F : Partition)
317      cloneFunctionDecl(*M, *F, &VMap);
318
319    // Move the function bodies.
320    for (auto *F : Partition)
321      moveFunctionBody(*F, VMap, &GDM);
322
323    // Create memory manager and symbol resolver.
324    auto MemMgr = llvm::make_unique<SectionMemoryManager>();
325    auto Resolver = createLambdaResolver(
326        [this, &LD, LMH](const std::string &Name) {
327          if (auto Symbol = LD.findSymbolInternally(LMH, Name))
328            return RuntimeDyld::SymbolInfo(Symbol.getAddress(),
329                                           Symbol.getFlags());
330          return LD.getDylibResources().ExternalSymbolResolver(Name);
331        },
332        [this, &LD, LMH](const std::string &Name) {
333          if (auto Symbol = LD.findSymbolInternally(LMH, Name))
334            return RuntimeDyld::SymbolInfo(Symbol.getAddress(),
335                                           Symbol.getFlags());
336          return RuntimeDyld::SymbolInfo(nullptr);
337        });
338    std::vector<std::unique_ptr<Module>> PartMSet;
339    PartMSet.push_back(std::move(M));
340    return BaseLayer.addModuleSet(std::move(PartMSet), std::move(MemMgr),
341                                  std::move(Resolver));
342  }
343
344  BaseLayerT &BaseLayer;
345  CompileCallbackMgrT &CompileCallbackMgr;
346  LogicalDylibList LogicalDylibs;
347  bool CloneStubsIntoPartitions;
348};
349
350} // End namespace orc.
351} // End namespace llvm.
352
353#endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
354