blob: bf946de532d3e2e5e50baaa84f31e3e247c289e7 [file] [log] [blame]
Andrew Scull0372a572018-11-16 15:47:06 +00001//===----------- 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
25namespace llvm {
26namespace 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.
30class ThreadSafeContext {
31private:
32 struct State {
33 State(std::unique_ptr<LLVMContext> Ctx) : Ctx(std::move(Ctx)) {}
34
35 std::unique_ptr<LLVMContext> Ctx;
36 std::recursive_mutex Mutex;
37 };
38
39public:
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:
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.
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.
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.
71 const LLVMContext *getContext() const { return S ? S->Ctx.get() : nullptr; }
72
73 Lock getLock() {
74 assert(S && "Can not lock an empty ThreadSafeContext");
75 return Lock(S);
76 }
77
78private:
79 std::shared_ptr<State> S;
80};
81
82/// An LLVM Module together with a shared ThreadSafeContext.
83class ThreadSafeModule {
84public:
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.
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.
115 ThreadSafeModule(std::unique_ptr<Module> M, ThreadSafeContext TSCtx)
116 : M(std::move(M)), TSCtx(std::move(TSCtx)) {}
117
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.
127 Module *getModule() { return M.get(); }
128
129 /// Get the module wrapped by this ThreadSafeModule.
130 const Module *getModule() const { return M.get(); }
131
132 /// Take out a lock on the ThreadSafeContext for this module.
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
146private:
147 std::unique_ptr<Module> M;
148 ThreadSafeContext TSCtx;
149};
150
151using GVPredicate = std::function<bool(const GlobalValue &)>;
152using GVModifier = std::function<void(GlobalValue &)>;
153
154/// Clones the given module on to a new context.
155ThreadSafeModule
156cloneToNewContext(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