mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-06 06:33:24 +00:00
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191848 91177308-0d34-0410-b5e6-96231b3b80d8
163 lines
4.6 KiB
C++
163 lines
4.6 KiB
C++
//===- 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
|
|
|
|
// 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);
|
|
}
|