X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FExecutionEngine%2FJIT%2FJITEmitter.cpp;h=6dd2d56f7f2044a490baca5c3c5f8e62213a3c62;hb=e738656c0b380e5059cb522927aeb49554d01e46;hp=242576604a9e7fa13f44faeb7e45e945701d1b82;hpb=1d4408506b5704a64ad76a295ee8f7b94b79ffd0;p=oota-llvm.git diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index 242576604a9..6dd2d56f7f2 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -5,20 +5,122 @@ // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "jit" +#ifndef _POSIX_MAPPED_FILES +#define _POSIX_MAPPED_FILES +#endif #include "VM.h" #include "llvm/CodeGen/MachineCodeEmitter.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/Target/TargetData.h" -#include "llvm/Function.h" +#include "llvm/Module.h" +#include "Support/Debug.h" #include "Support/Statistic.h" - -static VM *TheVM = 0; +#include "Config/unistd.h" +#include "Config/sys/mman.h" namespace { - Statistic<> NumBytes("jello", "Number of bytes of machine code compiled"); + Statistic<> NumBytes("jit", "Number of bytes of machine code compiled"); + VM *TheVM = 0; + + /// JITMemoryManager - Manage memory for the JIT code generation in a logical, + /// sane way. This splits a large block of MAP_NORESERVE'd memory into two + /// sections, one for function stubs, one for the functions themselves. We + /// have to do this because we may need to emit a function stub while in the + /// middle of emitting a function, and we don't know how large the function we + /// are emitting is. This never bothers to release the memory, because when + /// we are ready to destroy the JIT, the program exits. + class JITMemoryManager { + unsigned char *MemBase; // Base of block of memory, start of stub mem + unsigned char *FunctionBase; // Start of the function body area + unsigned char *CurStubPtr, *CurFunctionPtr; + public: + JITMemoryManager(); + + inline unsigned char *allocateStub(unsigned StubSize); + inline unsigned char *startFunctionBody(); + inline void endFunctionBody(unsigned char *FunctionEnd); + }; +} + +// getMemory - Return a pointer to the specified number of bytes, which is +// mapped as executable readable and writable. +static void *getMemory(unsigned NumBytes) { + if (NumBytes == 0) return 0; + static const long pageSize = sysconf(_SC_PAGESIZE); + unsigned NumPages = (NumBytes+pageSize-1)/pageSize; + +#if defined(i386) || defined(__i386__) || defined(__x86__) + /* Linux and *BSD tend to have these flags named differently. */ +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) +# define MAP_ANONYMOUS MAP_ANON +#endif /* defined(MAP_ANON) && !defined(MAP_ANONYMOUS) */ +#elif defined(sparc) || defined(__sparc__) || defined(__sparcv9) +/* nothing */ +#else + std::cerr << "This architecture is not supported by the JIT!\n"; + abort(); +#endif + +#if defined(__linux__) +#define fd 0 +#else +#define fd -1 +#endif + + unsigned mmapFlags = MAP_PRIVATE|MAP_ANONYMOUS; +#ifdef MAP_NORESERVE + mmapFlags |= MAP_NORESERVE; +#endif + + void *pa = mmap(0, pageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC, + mmapFlags, fd, 0); + if (pa == MAP_FAILED) { + perror("mmap"); + abort(); + } + return pa; +} + +JITMemoryManager::JITMemoryManager() { + // Allocate a 16M block of memory... + MemBase = (unsigned char*)getMemory(16 << 20); + FunctionBase = MemBase + 512*1024; // Use 512k for stubs + + // Allocate stubs backwards from the function base, allocate functions forward + // from the function base. + CurStubPtr = CurFunctionPtr = FunctionBase; +} +unsigned char *JITMemoryManager::allocateStub(unsigned StubSize) { + CurStubPtr -= StubSize; + if (CurStubPtr < MemBase) { + std::cerr << "JIT ran out of memory for function stubs!\n"; + abort(); + } + return CurStubPtr; +} + +unsigned char *JITMemoryManager::startFunctionBody() { + // Round up to an even multiple of 4 bytes, this should eventually be target + // specific. + return (unsigned char*)(((intptr_t)CurFunctionPtr + 3) & ~3); +} + +void JITMemoryManager::endFunctionBody(unsigned char *FunctionEnd) { + assert(FunctionEnd > CurFunctionPtr); + CurFunctionPtr = FunctionEnd; +} + + + +namespace { + /// Emitter - The JIT implementation of the MachineCodeEmitter, which is used + /// to output functions to memory for execution. class Emitter : public MachineCodeEmitter { + JITMemoryManager MemMgr; + // CurBlock - The start of the current block of memory. CurByte - The // current byte being emitted to. unsigned char *CurBlock, *CurByte; @@ -59,51 +161,17 @@ MachineCodeEmitter *VM::createEmitter(VM &V) { return new Emitter(V); } - -#define _POSIX_MAPPED_FILES -#include -#include - -// FIXME: This should be rewritten to support a real memory manager for -// executable memory pages! -static void *getMemory(unsigned NumPages) { - void *pa; - if (NumPages == 0) return 0; - static const long pageSize = sysconf(_SC_PAGESIZE); - -#if defined(i386) || defined(__i386__) || defined(__x86__) - pa = mmap(0, pageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); /* fd = 0 */ -#elif defined(sparc) || defined(__sparc__) || defined(__sparcv9) - static unsigned long Counter = 0; - pa = mmap((void*)(0x140000000UL+Counter), pageSize*NumPages, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0); /* fd = -1 */ - Counter += pageSize*NumPages; -#else - std::cerr << "This architecture is not supported by the JIT\n"; - abort(); -#endif - - if (pa == MAP_FAILED) { - perror("mmap"); - abort(); - } - return pa; -} - - void Emitter::startFunction(MachineFunction &F) { - CurBlock = (unsigned char *)getMemory(16); - CurByte = CurBlock; // Start writing at the beginning of the fn. + CurByte = CurBlock = MemMgr.startFunctionBody(); TheVM->addGlobalMapping(F.getFunction(), CurBlock); } void Emitter::finishFunction(MachineFunction &F) { + MemMgr.endFunctionBody(CurByte); ConstantPoolAddresses.clear(); NumBytes += CurByte-CurBlock; - DEBUG(std::cerr << "Finished CodeGen of [0x" << (void*)CurBlock + DEBUG(std::cerr << "Finished CodeGen of [" << (void*)CurBlock << "] Function: " << F.getFunction()->getName() << ": " << CurByte-CurBlock << " bytes of text\n"); } @@ -121,11 +189,8 @@ void Emitter::emitConstantPool(MachineConstantPool *MCP) { } void Emitter::startFunctionStub(const Function &F, unsigned StubSize) { - static const long pageSize = sysconf(_SC_PAGESIZE); SavedCurBlock = CurBlock; SavedCurByte = CurByte; - // FIXME: this is a huge waste of memory. - CurBlock = (unsigned char *)getMemory((StubSize+pageSize-1)/pageSize); - CurByte = CurBlock; // Start writing at the beginning of the fn. + CurByte = CurBlock = MemMgr.allocateStub(StubSize); } void *Emitter::finishFunctionStub(const Function &F) { @@ -144,13 +209,12 @@ void Emitter::emitByte(unsigned char B) { } void Emitter::emitWord(unsigned W) { - // FIXME: This won't work if the endianness of the host and target don't - // agree! (For a JIT this can't happen though. :) + // This won't work if the endianness of the host and target don't agree! (For + // a JIT this can't happen though. :) *(unsigned*)CurByte = W; CurByte += sizeof(unsigned); } - uint64_t Emitter::getGlobalValueAddress(GlobalValue *V) { // Try looking up the function to see if it is already compiled, if not return // 0. @@ -181,3 +245,16 @@ uint64_t Emitter::forceCompilationOf(Function *F) { return (intptr_t)TheVM->getPointerToFunction(F); } +// getPointerToNamedFunction - This function is used as a global wrapper to +// VM::getPointerToNamedFunction for the purpose of resolving symbols when +// bugpoint is debugging the JIT. In that scenario, we are loading an .so and +// need to resolve function(s) that are being mis-codegenerated, so we need to +// resolve their addresses at runtime, and this is the way to do it. +extern "C" { + void *getPointerToNamedFunction(const char *Name) { + Module &M = TheVM->getModule(); + if (Function *F = M.getNamedFunction(Name)) + return TheVM->getPointerToFunction(F); + return TheVM->getPointerToNamedFunction(Name); + } +}