diff options
Diffstat (limited to 'contrib/llvm/tools/lli/ChildTarget/Unix/ChildTarget.inc')
-rw-r--r-- | contrib/llvm/tools/lli/ChildTarget/Unix/ChildTarget.inc | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lli/ChildTarget/Unix/ChildTarget.inc b/contrib/llvm/tools/lli/ChildTarget/Unix/ChildTarget.inc new file mode 100644 index 0000000..cc95810 --- /dev/null +++ b/contrib/llvm/tools/lli/ChildTarget/Unix/ChildTarget.inc @@ -0,0 +1,166 @@ +//===- 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); +} |