diff options
Diffstat (limited to 'clang-r353983e/include/llvm/ExecutionEngine/Orc/ThreadSafeModule.h')
| -rw-r--r-- | clang-r353983e/include/llvm/ExecutionEngine/Orc/ThreadSafeModule.h | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/clang-r353983e/include/llvm/ExecutionEngine/Orc/ThreadSafeModule.h b/clang-r353983e/include/llvm/ExecutionEngine/Orc/ThreadSafeModule.h new file mode 100644 index 00000000..57875003 --- /dev/null +++ b/clang-r353983e/include/llvm/ExecutionEngine/Orc/ThreadSafeModule.h @@ -0,0 +1,162 @@ +//===----------- ThreadSafeModule.h -- Layer interfaces ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Thread safe wrappers and utilities for Module and LLVMContext. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H +#define LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H + +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/Compiler.h" + +#include <functional> +#include <memory> +#include <mutex> + +namespace llvm { +namespace orc { + +/// An LLVMContext together with an associated mutex that can be used to lock +/// the context to prevent concurrent access by other threads. +class ThreadSafeContext { +private: + struct State { + State(std::unique_ptr<LLVMContext> Ctx) : Ctx(std::move(Ctx)) {} + + std::unique_ptr<LLVMContext> Ctx; + std::recursive_mutex Mutex; + }; + +public: + // RAII based lock for ThreadSafeContext. + class LLVM_NODISCARD Lock { + private: + using UnderlyingLock = std::lock_guard<std::recursive_mutex>; + + public: + Lock(std::shared_ptr<State> S) + : S(std::move(S)), + L(llvm::make_unique<UnderlyingLock>(this->S->Mutex)) {} + + private: + std::shared_ptr<State> S; + std::unique_ptr<UnderlyingLock> L; + }; + + /// Construct a null context. + ThreadSafeContext() = default; + + /// Construct a ThreadSafeContext from the given LLVMContext. + ThreadSafeContext(std::unique_ptr<LLVMContext> NewCtx) + : S(std::make_shared<State>(std::move(NewCtx))) { + assert(S->Ctx != nullptr && + "Can not construct a ThreadSafeContext from a nullptr"); + } + + /// Returns a pointer to the LLVMContext that was used to construct this + /// instance, or null if the instance was default constructed. + LLVMContext *getContext() { return S ? S->Ctx.get() : nullptr; } + + /// Returns a pointer to the LLVMContext that was used to construct this + /// instance, or null if the instance was default constructed. + const LLVMContext *getContext() const { return S ? S->Ctx.get() : nullptr; } + + Lock getLock() { + assert(S && "Can not lock an empty ThreadSafeContext"); + return Lock(S); + } + +private: + std::shared_ptr<State> S; +}; + +/// An LLVM Module together with a shared ThreadSafeContext. +class ThreadSafeModule { +public: + /// Default construct a ThreadSafeModule. This results in a null module and + /// null context. + ThreadSafeModule() = default; + + ThreadSafeModule(ThreadSafeModule &&Other) = default; + + ThreadSafeModule &operator=(ThreadSafeModule &&Other) { + // We have to explicitly define this move operator to copy the fields in + // reverse order (i.e. module first) to ensure the dependencies are + // protected: The old module that is being overwritten must be destroyed + // *before* the context that it depends on. + // We also need to lock the context to make sure the module tear-down + // does not overlap any other work on the context. + if (M) { + auto L = getContextLock(); + M = nullptr; + } + M = std::move(Other.M); + TSCtx = std::move(Other.TSCtx); + return *this; + } + + /// Construct a ThreadSafeModule from a unique_ptr<Module> and a + /// unique_ptr<LLVMContext>. This creates a new ThreadSafeContext from the + /// given context. + ThreadSafeModule(std::unique_ptr<Module> M, std::unique_ptr<LLVMContext> Ctx) + : M(std::move(M)), TSCtx(std::move(Ctx)) {} + + /// Construct a ThreadSafeModule from a unique_ptr<Module> and an + /// existing ThreadSafeContext. + ThreadSafeModule(std::unique_ptr<Module> M, ThreadSafeContext TSCtx) + : M(std::move(M)), TSCtx(std::move(TSCtx)) {} + + ~ThreadSafeModule() { + // We need to lock the context while we destruct the module. + if (M) { + auto L = getContextLock(); + M = nullptr; + } + } + + /// Get the module wrapped by this ThreadSafeModule. + Module *getModule() { return M.get(); } + + /// Get the module wrapped by this ThreadSafeModule. + const Module *getModule() const { return M.get(); } + + /// Take out a lock on the ThreadSafeContext for this module. + ThreadSafeContext::Lock getContextLock() { return TSCtx.getLock(); } + + /// Boolean conversion: This ThreadSafeModule will evaluate to true if it + /// wraps a non-null module. + explicit operator bool() { + if (M) { + assert(TSCtx.getContext() && + "Non-null module must have non-null context"); + return true; + } + return false; + } + +private: + std::unique_ptr<Module> M; + ThreadSafeContext TSCtx; +}; + +using GVPredicate = std::function<bool(const GlobalValue &)>; +using GVModifier = std::function<void(GlobalValue &)>; + +/// Clones the given module on to a new context. +ThreadSafeModule +cloneToNewContext(ThreadSafeModule &TSMW, + GVPredicate ShouldCloneDef = GVPredicate(), + GVModifier UpdateClonedDefSource = GVModifier()); + +} // End namespace orc +} // End namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H |
