summaryrefslogtreecommitdiff
path: root/tools/lli/ChildTarget
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lli/ChildTarget')
-rw-r--r--tools/lli/ChildTarget/CMakeLists.txt3
-rw-r--r--tools/lli/ChildTarget/ChildTarget.cpp241
-rw-r--r--tools/lli/ChildTarget/Makefile17
-rw-r--r--tools/lli/ChildTarget/Unix/ChildTarget.inc141
-rw-r--r--tools/lli/ChildTarget/Windows/ChildTarget.inc41
5 files changed, 443 insertions, 0 deletions
diff --git a/tools/lli/ChildTarget/CMakeLists.txt b/tools/lli/ChildTarget/CMakeLists.txt
new file mode 100644
index 0000000000..fd1ac24f04
--- /dev/null
+++ b/tools/lli/ChildTarget/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_llvm_tool(lli-child-target
+ ChildTarget.cpp
+ )
diff --git a/tools/lli/ChildTarget/ChildTarget.cpp b/tools/lli/ChildTarget/ChildTarget.cpp
new file mode 100644
index 0000000000..a59209a160
--- /dev/null
+++ b/tools/lli/ChildTarget/ChildTarget.cpp
@@ -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
diff --git a/tools/lli/ChildTarget/Makefile b/tools/lli/ChildTarget/Makefile
new file mode 100644
index 0000000000..f77b144aab
--- /dev/null
+++ b/tools/lli/ChildTarget/Makefile
@@ -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
diff --git a/tools/lli/ChildTarget/Unix/ChildTarget.inc b/tools/lli/ChildTarget/Unix/ChildTarget.inc
new file mode 100644
index 0000000000..9550e508d6
--- /dev/null
+++ b/tools/lli/ChildTarget/Unix/ChildTarget.inc
@@ -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);
+}
diff --git a/tools/lli/ChildTarget/Windows/ChildTarget.inc b/tools/lli/ChildTarget/Windows/ChildTarget.inc
new file mode 100644
index 0000000000..bb95aff000
--- /dev/null
+++ b/tools/lli/ChildTarget/Windows/ChildTarget.inc
@@ -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) {
+}