mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-26 05:32:25 +00:00
Adding out-of-process execution support to lli.
At this time only Unix-based systems are supported. Windows has stubs and should re-route to the simulated mode. Thanks to Sriram Murali for contributions to this patch. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191843 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
af7ae9d689
commit
0ab5c6c16b
@ -1,4 +1,4 @@
|
||||
; RUN: %lli_mcjit -remote-mcjit %s > /dev/null
|
||||
; RUN: %lli_mcjit -remote-mcjit -mcjit-remote-process=lli-child-target %s > /dev/null
|
||||
; XFAIL: mips
|
||||
|
||||
define i32 @bar() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: %lli_mcjit -remote-mcjit -disable-lazy-compilation=false %s
|
||||
; RUN: %lli_mcjit -remote-mcjit -disable-lazy-compilation=false -mcjit-remote-process=lli-child-target %s
|
||||
; XFAIL: mips
|
||||
|
||||
define i32 @main() nounwind {
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: %lli_mcjit -remote-mcjit -O0 -disable-lazy-compilation=false %s
|
||||
; RUN: %lli_mcjit -remote-mcjit -O0 -disable-lazy-compilation=false -mcjit-remote-process=lli-child-target %s
|
||||
; XFAIL: mips
|
||||
|
||||
; The intention of this test is to verify that symbols mapped to COMMON in ELF
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: %lli_mcjit -remote-mcjit -O0 %s
|
||||
; RUN: %lli_mcjit -remote-mcjit -O0 -mcjit-remote-process=lli-child-target %s
|
||||
; XFAIL: mips
|
||||
|
||||
; Check that a variable is always aligned as specified.
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: %lli_mcjit -remote-mcjit %s > /dev/null
|
||||
; RUN: %lli_mcjit -remote-mcjit -mcjit-remote-process=lli-child-target %s > /dev/null
|
||||
; XFAIL: mips
|
||||
|
||||
define double @test(double* %DP, double %Arg) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: %lli_mcjit -remote-mcjit %s > /dev/null
|
||||
; RUN: %lli_mcjit -remote-mcjit -mcjit-remote-process=lli-child-target %s > /dev/null
|
||||
; XFAIL: mips
|
||||
|
||||
@count = global i32 1, align 4
|
||||
|
@ -1,4 +1,4 @@
|
||||
; RUN: %lli_mcjit -remote-mcjit -O0 %s
|
||||
; RUN: %lli_mcjit -remote-mcjit -O0 -mcjit-remote-process=lli-child-target %s
|
||||
|
||||
@.str = private unnamed_addr constant [6 x i8] c"data1\00", align 1
|
||||
@ptr = global i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), align 4
|
||||
|
@ -1,6 +1,8 @@
|
||||
|
||||
set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag native instrumentation)
|
||||
|
||||
add_subdirectory(ChildTarget)
|
||||
|
||||
if( LLVM_USE_OPROFILE )
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
${LLVM_LINK_COMPONENTS}
|
||||
@ -21,4 +23,5 @@ add_llvm_tool(lli
|
||||
lli.cpp
|
||||
RecordingMemoryManager.cpp
|
||||
RemoteTarget.cpp
|
||||
RemoteTargetExternal.cpp
|
||||
)
|
||||
|
3
tools/lli/ChildTarget/CMakeLists.txt
Normal file
3
tools/lli/ChildTarget/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
add_llvm_tool(lli-child-target
|
||||
ChildTarget.cpp
|
||||
)
|
241
tools/lli/ChildTarget/ChildTarget.cpp
Normal file
241
tools/lli/ChildTarget/ChildTarget.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
#include "llvm/Config/config.h"
|
||||
|
||||
#include "../RemoteTargetMessage.h"
|
||||
#include <assert.h>
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
class LLIChildTarget {
|
||||
public:
|
||||
void initialize();
|
||||
LLIMessageType waitForIncomingMessage();
|
||||
void handleMessage(LLIMessageType messageType);
|
||||
|
||||
private:
|
||||
// Incoming message handlers
|
||||
void handleAllocateSpace();
|
||||
void handleLoadSection(bool IsCode);
|
||||
void handleExecute();
|
||||
void handleTerminate();
|
||||
|
||||
// Outgoing message handlers
|
||||
void sendChildActive();
|
||||
void sendAllocationResult(uint64_t Addr);
|
||||
void sendLoadComplete();
|
||||
void sendExecutionComplete(uint64_t Result);
|
||||
|
||||
// OS-specific functions
|
||||
void initializeConnection();
|
||||
int WriteBytes(const void *Data, size_t Size);
|
||||
int ReadBytes(void *Data, size_t Size);
|
||||
uint64_t allocate(uint32_t Alignment, uint32_t Size);
|
||||
void makeSectionExecutable(uint64_t Addr, uint32_t Size);
|
||||
void InvalidateInstructionCache(const void *Addr, size_t Len);
|
||||
void releaseMemory(uint64_t Addr, uint32_t Size);
|
||||
|
||||
// Store a map of allocated buffers to sizes.
|
||||
typedef std::map<uint64_t, uint32_t> AllocMapType;
|
||||
AllocMapType m_AllocatedBufferMap;
|
||||
|
||||
// Communication handles (OS-specific)
|
||||
void *ConnectionData;
|
||||
};
|
||||
|
||||
int main() {
|
||||
LLIChildTarget ThisChild;
|
||||
ThisChild.initialize();
|
||||
LLIMessageType MsgType;
|
||||
do {
|
||||
MsgType = ThisChild.waitForIncomingMessage();
|
||||
ThisChild.handleMessage(MsgType);
|
||||
} while (MsgType != LLI_Terminate &&
|
||||
MsgType != LLI_Error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Public methods
|
||||
void LLIChildTarget::initialize() {
|
||||
initializeConnection();
|
||||
sendChildActive();
|
||||
}
|
||||
|
||||
LLIMessageType LLIChildTarget::waitForIncomingMessage() {
|
||||
int32_t MsgType = -1;
|
||||
if (ReadBytes(&MsgType, 4) > 0)
|
||||
return (LLIMessageType)MsgType;
|
||||
return LLI_Error;
|
||||
}
|
||||
|
||||
void LLIChildTarget::handleMessage(LLIMessageType messageType) {
|
||||
switch (messageType) {
|
||||
case LLI_AllocateSpace:
|
||||
handleAllocateSpace();
|
||||
break;
|
||||
case LLI_LoadCodeSection:
|
||||
handleLoadSection(true);
|
||||
break;
|
||||
case LLI_LoadDataSection:
|
||||
handleLoadSection(false);
|
||||
break;
|
||||
case LLI_Execute:
|
||||
handleExecute();
|
||||
break;
|
||||
case LLI_Terminate:
|
||||
handleTerminate();
|
||||
break;
|
||||
default:
|
||||
// FIXME: Handle error!
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Incoming message handlers
|
||||
void LLIChildTarget::handleAllocateSpace() {
|
||||
// Read and verify the message data size.
|
||||
uint32_t DataSize;
|
||||
int rc = ReadBytes(&DataSize, 4);
|
||||
assert(rc == 4);
|
||||
assert(DataSize == 8);
|
||||
|
||||
// Read the message arguments.
|
||||
uint32_t Alignment;
|
||||
uint32_t AllocSize;
|
||||
rc = ReadBytes(&Alignment, 4);
|
||||
assert(rc == 4);
|
||||
rc = ReadBytes(&AllocSize, 4);
|
||||
assert(rc == 4);
|
||||
|
||||
// Allocate the memory.
|
||||
uint64_t Addr = allocate(Alignment, AllocSize);
|
||||
|
||||
// Send AllocationResult message.
|
||||
sendAllocationResult(Addr);
|
||||
}
|
||||
|
||||
void LLIChildTarget::handleLoadSection(bool IsCode) {
|
||||
// Read the message data size.
|
||||
uint32_t DataSize;
|
||||
int rc = ReadBytes(&DataSize, 4);
|
||||
assert(rc == 4);
|
||||
|
||||
// Read the target load address.
|
||||
uint64_t Addr;
|
||||
rc = ReadBytes(&Addr, 8);
|
||||
assert(rc == 8);
|
||||
|
||||
size_t BufferSize = DataSize - 8;
|
||||
|
||||
// FIXME: Verify that this is in allocated space
|
||||
|
||||
// Read section data into previously allocated buffer
|
||||
rc = ReadBytes((void*)Addr, DataSize - 8);
|
||||
assert(rc == (int)(BufferSize));
|
||||
|
||||
// If IsCode, mark memory executable
|
||||
if (IsCode)
|
||||
makeSectionExecutable(Addr, BufferSize);
|
||||
|
||||
// Send MarkLoadComplete message.
|
||||
sendLoadComplete();
|
||||
}
|
||||
|
||||
void LLIChildTarget::handleExecute() {
|
||||
// Read the message data size.
|
||||
uint32_t DataSize;
|
||||
int rc = ReadBytes(&DataSize, 4);
|
||||
assert(rc == 4);
|
||||
assert(DataSize == 8);
|
||||
|
||||
// Read the target address.
|
||||
uint64_t Addr;
|
||||
rc = ReadBytes(&Addr, 8);
|
||||
assert(rc == 8);
|
||||
|
||||
// Call function
|
||||
int Result;
|
||||
int (*fn)(void) = (int(*)(void))Addr;
|
||||
Result = fn();
|
||||
|
||||
// Send ExecutionResult message.
|
||||
sendExecutionComplete((int64_t)Result);
|
||||
}
|
||||
|
||||
void LLIChildTarget::handleTerminate() {
|
||||
// Release all allocated memory
|
||||
AllocMapType::iterator Begin = m_AllocatedBufferMap.begin();
|
||||
AllocMapType::iterator End = m_AllocatedBufferMap.end();
|
||||
for (AllocMapType::iterator It = Begin; It != End; ++It) {
|
||||
releaseMemory(It->first, It->second);
|
||||
}
|
||||
m_AllocatedBufferMap.clear();
|
||||
}
|
||||
|
||||
// Outgoing message handlers
|
||||
void LLIChildTarget::sendChildActive() {
|
||||
// Write the message type.
|
||||
uint32_t MsgType = (uint32_t)LLI_ChildActive;
|
||||
int rc = WriteBytes(&MsgType, 4);
|
||||
assert(rc == 4);
|
||||
|
||||
// Write the data size.
|
||||
uint32_t DataSize = 0;
|
||||
rc = WriteBytes(&DataSize, 4);
|
||||
assert(rc == 4);
|
||||
}
|
||||
|
||||
void LLIChildTarget::sendAllocationResult(uint64_t Addr) {
|
||||
// Write the message type.
|
||||
uint32_t MsgType = (uint32_t)LLI_AllocationResult;
|
||||
int rc = WriteBytes(&MsgType, 4);
|
||||
assert(rc == 4);
|
||||
|
||||
// Write the data size.
|
||||
uint32_t DataSize = 8;
|
||||
rc = WriteBytes(&DataSize, 4);
|
||||
assert(rc == 4);
|
||||
|
||||
// Write the allocated address.
|
||||
rc = WriteBytes(&Addr, 8);
|
||||
assert(rc == 8);
|
||||
}
|
||||
|
||||
void LLIChildTarget::sendLoadComplete() {
|
||||
// Write the message type.
|
||||
uint32_t MsgType = (uint32_t)LLI_LoadComplete;
|
||||
int rc = WriteBytes(&MsgType, 4);
|
||||
assert(rc == 4);
|
||||
|
||||
// Write the data size.
|
||||
uint32_t DataSize = 0;
|
||||
rc = WriteBytes(&DataSize, 4);
|
||||
assert(rc == 4);
|
||||
}
|
||||
|
||||
void LLIChildTarget::sendExecutionComplete(uint64_t Result) {
|
||||
// Write the message type.
|
||||
uint32_t MsgType = (uint32_t)LLI_ExecutionResult;
|
||||
int rc = WriteBytes(&MsgType, 4);
|
||||
assert(rc == 4);
|
||||
|
||||
|
||||
// Write the data size.
|
||||
uint32_t DataSize = 8;
|
||||
rc = WriteBytes(&DataSize, 4);
|
||||
assert(rc == 4);
|
||||
|
||||
// Write the result.
|
||||
rc = WriteBytes(&Result, 8);
|
||||
assert(rc == 8);
|
||||
}
|
||||
|
||||
#ifdef LLVM_ON_UNIX
|
||||
#include "Unix/ChildTarget.inc"
|
||||
#endif
|
||||
|
||||
#ifdef LLVM_ON_WIN32
|
||||
#include "Windows/ChildTarget.inc"
|
||||
#endif
|
17
tools/lli/ChildTarget/Makefile
Normal file
17
tools/lli/ChildTarget/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
##===- tools/lli/Makefile ------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL := ../../..
|
||||
TOOLNAME := lli-child-target
|
||||
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
LINK_COMPONENTS :=
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
141
tools/lli/ChildTarget/Unix/ChildTarget.inc
Normal file
141
tools/lli/ChildTarget/Unix/ChildTarget.inc
Normal file
@ -0,0 +1,141 @@
|
||||
//===- ChildTarget.inc - Child process for external JIT execution for Unix -==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implementation of the Unix-specific parts of the ChildTarget class
|
||||
// which executes JITed code in a separate process from where it was built.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace {
|
||||
|
||||
struct ConnectionData_t {
|
||||
int InputPipe;
|
||||
int OutputPipe;
|
||||
|
||||
ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// OS-specific methods
|
||||
void LLIChildTarget::initializeConnection() {
|
||||
// Store the parent ends of the pipes
|
||||
ConnectionData = (void*)new ConnectionData_t(STDIN_FILENO, STDOUT_FILENO);
|
||||
}
|
||||
|
||||
int LLIChildTarget::WriteBytes(const void *Data, size_t Size) {
|
||||
return write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size);
|
||||
}
|
||||
|
||||
int LLIChildTarget::ReadBytes(void *Data, size_t Size) {
|
||||
return read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size);
|
||||
}
|
||||
|
||||
// The functions below duplicate functionality that is implemented in
|
||||
// Support/Memory.cpp with the goal of avoiding a dependency on any
|
||||
// llvm libraries.
|
||||
|
||||
uint64_t LLIChildTarget::allocate(uint32_t Alignment, uint32_t Size) {
|
||||
if (!Alignment)
|
||||
Alignment = 16;
|
||||
|
||||
static const size_t PageSize = getpagesize();
|
||||
const size_t NumPages = (Size+PageSize-1)/PageSize;
|
||||
Size = NumPages*PageSize;
|
||||
|
||||
int fd = -1;
|
||||
#ifdef NEED_DEV_ZERO_FOR_MMAP
|
||||
static int zero_fd = open("/dev/zero", O_RDWR);
|
||||
if (zero_fd == -1)
|
||||
return 0;
|
||||
fd = zero_fd;
|
||||
#endif
|
||||
|
||||
int MMFlags = MAP_PRIVATE |
|
||||
#ifdef HAVE_MMAP_ANONYMOUS
|
||||
MAP_ANONYMOUS
|
||||
#else
|
||||
MAP_ANON
|
||||
#endif
|
||||
; // Ends statement above
|
||||
|
||||
uint64_t Addr = (uint64_t)::mmap(0, Size, PROT_READ | PROT_WRITE, MMFlags, fd, 0);
|
||||
if (Addr == (uint64_t)MAP_FAILED)
|
||||
return 0;
|
||||
|
||||
// Align the address.
|
||||
Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
|
||||
|
||||
m_AllocatedBufferMap[Addr] = Size;
|
||||
|
||||
// Return aligned address
|
||||
return Addr;
|
||||
}
|
||||
|
||||
void LLIChildTarget::makeSectionExecutable(uint64_t Addr, uint32_t Size) {
|
||||
// FIXME: We have to mark the memory as RWX because multiple code chunks may
|
||||
// be on the same page. The RemoteTarget interface should be changed to
|
||||
// work around that.
|
||||
int Result = ::mprotect((void*)Addr, Size, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
if (Result != 0)
|
||||
InvalidateInstructionCache((const void *)Addr, Size);
|
||||
}
|
||||
|
||||
/// InvalidateInstructionCache - Before the JIT can run a block of code
|
||||
/// that has been emitted it must invalidate the instruction cache on some
|
||||
/// platforms.
|
||||
void LLIChildTarget::InvalidateInstructionCache(const void *Addr,
|
||||
size_t Len) {
|
||||
|
||||
// icache invalidation for PPC and ARM.
|
||||
#if defined(__APPLE__)
|
||||
|
||||
# if (defined(__POWERPC__) || defined (__ppc__) || \
|
||||
defined(_POWER) || defined(_ARCH_PPC)) || defined(__arm__)
|
||||
sys_icache_invalidate(const_cast<void *>(Addr), Len);
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
# if (defined(__POWERPC__) || defined (__ppc__) || \
|
||||
defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__)
|
||||
const size_t LineSize = 32;
|
||||
|
||||
const intptr_t Mask = ~(LineSize - 1);
|
||||
const intptr_t StartLine = ((intptr_t) Addr) & Mask;
|
||||
const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask;
|
||||
|
||||
for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize)
|
||||
asm volatile("dcbf 0, %0" : : "r"(Line));
|
||||
asm volatile("sync");
|
||||
|
||||
for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize)
|
||||
asm volatile("icbi 0, %0" : : "r"(Line));
|
||||
asm volatile("isync");
|
||||
# elif defined(__arm__) && defined(__GNUC__)
|
||||
// FIXME: Can we safely always call this for __GNUC__ everywhere?
|
||||
const char *Start = static_cast<const char *>(Addr);
|
||||
const char *End = Start + Len;
|
||||
__clear_cache(const_cast<char *>(Start), const_cast<char *>(End));
|
||||
# elif defined(__mips__)
|
||||
const char *Start = static_cast<const char *>(Addr);
|
||||
cacheflush(const_cast<char *>(Start), Len, BCACHE);
|
||||
# endif
|
||||
|
||||
#endif // end apple
|
||||
}
|
||||
|
||||
void LLIChildTarget::releaseMemory(uint64_t Addr, uint32_t Size) {
|
||||
::munmap((void*)Addr, Size);
|
||||
}
|
41
tools/lli/ChildTarget/Windows/ChildTarget.inc
Normal file
41
tools/lli/ChildTarget/Windows/ChildTarget.inc
Normal file
@ -0,0 +1,41 @@
|
||||
//=- ChildTarget.inc - Child process for external JIT execution for Windows -=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Non-implementation of the Windows-specific parts of the ChildTarget class
|
||||
// which executes JITed code in a separate process from where it was built.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// The RemoteTargetExternal implementation should prevent us from ever getting
|
||||
// here on Windows, but nothing prevents a user from running this directly.
|
||||
void LLIChildTarget::initializeConnection() {
|
||||
assert(0 && "lli-child-target is not implemented for Windows");
|
||||
}
|
||||
|
||||
int LLIChildTarget::WriteBytes(const void *Data, size_t Size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LLIChildTarget::ReadBytes(void *Data, size_t Size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t LLIChildTarget::allocate(uint32_t Alignment, uint32_t Size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LLIChildTarget::makeSectionExecutable(uint64_t Addr, uint32_t Size) {
|
||||
}
|
||||
|
||||
void LLIChildTarget::InvalidateInstructionCache(const void *Addr,
|
||||
size_t Len) {
|
||||
}
|
||||
|
||||
void LLIChildTarget::releaseMemory(uint64_t Addr, uint32_t Size) {
|
||||
}
|
@ -10,6 +10,8 @@
|
||||
LEVEL := ../..
|
||||
TOOLNAME := lli
|
||||
|
||||
PARALLEL_DIRS := ChildTarget
|
||||
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
LINK_COMPONENTS := mcjit jit instrumentation interpreter nativecodegen bitreader asmparser irreader selectiondag native
|
||||
|
@ -13,13 +13,44 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "RemoteTarget.h"
|
||||
#include "RemoteTargetExternal.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
// Static methods
|
||||
RemoteTarget *RemoteTarget::createRemoteTarget() {
|
||||
return new RemoteTarget;
|
||||
}
|
||||
|
||||
RemoteTarget *RemoteTarget::createExternalRemoteTarget(std::string &ChildName) {
|
||||
#ifdef LLVM_ON_UNIX
|
||||
return new RemoteTargetExternal(ChildName);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool RemoteTarget::hostSupportsExternalRemoteTarget() {
|
||||
#ifdef LLVM_ON_UNIX
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Simulated remote execution
|
||||
//
|
||||
// This implementation will simply move generated code and data to a new memory
|
||||
// location in the current executable and let it run from there.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool RemoteTarget::allocateSpace(size_t Size, unsigned Alignment,
|
||||
uint64_t &Address) {
|
||||
sys::MemoryBlock *Prev = Allocations.size() ? &Allocations.back() : NULL;
|
||||
|
@ -41,7 +41,9 @@ public:
|
||||
///
|
||||
/// @returns False on success. On failure, ErrorMsg is updated with
|
||||
/// descriptive text of the encountered error.
|
||||
bool allocateSpace(size_t Size, unsigned Alignment, uint64_t &Address);
|
||||
virtual bool allocateSpace(size_t Size,
|
||||
unsigned Alignment,
|
||||
uint64_t &Address);
|
||||
|
||||
/// Load data into the target address space.
|
||||
///
|
||||
@ -51,7 +53,9 @@ public:
|
||||
///
|
||||
/// @returns False on success. On failure, ErrorMsg is updated with
|
||||
/// descriptive text of the encountered error.
|
||||
bool loadData(uint64_t Address, const void *Data, size_t Size);
|
||||
virtual bool loadData(uint64_t Address,
|
||||
const void *Data,
|
||||
size_t Size);
|
||||
|
||||
/// Load code into the target address space and prepare it for execution.
|
||||
///
|
||||
@ -61,7 +65,9 @@ public:
|
||||
///
|
||||
/// @returns False on success. On failure, ErrorMsg is updated with
|
||||
/// descriptive text of the encountered error.
|
||||
bool loadCode(uint64_t Address, const void *Data, size_t Size);
|
||||
virtual bool loadCode(uint64_t Address,
|
||||
const void *Data,
|
||||
size_t Size);
|
||||
|
||||
/// Execute code in the target process. The called function is required
|
||||
/// to be of signature int "(*)(void)".
|
||||
@ -72,24 +78,29 @@ public:
|
||||
///
|
||||
/// @returns False on success. On failure, ErrorMsg is updated with
|
||||
/// descriptive text of the encountered error.
|
||||
bool executeCode(uint64_t Address, int &RetVal);
|
||||
virtual bool executeCode(uint64_t Address,
|
||||
int &RetVal);
|
||||
|
||||
/// Minimum alignment for memory permissions. Used to seperate code and
|
||||
/// data regions to make sure data doesn't get marked as code or vice
|
||||
/// versa.
|
||||
///
|
||||
/// @returns Page alignment return value. Default of 4k.
|
||||
unsigned getPageAlignment() { return 4096; }
|
||||
virtual unsigned getPageAlignment() { return 4096; }
|
||||
|
||||
/// Start the remote process.
|
||||
void create();
|
||||
virtual void create();
|
||||
|
||||
/// Terminate the remote process.
|
||||
void stop();
|
||||
virtual void stop();
|
||||
|
||||
RemoteTarget() : ErrorMsg(""), IsRunning(false) {}
|
||||
~RemoteTarget() { if (IsRunning) stop(); }
|
||||
virtual ~RemoteTarget() { if (IsRunning) stop(); }
|
||||
|
||||
// Create an instance of the system-specific remote target class.
|
||||
static RemoteTarget *createRemoteTarget();
|
||||
static RemoteTarget *createExternalRemoteTarget(std::string &ChildName);
|
||||
static bool hostSupportsExternalRemoteTarget();
|
||||
private:
|
||||
// Main processing function for the remote target process. Command messages
|
||||
// are received on file descriptor CmdFD and responses come back on OutFD.
|
||||
|
162
tools/lli/RemoteTargetExternal.cpp
Normal file
162
tools/lli/RemoteTargetExternal.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
//===---- 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/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) {
|
||||
SendAllocateSpace(Alignment, Size);
|
||||
Receive(LLI_AllocationResult, Address);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RemoteTargetExternal::loadData(uint64_t Address, const void *Data, size_t Size) {
|
||||
SendLoadSection(Address, Data, (uint32_t)Size, false);
|
||||
Receive(LLI_LoadComplete);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RemoteTargetExternal::loadCode(uint64_t Address, const void *Data, size_t Size) {
|
||||
SendLoadSection(Address, Data, (uint32_t)Size, true);
|
||||
Receive(LLI_LoadComplete);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RemoteTargetExternal::executeCode(uint64_t Address, int &RetVal) {
|
||||
SendExecute(Address);
|
||||
|
||||
Receive(LLI_ExecutionResult, RetVal);
|
||||
return false;
|
||||
}
|
||||
|
||||
void RemoteTargetExternal::stop() {
|
||||
SendTerminate();
|
||||
Wait();
|
||||
}
|
||||
|
||||
void RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) {
|
||||
int rc;
|
||||
uint32_t MsgType = (uint32_t)LLI_AllocateSpace;
|
||||
rc = WriteBytes(&MsgType, 4);
|
||||
assert(rc == 4 && "Error writing message type.");
|
||||
|
||||
uint32_t DataSize = 8;
|
||||
rc = WriteBytes(&DataSize, 4);
|
||||
assert(rc == 4 && "Error writing data size.");
|
||||
|
||||
rc = WriteBytes(&Alignment, 4);
|
||||
assert(rc == 4 && "Error writing alignment data.");
|
||||
|
||||
rc = WriteBytes(&Size, 4);
|
||||
assert(rc == 4 && "Error writing size data.");
|
||||
}
|
||||
|
||||
void RemoteTargetExternal::SendLoadSection(uint64_t Addr,
|
||||
const void *Data,
|
||||
uint32_t Size,
|
||||
bool IsCode) {
|
||||
int rc;
|
||||
uint32_t MsgType = IsCode ? LLI_LoadCodeSection : LLI_LoadDataSection;
|
||||
rc = WriteBytes(&MsgType, 4);
|
||||
assert(rc == 4 && "Error writing message type.");
|
||||
|
||||
uint32_t DataSize = Size + 8;
|
||||
rc = WriteBytes(&DataSize, 4);
|
||||
assert(rc == 4 && "Error writing data size.");
|
||||
|
||||
rc = WriteBytes(&Addr, 8);
|
||||
assert(rc == 8 && "Error writing data.");
|
||||
|
||||
rc = WriteBytes(Data, Size);
|
||||
assert(rc == (int)Size && "Error writing data.");
|
||||
}
|
||||
|
||||
void RemoteTargetExternal::SendExecute(uint64_t Addr) {
|
||||
int rc;
|
||||
uint32_t MsgType = (uint32_t)LLI_Execute;
|
||||
rc = WriteBytes(&MsgType, 4);
|
||||
assert(rc == 4 && "Error writing message type.");
|
||||
|
||||
uint32_t DataSize = 8;
|
||||
rc = WriteBytes(&DataSize, 4);
|
||||
assert(rc == 4 && "Error writing data size.");
|
||||
|
||||
rc = WriteBytes(&Addr, 8);
|
||||
assert(rc == 8 && "Error writing data.");
|
||||
}
|
||||
|
||||
void RemoteTargetExternal::SendTerminate() {
|
||||
int rc;
|
||||
uint32_t MsgType = (uint32_t)LLI_Terminate;
|
||||
rc = WriteBytes(&MsgType, 4);
|
||||
assert(rc == 4 && "Error writing message type.");
|
||||
|
||||
// No data or data size is sent with Terminate
|
||||
}
|
||||
|
||||
|
||||
void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType) {
|
||||
int rc;
|
||||
uint32_t MsgType;
|
||||
rc = ReadBytes(&MsgType, 4);
|
||||
assert(rc == 4 && "Error reading message type.");
|
||||
assert(MsgType == ExpectedMsgType && "Error: received unexpected message type.");
|
||||
|
||||
uint32_t DataSize;
|
||||
rc = ReadBytes(&DataSize, 4);
|
||||
assert(rc == 4 && "Error reading data size.");
|
||||
assert(DataSize == 0 && "Error: unexpected data size.");
|
||||
}
|
||||
|
||||
void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType, int &Data) {
|
||||
uint64_t Temp;
|
||||
Receive(ExpectedMsgType, Temp);
|
||||
Data = (int)(int64_t)Temp;
|
||||
}
|
||||
|
||||
void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType, uint64_t &Data) {
|
||||
int rc;
|
||||
uint32_t MsgType;
|
||||
rc = ReadBytes(&MsgType, 4);
|
||||
assert(rc == 4 && "Error reading message type.");
|
||||
assert(MsgType == ExpectedMsgType && "Error: received unexpected message type.");
|
||||
|
||||
uint32_t DataSize;
|
||||
rc = ReadBytes(&DataSize, 4);
|
||||
assert(rc == 4 && "Error reading data size.");
|
||||
assert(DataSize == 8 && "Error: unexpected data size.");
|
||||
|
||||
rc = ReadBytes(&Data, 8);
|
||||
assert(DataSize == 8 && "Error: unexpected data.");
|
||||
}
|
||||
|
||||
#ifdef LLVM_ON_UNIX
|
||||
#include "Unix/RemoteTargetExternal.inc"
|
||||
#endif
|
||||
|
||||
#ifdef LLVM_ON_WIN32
|
||||
#include "Windows/RemoteTargetExternal.inc"
|
||||
#endif
|
118
tools/lli/RemoteTargetExternal.h
Normal file
118
tools/lli/RemoteTargetExternal.h
Normal file
@ -0,0 +1,118 @@
|
||||
//===----- RemoteTargetExternal.h - 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Definition of the RemoteTargetExternal class which executes JITed code in a
|
||||
// separate process from where it was built.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLI_REMOTETARGETEXTERNAL_H
|
||||
#define LLI_REMOTETARGETEXTERNAL_H
|
||||
|
||||
#include "llvm/Config/config.h"
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
#include "RemoteTarget.h"
|
||||
#include "RemoteTargetMessage.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class RemoteTargetExternal : public RemoteTarget {
|
||||
public:
|
||||
/// Allocate space in the remote target address space.
|
||||
///
|
||||
/// @param Size Amount of space, in bytes, to allocate.
|
||||
/// @param Alignment Required minimum alignment for allocated space.
|
||||
/// @param[out] Address Remote address of the allocated memory.
|
||||
///
|
||||
/// @returns False on success. On failure, ErrorMsg is updated with
|
||||
/// descriptive text of the encountered error.
|
||||
virtual bool allocateSpace(size_t Size,
|
||||
unsigned Alignment,
|
||||
uint64_t &Address);
|
||||
|
||||
/// Load data into the target address space.
|
||||
///
|
||||
/// @param Address Destination address in the target process.
|
||||
/// @param Data Source address in the host process.
|
||||
/// @param Size Number of bytes to copy.
|
||||
///
|
||||
/// @returns False on success. On failure, ErrorMsg is updated with
|
||||
/// descriptive text of the encountered error.
|
||||
virtual bool loadData(uint64_t Address, const void *Data, size_t Size);
|
||||
|
||||
/// Load code into the target address space and prepare it for execution.
|
||||
///
|
||||
/// @param Address Destination address in the target process.
|
||||
/// @param Data Source address in the host process.
|
||||
/// @param Size Number of bytes to copy.
|
||||
///
|
||||
/// @returns False on success. On failure, ErrorMsg is updated with
|
||||
/// descriptive text of the encountered error.
|
||||
virtual bool loadCode(uint64_t Address, const void *Data, size_t Size);
|
||||
|
||||
/// Execute code in the target process. The called function is required
|
||||
/// to be of signature int "(*)(void)".
|
||||
///
|
||||
/// @param Address Address of the loaded function in the target
|
||||
/// process.
|
||||
/// @param[out] RetVal The integer return value of the called function.
|
||||
///
|
||||
/// @returns False on success. On failure, ErrorMsg is updated with
|
||||
/// descriptive text of the encountered error.
|
||||
virtual bool executeCode(uint64_t Address, int &RetVal);
|
||||
|
||||
/// Minimum alignment for memory permissions. Used to seperate code and
|
||||
/// data regions to make sure data doesn't get marked as code or vice
|
||||
/// versa.
|
||||
///
|
||||
/// @returns Page alignment return value. Default of 4k.
|
||||
virtual unsigned getPageAlignment() { return 4096; }
|
||||
|
||||
/// Start the remote process.
|
||||
virtual void create();
|
||||
|
||||
/// Terminate the remote process.
|
||||
virtual void stop();
|
||||
|
||||
RemoteTargetExternal(std::string &Name) : RemoteTarget(), ChildName(Name) {}
|
||||
virtual ~RemoteTargetExternal() {}
|
||||
|
||||
private:
|
||||
std::string ChildName;
|
||||
|
||||
// This will get filled in as a point to an OS-specific structure.
|
||||
void *ConnectionData;
|
||||
|
||||
void SendAllocateSpace(uint32_t Alignment, uint32_t Size);
|
||||
void SendLoadSection(uint64_t Addr,
|
||||
const void *Data,
|
||||
uint32_t Size,
|
||||
bool IsCode);
|
||||
void SendExecute(uint64_t Addr);
|
||||
void SendTerminate();
|
||||
|
||||
void Receive(LLIMessageType Msg);
|
||||
void Receive(LLIMessageType Msg, int &Data);
|
||||
void Receive(LLIMessageType Msg, uint64_t &Data);
|
||||
|
||||
int WriteBytes(const void *Data, size_t Size);
|
||||
int ReadBytes(void *Data, size_t Size);
|
||||
void Wait();
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLI_REMOTETARGETEXTERNAL_H
|
45
tools/lli/RemoteTargetMessage.h
Normal file
45
tools/lli/RemoteTargetMessage.h
Normal file
@ -0,0 +1,45 @@
|
||||
//===---- RemoteTargetMessage.h - LLI out-of-process message protocol -----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Definition of the LLIMessageType enum which is used for communication with a
|
||||
// child process for remote execution.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLI_REMOTETARGETMESSAGE_H
|
||||
#define LLI_REMOTETARGETMESSAGE_H
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// LLI messages from parent-to-child or vice versa follow an exceedingly simple
|
||||
// protocol where the first four bytes represent the message type, the next
|
||||
// four bytes represent the size of data for the command and following bytes
|
||||
// represent the actual data.
|
||||
//
|
||||
// The protocol is not intended to be robust, secure or fault-tolerant. It is
|
||||
// only here for testing purposes and is therefore intended to be the simplest
|
||||
// implementation that will work. It is assumed that the parent and child
|
||||
// share characteristics like endianness.
|
||||
|
||||
enum LLIMessageType {
|
||||
LLI_Error = -1,
|
||||
LLI_ChildActive = 0, // Data = not used
|
||||
LLI_AllocateSpace, // Data = struct { uint_32t Align, uint_32t Size }
|
||||
LLI_AllocationResult, // Data = uint64_t AllocAddress (in Child memory space)
|
||||
LLI_LoadCodeSection, // Data = uint32_t Addr, followed by section contests
|
||||
LLI_LoadDataSection, // Data = uint32_t Addr, followed by section contents
|
||||
LLI_LoadComplete, // Data = not used
|
||||
LLI_Execute, // Data = Address of function to execute
|
||||
LLI_ExecutionResult, // Data = uint64_t Result
|
||||
LLI_Terminate // Data = not used
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
91
tools/lli/Unix/RemoteTargetExternal.inc
Normal file
91
tools/lli/Unix/RemoteTargetExternal.inc
Normal file
@ -0,0 +1,91 @@
|
||||
//=- RemoteTargetExternal.inc - LLVM out-of-process JIT execution for Unix --=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implementation of the Unix-specific parts of the RemoteTargetExternal class
|
||||
// which executes JITed code in a separate process from where it was built.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
namespace {
|
||||
|
||||
struct ConnectionData_t {
|
||||
int InputPipe;
|
||||
int OutputPipe;
|
||||
|
||||
ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace llvm {
|
||||
|
||||
void RemoteTargetExternal::create() {
|
||||
int PipeFD[2][2];
|
||||
pid_t ChildPID;
|
||||
|
||||
pipe(PipeFD[0]);
|
||||
pipe(PipeFD[1]);
|
||||
|
||||
ChildPID = fork();
|
||||
|
||||
if (ChildPID == 0) {
|
||||
// In the child...
|
||||
|
||||
// Close the parent ends of the pipes
|
||||
close(PipeFD[0][1]);
|
||||
close(PipeFD[1][0]);
|
||||
|
||||
// Use our pipes as stdin and stdout
|
||||
if (PipeFD[0][0] != STDIN_FILENO) {
|
||||
dup2(PipeFD[0][0], STDIN_FILENO);
|
||||
close(PipeFD[0][0]);
|
||||
}
|
||||
if (PipeFD[1][1] != STDOUT_FILENO) {
|
||||
dup2(PipeFD[1][1], STDOUT_FILENO);
|
||||
close(PipeFD[1][1]);
|
||||
}
|
||||
|
||||
// Execute the child process.
|
||||
char *args[1] = { NULL };
|
||||
int rc = execv(ChildName.c_str(), args);
|
||||
if (rc != 0)
|
||||
perror("Error executing child process: ");
|
||||
}
|
||||
else {
|
||||
// In the parent...
|
||||
|
||||
// Close the child ends of the pipes
|
||||
close(PipeFD[0][0]);
|
||||
close(PipeFD[1][1]);
|
||||
|
||||
// Store the parent ends of the pipes
|
||||
ConnectionData = (void*)new ConnectionData_t(PipeFD[1][0], PipeFD[0][1]);
|
||||
|
||||
Receive(LLI_ChildActive);
|
||||
}
|
||||
}
|
||||
|
||||
int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) {
|
||||
return write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size);
|
||||
}
|
||||
|
||||
int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) {
|
||||
return read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size);
|
||||
}
|
||||
|
||||
void RemoteTargetExternal::Wait() {
|
||||
wait(NULL);
|
||||
}
|
||||
|
||||
} // namespace llvm
|
32
tools/lli/Windows/RemoteTargetExternal.inc
Normal file
32
tools/lli/Windows/RemoteTargetExternal.inc
Normal file
@ -0,0 +1,32 @@
|
||||
//= RemoteTargetExternal.inc - LLVM out-of-process JIT execution for Windows =//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Definition of the Windows-specific parts of the RemoteTargetExternal class
|
||||
// which is meant to execute JITed code in a separate process from where it was
|
||||
// built. To support this functionality on Windows, implement these functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace llvm {
|
||||
|
||||
void RemoteTargetExternal::create() {
|
||||
}
|
||||
|
||||
int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RemoteTargetExternal::Wait() {
|
||||
}
|
||||
|
||||
} // namespace llvm
|
@ -41,6 +41,7 @@
|
||||
#include "llvm/Support/PluginLoader.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
@ -83,6 +84,18 @@ namespace {
|
||||
cl::desc("Execute MCJIT'ed code in a separate process."),
|
||||
cl::init(false));
|
||||
|
||||
// Manually specify the child process for remote execution. This overrides
|
||||
// the simulated remote execution that allocates address space for child
|
||||
// execution. The child process resides in the disk and communicates with lli
|
||||
// via stdin/stdout pipes.
|
||||
cl::opt<std::string>
|
||||
MCJITRemoteProcess("mcjit-remote-process",
|
||||
cl::desc("Specify the filename of the process to launch "
|
||||
"for remote MCJIT execution. If none is specified,"
|
||||
"\n\tremote execution will be simulated in-process."),
|
||||
cl::value_desc("filename"),
|
||||
cl::init(""));
|
||||
|
||||
// Determine optimization level.
|
||||
cl::opt<char>
|
||||
OptLevel("O",
|
||||
@ -481,30 +494,50 @@ int main(int argc, char **argv, char * const *envp) {
|
||||
// Everything is prepared now, so lay out our program for the target
|
||||
// address space, assign the section addresses to resolve any relocations,
|
||||
// and send it to the target.
|
||||
RemoteTarget Target;
|
||||
Target.create();
|
||||
|
||||
OwningPtr<RemoteTarget> Target;
|
||||
if (!MCJITRemoteProcess.empty()) { // Remote execution on a child process
|
||||
if (!RemoteTarget::hostSupportsExternalRemoteTarget()) {
|
||||
errs() << "Warning: host does not support external remote targets.\n"
|
||||
<< " Defaulting to simulated remote execution\n";
|
||||
Target.reset(RemoteTarget::createRemoteTarget());
|
||||
} else {
|
||||
std::string ChildEXE = sys::FindProgramByName(MCJITRemoteProcess);
|
||||
if (ChildEXE == "") {
|
||||
errs() << "Unable to find child target: '\''" << MCJITRemoteProcess << "\'\n";
|
||||
return -1;
|
||||
}
|
||||
Target.reset(RemoteTarget::createExternalRemoteTarget(MCJITRemoteProcess));
|
||||
}
|
||||
} else {
|
||||
// No child process name provided, use simulated remote execution.
|
||||
Target.reset(RemoteTarget::createRemoteTarget());
|
||||
}
|
||||
|
||||
// Create the remote target
|
||||
Target->create();
|
||||
|
||||
// Trigger compilation.
|
||||
EE->generateCodeForModule(Mod);
|
||||
|
||||
// Layout the target memory.
|
||||
layoutRemoteTargetMemory(&Target, MM);
|
||||
layoutRemoteTargetMemory(Target.get(), MM);
|
||||
|
||||
// Since we're executing in a (at least simulated) remote address space,
|
||||
// we can't use the ExecutionEngine::runFunctionAsMain(). We have to
|
||||
// grab the function address directly here and tell the remote target
|
||||
// to execute the function.
|
||||
// FIXME: argv and envp handling.
|
||||
uint64_t Entry = (uint64_t)EE->getPointerToFunction(EntryFn);
|
||||
uint64_t Entry = EE->getFunctionAddress(EntryFn->getName().str());
|
||||
|
||||
DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x"
|
||||
<< format("%llx", Entry) << "\n");
|
||||
|
||||
if (Target.executeCode(Entry, Result))
|
||||
errs() << "ERROR: " << Target.getErrorMsg() << "\n";
|
||||
if (Target->executeCode(Entry, Result))
|
||||
errs() << "ERROR: " << Target->getErrorMsg() << "\n";
|
||||
|
||||
Target.stop();
|
||||
} else {
|
||||
Target->stop();
|
||||
} else { // !RemoteMCJIT
|
||||
// Trigger compilation separately so code regions that need to be
|
||||
// invalidated will be known.
|
||||
(void)EE->getPointerToFunction(EntryFn);
|
||||
|
Loading…
Reference in New Issue
Block a user