mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
a397416183
This is a first step towards consistently using the term 'executor' for the process that executes JIT'd code. I've opted for 'executor' as the preferred term over 'target' as target is already heavily overloaded ("the target machine for the executor" is much clearer than "the target machine for the target").
223 lines
8.5 KiB
C++
223 lines
8.5 KiB
C++
//===--- EPCIndirectionUtils.h - EPC based indirection utils ----*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Indirection utilities (stubs, trampolines, lazy call-throughs) that use the
|
|
// ExecutorProcessControl API to interact with the executor process.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H
|
|
#define LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H
|
|
|
|
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
|
|
#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
|
|
#include "llvm/ExecutionEngine/Orc/LazyReexports.h"
|
|
|
|
#include <mutex>
|
|
|
|
namespace llvm {
|
|
namespace orc {
|
|
|
|
class ExecutorProcessControl;
|
|
|
|
/// Provides ExecutorProcessControl based indirect stubs, trampoline pool and
|
|
/// lazy call through manager.
|
|
class EPCIndirectionUtils {
|
|
friend class EPCIndirectionUtilsAccess;
|
|
|
|
public:
|
|
/// ABI support base class. Used to write resolver, stub, and trampoline
|
|
/// blocks.
|
|
class ABISupport {
|
|
protected:
|
|
ABISupport(unsigned PointerSize, unsigned TrampolineSize, unsigned StubSize,
|
|
unsigned StubToPointerMaxDisplacement, unsigned ResolverCodeSize)
|
|
: PointerSize(PointerSize), TrampolineSize(TrampolineSize),
|
|
StubSize(StubSize),
|
|
StubToPointerMaxDisplacement(StubToPointerMaxDisplacement),
|
|
ResolverCodeSize(ResolverCodeSize) {}
|
|
|
|
public:
|
|
virtual ~ABISupport();
|
|
|
|
unsigned getPointerSize() const { return PointerSize; }
|
|
unsigned getTrampolineSize() const { return TrampolineSize; }
|
|
unsigned getStubSize() const { return StubSize; }
|
|
unsigned getStubToPointerMaxDisplacement() const {
|
|
return StubToPointerMaxDisplacement;
|
|
}
|
|
unsigned getResolverCodeSize() const { return ResolverCodeSize; }
|
|
|
|
virtual void writeResolverCode(char *ResolverWorkingMem,
|
|
JITTargetAddress ResolverTargetAddr,
|
|
JITTargetAddress ReentryFnAddr,
|
|
JITTargetAddress ReentryCtxAddr) const = 0;
|
|
|
|
virtual void writeTrampolines(char *TrampolineBlockWorkingMem,
|
|
JITTargetAddress TrampolineBlockTragetAddr,
|
|
JITTargetAddress ResolverAddr,
|
|
unsigned NumTrampolines) const = 0;
|
|
|
|
virtual void
|
|
writeIndirectStubsBlock(char *StubsBlockWorkingMem,
|
|
JITTargetAddress StubsBlockTargetAddress,
|
|
JITTargetAddress PointersBlockTargetAddress,
|
|
unsigned NumStubs) const = 0;
|
|
|
|
private:
|
|
unsigned PointerSize = 0;
|
|
unsigned TrampolineSize = 0;
|
|
unsigned StubSize = 0;
|
|
unsigned StubToPointerMaxDisplacement = 0;
|
|
unsigned ResolverCodeSize = 0;
|
|
};
|
|
|
|
/// Create using the given ABI class.
|
|
template <typename ORCABI>
|
|
static std::unique_ptr<EPCIndirectionUtils>
|
|
CreateWithABI(ExecutorProcessControl &EPC);
|
|
|
|
/// Create based on the ExecutorProcessControl triple.
|
|
static Expected<std::unique_ptr<EPCIndirectionUtils>>
|
|
Create(ExecutorProcessControl &EPC);
|
|
|
|
/// Return a reference to the ExecutorProcessControl object.
|
|
ExecutorProcessControl &getExecutorProcessControl() const { return EPC; }
|
|
|
|
/// Return a reference to the ABISupport object for this instance.
|
|
ABISupport &getABISupport() const { return *ABI; }
|
|
|
|
/// Release memory for resources held by this instance. This *must* be called
|
|
/// prior to destruction of the class.
|
|
Error cleanup();
|
|
|
|
/// Write resolver code to the executor process and return its address.
|
|
/// This must be called before any call to createTrampolinePool or
|
|
/// createLazyCallThroughManager.
|
|
Expected<JITTargetAddress>
|
|
writeResolverBlock(JITTargetAddress ReentryFnAddr,
|
|
JITTargetAddress ReentryCtxAddr);
|
|
|
|
/// Returns the address of the Resolver block. Returns zero if the
|
|
/// writeResolverBlock method has not previously been called.
|
|
JITTargetAddress getResolverBlockAddress() const { return ResolverBlockAddr; }
|
|
|
|
/// Create an IndirectStubsManager for the executor process.
|
|
std::unique_ptr<IndirectStubsManager> createIndirectStubsManager();
|
|
|
|
/// Create a TrampolinePool for the executor process.
|
|
TrampolinePool &getTrampolinePool();
|
|
|
|
/// Create a LazyCallThroughManager.
|
|
/// This function should only be called once.
|
|
LazyCallThroughManager &
|
|
createLazyCallThroughManager(ExecutionSession &ES,
|
|
JITTargetAddress ErrorHandlerAddr);
|
|
|
|
/// Create a LazyCallThroughManager for the executor process.
|
|
LazyCallThroughManager &getLazyCallThroughManager() {
|
|
assert(LCTM && "createLazyCallThroughManager must be called first");
|
|
return *LCTM;
|
|
}
|
|
|
|
private:
|
|
using Allocation = jitlink::JITLinkMemoryManager::Allocation;
|
|
|
|
struct IndirectStubInfo {
|
|
IndirectStubInfo() = default;
|
|
IndirectStubInfo(JITTargetAddress StubAddress,
|
|
JITTargetAddress PointerAddress)
|
|
: StubAddress(StubAddress), PointerAddress(PointerAddress) {}
|
|
JITTargetAddress StubAddress = 0;
|
|
JITTargetAddress PointerAddress = 0;
|
|
};
|
|
|
|
using IndirectStubInfoVector = std::vector<IndirectStubInfo>;
|
|
|
|
/// Create an EPCIndirectionUtils instance.
|
|
EPCIndirectionUtils(ExecutorProcessControl &EPC,
|
|
std::unique_ptr<ABISupport> ABI);
|
|
|
|
Expected<IndirectStubInfoVector> getIndirectStubs(unsigned NumStubs);
|
|
|
|
std::mutex EPCUIMutex;
|
|
ExecutorProcessControl &EPC;
|
|
std::unique_ptr<ABISupport> ABI;
|
|
JITTargetAddress ResolverBlockAddr;
|
|
std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation> ResolverBlock;
|
|
std::unique_ptr<TrampolinePool> TP;
|
|
std::unique_ptr<LazyCallThroughManager> LCTM;
|
|
|
|
std::vector<IndirectStubInfo> AvailableIndirectStubs;
|
|
std::vector<std::unique_ptr<Allocation>> IndirectStubAllocs;
|
|
};
|
|
|
|
/// This will call writeResolver on the given EPCIndirectionUtils instance
|
|
/// to set up re-entry via a function that will directly return the trampoline
|
|
/// landing address.
|
|
///
|
|
/// The EPCIndirectionUtils' LazyCallThroughManager must have been previously
|
|
/// created via EPCIndirectionUtils::createLazyCallThroughManager.
|
|
///
|
|
/// The EPCIndirectionUtils' writeResolver method must not have been previously
|
|
/// called.
|
|
///
|
|
/// This function is experimental and likely subject to revision.
|
|
Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU);
|
|
|
|
namespace detail {
|
|
|
|
template <typename ORCABI>
|
|
class ABISupportImpl : public EPCIndirectionUtils::ABISupport {
|
|
public:
|
|
ABISupportImpl()
|
|
: ABISupport(ORCABI::PointerSize, ORCABI::TrampolineSize,
|
|
ORCABI::StubSize, ORCABI::StubToPointerMaxDisplacement,
|
|
ORCABI::ResolverCodeSize) {}
|
|
|
|
void writeResolverCode(char *ResolverWorkingMem,
|
|
JITTargetAddress ResolverTargetAddr,
|
|
JITTargetAddress ReentryFnAddr,
|
|
JITTargetAddress ReentryCtxAddr) const override {
|
|
ORCABI::writeResolverCode(ResolverWorkingMem, ResolverTargetAddr,
|
|
ReentryFnAddr, ReentryCtxAddr);
|
|
}
|
|
|
|
void writeTrampolines(char *TrampolineBlockWorkingMem,
|
|
JITTargetAddress TrampolineBlockTargetAddr,
|
|
JITTargetAddress ResolverAddr,
|
|
unsigned NumTrampolines) const override {
|
|
ORCABI::writeTrampolines(TrampolineBlockWorkingMem,
|
|
TrampolineBlockTargetAddr, ResolverAddr,
|
|
NumTrampolines);
|
|
}
|
|
|
|
void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
|
|
JITTargetAddress StubsBlockTargetAddress,
|
|
JITTargetAddress PointersBlockTargetAddress,
|
|
unsigned NumStubs) const override {
|
|
ORCABI::writeIndirectStubsBlock(StubsBlockWorkingMem,
|
|
StubsBlockTargetAddress,
|
|
PointersBlockTargetAddress, NumStubs);
|
|
}
|
|
};
|
|
|
|
} // end namespace detail
|
|
|
|
template <typename ORCABI>
|
|
std::unique_ptr<EPCIndirectionUtils>
|
|
EPCIndirectionUtils::CreateWithABI(ExecutorProcessControl &EPC) {
|
|
return std::unique_ptr<EPCIndirectionUtils>(new EPCIndirectionUtils(
|
|
EPC, std::make_unique<detail::ABISupportImpl<ORCABI>>()));
|
|
}
|
|
|
|
} // end namespace orc
|
|
} // end namespace llvm
|
|
|
|
#endif // LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H
|