diff options
author | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
commit | 9cedb8bb69b89b0f0c529937247a6a80cabdbaec (patch) | |
tree | c978f0e9ec1ab92dc8123783f30b08a7fd1e2a39 /contrib/llvm/tools/lli | |
parent | 03fdc2934eb61c44c049a02b02aa974cfdd8a0eb (diff) | |
download | FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.zip FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.tar.gz |
MFC 261991:
Upgrade our copy of llvm/clang to 3.4 release. This version supports
all of the features in the current working draft of the upcoming C++
standard, provisionally named C++1y.
The code generator's performance is greatly increased, and the loop
auto-vectorizer is now enabled at -Os and -O2 in addition to -O3. The
PowerPC backend has made several major improvements to code generation
quality and compile time, and the X86, SPARC, ARM32, Aarch64 and SystemZ
backends have all seen major feature work.
Release notes for llvm and clang can be found here:
<http://llvm.org/releases/3.4/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.4/tools/clang/docs/ReleaseNotes.html>
MFC 262121 (by emaste):
Update lldb for clang/llvm 3.4 import
This commit largely restores the lldb source to the upstream r196259
snapshot with the addition of threaded inferior support and a few bug
fixes.
Specific upstream lldb revisions restored include:
SVN git
181387 779e6ac
181703 7bef4e2
182099 b31044e
182650 f2dcf35
182683 0d91b80
183862 15c1774
183929 99447a6
184177 0b2934b
184948 4dc3761
184954 007e7bc
186990 eebd175
Sponsored by: DARPA, AFRL
MFC 262186 (by emaste):
Fix mismerge in r262121
A break statement was lost in the merge. The error had no functional
impact, but restore it to reduce the diff against upstream.
MFC 262303:
Pull in r197521 from upstream clang trunk (by rdivacky):
Use the integrated assembler by default on FreeBSD/ppc and ppc64.
Requested by: jhibbits
MFC 262611:
Pull in r196874 from upstream llvm trunk:
Fix a crash that occurs when PWD is invalid.
MCJIT needs to be able to run in hostile environments, even when PWD
is invalid. There's no need to crash MCJIT in this case.
The obvious fix is to simply leave MCContext's CompilationDir empty
when PWD can't be determined. This way, MCJIT clients,
and other clients that link with LLVM don't need a valid working directory.
If we do want to guarantee valid CompilationDir, that should be done
only for clients of getCompilationDir(). This is as simple as checking
for an empty string.
The only current use of getCompilationDir is EmitGenDwarfInfo, which
won't conceivably run with an invalid working dir. However, in the
purely hypothetically and untestable case that this happens, the
AT_comp_dir will be omitted from the compilation_unit DIE.
This should help fix assertions occurring with ports-mgmt/tinderbox,
when it is using jails, and sometimes invalidates clang's current
working directory.
Reported by: decke
MFC 262809:
Pull in r203007 from upstream clang trunk:
Don't produce an alias between destructors with different calling conventions.
Fixes pr19007.
(Please note that is an LLVM PR identifier, not a FreeBSD one.)
This should fix Firefox and/or libxul crashes (due to problems with
regparm/stdcall calling conventions) on i386.
Reported by: multiple users on freebsd-current
PR: bin/187103
MFC 263048:
Repair recognition of "CC" as an alias for the C++ compiler, since it
was silently broken by upstream for a Windows-specific use-case.
Apparently some versions of CMake still rely on this archaic feature...
Reported by: rakuco
MFC 263049:
Garbage collect the old way of adding the libstdc++ include directories
in clang's InitHeaderSearch.cpp. This has been superseded by David
Chisnall's commit in r255321.
Moreover, if libc++ is used, the libstdc++ include directories should
not be in the search path at all. These directories are now only used
if you pass -stdlib=libstdc++.
Diffstat (limited to 'contrib/llvm/tools/lli')
-rw-r--r-- | contrib/llvm/tools/lli/ChildTarget/ChildTarget.cpp | 242 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/ChildTarget/Unix/ChildTarget.inc | 166 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/ChildTarget/Windows/ChildTarget.inc | 44 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/RecordingMemoryManager.cpp | 128 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/RecordingMemoryManager.h | 87 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/RemoteMemoryManager.cpp | 206 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/RemoteMemoryManager.h | 114 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/RemoteTarget.cpp | 31 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/RemoteTarget.h | 27 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/RemoteTargetExternal.cpp | 162 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/RemoteTargetExternal.h | 118 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/RemoteTargetMessage.h | 45 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/Unix/RemoteTargetExternal.inc | 96 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/Windows/RemoteTargetExternal.inc | 35 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/lli.cpp | 322 |
15 files changed, 1455 insertions, 368 deletions
diff --git a/contrib/llvm/tools/lli/ChildTarget/ChildTarget.cpp b/contrib/llvm/tools/lli/ChildTarget/ChildTarget.cpp new file mode 100644 index 0000000..55fcae9 --- /dev/null +++ b/contrib/llvm/tools/lli/ChildTarget/ChildTarget.cpp @@ -0,0 +1,242 @@ +#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: + ~LLIChildTarget(); // OS-specific destructor + 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/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); +} diff --git a/contrib/llvm/tools/lli/ChildTarget/Windows/ChildTarget.inc b/contrib/llvm/tools/lli/ChildTarget/Windows/ChildTarget.inc new file mode 100644 index 0000000..45db2b0 --- /dev/null +++ b/contrib/llvm/tools/lli/ChildTarget/Windows/ChildTarget.inc @@ -0,0 +1,44 @@ +//=- 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/contrib/llvm/tools/lli/RecordingMemoryManager.cpp b/contrib/llvm/tools/lli/RecordingMemoryManager.cpp deleted file mode 100644 index e4d992d..0000000 --- a/contrib/llvm/tools/lli/RecordingMemoryManager.cpp +++ /dev/null @@ -1,128 +0,0 @@ -//===- RecordingMemoryManager.cpp - Recording memory manager --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This memory manager allocates local storage and keeps a record of each -// allocation. Iterators are provided for all data and code allocations. -// -//===----------------------------------------------------------------------===// - -#include "RecordingMemoryManager.h" -using namespace llvm; - -RecordingMemoryManager::~RecordingMemoryManager() { - for (SmallVectorImpl<Allocation>::iterator - I = AllocatedCodeMem.begin(), E = AllocatedCodeMem.end(); - I != E; ++I) - sys::Memory::releaseMappedMemory(I->first); - for (SmallVectorImpl<Allocation>::iterator - I = AllocatedDataMem.begin(), E = AllocatedDataMem.end(); - I != E; ++I) - sys::Memory::releaseMappedMemory(I->first); -} - -uint8_t *RecordingMemoryManager:: -allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) { - // The recording memory manager is just a local copy of the remote target. - // The alignment requirement is just stored here for later use. Regular - // heap storage is sufficient here, but we're using mapped memory to work - // around a bug in MCJIT. - sys::MemoryBlock Block = allocateSection(Size); - AllocatedCodeMem.push_back(Allocation(Block, Alignment)); - return (uint8_t*)Block.base(); -} - -uint8_t *RecordingMemoryManager:: -allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, bool IsReadOnly) { - // The recording memory manager is just a local copy of the remote target. - // The alignment requirement is just stored here for later use. Regular - // heap storage is sufficient here, but we're using mapped memory to work - // around a bug in MCJIT. - sys::MemoryBlock Block = allocateSection(Size); - AllocatedDataMem.push_back(Allocation(Block, Alignment)); - return (uint8_t*)Block.base(); -} - -sys::MemoryBlock RecordingMemoryManager::allocateSection(uintptr_t Size) { - error_code ec; - sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size, - &Near, - sys::Memory::MF_READ | - sys::Memory::MF_WRITE, - ec); - assert(!ec && MB.base()); - - // FIXME: This is part of a work around to keep sections near one another - // when MCJIT performs relocations after code emission but before - // the generated code is moved to the remote target. - // Save this address as the basis for our next request - Near = MB; - return MB; -} - -void RecordingMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); } -void RecordingMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); } -void RecordingMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); } -void RecordingMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); } -uint8_t *RecordingMemoryManager::getGOTBase() const { - llvm_unreachable("Unexpected!"); - return 0; -} -uint8_t *RecordingMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){ - llvm_unreachable("Unexpected!"); - return 0; -} -uint8_t *RecordingMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize, - unsigned Alignment) { - llvm_unreachable("Unexpected!"); - return 0; -} -void RecordingMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart, - uint8_t *FunctionEnd) { - llvm_unreachable("Unexpected!"); -} -uint8_t *RecordingMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) { - llvm_unreachable("Unexpected!"); - return 0; -} -uint8_t *RecordingMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) { - llvm_unreachable("Unexpected!"); - return 0; -} -void RecordingMemoryManager::deallocateFunctionBody(void *Body) { - llvm_unreachable("Unexpected!"); -} -uint8_t* RecordingMemoryManager::startExceptionTable(const Function* F, uintptr_t &ActualSize) { - llvm_unreachable("Unexpected!"); - return 0; -} -void RecordingMemoryManager::endExceptionTable(const Function *F, uint8_t *TableStart, - uint8_t *TableEnd, uint8_t* FrameRegister) { - llvm_unreachable("Unexpected!"); -} -void RecordingMemoryManager::deallocateExceptionTable(void *ET) { - llvm_unreachable("Unexpected!"); -} - -static int jit_noop() { - return 0; -} - -void *RecordingMemoryManager::getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure) { - // We should not invoke parent's ctors/dtors from generated main()! - // On Mingw and Cygwin, the symbol __main is resolved to - // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors - // (and register wrong callee's dtors with atexit(3)). - // We expect ExecutionEngine::runStaticConstructorsDestructors() - // is called before ExecutionEngine::runFunctionAsMain() is called. - if (Name == "__main") return (void*)(intptr_t)&jit_noop; - - return NULL; -} diff --git a/contrib/llvm/tools/lli/RecordingMemoryManager.h b/contrib/llvm/tools/lli/RecordingMemoryManager.h deleted file mode 100644 index 991f535..0000000 --- a/contrib/llvm/tools/lli/RecordingMemoryManager.h +++ /dev/null @@ -1,87 +0,0 @@ -//===- RecordingMemoryManager.h - LLI MCJIT recording memory manager ------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This memory manager allocates local storage and keeps a record of each -// allocation. Iterators are provided for all data and code allocations. -// -//===----------------------------------------------------------------------===// - -#ifndef RECORDINGMEMORYMANAGER_H -#define RECORDINGMEMORYMANAGER_H - -#include "llvm/ADT/SmallVector.h" -#include "llvm/ExecutionEngine/JITMemoryManager.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Memory.h" -#include <utility> - -namespace llvm { - -class RecordingMemoryManager : public JITMemoryManager { -public: - typedef std::pair<sys::MemoryBlock, unsigned> Allocation; - -private: - SmallVector<Allocation, 16> AllocatedDataMem; - SmallVector<Allocation, 16> AllocatedCodeMem; - - // FIXME: This is part of a work around to keep sections near one another - // when MCJIT performs relocations after code emission but before - // the generated code is moved to the remote target. - sys::MemoryBlock Near; - sys::MemoryBlock allocateSection(uintptr_t Size); - -public: - RecordingMemoryManager() {} - virtual ~RecordingMemoryManager(); - - typedef SmallVectorImpl<Allocation>::const_iterator const_data_iterator; - typedef SmallVectorImpl<Allocation>::const_iterator const_code_iterator; - - const_data_iterator data_begin() const { return AllocatedDataMem.begin(); } - const_data_iterator data_end() const { return AllocatedDataMem.end(); } - const_code_iterator code_begin() const { return AllocatedCodeMem.begin(); } - const_code_iterator code_end() const { return AllocatedCodeMem.end(); } - - uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID); - - uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, bool IsReadOnly); - - void *getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure = true); - - bool applyPermissions(std::string *ErrMsg) { return false; } - - // The following obsolete JITMemoryManager calls are stubbed out for - // this model. - void setMemoryWritable(); - void setMemoryExecutable(); - void setPoisonMemory(bool poison); - void AllocateGOT(); - uint8_t *getGOTBase() const; - uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize); - uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize, - unsigned Alignment); - void endFunctionBody(const Function *F, uint8_t *FunctionStart, - uint8_t *FunctionEnd); - uint8_t *allocateSpace(intptr_t Size, unsigned Alignment); - uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment); - void deallocateFunctionBody(void *Body); - uint8_t* startExceptionTable(const Function* F, uintptr_t &ActualSize); - void endExceptionTable(const Function *F, uint8_t *TableStart, - uint8_t *TableEnd, uint8_t* FrameRegister); - void deallocateExceptionTable(void *ET); - -}; - -} // end namespace llvm - -#endif diff --git a/contrib/llvm/tools/lli/RemoteMemoryManager.cpp b/contrib/llvm/tools/lli/RemoteMemoryManager.cpp new file mode 100644 index 0000000..04fc40e --- /dev/null +++ b/contrib/llvm/tools/lli/RemoteMemoryManager.cpp @@ -0,0 +1,206 @@ +//===---- RemoteMemoryManager.cpp - Recording memory manager --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This memory manager allocates local storage and keeps a record of each +// allocation. Iterators are provided for all data and code allocations. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "lli" +#include "RemoteMemoryManager.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/ObjectImage.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" + +using namespace llvm; + +RemoteMemoryManager::~RemoteMemoryManager() { + for (SmallVector<Allocation, 2>::iterator + I = AllocatedSections.begin(), E = AllocatedSections.end(); + I != E; ++I) + sys::Memory::releaseMappedMemory(I->MB); +} + +uint8_t *RemoteMemoryManager:: +allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, + StringRef SectionName) { + // The recording memory manager is just a local copy of the remote target. + // The alignment requirement is just stored here for later use. Regular + // heap storage is sufficient here, but we're using mapped memory to work + // around a bug in MCJIT. + sys::MemoryBlock Block = allocateSection(Size); + // AllocatedSections will own this memory. + AllocatedSections.push_back( Allocation(Block, Alignment, true) ); + // UnmappedSections has the same information but does not own the memory. + UnmappedSections.push_back( Allocation(Block, Alignment, true) ); + return (uint8_t*)Block.base(); +} + +uint8_t *RemoteMemoryManager:: +allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName, + bool IsReadOnly) { + // The recording memory manager is just a local copy of the remote target. + // The alignment requirement is just stored here for later use. Regular + // heap storage is sufficient here, but we're using mapped memory to work + // around a bug in MCJIT. + sys::MemoryBlock Block = allocateSection(Size); + // AllocatedSections will own this memory. + AllocatedSections.push_back( Allocation(Block, Alignment, false) ); + // UnmappedSections has the same information but does not own the memory. + UnmappedSections.push_back( Allocation(Block, Alignment, false) ); + return (uint8_t*)Block.base(); +} + +sys::MemoryBlock RemoteMemoryManager::allocateSection(uintptr_t Size) { + error_code ec; + sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size, + &Near, + sys::Memory::MF_READ | + sys::Memory::MF_WRITE, + ec); + assert(!ec && MB.base()); + + // FIXME: This is part of a work around to keep sections near one another + // when MCJIT performs relocations after code emission but before + // the generated code is moved to the remote target. + // Save this address as the basis for our next request + Near = MB; + return MB; +} + +void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE, + const ObjectImage *Obj) { + // The client should have called setRemoteTarget() before triggering any + // code generation. + assert(Target); + if (!Target) + return; + + // FIXME: Make this function thread safe. + + // Lay out our sections in order, with all the code sections first, then + // all the data sections. + uint64_t CurOffset = 0; + unsigned MaxAlign = Target->getPageAlignment(); + SmallVector<std::pair<Allocation, uint64_t>, 16> Offsets; + unsigned NumSections = UnmappedSections.size(); + // We're going to go through the list twice to separate code and data, but + // it's a very small list, so that's OK. + for (size_t i = 0, e = NumSections; i != e; ++i) { + Allocation &Section = UnmappedSections[i]; + if (Section.IsCode) { + unsigned Size = Section.MB.size(); + unsigned Align = Section.Alignment; + DEBUG(dbgs() << "code region: size " << Size + << ", alignment " << Align << "\n"); + // Align the current offset up to whatever is needed for the next + // section. + CurOffset = (CurOffset + Align - 1) / Align * Align; + // Save off the address of the new section and allocate its space. + Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset)); + CurOffset += Size; + } + } + // Adjust to keep code and data aligned on seperate pages. + CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign; + for (size_t i = 0, e = NumSections; i != e; ++i) { + Allocation &Section = UnmappedSections[i]; + if (!Section.IsCode) { + unsigned Size = Section.MB.size(); + unsigned Align = Section.Alignment; + DEBUG(dbgs() << "data region: size " << Size + << ", alignment " << Align << "\n"); + // Align the current offset up to whatever is needed for the next + // section. + CurOffset = (CurOffset + Align - 1) / Align * Align; + // Save off the address of the new section and allocate its space. + Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset)); + CurOffset += Size; + } + } + + // Allocate space in the remote target. + uint64_t RemoteAddr; + if (Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr)) + report_fatal_error(Target->getErrorMsg()); + + // Map the section addresses so relocations will get updated in the local + // copies of the sections. + for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { + uint64_t Addr = RemoteAddr + Offsets[i].second; + EE->mapSectionAddress(const_cast<void*>(Offsets[i].first.MB.base()), Addr); + + DEBUG(dbgs() << " Mapping local: " << Offsets[i].first.MB.base() + << " to remote: 0x" << format("%llx", Addr) << "\n"); + + MappedSections[Addr] = Offsets[i].first; + } + + UnmappedSections.clear(); +} + +bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) { + // FIXME: Make this function thread safe. + for (DenseMap<uint64_t, Allocation>::iterator + I = MappedSections.begin(), E = MappedSections.end(); + I != E; ++I) { + uint64_t RemoteAddr = I->first; + const Allocation &Section = I->second; + if (Section.IsCode) { + Target->loadCode(RemoteAddr, Section.MB.base(), Section.MB.size()); + + DEBUG(dbgs() << " loading code: " << Section.MB.base() + << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); + } else { + Target->loadData(RemoteAddr, Section.MB.base(), Section.MB.size()); + + DEBUG(dbgs() << " loading data: " << Section.MB.base() + << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); + } + } + + MappedSections.clear(); + + return false; +} + +void RemoteMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); } +void RemoteMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); } +void RemoteMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); } +void RemoteMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); } +uint8_t *RemoteMemoryManager::getGOTBase() const { + llvm_unreachable("Unexpected!"); + return 0; +} +uint8_t *RemoteMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){ + llvm_unreachable("Unexpected!"); + return 0; +} +uint8_t *RemoteMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize, + unsigned Alignment) { + llvm_unreachable("Unexpected!"); + return 0; +} +void RemoteMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart, + uint8_t *FunctionEnd) { + llvm_unreachable("Unexpected!"); +} +uint8_t *RemoteMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) { + llvm_unreachable("Unexpected!"); + return 0; +} +uint8_t *RemoteMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) { + llvm_unreachable("Unexpected!"); + return 0; +} +void RemoteMemoryManager::deallocateFunctionBody(void *Body) { + llvm_unreachable("Unexpected!"); +} diff --git a/contrib/llvm/tools/lli/RemoteMemoryManager.h b/contrib/llvm/tools/lli/RemoteMemoryManager.h new file mode 100644 index 0000000..5d0456f --- /dev/null +++ b/contrib/llvm/tools/lli/RemoteMemoryManager.h @@ -0,0 +1,114 @@ +//===- RemoteMemoryManager.h - LLI MCJIT recording memory manager ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This memory manager allocates local storage and keeps a record of each +// allocation. Iterators are provided for all data and code allocations. +// +//===----------------------------------------------------------------------===// + +#ifndef REMOTEMEMORYMANAGER_H +#define REMOTEMEMORYMANAGER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ExecutionEngine/JITMemoryManager.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Memory.h" +#include <utility> + +#include "RemoteTarget.h" + +namespace llvm { + +class RemoteMemoryManager : public JITMemoryManager { +public: + // Notice that this structure takes ownership of the memory allocated. + struct Allocation { + Allocation() {} + Allocation(sys::MemoryBlock mb, unsigned a, bool code) + : MB(mb), Alignment(a), IsCode(code) {} + + sys::MemoryBlock MB; + unsigned Alignment; + bool IsCode; + }; + +private: + // This vector contains Allocation objects for all sections which we have + // allocated. This vector effectively owns the memory associated with the + // allocations. + SmallVector<Allocation, 2> AllocatedSections; + + // This vector contains pointers to Allocation objects for any sections we + // have allocated locally but have not yet remapped for the remote target. + // When we receive notification of a completed module load, we will map + // these sections into the remote target. + SmallVector<Allocation, 2> UnmappedSections; + + // This map tracks the sections we have remapped for the remote target + // but have not yet copied to the target. + DenseMap<uint64_t, Allocation> MappedSections; + + // FIXME: This is part of a work around to keep sections near one another + // when MCJIT performs relocations after code emission but before + // the generated code is moved to the remote target. + sys::MemoryBlock Near; + sys::MemoryBlock allocateSection(uintptr_t Size); + + RemoteTarget *Target; + +public: + RemoteMemoryManager() : Target(NULL) {} + virtual ~RemoteMemoryManager(); + + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName); + + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName, + bool IsReadOnly); + + // For now, remote symbol resolution is not support in lli. The MCJIT + // interface does support this, but clients must provide their own + // mechanism for finding remote symbol addresses. MCJIT will resolve + // symbols from Modules it contains. + uint64_t getSymbolAddress(const std::string &Name) { return 0; } + + void notifyObjectLoaded(ExecutionEngine *EE, const ObjectImage *Obj); + + bool finalizeMemory(std::string *ErrMsg); + + // For now, remote EH frame registration isn't supported. Remote symbol + // resolution is a prerequisite to supporting remote EH frame registration. + void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {} + void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {} + + // This is a non-interface function used by lli + void setRemoteTarget(RemoteTarget *T) { Target = T; } + + // The following obsolete JITMemoryManager calls are stubbed out for + // this model. + void setMemoryWritable(); + void setMemoryExecutable(); + void setPoisonMemory(bool poison); + void AllocateGOT(); + uint8_t *getGOTBase() const; + uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize); + uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize, + unsigned Alignment); + void endFunctionBody(const Function *F, uint8_t *FunctionStart, + uint8_t *FunctionEnd); + uint8_t *allocateSpace(intptr_t Size, unsigned Alignment); + uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment); + void deallocateFunctionBody(void *Body); +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/tools/lli/RemoteTarget.cpp b/contrib/llvm/tools/lli/RemoteTarget.cpp index 212bdfd..5c74e6e 100644 --- a/contrib/llvm/tools/lli/RemoteTarget.cpp +++ b/contrib/llvm/tools/lli/RemoteTarget.cpp @@ -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; diff --git a/contrib/llvm/tools/lli/RemoteTarget.h b/contrib/llvm/tools/lli/RemoteTarget.h index b2a6d0e..c95fbd1 100644 --- a/contrib/llvm/tools/lli/RemoteTarget.h +++ b/contrib/llvm/tools/lli/RemoteTarget.h @@ -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. diff --git a/contrib/llvm/tools/lli/RemoteTargetExternal.cpp b/contrib/llvm/tools/lli/RemoteTargetExternal.cpp new file mode 100644 index 0000000..742a948 --- /dev/null +++ b/contrib/llvm/tools/lli/RemoteTargetExternal.cpp @@ -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 == (uint32_t)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 == (uint32_t)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 diff --git a/contrib/llvm/tools/lli/RemoteTargetExternal.h b/contrib/llvm/tools/lli/RemoteTargetExternal.h new file mode 100644 index 0000000..a4bfad2 --- /dev/null +++ b/contrib/llvm/tools/lli/RemoteTargetExternal.h @@ -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 diff --git a/contrib/llvm/tools/lli/RemoteTargetMessage.h b/contrib/llvm/tools/lli/RemoteTargetMessage.h new file mode 100644 index 0000000..12cfa9a --- /dev/null +++ b/contrib/llvm/tools/lli/RemoteTargetMessage.h @@ -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 diff --git a/contrib/llvm/tools/lli/Unix/RemoteTargetExternal.inc b/contrib/llvm/tools/lli/Unix/RemoteTargetExternal.inc new file mode 100644 index 0000000..9c1a4cc --- /dev/null +++ b/contrib/llvm/tools/lli/Unix/RemoteTargetExternal.inc @@ -0,0 +1,96 @@ +//=- 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; + + // Create two pipes. + if (pipe(PipeFD[0]) != 0 || pipe(PipeFD[1]) != 0) + perror("Error creating pipe: "); + + 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); +} + +RemoteTargetExternal::~RemoteTargetExternal() { + delete static_cast<ConnectionData_t *>(ConnectionData); +} + +} // namespace llvm diff --git a/contrib/llvm/tools/lli/Windows/RemoteTargetExternal.inc b/contrib/llvm/tools/lli/Windows/RemoteTargetExternal.inc new file mode 100644 index 0000000..aef4627 --- /dev/null +++ b/contrib/llvm/tools/lli/Windows/RemoteTargetExternal.inc @@ -0,0 +1,35 @@ +//= 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() { +} + +RemoteTargetExternal::~RemoteTargetExternal() { +} + +} // namespace llvm diff --git a/contrib/llvm/tools/lli/lli.cpp b/contrib/llvm/tools/lli/lli.cpp index 297763f..f317566 100644 --- a/contrib/llvm/tools/lli/lli.cpp +++ b/contrib/llvm/tools/lli/lli.cpp @@ -15,7 +15,7 @@ #define DEBUG_TYPE "lli" #include "llvm/IR/LLVMContext.h" -#include "RecordingMemoryManager.h" +#include "RemoteMemoryManager.h" #include "RemoteTarget.h" #include "llvm/ADT/Triple.h" #include "llvm/Bitcode/ReaderWriter.h" @@ -27,8 +27,10 @@ #include "llvm/ExecutionEngine/JITMemoryManager.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" +#include "llvm/IR/TypeBuilder.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -41,10 +43,12 @@ #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" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Instrumentation.h" #include <cerrno> #ifdef __CYGWIN__ @@ -71,6 +75,10 @@ namespace { "use-mcjit", cl::desc("Enable use of the MC-based JIT (if available)"), cl::init(false)); + cl::opt<bool> DebugIR( + "debug-ir", cl::desc("Generate debug information to allow debugging IR."), + cl::init(false)); + // The MCJIT supports building for a target address space separate from // the JIT compilation process. Use a forked process and a copying // memory manager with IPC to execute using this functionality. @@ -78,6 +86,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 will be executed and will communicate 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", @@ -113,6 +133,11 @@ namespace { cl::value_desc("function"), cl::init("main")); + cl::list<std::string> + ExtraModules("extra-module", + cl::desc("Extra modules to be loaded"), + cl::value_desc("input bitcode")); + cl::opt<std::string> FakeArgv0("fake-argv0", cl::desc("Override the 'argv[0]' value passed into the executing" @@ -159,11 +184,6 @@ namespace { clEnumValEnd)); cl::opt<bool> - EnableJITExceptionHandling("jit-enable-eh", - cl::desc("Emit exception handling information"), - cl::init(false)); - - cl::opt<bool> GenerateSoftFloatCalls("soft-float", cl::desc("Generate software floating point library calls"), cl::init(false)); @@ -209,82 +229,46 @@ static void do_shutdown() { #endif } -void layoutRemoteTargetMemory(RemoteTarget *T, RecordingMemoryManager *JMM) { - // Lay out our sections in order, with all the code sections first, then - // all the data sections. - uint64_t CurOffset = 0; - unsigned MaxAlign = T->getPageAlignment(); - SmallVector<std::pair<const void*, uint64_t>, 16> Offsets; - SmallVector<unsigned, 16> Sizes; - for (RecordingMemoryManager::const_code_iterator I = JMM->code_begin(), - E = JMM->code_end(); - I != E; ++I) { - DEBUG(dbgs() << "code region: size " << I->first.size() - << ", alignment " << I->second << "\n"); - // Align the current offset up to whatever is needed for the next - // section. - unsigned Align = I->second; - CurOffset = (CurOffset + Align - 1) / Align * Align; - // Save off the address of the new section and allocate its space. - Offsets.push_back(std::pair<const void*,uint64_t>(I->first.base(), CurOffset)); - Sizes.push_back(I->first.size()); - CurOffset += I->first.size(); - } - // Adjust to keep code and data aligned on seperate pages. - CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign; - unsigned FirstDataIndex = Offsets.size(); - for (RecordingMemoryManager::const_data_iterator I = JMM->data_begin(), - E = JMM->data_end(); - I != E; ++I) { - DEBUG(dbgs() << "data region: size " << I->first.size() - << ", alignment " << I->second << "\n"); - // Align the current offset up to whatever is needed for the next - // section. - unsigned Align = I->second; - CurOffset = (CurOffset + Align - 1) / Align * Align; - // Save off the address of the new section and allocate its space. - Offsets.push_back(std::pair<const void*,uint64_t>(I->first.base(), CurOffset)); - Sizes.push_back(I->first.size()); - CurOffset += I->first.size(); - } - - // Allocate space in the remote target. - uint64_t RemoteAddr; - if (T->allocateSpace(CurOffset, MaxAlign, RemoteAddr)) - report_fatal_error(T->getErrorMsg()); - // Map the section addresses so relocations will get updated in the local - // copies of the sections. - for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { - uint64_t Addr = RemoteAddr + Offsets[i].second; - EE->mapSectionAddress(const_cast<void*>(Offsets[i].first), Addr); - - DEBUG(dbgs() << " Mapping local: " << Offsets[i].first - << " to remote: " << format("%p", Addr) << "\n"); - - } - - // Trigger application of relocations - EE->finalizeObject(); - - // Now load it all to the target. - for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { - uint64_t Addr = RemoteAddr + Offsets[i].second; - - if (i < FirstDataIndex) { - T->loadCode(Addr, Offsets[i].first, Sizes[i]); - - DEBUG(dbgs() << " loading code: " << Offsets[i].first - << " to remote: " << format("%p", Addr) << "\n"); - } else { - T->loadData(Addr, Offsets[i].first, Sizes[i]); - - DEBUG(dbgs() << " loading data: " << Offsets[i].first - << " to remote: " << format("%p", Addr) << "\n"); - } - +// On Mingw and Cygwin, an external symbol named '__main' is called from the +// generated 'main' function to allow static intialization. To avoid linking +// problems with remote targets (because lli's remote target support does not +// currently handle external linking) we add a secondary module which defines +// an empty '__main' function. +static void addCygMingExtraModule(ExecutionEngine *EE, + LLVMContext &Context, + StringRef TargetTripleStr) { + IRBuilder<> Builder(Context); + Triple TargetTriple(TargetTripleStr); + + // Create a new module. + Module *M = new Module("CygMingHelper", Context); + M->setTargetTriple(TargetTripleStr); + + // Create an empty function named "__main". + Function *Result; + if (TargetTriple.isArch64Bit()) { + Result = Function::Create( + TypeBuilder<int64_t(void), false>::get(Context), + GlobalValue::ExternalLinkage, "__main", M); + } else { + Result = Function::Create( + TypeBuilder<int32_t(void), false>::get(Context), + GlobalValue::ExternalLinkage, "__main", M); } + BasicBlock *BB = BasicBlock::Create(Context, "__main", Result); + Builder.SetInsertPoint(BB); + Value *ReturnVal; + if (TargetTriple.isArch64Bit()) + ReturnVal = ConstantInt::get(Context, APInt(64, 0)); + else + ReturnVal = ConstantInt::get(Context, APInt(32, 0)); + Builder.CreateRet(ReturnVal); + + // Add this new module to the ExecutionEngine. + EE->addModule(M); } + //===----------------------------------------------------------------------===// // main Driver function // @@ -326,6 +310,17 @@ int main(int argc, char **argv, char * const *envp) { } } + if (DebugIR) { + if (!UseMCJIT) { + errs() << "warning: -debug-ir used without -use-mcjit. Only partial debug" + << " information will be emitted by the non-MC JIT engine. To see full" + << " source debug information, enable the flag '-use-mcjit'.\n"; + + } + ModulePass *DebugIRPass = createDebugIRPass(); + DebugIRPass->runOnModule(*Mod); + } + EngineBuilder builder(Mod); builder.setMArch(MArch); builder.setMCPU(MCPU); @@ -342,14 +337,14 @@ int main(int argc, char **argv, char * const *envp) { Mod->setTargetTriple(Triple::normalize(TargetTriple)); // Enable MCJIT if desired. - JITMemoryManager *JMM = 0; + RTDyldMemoryManager *RTDyldMM = 0; if (UseMCJIT && !ForceInterpreter) { builder.setUseMCJIT(true); if (RemoteMCJIT) - JMM = new RecordingMemoryManager(); + RTDyldMM = new RemoteMemoryManager(); else - JMM = new SectionMemoryManager(); - builder.setJITMemoryManager(JMM); + RTDyldMM = new SectionMemoryManager(); + builder.setMCJITMemoryManager(RTDyldMM); } else { if (RemoteMCJIT) { errs() << "error: Remote process execution requires -use-mcjit\n"; @@ -381,7 +376,6 @@ int main(int argc, char **argv, char * const *envp) { // Remote target execution doesn't handle EH or debug registration. if (!RemoteMCJIT) { - Options.JITExceptionHandling = EnableJITExceptionHandling; Options.JITEmitDebugInfo = EmitJitDebugInfo; Options.JITEmitDebugInfoToDisk = EmitJitDebugInfoToDisk; } @@ -397,6 +391,22 @@ int main(int argc, char **argv, char * const *envp) { exit(1); } + // Load any additional modules specified on the command line. + for (unsigned i = 0, e = ExtraModules.size(); i != e; ++i) { + Module *XMod = ParseIRFile(ExtraModules[i], Err, Context); + if (!XMod) { + Err.print(argv[0], errs()); + return 1; + } + EE->addModule(XMod); + } + + // If the target is Cygwin/MingW and we are generating remote code, we + // need an extra module to help out with linking. + if (RemoteMCJIT && Triple(Mod->getTargetTriple()).isOSCygMing()) { + addCygMingExtraModule(EE, Context, Mod->getTargetTriple()); + } + // The following functions have no effect if their respective profiling // support wasn't enabled in the build configuration. EE->RegisterJITEventListener( @@ -435,82 +445,43 @@ int main(int argc, char **argv, char * const *envp) { return -1; } - // If the program doesn't explicitly call exit, we will need the Exit - // function later on to make an explicit call, so get the function now. - Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context), - Type::getInt32Ty(Context), - NULL); - // Reset errno to zero on entry to main. errno = 0; - // Remote target MCJIT doesn't (yet) support static constructors. No reason - // it couldn't. This is a limitation of the LLI implemantation, not the - // MCJIT itself. FIXME. - // - // Run static constructors. - if (!RemoteMCJIT) { - if (UseMCJIT && !ForceInterpreter) { - // Give MCJIT a chance to apply relocations and set page permissions. - EE->finalizeObject(); - } - EE->runStaticConstructorsDestructors(false); - } - - if (NoLazyCompilation) { - for (Module::iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) { - Function *Fn = &*I; - if (Fn != EntryFn && !Fn->isDeclaration()) - EE->getPointerToFunction(Fn); - } - } - int Result; - if (RemoteMCJIT) { - RecordingMemoryManager *MM = static_cast<RecordingMemoryManager*>(JMM); - // 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(); - - // Ask for a pointer to the entry function. This triggers the actual - // compilation. - (void)EE->getPointerToFunction(EntryFn); - // Enough has been compiled to execute the entry function now, so - // layout the target memory. - layoutRemoteTargetMemory(&Target, 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); - - DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at " - << format("%p", Entry) << "\n"); + if (!RemoteMCJIT) { + // If the program doesn't explicitly call exit, we will need the Exit + // function later on to make an explicit call, so get the function now. + Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context), + Type::getInt32Ty(Context), + NULL); + + // Run static constructors. + if (UseMCJIT && !ForceInterpreter) { + // Give MCJIT a chance to apply relocations and set page permissions. + EE->finalizeObject(); + } + EE->runStaticConstructorsDestructors(false); - if (Target.executeCode(Entry, Result)) - errs() << "ERROR: " << Target.getErrorMsg() << "\n"; + if (!UseMCJIT && NoLazyCompilation) { + for (Module::iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) { + Function *Fn = &*I; + if (Fn != EntryFn && !Fn->isDeclaration()) + EE->getPointerToFunction(Fn); + } + } - Target.stop(); - } else { // Trigger compilation separately so code regions that need to be // invalidated will be known. (void)EE->getPointerToFunction(EntryFn); // Clear instruction cache before code will be executed. - if (JMM) - static_cast<SectionMemoryManager*>(JMM)->invalidateInstructionCache(); + if (RTDyldMM) + static_cast<SectionMemoryManager*>(RTDyldMM)->invalidateInstructionCache(); // Run main. Result = EE->runFunctionAsMain(EntryFn, InputArgv, envp); - } - // Like static constructors, the remote target MCJIT support doesn't handle - // this yet. It could. FIXME. - if (!RemoteMCJIT) { // Run static destructors. EE->runStaticConstructorsDestructors(true); @@ -528,6 +499,67 @@ int main(int argc, char **argv, char * const *envp) { errs() << "ERROR: exit defined with wrong prototype!\n"; abort(); } + } else { + // else == "if (RemoteMCJIT)" + + // Remote target MCJIT doesn't (yet) support static constructors. No reason + // it couldn't. This is a limitation of the LLI implemantation, not the + // MCJIT itself. FIXME. + // + RemoteMemoryManager *MM = static_cast<RemoteMemoryManager*>(RTDyldMM); + // 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. + + 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(ChildEXE)); + } + } else { + // No child process name provided, use simulated remote execution. + Target.reset(RemoteTarget::createRemoteTarget()); + } + + // Give the memory manager a pointer to our remote target interface object. + MM->setRemoteTarget(Target.get()); + + // Create the remote target. + Target->create(); + + // 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. + // + // Our memory manager will map generated code into the remote address + // space as it is loaded and copy the bits over during the finalizeMemory + // operation. + // + // FIXME: argv and envp handling. + 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"; + + // Like static constructors, the remote target MCJIT support doesn't handle + // this yet. It could. FIXME. + + // Stop the remote target + Target->stop(); } + return Result; } |