mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-25 00:29:20 +00:00
The client and server now use a single unified low-level RPC core built around LLVM's existing cross-platform abstractions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@199947 91177308-0d34-0410-b5e6-96231b3b80d8
326 lines
8.9 KiB
C++
326 lines
8.9 KiB
C++
//===---- RemoteTargetExternal.cpp - LLVM out-of-process JIT execution ----===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Implementation of the RemoteTargetExternal class which executes JITed code
|
|
// in a separate process from where it was built.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Config/config.h"
|
|
#include "RemoteTarget.h"
|
|
#include "RemoteTargetExternal.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/DataTypes.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/Format.h"
|
|
#include "llvm/Support/Memory.h"
|
|
#include "llvm/Support/Program.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <string>
|
|
|
|
using namespace llvm;
|
|
|
|
bool RemoteTargetExternal::allocateSpace(size_t Size, unsigned Alignment,
|
|
uint64_t &Address) {
|
|
DEBUG(dbgs() << "Message [allocate space] size: " << Size <<
|
|
", align: " << Alignment << "\n");
|
|
if (!SendAllocateSpace(Alignment, Size)) {
|
|
ErrorMsg += ", (RemoteTargetExternal::allocateSpace)";
|
|
return false;
|
|
}
|
|
if (!Receive(LLI_AllocationResult, Address)) {
|
|
ErrorMsg += ", (RemoteTargetExternal::allocateSpace)";
|
|
return false;
|
|
}
|
|
if (Address == 0) {
|
|
ErrorMsg += "failed allocation, (RemoteTargetExternal::allocateSpace)";
|
|
return false;
|
|
}
|
|
DEBUG(dbgs() << "Message [allocate space] addr: 0x" <<
|
|
format("%llx", Address) << "\n");
|
|
return true;
|
|
}
|
|
|
|
bool RemoteTargetExternal::loadData(uint64_t Address, const void *Data, size_t Size) {
|
|
DEBUG(dbgs() << "Message [load data] addr: 0x" << format("%llx", Address) <<
|
|
", size: " << Size << "\n");
|
|
if (!SendLoadSection(Address, Data, (uint32_t)Size, false)) {
|
|
ErrorMsg += ", (RemoteTargetExternal::loadData)";
|
|
return false;
|
|
}
|
|
int Status = LLI_Status_Success;
|
|
if (!Receive(LLI_LoadResult, Status)) {
|
|
ErrorMsg += ", (RemoteTargetExternal::loadData)";
|
|
return false;
|
|
}
|
|
if (Status == LLI_Status_IncompleteMsg) {
|
|
ErrorMsg += "incomplete load data, (RemoteTargetExternal::loadData)";
|
|
return false;
|
|
}
|
|
if (Status == LLI_Status_NotAllocated) {
|
|
ErrorMsg += "data memory not allocated, (RemoteTargetExternal::loadData)";
|
|
return false;
|
|
}
|
|
DEBUG(dbgs() << "Message [load data] complete\n");
|
|
return true;
|
|
}
|
|
|
|
bool RemoteTargetExternal::loadCode(uint64_t Address, const void *Data, size_t Size) {
|
|
DEBUG(dbgs() << "Message [load code] addr: 0x" << format("%llx", Address) <<
|
|
", size: " << Size << "\n");
|
|
if (!SendLoadSection(Address, Data, (uint32_t)Size, true)) {
|
|
ErrorMsg += ", (RemoteTargetExternal::loadCode)";
|
|
return false;
|
|
}
|
|
int Status = LLI_Status_Success;
|
|
if (!Receive(LLI_LoadResult, Status)) {
|
|
ErrorMsg += ", (RemoteTargetExternal::loadCode)";
|
|
return false;
|
|
}
|
|
if (Status == LLI_Status_IncompleteMsg) {
|
|
ErrorMsg += "incomplete load data, (RemoteTargetExternal::loadData)";
|
|
return false;
|
|
}
|
|
if (Status == LLI_Status_NotAllocated) {
|
|
ErrorMsg += "data memory not allocated, (RemoteTargetExternal::loadData)";
|
|
return false;
|
|
}
|
|
DEBUG(dbgs() << "Message [load code] complete\n");
|
|
return true;
|
|
}
|
|
|
|
bool RemoteTargetExternal::executeCode(uint64_t Address, int32_t &RetVal) {
|
|
DEBUG(dbgs() << "Message [exectue code] addr: " << Address << "\n");
|
|
if (!SendExecute(Address)) {
|
|
ErrorMsg += ", (RemoteTargetExternal::executeCode)";
|
|
return false;
|
|
}
|
|
if (!Receive(LLI_ExecutionResult, RetVal)) {
|
|
ErrorMsg += ", (RemoteTargetExternal::executeCode)";
|
|
return false;
|
|
}
|
|
DEBUG(dbgs() << "Message [exectue code] return: " << RetVal << "\n");
|
|
return true;
|
|
}
|
|
|
|
void RemoteTargetExternal::stop() {
|
|
SendTerminate();
|
|
RPC.Wait();
|
|
}
|
|
|
|
bool RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) {
|
|
if (!SendHeader(LLI_AllocateSpace)) {
|
|
ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)";
|
|
return false;
|
|
}
|
|
|
|
AppendWrite((const void *)&Alignment, 4);
|
|
AppendWrite((const void *)&Size, 4);
|
|
|
|
if (!SendPayload()) {
|
|
ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool RemoteTargetExternal::SendLoadSection(uint64_t Addr,
|
|
const void *Data,
|
|
uint32_t Size,
|
|
bool IsCode) {
|
|
LLIMessageType MsgType = IsCode ? LLI_LoadCodeSection : LLI_LoadDataSection;
|
|
if (!SendHeader(MsgType)) {
|
|
ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)";
|
|
return false;
|
|
}
|
|
|
|
AppendWrite((const void *)&Addr, 8);
|
|
AppendWrite(Data, Size);
|
|
|
|
if (!SendPayload()) {
|
|
ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool RemoteTargetExternal::SendExecute(uint64_t Addr) {
|
|
if (!SendHeader(LLI_Execute)) {
|
|
ErrorMsg += ", (RemoteTargetExternal::SendExecute)";
|
|
return false;
|
|
}
|
|
|
|
AppendWrite((const void *)&Addr, 8);
|
|
|
|
if (!SendPayload()) {
|
|
ErrorMsg += ", (RemoteTargetExternal::SendExecute)";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool RemoteTargetExternal::SendTerminate() {
|
|
return SendHeader(LLI_Terminate);
|
|
// No data or data size is sent with Terminate
|
|
}
|
|
|
|
bool RemoteTargetExternal::Receive(LLIMessageType Msg) {
|
|
if (!ReceiveHeader(Msg))
|
|
return false;
|
|
int Unused;
|
|
AppendRead(&Unused, 0);
|
|
if (!ReceivePayload())
|
|
return false;
|
|
ReceiveData.clear();
|
|
Sizes.clear();
|
|
return true;
|
|
}
|
|
|
|
bool RemoteTargetExternal::Receive(LLIMessageType Msg, int32_t &Data) {
|
|
if (!ReceiveHeader(Msg))
|
|
return false;
|
|
AppendRead(&Data, 4);
|
|
if (!ReceivePayload())
|
|
return false;
|
|
ReceiveData.clear();
|
|
Sizes.clear();
|
|
return true;
|
|
}
|
|
|
|
bool RemoteTargetExternal::Receive(LLIMessageType Msg, uint64_t &Data) {
|
|
if (!ReceiveHeader(Msg))
|
|
return false;
|
|
AppendRead(&Data, 8);
|
|
if (!ReceivePayload())
|
|
return false;
|
|
ReceiveData.clear();
|
|
Sizes.clear();
|
|
return true;
|
|
}
|
|
|
|
bool RemoteTargetExternal::ReceiveHeader(LLIMessageType ExpectedMsgType) {
|
|
assert(ReceiveData.empty() && Sizes.empty() &&
|
|
"Payload vector not empty to receive header");
|
|
|
|
// Message header, with type to follow
|
|
uint32_t MsgType;
|
|
if (!ReadBytes(&MsgType, 4)) {
|
|
ErrorMsg += ", (RemoteTargetExternal::ReceiveHeader)";
|
|
return false;
|
|
}
|
|
if (MsgType != (uint32_t)ExpectedMsgType) {
|
|
ErrorMsg = "received unexpected message type";
|
|
ErrorMsg += ". Expecting: ";
|
|
ErrorMsg += ExpectedMsgType;
|
|
ErrorMsg += ", Got: ";
|
|
ErrorMsg += MsgType;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool RemoteTargetExternal::ReceivePayload() {
|
|
assert(!ReceiveData.empty() &&
|
|
"Payload vector empty to receive");
|
|
assert(ReceiveData.size() == Sizes.size() &&
|
|
"Unexpected mismatch between data and size");
|
|
|
|
uint32_t TotalSize = 0;
|
|
for (int I=0, E=Sizes.size(); I < E; I++)
|
|
TotalSize += Sizes[I];
|
|
|
|
// Payload size header
|
|
uint32_t DataSize;
|
|
if (!ReadBytes(&DataSize, 4)) {
|
|
ErrorMsg += ", invalid data size";
|
|
return false;
|
|
}
|
|
if (DataSize != TotalSize) {
|
|
ErrorMsg = "unexpected data size";
|
|
ErrorMsg += ". Expecting: ";
|
|
ErrorMsg += TotalSize;
|
|
ErrorMsg += ", Got: ";
|
|
ErrorMsg += DataSize;
|
|
return false;
|
|
}
|
|
if (DataSize == 0)
|
|
return true;
|
|
|
|
// Payload itself
|
|
for (int I=0, E=Sizes.size(); I < E; I++) {
|
|
if (!ReadBytes(ReceiveData[I], Sizes[I])) {
|
|
ErrorMsg = "unexpected data while reading message";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RemoteTargetExternal::SendHeader(LLIMessageType MsgType) {
|
|
assert(SendData.empty() && Sizes.empty() &&
|
|
"Payload vector not empty to send header");
|
|
|
|
// Message header, with type to follow
|
|
if (!WriteBytes(&MsgType, 4)) {
|
|
ErrorMsg += ", (RemoteTargetExternal::SendHeader)";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool RemoteTargetExternal::SendPayload() {
|
|
assert(!SendData.empty() && !Sizes.empty() &&
|
|
"Payload vector empty to send");
|
|
assert(SendData.size() == Sizes.size() &&
|
|
"Unexpected mismatch between data and size");
|
|
|
|
uint32_t TotalSize = 0;
|
|
for (int I=0, E=Sizes.size(); I < E; I++)
|
|
TotalSize += Sizes[I];
|
|
|
|
// Payload size header
|
|
if (!WriteBytes(&TotalSize, 4)) {
|
|
ErrorMsg += ", invalid data size";
|
|
return false;
|
|
}
|
|
if (TotalSize == 0)
|
|
return true;
|
|
|
|
// Payload itself
|
|
for (int I=0, E=Sizes.size(); I < E; I++) {
|
|
if (!WriteBytes(SendData[I], Sizes[I])) {
|
|
ErrorMsg = "unexpected data while writing message";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
SendData.clear();
|
|
Sizes.clear();
|
|
return true;
|
|
}
|
|
|
|
void RemoteTargetExternal::AppendWrite(const void *Data, uint32_t Size) {
|
|
SendData.push_back(Data);
|
|
Sizes.push_back(Size);
|
|
}
|
|
|
|
void RemoteTargetExternal::AppendRead(void *Data, uint32_t Size) {
|
|
ReceiveData.push_back(Data);
|
|
Sizes.push_back(Size);
|
|
}
|
|
|
|
#ifdef LLVM_ON_UNIX
|
|
#include "Unix/RPCChannel.inc"
|
|
#endif
|
|
|
|
#ifdef LLVM_ON_WIN32
|
|
#include "Windows/RPCChannel.inc"
|
|
#endif
|