Home | History | Annotate | Download | only in Orc
      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:
     48     LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {}
     49     Value *materialize(Value *V) final { return M(V); }
     50 
     51   private:
     52     MaterializerFtor M;
     53   };
     54 
     55   template <typename MaterializerFtor>
     56   LambdaMaterializer<MaterializerFtor>
     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;
     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:
     77     ResourceOwnerImpl(ResourcePtrT ResourcePtr)
     78       : ResourcePtr(std::move(ResourcePtr)) {}
     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>>
     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.
     99     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 
    112     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.
    135     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)
    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>
    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.
    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.
    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.
    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>
    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 
    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 
    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>
    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