[PATCH] Rework lli-child-target for portability and correctness
Alp Toker
alp at nuanti.com
Tue Dec 3 09:31:22 PST 2013
This is a bumper patch to fix assorted MCJIT remote issues, split into
two parts for ease of review.
Minor tweaks outside of lli were necessary to support reuse of LLVM's
Support implementation by inclusion without having to link to LLVM.
9 files changed, 157 insertions(+), 253 deletions(-)
Patch 1:
Provide LLVM_STANDALONE for lightweight Support embedders
This is sufficient to build lli-child-target in a standalone configuration
without having to link any LLVM libraries.
Also fixes a problem in AllocateRWX() where process::get_self()->page_size()
was being called repeatedly.
Patch 2:
Share a single IPC transport implementation between the child and parent
instead of duplicating the code.
Share the existing LLVM memory management and cache invalidation code
instead
of copy-and-pasting it. This is complicated; we don't want to maintain two
versions but at the same time need to keep lli-child-target free of
dependencies.
Make memory management and instruction cache flushing portable in the child
application using LLVM's Support headers in standalone mode. Eliminate
lots of
copy-and-pasted code.
Fix a typo that caused the instruction cache invalidation never to run on
executable pages, which could be a problem on ARM, PowerPC etc.
Add assertions for piped read/write. This should help cut down on needless
assertions at the callsites.
Build lli-child-target in a standalone configuration, reducing binary
size to
24KB down from ~500KB.
These fixes pave the way for a Windows implementation.
Alp.
--
http://www.nuanti.com
the browser experts
-------------- next part --------------
>From 0cef3b3d096bd7537e41a78f11603c3543c58bb7 Mon Sep 17 00:00:00 2001
From: Alp Toker <alp at nuanti.com>
Date: Tue, 3 Dec 2013 16:38:31 +0000
Subject: [PATCH 1/2] Provide LLVM_STANDALONE for lightweight Support embedders
This is sufficient to build lli-child-target in a standalone configuration
without having to link any LLVM libraries.
Also fixes a problem in AllocateRWX() where process::get_self()->page_size()
was being called repeatedly.
---
include/llvm/Support/ErrorHandling.h | 5 ++++-
lib/Support/Unix/Memory.inc | 14 ++++++++++--
lib/Support/Unix/Process.inc | 41 +++++++++++++++++++-----------------
3 files changed, 38 insertions(+), 22 deletions(-)
diff --git a/include/llvm/Support/ErrorHandling.h b/include/llvm/Support/ErrorHandling.h
index b948d97..4bf531b 100644
--- a/include/llvm/Support/ErrorHandling.h
+++ b/include/llvm/Support/ErrorHandling.h
@@ -99,7 +99,10 @@ namespace llvm {
///
/// Use this instead of assert(0). It conveys intent more clearly and
/// allows compilers to omit some unnecessary code.
-#ifndef NDEBUG
+#if defined(llvm_unreachable)
+#elif defined(LLVM_STANDALONE)
+#define llvm_unreachable(msg) assert(0 && msg)
+#elif !defined(NDEBUG)
#define llvm_unreachable(msg) \
::llvm::llvm_unreachable_internal(msg, __FILE__, __LINE__)
#elif defined(LLVM_BUILTIN_UNREACHABLE)
diff --git a/lib/Support/Unix/Memory.inc b/lib/Support/Unix/Memory.inc
index 58fda42..d3e160e 100644
--- a/lib/Support/Unix/Memory.inc
+++ b/lib/Support/Unix/Memory.inc
@@ -79,6 +79,14 @@ int getPosixProtectionFlags(unsigned Flags) {
namespace llvm {
namespace sys {
+static unsigned llvm_pagesize() {
+#ifdef LLVM_STANDALONE
+ return getPageSize();
+#else
+ return process::get_self()->page_size();
+#endif
+}
+
MemoryBlock
Memory::allocateMappedMemory(size_t NumBytes,
const MemoryBlock *const NearBlock,
@@ -88,7 +96,7 @@ Memory::allocateMappedMemory(size_t NumBytes,
if (NumBytes == 0)
return MemoryBlock();
- static const size_t PageSize = process::get_self()->page_size();
+ static const size_t PageSize = llvm_pagesize();
const size_t NumPages = (NumBytes+PageSize-1)/PageSize;
int fd = -1;
@@ -181,7 +189,7 @@ Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock,
std::string *ErrMsg) {
if (NumBytes == 0) return MemoryBlock();
- size_t PageSize = process::get_self()->page_size();
+ static const size_t PageSize = llvm_pagesize();
size_t NumPages = (NumBytes+PageSize-1)/PageSize;
int fd = -1;
@@ -353,7 +361,9 @@ void Memory::InvalidateInstructionCache(const void *Addr,
#endif // end apple
+#ifndef LLVM_STANDALONE
ValgrindDiscardTranslations(Addr, Len);
+#endif
}
} // namespace sys
diff --git a/lib/Support/Unix/Process.inc b/lib/Support/Unix/Process.inc
index c5778e7..58612f0 100644
--- a/lib/Support/Unix/Process.inc
+++ b/lib/Support/Unix/Process.inc
@@ -52,6 +52,26 @@ process::id_type self_process::get_id() {
return getpid();
}
+// On Cygwin, getpagesize() returns 64k(AllocationGranularity) and
+// offset in mmap(3) should be aligned to the AllocationGranularity.
+static unsigned getPageSize() {
+#if defined(HAVE_GETPAGESIZE)
+ const int page_size = ::getpagesize();
+#elif defined(HAVE_SYSCONF)
+ long page_size = ::sysconf(_SC_PAGE_SIZE);
+#else
+#warning Cannot get the page size on this machine
+#endif
+ return static_cast<unsigned>(page_size);
+}
+
+#ifndef LLVM_STANDALONE
+
+// This constructor guaranteed to be run exactly once on a single thread, and
+// sets up various process invariants that can be queried cheaply from then on.
+self_process::self_process() : PageSize(getPageSize()) {
+}
+
static std::pair<TimeValue, TimeValue> getRUsageTimes() {
#if defined(HAVE_GETRUSAGE)
struct rusage RU;
@@ -89,25 +109,6 @@ TimeValue self_process::get_system_time() const {
return getRUsageTimes().second;
}
-// On Cygwin, getpagesize() returns 64k(AllocationGranularity) and
-// offset in mmap(3) should be aligned to the AllocationGranularity.
-static unsigned getPageSize() {
-#if defined(HAVE_GETPAGESIZE)
- const int page_size = ::getpagesize();
-#elif defined(HAVE_SYSCONF)
- long page_size = ::sysconf(_SC_PAGE_SIZE);
-#else
-#warning Cannot get the page size on this machine
-#endif
- return static_cast<unsigned>(page_size);
-}
-
-// This constructor guaranteed to be run exactly once on a single thread, and
-// sets up various process invariants that can be queried cheaply from then on.
-self_process::self_process() : PageSize(getPageSize()) {
-}
-
-
size_t Process::GetMallocUsage() {
#if defined(HAVE_MALLINFO)
struct mallinfo mi;
@@ -372,3 +373,5 @@ unsigned llvm::sys::Process::GetRandomNumber() {
return ::rand();
#endif
}
+
+#endif // LLVM_STANDALONE
--
1.8.5
-------------- next part --------------
>From f798a5b8e5174de8a42106401aff775bc9c5305a Mon Sep 17 00:00:00 2001
From: Alp Toker <alp at nuanti.com>
Date: Tue, 3 Dec 2013 12:41:56 +0000
Subject: [PATCH 2/2] Refactor lli-child-target for portability and correctness
Share a single IPC transport implementation between the child and parent
instead of duplicating the code.
Share the existing LLVM memory management and cache invalidation code instead
of copy-and-pasting it. This is complicated; we don't want to maintain two
versions but at the same time need to keep lli-child-target free of
dependencies.
Make memory management and instruction cache flushing portable in the child
application using LLVM's Support headers in standalone mode. Eliminate lots of
copy-and-pasted code.
Fix a typo that caused the instruction cache invalidation never to run on
executable pages, which could be a problem on ARM, PowerPC etc.
Add assertions for piped read/write. This should help cut down on needless
assertions at the callsites.
Build lli-child-target in a standalone configuration, reducing binary size to
24KB down from ~500KB.
These fixes were made to pave the way for a Windows implementation.
This reduces binary size from ~400kb to 24kb.
---
tools/lli/ChildTarget/CMakeLists.txt | 4 +-
tools/lli/ChildTarget/ChildTarget.cpp | 85 +++++++++++--
tools/lli/ChildTarget/Unix/ChildTarget.inc | 166 --------------------------
tools/lli/ChildTarget/Windows/ChildTarget.inc | 44 -------
tools/lli/Unix/RemoteTargetExternal.inc | 37 ++++--
tools/lli/Windows/RemoteTargetExternal.inc | 14 ++-
6 files changed, 119 insertions(+), 231 deletions(-)
delete mode 100644 tools/lli/ChildTarget/Unix/ChildTarget.inc
delete mode 100644 tools/lli/ChildTarget/Windows/ChildTarget.inc
diff --git a/tools/lli/ChildTarget/CMakeLists.txt b/tools/lli/ChildTarget/CMakeLists.txt
index fd1ac24..5ae10f0 100644
--- a/tools/lli/ChildTarget/CMakeLists.txt
+++ b/tools/lli/ChildTarget/CMakeLists.txt
@@ -1,3 +1,5 @@
-add_llvm_tool(lli-child-target
+set(LLVM_LINK_COMPONENTS)
+
+add_llvm_executable(lli-child-target
ChildTarget.cpp
)
diff --git a/tools/lli/ChildTarget/ChildTarget.cpp b/tools/lli/ChildTarget/ChildTarget.cpp
index 55fcae9..852996a 100644
--- a/tools/lli/ChildTarget/ChildTarget.cpp
+++ b/tools/lli/ChildTarget/ChildTarget.cpp
@@ -1,4 +1,6 @@
#include "llvm/Config/config.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Memory.h"
#include "../RemoteTargetMessage.h"
#include <assert.h>
@@ -33,13 +35,35 @@ private:
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);
+ uint64_t allocate(uint32_t Alignment, uint32_t Size) {
+ if (!Alignment)
+ Alignment = 16;
+
+ error_code ec;
+ sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(
+ Size + Alignment, 0, sys::Memory::MF_READ | sys::Memory::MF_WRITE, ec);
+ assert(ec == 0);
+ if (ec)
+ return 0;
+
+ uint64_t Addr = (uint64_t)MB.base();
+ Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
+ m_AllocatedBufferMap[Addr] = MB;
+
+ return Addr;
+ }
void makeSectionExecutable(uint64_t Addr, uint32_t Size);
- void InvalidateInstructionCache(const void *Addr, size_t Len);
- void releaseMemory(uint64_t Addr, uint32_t Size);
+ void releaseMemory(uint64_t Addr) {
+ AllocMapType::iterator it = m_AllocatedBufferMap.find(Addr);
+ assert(it != m_AllocatedBufferMap.end());
+ error_code ec;
+ sys::Memory::releaseMappedMemory(it->second);
+ assert(ec == 0);
+ m_AllocatedBufferMap.erase(it);
+ }
// Store a map of allocated buffers to sizes.
- typedef std::map<uint64_t, uint32_t> AllocMapType;
+ typedef std::map<uint64_t, sys::MemoryBlock> AllocMapType;
AllocMapType m_AllocatedBufferMap;
// Communication handles (OS-specific)
@@ -169,9 +193,8 @@ 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);
- }
+ for (AllocMapType::iterator It = Begin; It != End; ++It)
+ releaseMemory(It->first);
m_AllocatedBufferMap.clear();
}
@@ -233,10 +256,54 @@ void LLIChildTarget::sendExecutionComplete(uint64_t Result) {
assert(rc == 8);
}
+#define LLVM_STANDALONE
+
+#ifdef LLVM_ON_UNIX
+#include "../lib/Support/Unix/Process.inc"
+#include "../lib/Support/Unix/Memory.inc"
+#include "../lib/Support/Errno.cpp"
+
+// TODO: LLVM_STANDALONE should not require these error_category definitions.
+const error_category &llvm::system_category() {
+ static error_category *s = 0;
+ return *s;
+}
+const error_category &llvm::generic_category() {
+ static error_category *s = 0;
+ return *s;
+}
+const error_category &llvm::posix_category() {
+ static error_category *s = 0;
+ return *s;
+}
+
+// This should work for LLVM_ON_WIN32 too.
+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.
+
+ error_code ec;
+ // This invalidates the instruction cache for us...
+ ec = sys::Memory::protectMappedMemory(
+ m_AllocatedBufferMap[Addr],
+ sys::Memory::MF_READ | sys::Memory::MF_WRITE | sys::Memory::MF_EXEC);
+ assert(ec == 0);
+}
+#endif
+
+#ifdef LLVM_ON_WIN32
+void LLIChildTarget::makeSectionExecutable(uint64_t Addr, uint32_t Size) {}
+#endif
+
+// TODO: Rename and share IPC transport code more elegantly.
+#define LLI_IS_CHILD
+#define RemoteTargetExternal LLIChildTarget
+
#ifdef LLVM_ON_UNIX
-#include "Unix/ChildTarget.inc"
+#include "../Unix/RemoteTargetExternal.inc"
#endif
#ifdef LLVM_ON_WIN32
-#include "Windows/ChildTarget.inc"
+#include "../Windows/RemoteTargetExternal.inc"
#endif
diff --git a/tools/lli/ChildTarget/Unix/ChildTarget.inc b/tools/lli/ChildTarget/Unix/ChildTarget.inc
deleted file mode 100644
index cc95810..0000000
--- a/tools/lli/ChildTarget/Unix/ChildTarget.inc
+++ /dev/null
@@ -1,166 +0,0 @@
-//===- 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>
-
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-
-#ifdef __APPLE__
-#include <mach/mach.h>
-#endif
-
-#if defined(__mips__)
-# if defined(__OpenBSD__)
-# include <mips64/sysarch.h>
-# else
-# include <sys/cachectl.h>
-# endif
-#endif
-
-#ifdef __APPLE__
-extern "C" void sys_icache_invalidate(const void *Addr, size_t len);
-#else
-extern "C" void __clear_cache(void *, void*);
-#endif
-
-namespace {
-
-struct ConnectionData_t {
- int InputPipe;
- int OutputPipe;
-
- ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {}
-};
-
-} // namespace
-
-LLIChildTarget::~LLIChildTarget() {
- delete static_cast<ConnectionData_t *>(ConnectionData);
-}
-
-// 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
deleted file mode 100644
index 45db2b0..0000000
--- a/tools/lli/ChildTarget/Windows/ChildTarget.inc
+++ /dev/null
@@ -1,44 +0,0 @@
-//=- 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.
-//
-//===----------------------------------------------------------------------===//
-
-LLIChildTarget::~LLIChildTarget() {
-}
-
-// 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) {
-}
diff --git a/tools/lli/Unix/RemoteTargetExternal.inc b/tools/lli/Unix/RemoteTargetExternal.inc
index 9c1a4cc..d2b00ce 100644
--- a/tools/lli/Unix/RemoteTargetExternal.inc
+++ b/tools/lli/Unix/RemoteTargetExternal.inc
@@ -24,12 +24,32 @@ struct ConnectionData_t {
int OutputPipe;
ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {}
+
+ int WriteBytes(const void *Data, size_t Size) {
+ ssize_t ret;
+ ret = write(OutputPipe, Data, Size);
+ assert(ret == (ssize_t)Size);
+ return ret;
+ }
+
+ int ReadBytes(void *Data, size_t Size) {
+ int ret;
+ ret = read(InputPipe, Data, Size);
+ assert(ret == (ssize_t)Size);
+ return ret;
+ }
};
} // namespace
-namespace llvm {
+//namespace llvm {
+#ifdef LLI_IS_CHILD
+void RemoteTargetExternal::initializeConnection() {
+ // Store the parent ends of the pipes
+ ConnectionData = (void *)new ConnectionData_t(STDIN_FILENO, STDOUT_FILENO);
+}
+#else
void RemoteTargetExternal::create() {
int PipeFD[2][2];
pid_t ChildPID;
@@ -77,20 +97,21 @@ void RemoteTargetExternal::create() {
}
}
-int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) {
- return write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size);
+void RemoteTargetExternal::Wait() {
+ wait(NULL);
}
+#endif
-int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) {
- return read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size);
+int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) {
+ return ((ConnectionData_t*)ConnectionData)->WriteBytes(Data, Size);
}
-void RemoteTargetExternal::Wait() {
- wait(NULL);
+int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) {
+ return ((ConnectionData_t*)ConnectionData)->ReadBytes(Data, Size);
}
RemoteTargetExternal::~RemoteTargetExternal() {
delete static_cast<ConnectionData_t *>(ConnectionData);
}
-} // namespace llvm
+//} // namespace llvm
diff --git a/tools/lli/Windows/RemoteTargetExternal.inc b/tools/lli/Windows/RemoteTargetExternal.inc
index aef4627..992cb58 100644
--- a/tools/lli/Windows/RemoteTargetExternal.inc
+++ b/tools/lli/Windows/RemoteTargetExternal.inc
@@ -15,9 +15,20 @@
namespace llvm {
+#ifdef LLI_IS_CHILD
+// The RemoteTargetExternal implementation should prevent us from ever getting
+// here on Windows, but nothing prevents a user from running this directly.
+void RemoteTargetExternal::initializeConnection() {
+ assert(0 && "lli-child-target is not implemented for Windows");
+}
+#else
void RemoteTargetExternal::create() {
}
+void RemoteTargetExternal::Wait() {
+}
+#endif
+
int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) {
return 0;
}
@@ -26,9 +37,6 @@ int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) {
return 0;
}
-void RemoteTargetExternal::Wait() {
-}
-
RemoteTargetExternal::~RemoteTargetExternal() {
}
--
1.8.5
More information about the cfe-commits
mailing list