• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/Support/Debug.h"
23 #include "llvm/Transforms/Utils/Cloning.h"
24 #include <list>
25 #include <memory>
26 #include <set>
27 #include <utility>
28 
29 namespace llvm {
30 namespace 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.
39 template <typename BaseLayerT,
40           typename CompileCallbackMgrT = JITCompileCallbackManager,
41           typename IndirectStubsMgrT = IndirectStubsManager>
42 class CompileOnDemandLayer {
43 private:
44 
45   template <typename MaterializerFtor>
46   class LambdaMaterializer final : public ValueMaterializer {
47   public:
LambdaMaterializer(MaterializerFtor M)48     LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {}
materialize(Value * V)49     Value *materialize(Value *V) final { return M(V); }
50 
51   private:
52     MaterializerFtor M;
53   };
54 
55   template <typename MaterializerFtor>
56   LambdaMaterializer<MaterializerFtor>
createLambdaMaterializer(MaterializerFtor M)57   createLambdaMaterializer(MaterializerFtor M) {
58     return LambdaMaterializer<MaterializerFtor>(std::move(M));
59   }
60 
61   typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
62 
63   // Provide type-erasure for the Modules and MemoryManagers.
64   template <typename ResourceT>
65   class ResourceOwner {
66   public:
67     ResourceOwner() = default;
68     ResourceOwner(const ResourceOwner&) = delete;
69     ResourceOwner& operator=(const ResourceOwner&) = delete;
~ResourceOwner()70     virtual ~ResourceOwner() { }
71     virtual ResourceT& getResource() const = 0;
72   };
73 
74   template <typename ResourceT, typename ResourcePtrT>
75   class ResourceOwnerImpl : public ResourceOwner<ResourceT> {
76   public:
ResourceOwnerImpl(ResourcePtrT ResourcePtr)77     ResourceOwnerImpl(ResourcePtrT ResourcePtr)
78       : ResourcePtr(std::move(ResourcePtr)) {}
getResource()79     ResourceT& getResource() const override { return *ResourcePtr; }
80   private:
81     ResourcePtrT ResourcePtr;
82   };
83 
84   template <typename ResourceT, typename ResourcePtrT>
85   std::unique_ptr<ResourceOwner<ResourceT>>
wrapOwnership(ResourcePtrT ResourcePtr)86   wrapOwnership(ResourcePtrT ResourcePtr) {
87     typedef ResourceOwnerImpl<ResourceT, ResourcePtrT> RO;
88     return llvm::make_unique<RO>(std::move(ResourcePtr));
89   }
90 
91   struct LogicalModuleResources {
92     std::unique_ptr<ResourceOwner<Module>> SourceModule;
93     std::set<const Function*> StubsToClone;
94     std::unique_ptr<IndirectStubsMgrT> StubsMgr;
95 
96     LogicalModuleResources() = default;
97 
98     // Explicit move constructor to make MSVC happy.
LogicalModuleResourcesLogicalModuleResources99     LogicalModuleResources(LogicalModuleResources &&Other)
100         : SourceModule(std::move(Other.SourceModule)),
101           StubsToClone(std::move(Other.StubsToClone)),
102           StubsMgr(std::move(Other.StubsMgr)) {}
103 
104     // Explicit move assignment to make MSVC happy.
105     LogicalModuleResources& operator=(LogicalModuleResources &&Other) {
106       SourceModule = std::move(Other.SourceModule);
107       StubsToClone = std::move(Other.StubsToClone);
108       StubsMgr = std::move(Other.StubsMgr);
109       return *this;
110     }
111 
findSymbolLogicalModuleResources112     JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
113       if (Name.endswith("$stub_ptr") && !ExportedSymbolsOnly) {
114         assert(!ExportedSymbolsOnly && "Stubs are never exported");
115         return StubsMgr->findPointer(Name.drop_back(9));
116       }
117       return StubsMgr->findStub(Name, ExportedSymbolsOnly);
118     }
119 
120   };
121 
122   struct LogicalDylibResources {
123     typedef std::function<RuntimeDyld::SymbolInfo(const std::string&)>
124       SymbolResolverFtor;
125 
126     typedef std::function<typename BaseLayerT::ModuleSetHandleT(
127                             BaseLayerT&,
128                             std::unique_ptr<Module>,
129                             std::unique_ptr<RuntimeDyld::SymbolResolver>)>
130       ModuleAdderFtor;
131 
132     LogicalDylibResources() = default;
133 
134     // Explicit move constructor to make MSVC happy.
LogicalDylibResourcesLogicalDylibResources135     LogicalDylibResources(LogicalDylibResources &&Other)
136       : ExternalSymbolResolver(std::move(Other.ExternalSymbolResolver)),
137         MemMgr(std::move(Other.MemMgr)),
138         ModuleAdder(std::move(Other.ModuleAdder)) {}
139 
140     // Explicit move assignment operator to make MSVC happy.
141     LogicalDylibResources& operator=(LogicalDylibResources &&Other) {
142       ExternalSymbolResolver = std::move(Other.ExternalSymbolResolver);
143       MemMgr = std::move(Other.MemMgr);
144       ModuleAdder = std::move(Other.ModuleAdder);
145       return *this;
146     }
147 
148     std::unique_ptr<RuntimeDyld::SymbolResolver> ExternalSymbolResolver;
149     std::unique_ptr<ResourceOwner<RuntimeDyld::MemoryManager>> MemMgr;
150     ModuleAdderFtor ModuleAdder;
151   };
152 
153   typedef LogicalDylib<BaseLayerT, LogicalModuleResources,
154                        LogicalDylibResources> CODLogicalDylib;
155 
156   typedef typename CODLogicalDylib::LogicalModuleHandle LogicalModuleHandle;
157   typedef std::list<CODLogicalDylib> LogicalDylibList;
158 
159 public:
160 
161   /// @brief Handle to a set of loaded modules.
162   typedef typename LogicalDylibList::iterator ModuleSetHandleT;
163 
164   /// @brief Module partitioning functor.
165   typedef std::function<std::set<Function*>(Function&)> PartitioningFtor;
166 
167   /// @brief Builder for IndirectStubsManagers.
168   typedef std::function<std::unique_ptr<IndirectStubsMgrT>()>
169     IndirectStubsManagerBuilderT;
170 
171   /// @brief Construct a compile-on-demand layer instance.
172   CompileOnDemandLayer(BaseLayerT &BaseLayer, PartitioningFtor Partition,
173                        CompileCallbackMgrT &CallbackMgr,
174                        IndirectStubsManagerBuilderT CreateIndirectStubsManager,
175                        bool CloneStubsIntoPartitions = true)
BaseLayer(BaseLayer)176       : BaseLayer(BaseLayer), Partition(std::move(Partition)),
177         CompileCallbackMgr(CallbackMgr),
178         CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)),
179         CloneStubsIntoPartitions(CloneStubsIntoPartitions) {}
180 
181   /// @brief Add a module to the compile-on-demand layer.
182   template <typename ModuleSetT, typename MemoryManagerPtrT,
183             typename SymbolResolverPtrT>
addModuleSet(ModuleSetT Ms,MemoryManagerPtrT MemMgr,SymbolResolverPtrT Resolver)184   ModuleSetHandleT addModuleSet(ModuleSetT Ms,
185                                 MemoryManagerPtrT MemMgr,
186                                 SymbolResolverPtrT Resolver) {
187 
188     LogicalDylibs.push_back(CODLogicalDylib(BaseLayer));
189     auto &LDResources = LogicalDylibs.back().getDylibResources();
190 
191     LDResources.ExternalSymbolResolver = std::move(Resolver);
192 
193     auto &MemMgrRef = *MemMgr;
194     LDResources.MemMgr =
195       wrapOwnership<RuntimeDyld::MemoryManager>(std::move(MemMgr));
196 
197     LDResources.ModuleAdder =
198       [&MemMgrRef](BaseLayerT &B, std::unique_ptr<Module> M,
199                    std::unique_ptr<RuntimeDyld::SymbolResolver> R) {
200         std::vector<std::unique_ptr<Module>> Ms;
201         Ms.push_back(std::move(M));
202         return B.addModuleSet(std::move(Ms), &MemMgrRef, std::move(R));
203       };
204 
205     // Process each of the modules in this module set.
206     for (auto &M : Ms)
207       addLogicalModule(LogicalDylibs.back(), std::move(M));
208 
209     return std::prev(LogicalDylibs.end());
210   }
211 
212   /// @brief Remove the module represented by the given handle.
213   ///
214   ///   This will remove all modules in the layers below that were derived from
215   /// the module represented by H.
removeModuleSet(ModuleSetHandleT H)216   void removeModuleSet(ModuleSetHandleT H) {
217     LogicalDylibs.erase(H);
218   }
219 
220   /// @brief Search for the given named symbol.
221   /// @param Name The name of the symbol to search for.
222   /// @param ExportedSymbolsOnly If true, search only for exported symbols.
223   /// @return A handle for the given named symbol, if it exists.
findSymbol(StringRef Name,bool ExportedSymbolsOnly)224   JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
225     for (auto LDI = LogicalDylibs.begin(), LDE = LogicalDylibs.end();
226          LDI != LDE; ++LDI)
227       if (auto Symbol = findSymbolIn(LDI, Name, ExportedSymbolsOnly))
228         return Symbol;
229     return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
230   }
231 
232   /// @brief Get the address of a symbol provided by this layer, or some layer
233   ///        below this one.
findSymbolIn(ModuleSetHandleT H,const std::string & Name,bool ExportedSymbolsOnly)234   JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
235                          bool ExportedSymbolsOnly) {
236     return H->findSymbol(Name, ExportedSymbolsOnly);
237   }
238 
239 private:
240 
241   template <typename ModulePtrT>
addLogicalModule(CODLogicalDylib & LD,ModulePtrT SrcMPtr)242   void addLogicalModule(CODLogicalDylib &LD, ModulePtrT SrcMPtr) {
243 
244     // Bump the linkage and rename any anonymous/privote members in SrcM to
245     // ensure that everything will resolve properly after we partition SrcM.
246     makeAllSymbolsExternallyAccessible(*SrcMPtr);
247 
248     // Create a logical module handle for SrcM within the logical dylib.
249     auto LMH = LD.createLogicalModule();
250     auto &LMResources =  LD.getLogicalModuleResources(LMH);
251 
252     LMResources.SourceModule = wrapOwnership<Module>(std::move(SrcMPtr));
253 
254     Module &SrcM = LMResources.SourceModule->getResource();
255 
256     // Create stub functions.
257     const DataLayout &DL = SrcM.getDataLayout();
258     {
259       typename IndirectStubsMgrT::StubInitsMap StubInits;
260       for (auto &F : SrcM) {
261         // Skip declarations.
262         if (F.isDeclaration())
263           continue;
264 
265         // Record all functions defined by this module.
266         if (CloneStubsIntoPartitions)
267           LMResources.StubsToClone.insert(&F);
268 
269         // Create a callback, associate it with the stub for the function,
270         // and set the compile action to compile the partition containing the
271         // function.
272         auto CCInfo = CompileCallbackMgr.getCompileCallback();
273         StubInits[mangle(F.getName(), DL)] =
274           std::make_pair(CCInfo.getAddress(),
275                          JITSymbolBase::flagsFromGlobalValue(F));
276         CCInfo.setCompileAction([this, &LD, LMH, &F]() {
277           return this->extractAndCompile(LD, LMH, F);
278         });
279       }
280 
281       LMResources.StubsMgr = CreateIndirectStubsManager();
282       auto EC = LMResources.StubsMgr->createStubs(StubInits);
283       (void)EC;
284       // FIXME: This should be propagated back to the user. Stub creation may
285       //        fail for remote JITs.
286       assert(!EC && "Error generating stubs");
287     }
288 
289     // If this module doesn't contain any globals or aliases we can bail out
290     // early and avoid the overhead of creating and managing an empty globals
291     // module.
292     if (SrcM.global_empty() && SrcM.alias_empty())
293       return;
294 
295     // Create the GlobalValues module.
296     auto GVsM = llvm::make_unique<Module>((SrcM.getName() + ".globals").str(),
297                                           SrcM.getContext());
298     GVsM->setDataLayout(DL);
299 
300     ValueToValueMapTy VMap;
301 
302     // Clone global variable decls.
303     for (auto &GV : SrcM.globals())
304       if (!GV.isDeclaration() && !VMap.count(&GV))
305         cloneGlobalVariableDecl(*GVsM, GV, &VMap);
306 
307     // And the aliases.
308     for (auto &A : SrcM.aliases())
309       if (!VMap.count(&A))
310         cloneGlobalAliasDecl(*GVsM, A, VMap);
311 
312     // Now we need to clone the GV and alias initializers.
313 
314     // Initializers may refer to functions declared (but not defined) in this
315     // module. Build a materializer to clone decls on demand.
316     auto Materializer = createLambdaMaterializer(
317       [this, &GVsM, &LMResources](Value *V) -> Value* {
318         if (auto *F = dyn_cast<Function>(V)) {
319           // Decls in the original module just get cloned.
320           if (F->isDeclaration())
321             return cloneFunctionDecl(*GVsM, *F);
322 
323           // Definitions in the original module (which we have emitted stubs
324           // for at this point) get turned into a constant alias to the stub
325           // instead.
326           const DataLayout &DL = GVsM->getDataLayout();
327           std::string FName = mangle(F->getName(), DL);
328           auto StubSym = LMResources.StubsMgr->findStub(FName, false);
329           unsigned PtrBitWidth = DL.getPointerTypeSizeInBits(F->getType());
330           ConstantInt *StubAddr =
331             ConstantInt::get(GVsM->getContext(),
332                              APInt(PtrBitWidth, StubSym.getAddress()));
333           Constant *Init = ConstantExpr::getCast(Instruction::IntToPtr,
334                                                  StubAddr, F->getType());
335           return GlobalAlias::create(F->getFunctionType(),
336                                      F->getType()->getAddressSpace(),
337                                      F->getLinkage(), F->getName(),
338                                      Init, GVsM.get());
339         }
340         // else....
341         return nullptr;
342       });
343 
344     // Clone the global variable initializers.
345     for (auto &GV : SrcM.globals())
346       if (!GV.isDeclaration())
347         moveGlobalVariableInitializer(GV, VMap, &Materializer);
348 
349     // Clone the global alias initializers.
350     for (auto &A : SrcM.aliases()) {
351       auto *NewA = cast<GlobalAlias>(VMap[&A]);
352       assert(NewA && "Alias not cloned?");
353       Value *Init = MapValue(A.getAliasee(), VMap, RF_None, nullptr,
354                              &Materializer);
355       NewA->setAliasee(cast<Constant>(Init));
356     }
357 
358     // Build a resolver for the globals module and add it to the base layer.
359     auto GVsResolver = createLambdaResolver(
360         [&LD, LMH](const std::string &Name) {
361           auto &LMResources = LD.getLogicalModuleResources(LMH);
362           if (auto Sym = LMResources.StubsMgr->findStub(Name, false))
363             return Sym.toRuntimeDyldSymbol();
364           auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver;
365           return LDResolver->findSymbolInLogicalDylib(Name);
366         },
367         [&LD](const std::string &Name) {
368           auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver;
369           return LDResolver->findSymbol(Name);
370         });
371 
372     auto GVsH = LD.getDylibResources().ModuleAdder(BaseLayer, std::move(GVsM),
373                                                    std::move(GVsResolver));
374     LD.addToLogicalModule(LMH, GVsH);
375   }
376 
mangle(StringRef Name,const DataLayout & DL)377   static std::string mangle(StringRef Name, const DataLayout &DL) {
378     std::string MangledName;
379     {
380       raw_string_ostream MangledNameStream(MangledName);
381       Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
382     }
383     return MangledName;
384   }
385 
extractAndCompile(CODLogicalDylib & LD,LogicalModuleHandle LMH,Function & F)386   TargetAddress extractAndCompile(CODLogicalDylib &LD,
387                                   LogicalModuleHandle LMH,
388                                   Function &F) {
389     auto &LMResources = LD.getLogicalModuleResources(LMH);
390     Module &SrcM = LMResources.SourceModule->getResource();
391 
392     // If F is a declaration we must already have compiled it.
393     if (F.isDeclaration())
394       return 0;
395 
396     // Grab the name of the function being called here.
397     std::string CalledFnName = mangle(F.getName(), SrcM.getDataLayout());
398 
399     auto Part = Partition(F);
400     auto PartH = emitPartition(LD, LMH, Part);
401 
402     TargetAddress CalledAddr = 0;
403     for (auto *SubF : Part) {
404       std::string FnName = mangle(SubF->getName(), SrcM.getDataLayout());
405       auto FnBodySym = BaseLayer.findSymbolIn(PartH, FnName, false);
406       assert(FnBodySym && "Couldn't find function body.");
407 
408       TargetAddress FnBodyAddr = FnBodySym.getAddress();
409 
410       // If this is the function we're calling record the address so we can
411       // return it from this function.
412       if (SubF == &F)
413         CalledAddr = FnBodyAddr;
414 
415       // Update the function body pointer for the stub.
416       if (auto EC = LMResources.StubsMgr->updatePointer(FnName, FnBodyAddr))
417         return 0;
418     }
419 
420     return CalledAddr;
421   }
422 
423   template <typename PartitionT>
emitPartition(CODLogicalDylib & LD,LogicalModuleHandle LMH,const PartitionT & Part)424   BaseLayerModuleSetHandleT emitPartition(CODLogicalDylib &LD,
425                                           LogicalModuleHandle LMH,
426                                           const PartitionT &Part) {
427     auto &LMResources = LD.getLogicalModuleResources(LMH);
428     Module &SrcM = LMResources.SourceModule->getResource();
429 
430     // Create the module.
431     std::string NewName = SrcM.getName();
432     for (auto *F : Part) {
433       NewName += ".";
434       NewName += F->getName();
435     }
436 
437     auto M = llvm::make_unique<Module>(NewName, SrcM.getContext());
438     M->setDataLayout(SrcM.getDataLayout());
439     ValueToValueMapTy VMap;
440 
441     auto Materializer = createLambdaMaterializer([this, &LMResources, &M,
442                                                   &VMap](Value *V) -> Value * {
443       if (auto *GV = dyn_cast<GlobalVariable>(V))
444         return cloneGlobalVariableDecl(*M, *GV);
445 
446       if (auto *F = dyn_cast<Function>(V)) {
447         // Check whether we want to clone an available_externally definition.
448         if (!LMResources.StubsToClone.count(F))
449           return cloneFunctionDecl(*M, *F);
450 
451         // Ok - we want an inlinable stub. For that to work we need a decl
452         // for the stub pointer.
453         auto *StubPtr = createImplPointer(*F->getType(), *M,
454                                           F->getName() + "$stub_ptr", nullptr);
455         auto *ClonedF = cloneFunctionDecl(*M, *F);
456         makeStub(*ClonedF, *StubPtr);
457         ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage);
458         ClonedF->addFnAttr(Attribute::AlwaysInline);
459         return ClonedF;
460       }
461 
462       if (auto *A = dyn_cast<GlobalAlias>(V)) {
463         auto *Ty = A->getValueType();
464         if (Ty->isFunctionTy())
465           return Function::Create(cast<FunctionType>(Ty),
466                                   GlobalValue::ExternalLinkage, A->getName(),
467                                   M.get());
468 
469         return new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage,
470                                   nullptr, A->getName(), nullptr,
471                                   GlobalValue::NotThreadLocal,
472                                   A->getType()->getAddressSpace());
473       }
474 
475       return nullptr;
476     });
477 
478     // Create decls in the new module.
479     for (auto *F : Part)
480       cloneFunctionDecl(*M, *F, &VMap);
481 
482     // Move the function bodies.
483     for (auto *F : Part)
484       moveFunctionBody(*F, VMap, &Materializer);
485 
486     // Create memory manager and symbol resolver.
487     auto Resolver = createLambdaResolver(
488         [this, &LD, LMH](const std::string &Name) {
489           if (auto Sym = LD.findSymbolInternally(LMH, Name))
490             return Sym.toRuntimeDyldSymbol();
491           auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver;
492           return LDResolver->findSymbolInLogicalDylib(Name);
493         },
494         [this, &LD](const std::string &Name) {
495           auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver;
496           return LDResolver->findSymbol(Name);
497         });
498 
499     return LD.getDylibResources().ModuleAdder(BaseLayer, std::move(M),
500                                               std::move(Resolver));
501   }
502 
503   BaseLayerT &BaseLayer;
504   PartitioningFtor Partition;
505   CompileCallbackMgrT &CompileCallbackMgr;
506   IndirectStubsManagerBuilderT CreateIndirectStubsManager;
507 
508   LogicalDylibList LogicalDylibs;
509   bool CloneStubsIntoPartitions;
510 };
511 
512 } // End namespace orc.
513 } // End namespace llvm.
514 
515 #endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
516