1 //===----------- ThreadSafeModule.h -- Layer interfaces ---------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Thread safe wrappers and utilities for Module and LLVMContext.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H
14 #define LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H
16 #include "llvm/IR/LLVMContext.h"
17 #include "llvm/IR/Module.h"
18 #include "llvm/Support/Compiler.h"
27 /// An LLVMContext together with an associated mutex that can be used to lock
28 /// the context to prevent concurrent access by other threads.
29 class ThreadSafeContext
{
32 State(std::unique_ptr
<LLVMContext
> Ctx
) : Ctx(std::move(Ctx
)) {}
34 std::unique_ptr
<LLVMContext
> Ctx
;
35 std::recursive_mutex Mutex
;
39 // RAII based lock for ThreadSafeContext.
40 class LLVM_NODISCARD Lock
{
42 Lock(std::shared_ptr
<State
> S
) : S(std::move(S
)), L(this->S
->Mutex
) {}
45 std::shared_ptr
<State
> S
;
46 std::unique_lock
<std::recursive_mutex
> L
;
49 /// Construct a null context.
50 ThreadSafeContext() = default;
52 /// Construct a ThreadSafeContext from the given LLVMContext.
53 ThreadSafeContext(std::unique_ptr
<LLVMContext
> NewCtx
)
54 : S(std::make_shared
<State
>(std::move(NewCtx
))) {
55 assert(S
->Ctx
!= nullptr &&
56 "Can not construct a ThreadSafeContext from a nullptr");
59 /// Returns a pointer to the LLVMContext that was used to construct this
60 /// instance, or null if the instance was default constructed.
61 LLVMContext
*getContext() { return S
? S
->Ctx
.get() : nullptr; }
63 /// Returns a pointer to the LLVMContext that was used to construct this
64 /// instance, or null if the instance was default constructed.
65 const LLVMContext
*getContext() const { return S
? S
->Ctx
.get() : nullptr; }
67 Lock
getLock() const {
68 assert(S
&& "Can not lock an empty ThreadSafeContext");
73 std::shared_ptr
<State
> S
;
76 /// An LLVM Module together with a shared ThreadSafeContext.
77 class ThreadSafeModule
{
79 /// Default construct a ThreadSafeModule. This results in a null module and
81 ThreadSafeModule() = default;
83 ThreadSafeModule(ThreadSafeModule
&&Other
) = default;
85 ThreadSafeModule
&operator=(ThreadSafeModule
&&Other
) {
86 // We have to explicitly define this move operator to copy the fields in
87 // reverse order (i.e. module first) to ensure the dependencies are
88 // protected: The old module that is being overwritten must be destroyed
89 // *before* the context that it depends on.
90 // We also need to lock the context to make sure the module tear-down
91 // does not overlap any other work on the context.
93 auto L
= TSCtx
.getLock();
96 M
= std::move(Other
.M
);
97 TSCtx
= std::move(Other
.TSCtx
);
101 /// Construct a ThreadSafeModule from a unique_ptr<Module> and a
102 /// unique_ptr<LLVMContext>. This creates a new ThreadSafeContext from the
104 ThreadSafeModule(std::unique_ptr
<Module
> M
, std::unique_ptr
<LLVMContext
> Ctx
)
105 : M(std::move(M
)), TSCtx(std::move(Ctx
)) {}
107 /// Construct a ThreadSafeModule from a unique_ptr<Module> and an
108 /// existing ThreadSafeContext.
109 ThreadSafeModule(std::unique_ptr
<Module
> M
, ThreadSafeContext TSCtx
)
110 : M(std::move(M
)), TSCtx(std::move(TSCtx
)) {}
112 ~ThreadSafeModule() {
113 // We need to lock the context while we destruct the module.
115 auto L
= TSCtx
.getLock();
120 /// Boolean conversion: This ThreadSafeModule will evaluate to true if it
121 /// wraps a non-null module.
122 explicit operator bool() const {
124 assert(TSCtx
.getContext() &&
125 "Non-null module must have non-null context");
131 /// Locks the associated ThreadSafeContext and calls the given function
132 /// on the contained Module.
133 template <typename Func
>
134 auto withModuleDo(Func
&&F
) -> decltype(F(std::declval
<Module
&>())) {
135 assert(M
&& "Can not call on null module");
136 auto Lock
= TSCtx
.getLock();
140 /// Locks the associated ThreadSafeContext and calls the given function
141 /// on the contained Module.
142 template <typename Func
>
143 auto withModuleDo(Func
&&F
) const
144 -> decltype(F(std::declval
<const Module
&>())) {
145 auto Lock
= TSCtx
.getLock();
149 /// Get a raw pointer to the contained module without locking the context.
150 Module
*getModuleUnlocked() { return M
.get(); }
152 /// Get a raw pointer to the contained module without locking the context.
153 const Module
*getModuleUnlocked() const { return M
.get(); }
155 /// Returns the context for this ThreadSafeModule.
156 ThreadSafeContext
getContext() const { return TSCtx
; }
159 std::unique_ptr
<Module
> M
;
160 ThreadSafeContext TSCtx
;
163 using GVPredicate
= std::function
<bool(const GlobalValue
&)>;
164 using GVModifier
= std::function
<void(GlobalValue
&)>;
166 /// Clones the given module on to a new context.
168 cloneToNewContext(ThreadSafeModule
&TSMW
,
169 GVPredicate ShouldCloneDef
= GVPredicate(),
170 GVModifier UpdateClonedDefSource
= GVModifier());
172 } // End namespace orc
173 } // End namespace llvm
175 #endif // LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H