1 //===----- LLJIT.h -- An ORC-based JIT for compiling LLVM IR ----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // An ORC-based JIT for compiling LLVM IR. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_EXECUTIONENGINE_ORC_LLJIT_H 14 #define LLVM_EXECUTIONENGINE_ORC_LLJIT_H 15 16 #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" 17 #include "llvm/ExecutionEngine/Orc/CompileUtils.h" 18 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" 19 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" 20 #include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" 21 #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" 22 #include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h" 23 #include "llvm/Support/Debug.h" 24 #include "llvm/Support/ThreadPool.h" 25 26 namespace llvm { 27 namespace orc { 28 29 class LLJITBuilderState; 30 class LLLazyJITBuilderState; 31 class ObjectTransformLayer; 32 class TargetProcessControl; 33 34 /// A pre-fabricated ORC JIT stack that can serve as an alternative to MCJIT. 35 /// 36 /// Create instances using LLJITBuilder. 37 class LLJIT { 38 template <typename, typename, typename> friend class LLJITBuilderSetters; 39 40 friend void setUpGenericLLVMIRPlatform(LLJIT &J); 41 42 public: 43 /// Initializer support for LLJIT. 44 class PlatformSupport { 45 public: 46 virtual ~PlatformSupport(); 47 48 virtual Error initialize(JITDylib &JD) = 0; 49 50 virtual Error deinitialize(JITDylib &JD) = 0; 51 52 protected: 53 static void setInitTransform(LLJIT &J, 54 IRTransformLayer::TransformFunction T); 55 }; 56 57 /// Destruct this instance. If a multi-threaded instance, waits for all 58 /// compile threads to complete. 59 ~LLJIT(); 60 61 /// Returns the ExecutionSession for this instance. getExecutionSession()62 ExecutionSession &getExecutionSession() { return *ES; } 63 64 /// Returns a reference to the triple for this instance. getTargetTriple()65 const Triple &getTargetTriple() const { return TT; } 66 67 /// Returns a reference to the DataLayout for this instance. getDataLayout()68 const DataLayout &getDataLayout() const { return DL; } 69 70 /// Returns a reference to the JITDylib representing the JIT'd main program. getMainJITDylib()71 JITDylib &getMainJITDylib() { return *Main; } 72 73 /// Returns the JITDylib with the given name, or nullptr if no JITDylib with 74 /// that name exists. getJITDylibByName(StringRef Name)75 JITDylib *getJITDylibByName(StringRef Name) { 76 return ES->getJITDylibByName(Name); 77 } 78 79 /// Create a new JITDylib with the given name and return a reference to it. 80 /// 81 /// JITDylib names must be unique. If the given name is derived from user 82 /// input or elsewhere in the environment then the client should check 83 /// (e.g. by calling getJITDylibByName) that the given name is not already in 84 /// use. createJITDylib(std::string Name)85 Expected<JITDylib &> createJITDylib(std::string Name) { 86 return ES->createJITDylib(std::move(Name)); 87 } 88 89 /// Adds an IR module with the given ResourceTracker. 90 Error addIRModule(ResourceTrackerSP RT, ThreadSafeModule TSM); 91 92 /// Adds an IR module to the given JITDylib. 93 Error addIRModule(JITDylib &JD, ThreadSafeModule TSM); 94 95 /// Adds an IR module to the Main JITDylib. addIRModule(ThreadSafeModule TSM)96 Error addIRModule(ThreadSafeModule TSM) { 97 return addIRModule(*Main, std::move(TSM)); 98 } 99 100 /// Adds an object file to the given JITDylib. 101 Error addObjectFile(ResourceTrackerSP RT, std::unique_ptr<MemoryBuffer> Obj); 102 103 /// Adds an object file to the given JITDylib. 104 Error addObjectFile(JITDylib &JD, std::unique_ptr<MemoryBuffer> Obj); 105 106 /// Adds an object file to the given JITDylib. addObjectFile(std::unique_ptr<MemoryBuffer> Obj)107 Error addObjectFile(std::unique_ptr<MemoryBuffer> Obj) { 108 return addObjectFile(*Main, std::move(Obj)); 109 } 110 111 /// Look up a symbol in JITDylib JD by the symbol's linker-mangled name (to 112 /// look up symbols based on their IR name use the lookup function instead). 113 Expected<JITEvaluatedSymbol> lookupLinkerMangled(JITDylib &JD, 114 SymbolStringPtr Name); 115 116 /// Look up a symbol in JITDylib JD by the symbol's linker-mangled name (to 117 /// look up symbols based on their IR name use the lookup function instead). lookupLinkerMangled(JITDylib & JD,StringRef Name)118 Expected<JITEvaluatedSymbol> lookupLinkerMangled(JITDylib &JD, 119 StringRef Name) { 120 return lookupLinkerMangled(JD, ES->intern(Name)); 121 } 122 123 /// Look up a symbol in the main JITDylib by the symbol's linker-mangled name 124 /// (to look up symbols based on their IR name use the lookup function 125 /// instead). lookupLinkerMangled(StringRef Name)126 Expected<JITEvaluatedSymbol> lookupLinkerMangled(StringRef Name) { 127 return lookupLinkerMangled(*Main, Name); 128 } 129 130 /// Look up a symbol in JITDylib JD based on its IR symbol name. lookup(JITDylib & JD,StringRef UnmangledName)131 Expected<JITEvaluatedSymbol> lookup(JITDylib &JD, StringRef UnmangledName) { 132 return lookupLinkerMangled(JD, mangle(UnmangledName)); 133 } 134 135 /// Look up a symbol in the main JITDylib based on its IR symbol name. lookup(StringRef UnmangledName)136 Expected<JITEvaluatedSymbol> lookup(StringRef UnmangledName) { 137 return lookup(*Main, UnmangledName); 138 } 139 140 /// Set the PlatformSupport instance. setPlatformSupport(std::unique_ptr<PlatformSupport> PS)141 void setPlatformSupport(std::unique_ptr<PlatformSupport> PS) { 142 this->PS = std::move(PS); 143 } 144 145 /// Get the PlatformSupport instance. getPlatformSupport()146 PlatformSupport *getPlatformSupport() { return PS.get(); } 147 148 /// Run the initializers for the given JITDylib. initialize(JITDylib & JD)149 Error initialize(JITDylib &JD) { 150 DEBUG_WITH_TYPE("orc", { 151 dbgs() << "LLJIT running initializers for JITDylib \"" << JD.getName() 152 << "\"\n"; 153 }); 154 assert(PS && "PlatformSupport must be set to run initializers."); 155 return PS->initialize(JD); 156 } 157 158 /// Run the deinitializers for the given JITDylib. deinitialize(JITDylib & JD)159 Error deinitialize(JITDylib &JD) { 160 DEBUG_WITH_TYPE("orc", { 161 dbgs() << "LLJIT running deinitializers for JITDylib \"" << JD.getName() 162 << "\"\n"; 163 }); 164 assert(PS && "PlatformSupport must be set to run initializers."); 165 return PS->deinitialize(JD); 166 } 167 168 /// Returns a reference to the ObjLinkingLayer getObjLinkingLayer()169 ObjectLayer &getObjLinkingLayer() { return *ObjLinkingLayer; } 170 171 /// Returns a reference to the object transform layer. getObjTransformLayer()172 ObjectTransformLayer &getObjTransformLayer() { return *ObjTransformLayer; } 173 174 /// Returns a reference to the IR transform layer. getIRTransformLayer()175 IRTransformLayer &getIRTransformLayer() { return *TransformLayer; } 176 177 /// Returns a reference to the IR compile layer. getIRCompileLayer()178 IRCompileLayer &getIRCompileLayer() { return *CompileLayer; } 179 180 /// Returns a linker-mangled version of UnmangledName. 181 std::string mangle(StringRef UnmangledName) const; 182 183 /// Returns an interned, linker-mangled version of UnmangledName. mangleAndIntern(StringRef UnmangledName)184 SymbolStringPtr mangleAndIntern(StringRef UnmangledName) const { 185 return ES->intern(mangle(UnmangledName)); 186 } 187 188 protected: 189 static Expected<std::unique_ptr<ObjectLayer>> 190 createObjectLinkingLayer(LLJITBuilderState &S, ExecutionSession &ES); 191 192 static Expected<std::unique_ptr<IRCompileLayer::IRCompiler>> 193 createCompileFunction(LLJITBuilderState &S, JITTargetMachineBuilder JTMB); 194 195 /// Create an LLJIT instance with a single compile thread. 196 LLJIT(LLJITBuilderState &S, Error &Err); 197 198 Error applyDataLayout(Module &M); 199 200 void recordCtorDtors(Module &M); 201 202 std::unique_ptr<ExecutionSession> ES; 203 std::unique_ptr<PlatformSupport> PS; 204 205 JITDylib *Main = nullptr; 206 207 DataLayout DL; 208 Triple TT; 209 std::unique_ptr<ThreadPool> CompileThreads; 210 211 std::unique_ptr<ObjectLayer> ObjLinkingLayer; 212 std::unique_ptr<ObjectTransformLayer> ObjTransformLayer; 213 std::unique_ptr<IRCompileLayer> CompileLayer; 214 std::unique_ptr<IRTransformLayer> TransformLayer; 215 std::unique_ptr<IRTransformLayer> InitHelperTransformLayer; 216 }; 217 218 /// An extended version of LLJIT that supports lazy function-at-a-time 219 /// compilation of LLVM IR. 220 class LLLazyJIT : public LLJIT { 221 template <typename, typename, typename> friend class LLJITBuilderSetters; 222 223 public: 224 225 /// Sets the partition function. 226 void setPartitionFunction(CompileOnDemandLayer::PartitionFunction Partition)227 setPartitionFunction(CompileOnDemandLayer::PartitionFunction Partition) { 228 CODLayer->setPartitionFunction(std::move(Partition)); 229 } 230 231 /// Returns a reference to the on-demand layer. getCompileOnDemandLayer()232 CompileOnDemandLayer &getCompileOnDemandLayer() { return *CODLayer; } 233 234 /// Add a module to be lazily compiled to JITDylib JD. 235 Error addLazyIRModule(JITDylib &JD, ThreadSafeModule M); 236 237 /// Add a module to be lazily compiled to the main JITDylib. addLazyIRModule(ThreadSafeModule M)238 Error addLazyIRModule(ThreadSafeModule M) { 239 return addLazyIRModule(*Main, std::move(M)); 240 } 241 242 private: 243 244 // Create a single-threaded LLLazyJIT instance. 245 LLLazyJIT(LLLazyJITBuilderState &S, Error &Err); 246 247 std::unique_ptr<LazyCallThroughManager> LCTMgr; 248 std::unique_ptr<CompileOnDemandLayer> CODLayer; 249 }; 250 251 class LLJITBuilderState { 252 public: 253 using ObjectLinkingLayerCreator = 254 std::function<Expected<std::unique_ptr<ObjectLayer>>(ExecutionSession &, 255 const Triple &)>; 256 257 using CompileFunctionCreator = 258 std::function<Expected<std::unique_ptr<IRCompileLayer::IRCompiler>>( 259 JITTargetMachineBuilder JTMB)>; 260 261 using PlatformSetupFunction = std::function<Error(LLJIT &J)>; 262 263 std::unique_ptr<ExecutionSession> ES; 264 Optional<JITTargetMachineBuilder> JTMB; 265 Optional<DataLayout> DL; 266 ObjectLinkingLayerCreator CreateObjectLinkingLayer; 267 CompileFunctionCreator CreateCompileFunction; 268 PlatformSetupFunction SetUpPlatform; 269 unsigned NumCompileThreads = 0; 270 TargetProcessControl *TPC = nullptr; 271 272 /// Called prior to JIT class construcion to fix up defaults. 273 Error prepareForConstruction(); 274 }; 275 276 template <typename JITType, typename SetterImpl, typename State> 277 class LLJITBuilderSetters { 278 public: 279 280 /// Set an ExecutionSession for this instance. setExecutionSession(std::unique_ptr<ExecutionSession> ES)281 SetterImpl &setExecutionSession(std::unique_ptr<ExecutionSession> ES) { 282 impl().ES = std::move(ES); 283 return impl(); 284 } 285 286 /// Set the JITTargetMachineBuilder for this instance. 287 /// 288 /// If this method is not called, JITTargetMachineBuilder::detectHost will be 289 /// used to construct a default target machine builder for the host platform. setJITTargetMachineBuilder(JITTargetMachineBuilder JTMB)290 SetterImpl &setJITTargetMachineBuilder(JITTargetMachineBuilder JTMB) { 291 impl().JTMB = std::move(JTMB); 292 return impl(); 293 } 294 295 /// Return a reference to the JITTargetMachineBuilder. 296 /// getJITTargetMachineBuilder()297 Optional<JITTargetMachineBuilder> &getJITTargetMachineBuilder() { 298 return impl().JTMB; 299 } 300 301 /// Set a DataLayout for this instance. If no data layout is specified then 302 /// the target's default data layout will be used. setDataLayout(Optional<DataLayout> DL)303 SetterImpl &setDataLayout(Optional<DataLayout> DL) { 304 impl().DL = std::move(DL); 305 return impl(); 306 } 307 308 /// Set an ObjectLinkingLayer creation function. 309 /// 310 /// If this method is not called, a default creation function will be used 311 /// that will construct an RTDyldObjectLinkingLayer. setObjectLinkingLayerCreator(LLJITBuilderState::ObjectLinkingLayerCreator CreateObjectLinkingLayer)312 SetterImpl &setObjectLinkingLayerCreator( 313 LLJITBuilderState::ObjectLinkingLayerCreator CreateObjectLinkingLayer) { 314 impl().CreateObjectLinkingLayer = std::move(CreateObjectLinkingLayer); 315 return impl(); 316 } 317 318 /// Set a CompileFunctionCreator. 319 /// 320 /// If this method is not called, a default creation function wil be used 321 /// that will construct a basic IR compile function that is compatible with 322 /// the selected number of threads (SimpleCompiler for '0' compile threads, 323 /// ConcurrentIRCompiler otherwise). setCompileFunctionCreator(LLJITBuilderState::CompileFunctionCreator CreateCompileFunction)324 SetterImpl &setCompileFunctionCreator( 325 LLJITBuilderState::CompileFunctionCreator CreateCompileFunction) { 326 impl().CreateCompileFunction = std::move(CreateCompileFunction); 327 return impl(); 328 } 329 330 /// Set up an PlatformSetupFunction. 331 /// 332 /// If this method is not called then setUpGenericLLVMIRPlatform 333 /// will be used to configure the JIT's platform support. 334 SetterImpl & setPlatformSetUp(LLJITBuilderState::PlatformSetupFunction SetUpPlatform)335 setPlatformSetUp(LLJITBuilderState::PlatformSetupFunction SetUpPlatform) { 336 impl().SetUpPlatform = std::move(SetUpPlatform); 337 return impl(); 338 } 339 340 /// Set the number of compile threads to use. 341 /// 342 /// If set to zero, compilation will be performed on the execution thread when 343 /// JITing in-process. If set to any other number N, a thread pool of N 344 /// threads will be created for compilation. 345 /// 346 /// If this method is not called, behavior will be as if it were called with 347 /// a zero argument. setNumCompileThreads(unsigned NumCompileThreads)348 SetterImpl &setNumCompileThreads(unsigned NumCompileThreads) { 349 impl().NumCompileThreads = NumCompileThreads; 350 return impl(); 351 } 352 353 /// Set a TargetProcessControl object. 354 /// 355 /// If the platform uses ObjectLinkingLayer by default and no 356 /// ObjectLinkingLayerCreator has been set then the TargetProcessControl 357 /// object will be used to supply the memory manager for the 358 /// ObjectLinkingLayer. setTargetProcessControl(TargetProcessControl & TPC)359 SetterImpl &setTargetProcessControl(TargetProcessControl &TPC) { 360 impl().TPC = &TPC; 361 return impl(); 362 } 363 364 /// Create an instance of the JIT. create()365 Expected<std::unique_ptr<JITType>> create() { 366 if (auto Err = impl().prepareForConstruction()) 367 return std::move(Err); 368 369 Error Err = Error::success(); 370 std::unique_ptr<JITType> J(new JITType(impl(), Err)); 371 if (Err) 372 return std::move(Err); 373 return std::move(J); 374 } 375 376 protected: impl()377 SetterImpl &impl() { return static_cast<SetterImpl &>(*this); } 378 }; 379 380 /// Constructs LLJIT instances. 381 class LLJITBuilder 382 : public LLJITBuilderState, 383 public LLJITBuilderSetters<LLJIT, LLJITBuilder, LLJITBuilderState> {}; 384 385 class LLLazyJITBuilderState : public LLJITBuilderState { 386 friend class LLLazyJIT; 387 388 public: 389 using IndirectStubsManagerBuilderFunction = 390 std::function<std::unique_ptr<IndirectStubsManager>()>; 391 392 Triple TT; 393 JITTargetAddress LazyCompileFailureAddr = 0; 394 std::unique_ptr<LazyCallThroughManager> LCTMgr; 395 IndirectStubsManagerBuilderFunction ISMBuilder; 396 397 Error prepareForConstruction(); 398 }; 399 400 template <typename JITType, typename SetterImpl, typename State> 401 class LLLazyJITBuilderSetters 402 : public LLJITBuilderSetters<JITType, SetterImpl, State> { 403 public: 404 /// Set the address in the target address to call if a lazy compile fails. 405 /// 406 /// If this method is not called then the value will default to 0. setLazyCompileFailureAddr(JITTargetAddress Addr)407 SetterImpl &setLazyCompileFailureAddr(JITTargetAddress Addr) { 408 this->impl().LazyCompileFailureAddr = Addr; 409 return this->impl(); 410 } 411 412 /// Set the lazy-callthrough manager. 413 /// 414 /// If this method is not called then a default, in-process lazy callthrough 415 /// manager for the host platform will be used. 416 SetterImpl & setLazyCallthroughManager(std::unique_ptr<LazyCallThroughManager> LCTMgr)417 setLazyCallthroughManager(std::unique_ptr<LazyCallThroughManager> LCTMgr) { 418 this->impl().LCTMgr = std::move(LCTMgr); 419 return this->impl(); 420 } 421 422 /// Set the IndirectStubsManager builder function. 423 /// 424 /// If this method is not called then a default, in-process 425 /// IndirectStubsManager builder for the host platform will be used. setIndirectStubsManagerBuilder(LLLazyJITBuilderState::IndirectStubsManagerBuilderFunction ISMBuilder)426 SetterImpl &setIndirectStubsManagerBuilder( 427 LLLazyJITBuilderState::IndirectStubsManagerBuilderFunction ISMBuilder) { 428 this->impl().ISMBuilder = std::move(ISMBuilder); 429 return this->impl(); 430 } 431 }; 432 433 /// Constructs LLLazyJIT instances. 434 class LLLazyJITBuilder 435 : public LLLazyJITBuilderState, 436 public LLLazyJITBuilderSetters<LLLazyJIT, LLLazyJITBuilder, 437 LLLazyJITBuilderState> {}; 438 439 /// Configure the LLJIT instance to scrape modules for llvm.global_ctors and 440 /// llvm.global_dtors variables and (if present) build initialization and 441 /// deinitialization functions. Platform specific initialization configurations 442 /// should be preferred where available. 443 void setUpGenericLLVMIRPlatform(LLJIT &J); 444 445 /// Configure the LLJIT instance to use MachOPlatform support. 446 /// 447 /// Warning: MachOPlatform *requires* that LLJIT be configured to use 448 /// ObjectLinkingLayer (default on platforms supported by JITLink). If 449 /// MachOPlatform is used with RTDyldObjectLinkingLayer it will result in 450 /// undefined behavior). 451 /// 452 /// MachOPlatform installs an ObjectLinkingLayer plugin to scrape initializers 453 /// from the __mod_inits section. It also provides interposes for the dlfcn 454 /// functions (dlopen, dlclose, dlsym, dlerror) that work for JITDylibs as 455 /// well as regular libraries (JITDylibs will be preferenced, so make sure 456 /// your JITDylib names do not shadow any real library paths). 457 Error setUpMachOPlatform(LLJIT &J); 458 459 /// Configure the LLJIT instance to disable platform support explicitly. This is 460 /// useful in two cases: for platforms that don't have such requirements and for 461 /// platforms, that we have no explicit support yet and that don't work well 462 /// with the generic IR platform. 463 Error setUpInactivePlatform(LLJIT &J); 464 465 } // End namespace orc 466 } // End namespace llvm 467 468 #endif // LLVM_EXECUTIONENGINE_ORC_LLJIT_H 469