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