CompileOnDemandLayer.h revision 296417
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/Transforms/Utils/Cloning.h" 23#include <list> 24#include <memory> 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, 40 typename CompileCallbackMgrT = JITCompileCallbackManager, 41 typename IndirectStubsMgrT = IndirectStubsManager> 42class CompileOnDemandLayer { 43private: 44 45 template <typename MaterializerFtor> 46 class LambdaMaterializer final : public ValueMaterializer { 47 public: 48 LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {} 49 Value *materializeDeclFor(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 SymbolResolverFtor 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 159public: 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(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 = 192 [Resolver](const std::string &Name) { 193 return Resolver->findSymbol(Name); 194 }; 195 196 auto &MemMgrRef = *MemMgr; 197 LDResources.MemMgr = 198 wrapOwnership<RuntimeDyld::MemoryManager>(std::move(MemMgr)); 199 200 LDResources.ModuleAdder = 201 [&MemMgrRef](BaseLayerT &B, std::unique_ptr<Module> M, 202 std::unique_ptr<RuntimeDyld::SymbolResolver> R) { 203 std::vector<std::unique_ptr<Module>> Ms; 204 Ms.push_back(std::move(M)); 205 return B.addModuleSet(std::move(Ms), &MemMgrRef, std::move(R)); 206 }; 207 208 // Process each of the modules in this module set. 209 for (auto &M : Ms) 210 addLogicalModule(LogicalDylibs.back(), std::move(M)); 211 212 return std::prev(LogicalDylibs.end()); 213 } 214 215 /// @brief Remove the module represented by the given handle. 216 /// 217 /// This will remove all modules in the layers below that were derived from 218 /// the module represented by H. 219 void removeModuleSet(ModuleSetHandleT H) { 220 LogicalDylibs.erase(H); 221 } 222 223 /// @brief Search for the given named symbol. 224 /// @param Name The name of the symbol to search for. 225 /// @param ExportedSymbolsOnly If true, search only for exported symbols. 226 /// @return A handle for the given named symbol, if it exists. 227 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) { 228 for (auto LDI = LogicalDylibs.begin(), LDE = LogicalDylibs.end(); 229 LDI != LDE; ++LDI) 230 if (auto Symbol = findSymbolIn(LDI, Name, ExportedSymbolsOnly)) 231 return Symbol; 232 return BaseLayer.findSymbol(Name, ExportedSymbolsOnly); 233 } 234 235 /// @brief Get the address of a symbol provided by this layer, or some layer 236 /// below this one. 237 JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name, 238 bool ExportedSymbolsOnly) { 239 return H->findSymbol(Name, ExportedSymbolsOnly); 240 } 241 242private: 243 244 template <typename ModulePtrT> 245 void addLogicalModule(CODLogicalDylib &LD, ModulePtrT SrcMPtr) { 246 247 // Bump the linkage and rename any anonymous/privote members in SrcM to 248 // ensure that everything will resolve properly after we partition SrcM. 249 makeAllSymbolsExternallyAccessible(*SrcMPtr); 250 251 // Create a logical module handle for SrcM within the logical dylib. 252 auto LMH = LD.createLogicalModule(); 253 auto &LMResources = LD.getLogicalModuleResources(LMH); 254 255 LMResources.SourceModule = wrapOwnership<Module>(std::move(SrcMPtr)); 256 257 Module &SrcM = LMResources.SourceModule->getResource(); 258 259 // Create the GlobalValues module. 260 const DataLayout &DL = SrcM.getDataLayout(); 261 auto GVsM = llvm::make_unique<Module>((SrcM.getName() + ".globals").str(), 262 SrcM.getContext()); 263 GVsM->setDataLayout(DL); 264 265 // Create function stubs. 266 ValueToValueMapTy VMap; 267 { 268 typename IndirectStubsMgrT::StubInitsMap StubInits; 269 for (auto &F : SrcM) { 270 // Skip declarations. 271 if (F.isDeclaration()) 272 continue; 273 274 // Record all functions defined by this module. 275 if (CloneStubsIntoPartitions) 276 LMResources.StubsToClone.insert(&F); 277 278 // Create a callback, associate it with the stub for the function, 279 // and set the compile action to compile the partition containing the 280 // function. 281 auto CCInfo = CompileCallbackMgr.getCompileCallback(); 282 StubInits[mangle(F.getName(), DL)] = 283 std::make_pair(CCInfo.getAddress(), 284 JITSymbolBase::flagsFromGlobalValue(F)); 285 CCInfo.setCompileAction([this, &LD, LMH, &F]() { 286 return this->extractAndCompile(LD, LMH, F); 287 }); 288 } 289 290 LMResources.StubsMgr = CreateIndirectStubsManager(); 291 auto EC = LMResources.StubsMgr->createStubs(StubInits); 292 (void)EC; 293 // FIXME: This should be propagated back to the user. Stub creation may 294 // fail for remote JITs. 295 assert(!EC && "Error generating stubs"); 296 } 297 298 // Clone global variable decls. 299 for (auto &GV : SrcM.globals()) 300 if (!GV.isDeclaration() && !VMap.count(&GV)) 301 cloneGlobalVariableDecl(*GVsM, GV, &VMap); 302 303 // And the aliases. 304 for (auto &A : SrcM.aliases()) 305 if (!VMap.count(&A)) 306 cloneGlobalAliasDecl(*GVsM, A, VMap); 307 308 // Now we need to clone the GV and alias initializers. 309 310 // Initializers may refer to functions declared (but not defined) in this 311 // module. Build a materializer to clone decls on demand. 312 auto Materializer = createLambdaMaterializer( 313 [this, &GVsM, &LMResources](Value *V) -> Value* { 314 if (auto *F = dyn_cast<Function>(V)) { 315 // Decls in the original module just get cloned. 316 if (F->isDeclaration()) 317 return cloneFunctionDecl(*GVsM, *F); 318 319 // Definitions in the original module (which we have emitted stubs 320 // for at this point) get turned into a constant alias to the stub 321 // instead. 322 const DataLayout &DL = GVsM->getDataLayout(); 323 std::string FName = mangle(F->getName(), DL); 324 auto StubSym = LMResources.StubsMgr->findStub(FName, false); 325 unsigned PtrBitWidth = DL.getPointerTypeSizeInBits(F->getType()); 326 ConstantInt *StubAddr = 327 ConstantInt::get(GVsM->getContext(), 328 APInt(PtrBitWidth, StubSym.getAddress())); 329 Constant *Init = ConstantExpr::getCast(Instruction::IntToPtr, 330 StubAddr, F->getType()); 331 return GlobalAlias::create(F->getFunctionType(), 332 F->getType()->getAddressSpace(), 333 F->getLinkage(), F->getName(), 334 Init, GVsM.get()); 335 } 336 // else.... 337 return nullptr; 338 }); 339 340 // Clone the global variable initializers. 341 for (auto &GV : SrcM.globals()) 342 if (!GV.isDeclaration()) 343 moveGlobalVariableInitializer(GV, VMap, &Materializer); 344 345 // Clone the global alias initializers. 346 for (auto &A : SrcM.aliases()) { 347 auto *NewA = cast<GlobalAlias>(VMap[&A]); 348 assert(NewA && "Alias not cloned?"); 349 Value *Init = MapValue(A.getAliasee(), VMap, RF_None, nullptr, 350 &Materializer); 351 NewA->setAliasee(cast<Constant>(Init)); 352 } 353 354 // Build a resolver for the globals module and add it to the base layer. 355 auto GVsResolver = createLambdaResolver( 356 [&LD, LMH](const std::string &Name) { 357 auto &LMResources = LD.getLogicalModuleResources(LMH); 358 if (auto Sym = LMResources.StubsMgr->findStub(Name, false)) 359 return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags()); 360 return LD.getDylibResources().ExternalSymbolResolver(Name); 361 }, 362 [](const std::string &Name) { 363 return RuntimeDyld::SymbolInfo(nullptr); 364 }); 365 366 auto GVsH = 367 LD.getDylibResources().ModuleAdder(BaseLayer, std::move(GVsM), 368 std::move(GVsResolver)); 369 LD.addToLogicalModule(LMH, GVsH); 370 } 371 372 static std::string mangle(StringRef Name, const DataLayout &DL) { 373 std::string MangledName; 374 { 375 raw_string_ostream MangledNameStream(MangledName); 376 Mangler::getNameWithPrefix(MangledNameStream, Name, DL); 377 } 378 return MangledName; 379 } 380 381 TargetAddress extractAndCompile(CODLogicalDylib &LD, 382 LogicalModuleHandle LMH, 383 Function &F) { 384 auto &LMResources = LD.getLogicalModuleResources(LMH); 385 Module &SrcM = LMResources.SourceModule->getResource(); 386 387 // If F is a declaration we must already have compiled it. 388 if (F.isDeclaration()) 389 return 0; 390 391 // Grab the name of the function being called here. 392 std::string CalledFnName = mangle(F.getName(), SrcM.getDataLayout()); 393 394 auto Part = Partition(F); 395 auto PartH = emitPartition(LD, LMH, Part); 396 397 TargetAddress CalledAddr = 0; 398 for (auto *SubF : Part) { 399 std::string FnName = mangle(SubF->getName(), SrcM.getDataLayout()); 400 auto FnBodySym = BaseLayer.findSymbolIn(PartH, FnName, false); 401 assert(FnBodySym && "Couldn't find function body."); 402 403 TargetAddress FnBodyAddr = FnBodySym.getAddress(); 404 405 // If this is the function we're calling record the address so we can 406 // return it from this function. 407 if (SubF == &F) 408 CalledAddr = FnBodyAddr; 409 410 // Update the function body pointer for the stub. 411 if (auto EC = LMResources.StubsMgr->updatePointer(FnName, FnBodyAddr)) 412 return 0; 413 } 414 415 return CalledAddr; 416 } 417 418 template <typename PartitionT> 419 BaseLayerModuleSetHandleT emitPartition(CODLogicalDylib &LD, 420 LogicalModuleHandle LMH, 421 const PartitionT &Part) { 422 auto &LMResources = LD.getLogicalModuleResources(LMH); 423 Module &SrcM = LMResources.SourceModule->getResource(); 424 425 // Create the module. 426 std::string NewName = SrcM.getName(); 427 for (auto *F : Part) { 428 NewName += "."; 429 NewName += F->getName(); 430 } 431 432 auto M = llvm::make_unique<Module>(NewName, SrcM.getContext()); 433 M->setDataLayout(SrcM.getDataLayout()); 434 ValueToValueMapTy VMap; 435 436 auto Materializer = createLambdaMaterializer([this, &LMResources, &M, 437 &VMap](Value *V) -> Value * { 438 if (auto *GV = dyn_cast<GlobalVariable>(V)) 439 return cloneGlobalVariableDecl(*M, *GV); 440 441 if (auto *F = dyn_cast<Function>(V)) { 442 // Check whether we want to clone an available_externally definition. 443 if (!LMResources.StubsToClone.count(F)) 444 return cloneFunctionDecl(*M, *F); 445 446 // Ok - we want an inlinable stub. For that to work we need a decl 447 // for the stub pointer. 448 auto *StubPtr = createImplPointer(*F->getType(), *M, 449 F->getName() + "$stub_ptr", nullptr); 450 auto *ClonedF = cloneFunctionDecl(*M, *F); 451 makeStub(*ClonedF, *StubPtr); 452 ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage); 453 ClonedF->addFnAttr(Attribute::AlwaysInline); 454 return ClonedF; 455 } 456 457 if (auto *A = dyn_cast<GlobalAlias>(V)) { 458 auto *Ty = A->getValueType(); 459 if (Ty->isFunctionTy()) 460 return Function::Create(cast<FunctionType>(Ty), 461 GlobalValue::ExternalLinkage, A->getName(), 462 M.get()); 463 464 return new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage, 465 nullptr, A->getName(), nullptr, 466 GlobalValue::NotThreadLocal, 467 A->getType()->getAddressSpace()); 468 } 469 470 return nullptr; 471 }); 472 473 // Create decls in the new module. 474 for (auto *F : Part) 475 cloneFunctionDecl(*M, *F, &VMap); 476 477 // Move the function bodies. 478 for (auto *F : Part) 479 moveFunctionBody(*F, VMap, &Materializer); 480 481 // Create memory manager and symbol resolver. 482 auto Resolver = createLambdaResolver( 483 [this, &LD, LMH](const std::string &Name) { 484 if (auto Symbol = LD.findSymbolInternally(LMH, Name)) 485 return RuntimeDyld::SymbolInfo(Symbol.getAddress(), 486 Symbol.getFlags()); 487 return LD.getDylibResources().ExternalSymbolResolver(Name); 488 }, 489 [this, &LD, LMH](const std::string &Name) { 490 if (auto Symbol = LD.findSymbolInternally(LMH, Name)) 491 return RuntimeDyld::SymbolInfo(Symbol.getAddress(), 492 Symbol.getFlags()); 493 return RuntimeDyld::SymbolInfo(nullptr); 494 }); 495 496 return LD.getDylibResources().ModuleAdder(BaseLayer, std::move(M), 497 std::move(Resolver)); 498 } 499 500 BaseLayerT &BaseLayer; 501 PartitioningFtor Partition; 502 CompileCallbackMgrT &CompileCallbackMgr; 503 IndirectStubsManagerBuilderT CreateIndirectStubsManager; 504 505 LogicalDylibList LogicalDylibs; 506 bool CloneStubsIntoPartitions; 507}; 508 509} // End namespace orc. 510} // End namespace llvm. 511 512#endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H 513