IndirectionUtils.h [plain text]
#ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
#define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
#include "JITSymbol.h"
#include "LambdaResolver.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ExecutionEngine/RuntimeDyld.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
#include <sstream>
namespace llvm {
namespace orc {
class JITCompileCallbackManagerBase {
public:
typedef std::function<TargetAddress()> CompileFtor;
class CompileCallbackInfo {
public:
CompileCallbackInfo(TargetAddress Addr, CompileFtor &Compile)
: Addr(Addr), Compile(Compile) {}
TargetAddress getAddress() const { return Addr; }
void setCompileAction(CompileFtor Compile) {
this->Compile = std::move(Compile);
}
private:
TargetAddress Addr;
CompileFtor &Compile;
};
JITCompileCallbackManagerBase(TargetAddress ErrorHandlerAddress)
: ErrorHandlerAddress(ErrorHandlerAddress) {}
virtual ~JITCompileCallbackManagerBase() {}
TargetAddress executeCompileCallback(TargetAddress TrampolineAddr) {
auto I = ActiveTrampolines.find(TrampolineAddr);
if (I == ActiveTrampolines.end())
return ErrorHandlerAddress;
auto Compile = std::move(I->second);
ActiveTrampolines.erase(I);
AvailableTrampolines.push_back(TrampolineAddr);
if (auto Addr = Compile())
return Addr;
return ErrorHandlerAddress;
}
virtual CompileCallbackInfo getCompileCallback() = 0;
CompileCallbackInfo getCompileCallbackInfo(TargetAddress TrampolineAddr) {
auto I = ActiveTrampolines.find(TrampolineAddr);
assert(I != ActiveTrampolines.end() && "Not an active trampoline.");
return CompileCallbackInfo(I->first, I->second);
}
void releaseCompileCallback(TargetAddress TrampolineAddr) {
auto I = ActiveTrampolines.find(TrampolineAddr);
assert(I != ActiveTrampolines.end() && "Not an active trampoline.");
ActiveTrampolines.erase(I);
AvailableTrampolines.push_back(TrampolineAddr);
}
protected:
TargetAddress ErrorHandlerAddress;
typedef std::map<TargetAddress, CompileFtor> TrampolineMapT;
TrampolineMapT ActiveTrampolines;
std::vector<TargetAddress> AvailableTrampolines;
private:
virtual void anchor();
};
template <typename TargetT>
class JITCompileCallbackManager : public JITCompileCallbackManagerBase {
public:
JITCompileCallbackManager(TargetAddress ErrorHandlerAddress)
: JITCompileCallbackManagerBase(ErrorHandlerAddress) {
std::error_code EC;
ResolverBlock =
sys::OwningMemoryBlock(
sys::Memory::allocateMappedMemory(TargetT::ResolverCodeSize, nullptr,
sys::Memory::MF_READ |
sys::Memory::MF_WRITE, EC));
assert(!EC && "Failed to allocate resolver block");
TargetT::writeResolverCode(static_cast<uint8_t*>(ResolverBlock.base()),
&reenter, this);
EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
sys::Memory::MF_READ |
sys::Memory::MF_EXEC);
assert(!EC && "Failed to mprotect resolver block");
}
CompileCallbackInfo getCompileCallback() final {
TargetAddress TrampolineAddr = getAvailableTrampolineAddr();
auto &Compile = this->ActiveTrampolines[TrampolineAddr];
return CompileCallbackInfo(TrampolineAddr, Compile);
}
private:
static TargetAddress reenter(void *CCMgr, void *TrampolineId) {
JITCompileCallbackManager *Mgr =
static_cast<JITCompileCallbackManager*>(CCMgr);
return Mgr->executeCompileCallback(
static_cast<TargetAddress>(
reinterpret_cast<uintptr_t>(TrampolineId)));
}
TargetAddress getAvailableTrampolineAddr() {
if (this->AvailableTrampolines.empty())
grow();
assert(!this->AvailableTrampolines.empty() &&
"Failed to grow available trampolines.");
TargetAddress TrampolineAddr = this->AvailableTrampolines.back();
this->AvailableTrampolines.pop_back();
return TrampolineAddr;
}
void grow() {
assert(this->AvailableTrampolines.empty() && "Growing prematurely?");
std::error_code EC;
auto TrampolineBlock =
sys::OwningMemoryBlock(
sys::Memory::allocateMappedMemory(TargetT::PageSize, nullptr,
sys::Memory::MF_READ |
sys::Memory::MF_WRITE, EC));
assert(!EC && "Failed to allocate trampoline block");
unsigned NumTrampolines =
(TargetT::PageSize - TargetT::PointerSize) / TargetT::TrampolineSize;
uint8_t *TrampolineMem = static_cast<uint8_t*>(TrampolineBlock.base());
TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
NumTrampolines);
for (unsigned I = 0; I < NumTrampolines; ++I)
this->AvailableTrampolines.push_back(
static_cast<TargetAddress>(
reinterpret_cast<uintptr_t>(
TrampolineMem + (I * TargetT::TrampolineSize))));
EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(),
sys::Memory::MF_READ |
sys::Memory::MF_EXEC);
assert(!EC && "Failed to mprotect trampoline block");
TrampolineBlocks.push_back(std::move(TrampolineBlock));
}
sys::OwningMemoryBlock ResolverBlock;
std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
};
class IndirectStubsManagerBase {
public:
typedef StringMap<std::pair<TargetAddress, JITSymbolFlags>> StubInitsMap;
virtual ~IndirectStubsManagerBase() {}
virtual std::error_code createStub(StringRef StubName, TargetAddress StubAddr,
JITSymbolFlags StubFlags) = 0;
virtual std::error_code createStubs(const StubInitsMap &StubInits) = 0;
virtual JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) = 0;
virtual JITSymbol findPointer(StringRef Name) = 0;
virtual std::error_code updatePointer(StringRef Name, TargetAddress NewAddr) = 0;
private:
virtual void anchor();
};
template <typename TargetT>
class IndirectStubsManager : public IndirectStubsManagerBase {
public:
std::error_code createStub(StringRef StubName, TargetAddress StubAddr,
JITSymbolFlags StubFlags) override {
if (auto EC = reserveStubs(1))
return EC;
createStubInternal(StubName, StubAddr, StubFlags);
return std::error_code();
}
std::error_code createStubs(const StubInitsMap &StubInits) override {
if (auto EC = reserveStubs(StubInits.size()))
return EC;
for (auto &Entry : StubInits)
createStubInternal(Entry.first(), Entry.second.first,
Entry.second.second);
return std::error_code();
}
JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
auto I = StubIndexes.find(Name);
if (I == StubIndexes.end())
return nullptr;
auto Key = I->second.first;
void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second);
assert(StubAddr && "Missing stub address");
auto StubTargetAddr =
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(StubAddr));
auto StubSymbol = JITSymbol(StubTargetAddr, I->second.second);
if (ExportedStubsOnly && !StubSymbol.isExported())
return nullptr;
return StubSymbol;
}
JITSymbol findPointer(StringRef Name) override {
auto I = StubIndexes.find(Name);
if (I == StubIndexes.end())
return nullptr;
auto Key = I->second.first;
void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second);
assert(PtrAddr && "Missing pointer address");
auto PtrTargetAddr =
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr));
return JITSymbol(PtrTargetAddr, I->second.second);
}
std::error_code updatePointer(StringRef Name, TargetAddress NewAddr) override {
auto I = StubIndexes.find(Name);
assert(I != StubIndexes.end() && "No stub pointer for symbol");
auto Key = I->second.first;
*IndirectStubsInfos[Key.first].getPtr(Key.second) =
reinterpret_cast<void*>(static_cast<uintptr_t>(NewAddr));
return std::error_code();
}
private:
std::error_code reserveStubs(unsigned NumStubs) {
if (NumStubs <= FreeStubs.size())
return std::error_code();
unsigned NewStubsRequired = NumStubs - FreeStubs.size();
unsigned NewBlockId = IndirectStubsInfos.size();
typename TargetT::IndirectStubsInfo ISI;
if (auto EC = TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired,
nullptr))
return EC;
for (unsigned I = 0; I < ISI.getNumStubs(); ++I)
FreeStubs.push_back(std::make_pair(NewBlockId, I));
IndirectStubsInfos.push_back(std::move(ISI));
return std::error_code();
}
void createStubInternal(StringRef StubName, TargetAddress InitAddr,
JITSymbolFlags StubFlags) {
auto Key = FreeStubs.back();
FreeStubs.pop_back();
*IndirectStubsInfos[Key.first].getPtr(Key.second) =
reinterpret_cast<void*>(static_cast<uintptr_t>(InitAddr));
StubIndexes[StubName] = std::make_pair(Key, StubFlags);
}
std::vector<typename TargetT::IndirectStubsInfo> IndirectStubsInfos;
typedef std::pair<uint16_t, uint16_t> StubKey;
std::vector<StubKey> FreeStubs;
StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
};
Constant* createIRTypedAddress(FunctionType &FT, TargetAddress Addr);
GlobalVariable* createImplPointer(PointerType &PT, Module &M,
const Twine &Name, Constant *Initializer);
void makeStub(Function &F, Value &ImplPointer);
void makeAllSymbolsExternallyAccessible(Module &M);
Function* cloneFunctionDecl(Module &Dst, const Function &F,
ValueToValueMapTy *VMap = nullptr);
void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap,
ValueMaterializer *Materializer = nullptr,
Function *NewF = nullptr);
GlobalVariable* cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
ValueToValueMapTy *VMap = nullptr);
void moveGlobalVariableInitializer(GlobalVariable &OrigGV,
ValueToValueMapTy &VMap,
ValueMaterializer *Materializer = nullptr,
GlobalVariable *NewGV = nullptr);
GlobalAlias* cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA,
ValueToValueMapTy &VMap);
} }
#endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H