1cca2f0f7e
Prior to the upgrade to LLVM13, child interpreters used to also lookup symbols in their parent. This commit introduces a `DefinitionGenerator` that allows for symbol lookup across different `IncrementalJIT` instances, which restores the old behavior. This change fixes the following tests: - CodeUnloading/AtExit.C - MultipleInterpreters/MultipleInterpreters.C Fixes #12455.
134 lines
4.8 KiB
C++
134 lines
4.8 KiB
C++
//--------------------------------------------------------------------*- C++ -*-
|
|
// CLING - the C++ LLVM-based InterpreterG :)
|
|
// author: Stefan Gränitz <stefan.graenitz@gmail.com>
|
|
//
|
|
// This file is dual-licensed: you can choose to license it under the University
|
|
// of Illinois Open Source License or the GNU Lesser General Public License. See
|
|
// LICENSE.TXT for details.
|
|
//------------------------------------------------------------------------------
|
|
|
|
#ifndef CLING_INCREMENTAL_JIT_H
|
|
#define CLING_INCREMENTAL_JIT_H
|
|
|
|
#include "llvm/ADT/FunctionExtras.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/StringSet.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/ExecutionEngine/Orc/Core.h"
|
|
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
|
|
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
|
|
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
namespace clang {
|
|
class CompilerInstance;
|
|
}
|
|
|
|
namespace cling {
|
|
|
|
class IncrementalExecutor;
|
|
class Transaction;
|
|
|
|
class SharedAtomicFlag {
|
|
public:
|
|
SharedAtomicFlag(bool UnlockedState)
|
|
: Lock(std::make_shared<std::atomic<bool>>(UnlockedState)),
|
|
LockedState(!UnlockedState) {}
|
|
|
|
// FIXME: We don't lock recursively. Can we assert it?
|
|
void lock() { Lock->store(LockedState); }
|
|
void unlock() { Lock->store(!LockedState); }
|
|
|
|
operator bool() const { return Lock->load(); }
|
|
|
|
private:
|
|
std::shared_ptr<std::atomic<bool>> Lock;
|
|
const bool LockedState;
|
|
};
|
|
|
|
class IncrementalJIT {
|
|
public:
|
|
IncrementalJIT(IncrementalExecutor& Executor,
|
|
const clang::CompilerInstance &CI,
|
|
std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
|
|
llvm::Error &Err, void *ExtraLibHandle, bool Verbose);
|
|
|
|
/// Register a DefinitionGenerator to dynamically provide symbols for
|
|
/// generated code that are not already available within the process.
|
|
void addGenerator(std::unique_ptr<llvm::orc::DefinitionGenerator> G) {
|
|
Jit->getMainJITDylib().addGenerator(std::move(G));
|
|
}
|
|
|
|
/// Return a `DefinitionGenerator` that can provide addresses for symbols
|
|
/// reachable from this IncrementalJIT object. This function can be used in
|
|
/// conjunction with `addGenerator()` to provide symbol resolution across
|
|
/// diferent IncrementalJIT instances.
|
|
std::unique_ptr<llvm::orc::DefinitionGenerator> getGenerator();
|
|
|
|
// FIXME: Accept a LLVMContext as well, e.g. the one that was used for the
|
|
// particular module in Interpreter, CIFactory or BackendPasses (would be
|
|
// more efficient)
|
|
void addModule(Transaction& T);
|
|
|
|
llvm::Error removeModule(const Transaction& T);
|
|
|
|
/// Get the address of a symbol based on its IR name (as coming from clang's
|
|
/// mangler). The IncludeHostSymbols parameter controls whether the lookup
|
|
/// should include symbols from the host process (via dlsym) or not.
|
|
void* getSymbolAddress(llvm::StringRef Name, bool IncludeHostSymbols);
|
|
|
|
/// @brief Check whether the JIT already has emitted or knows how to emit
|
|
/// a symbol based on its IR name (as coming from clang's mangler).
|
|
bool doesSymbolAlreadyExist(llvm::StringRef UnmangledName);
|
|
|
|
/// Inject a symbol with a known address. Name is not linker mangled, i.e.
|
|
/// as known by the IR.
|
|
llvm::JITTargetAddress addOrReplaceDefinition(llvm::StringRef Name,
|
|
llvm::JITTargetAddress KnownAddr);
|
|
|
|
llvm::Error runCtors() const {
|
|
return Jit->initialize(Jit->getMainJITDylib());
|
|
}
|
|
|
|
/// @brief Get the TargetMachine used by the JIT.
|
|
/// Non-const because BackendPasses need to update OptLevel.
|
|
llvm::TargetMachine &getTargetMachine() { return *m_TM; }
|
|
|
|
private:
|
|
std::unique_ptr<llvm::orc::LLJIT> Jit;
|
|
llvm::orc::SymbolMap m_InjectedSymbols;
|
|
SharedAtomicFlag SkipHostProcessLookup;
|
|
llvm::StringSet<> m_ForbidDlSymbols;
|
|
llvm::orc::ResourceTrackerSP m_CurrentRT;
|
|
|
|
/// FIXME: If the relation between modules and transactions is a bijection, the
|
|
/// mapping via module pointers here is unnecessary. The transaction should
|
|
/// store the resource tracker directly and pass it to `remove()` for
|
|
/// unloading.
|
|
std::map<const Transaction*, llvm::orc::ResourceTrackerSP> m_ResourceTrackers;
|
|
std::map<const llvm::Module *, llvm::orc::ThreadSafeModule> m_CompiledModules;
|
|
|
|
bool m_JITLink;
|
|
// FIXME: Move TargetMachine ownership to BackendPasses
|
|
std::unique_ptr<llvm::TargetMachine> m_TM;
|
|
|
|
// TODO: We only need the context for materialization. Instead of defining it
|
|
// here we might want to pass one in on a per-module basis.
|
|
//
|
|
// FIXME: Using a single context for all modules prevents concurrent
|
|
// compilation.
|
|
//
|
|
llvm::orc::ThreadSafeContext SingleThreadedContext;
|
|
};
|
|
|
|
} // namespace cling
|
|
|
|
#endif // CLING_INCREMENTAL_JIT_H
|