1 //===----------- ThreadSafeModule.h -- Layer interfaces ---------*- 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 // Thread safe wrappers and utilities for Module and LLVMContext. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H 15 #define LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H 16 17 #include "llvm/IR/LLVMContext.h" 18 #include "llvm/IR/Module.h" 19 #include "llvm/Support/Compiler.h" 20 21 #include <functional> 22 #include <memory> 23 #include <mutex> 24 25 namespace llvm { 26 namespace orc { 27 28 /// An LLVMContext together with an associated mutex that can be used to lock 29 /// the context to prevent concurrent access by other threads. 30 class ThreadSafeContext { 31 private: 32 struct State { StateState33 State(std::unique_ptr<LLVMContext> Ctx) : Ctx(std::move(Ctx)) {} 34 35 std::unique_ptr<LLVMContext> Ctx; 36 std::recursive_mutex Mutex; 37 }; 38 39 public: 40 // RAII based lock for ThreadSafeContext. 41 class LLVM_NODISCARD Lock { 42 private: 43 using UnderlyingLock = std::lock_guard<std::recursive_mutex>; 44 45 public: Lock(std::shared_ptr<State> S)46 Lock(std::shared_ptr<State> S) 47 : S(std::move(S)), 48 L(llvm::make_unique<UnderlyingLock>(this->S->Mutex)) {} 49 50 private: 51 std::shared_ptr<State> S; 52 std::unique_ptr<UnderlyingLock> L; 53 }; 54 55 /// Construct a null context. 56 ThreadSafeContext() = default; 57 58 /// Construct a ThreadSafeContext from the given LLVMContext. ThreadSafeContext(std::unique_ptr<LLVMContext> NewCtx)59 ThreadSafeContext(std::unique_ptr<LLVMContext> NewCtx) 60 : S(std::make_shared<State>(std::move(NewCtx))) { 61 assert(S->Ctx != nullptr && 62 "Can not construct a ThreadSafeContext from a nullptr"); 63 } 64 65 /// Returns a pointer to the LLVMContext that was used to construct this 66 /// instance, or null if the instance was default constructed. getContext()67 LLVMContext *getContext() { return S ? S->Ctx.get() : nullptr; } 68 69 /// Returns a pointer to the LLVMContext that was used to construct this 70 /// instance, or null if the instance was default constructed. getContext()71 const LLVMContext *getContext() const { return S ? S->Ctx.get() : nullptr; } 72 getLock()73 Lock getLock() { 74 assert(S && "Can not lock an empty ThreadSafeContext"); 75 return Lock(S); 76 } 77 78 private: 79 std::shared_ptr<State> S; 80 }; 81 82 /// An LLVM Module together with a shared ThreadSafeContext. 83 class ThreadSafeModule { 84 public: 85 /// Default construct a ThreadSafeModule. This results in a null module and 86 /// null context. 87 ThreadSafeModule() = default; 88 89 ThreadSafeModule(ThreadSafeModule &&Other) = default; 90 91 ThreadSafeModule &operator=(ThreadSafeModule &&Other) { 92 // We have to explicitly define this move operator to copy the fields in 93 // reverse order (i.e. module first) to ensure the dependencies are 94 // protected: The old module that is being overwritten must be destroyed 95 // *before* the context that it depends on. 96 // We also need to lock the context to make sure the module tear-down 97 // does not overlap any other work on the context. 98 if (M) { 99 auto L = getContextLock(); 100 M = nullptr; 101 } 102 M = std::move(Other.M); 103 TSCtx = std::move(Other.TSCtx); 104 return *this; 105 } 106 107 /// Construct a ThreadSafeModule from a unique_ptr<Module> and a 108 /// unique_ptr<LLVMContext>. This creates a new ThreadSafeContext from the 109 /// given context. ThreadSafeModule(std::unique_ptr<Module> M,std::unique_ptr<LLVMContext> Ctx)110 ThreadSafeModule(std::unique_ptr<Module> M, std::unique_ptr<LLVMContext> Ctx) 111 : M(std::move(M)), TSCtx(std::move(Ctx)) {} 112 113 /// Construct a ThreadSafeModule from a unique_ptr<Module> and an 114 /// existing ThreadSafeContext. ThreadSafeModule(std::unique_ptr<Module> M,ThreadSafeContext TSCtx)115 ThreadSafeModule(std::unique_ptr<Module> M, ThreadSafeContext TSCtx) 116 : M(std::move(M)), TSCtx(std::move(TSCtx)) {} 117 ~ThreadSafeModule()118 ~ThreadSafeModule() { 119 // We need to lock the context while we destruct the module. 120 if (M) { 121 auto L = getContextLock(); 122 M = nullptr; 123 } 124 } 125 126 /// Get the module wrapped by this ThreadSafeModule. getModule()127 Module *getModule() { return M.get(); } 128 129 /// Get the module wrapped by this ThreadSafeModule. getModule()130 const Module *getModule() const { return M.get(); } 131 132 /// Take out a lock on the ThreadSafeContext for this module. getContextLock()133 ThreadSafeContext::Lock getContextLock() { return TSCtx.getLock(); } 134 135 /// Boolean conversion: This ThreadSafeModule will evaluate to true if it 136 /// wraps a non-null module. 137 explicit operator bool() { 138 if (M) { 139 assert(TSCtx.getContext() && 140 "Non-null module must have non-null context"); 141 return true; 142 } 143 return false; 144 } 145 146 private: 147 std::unique_ptr<Module> M; 148 ThreadSafeContext TSCtx; 149 }; 150 151 using GVPredicate = std::function<bool(const GlobalValue &)>; 152 using GVModifier = std::function<void(GlobalValue &)>; 153 154 /// Clones the given module on to a new context. 155 ThreadSafeModule 156 cloneToNewContext(ThreadSafeModule &TSMW, 157 GVPredicate ShouldCloneDef = GVPredicate(), 158 GVModifier UpdateClonedDefSource = GVModifier()); 159 160 } // End namespace orc 161 } // End namespace llvm 162 163 #endif // LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H 164