Home | History | Annotate | Download | only in CodeGen
      1 //===-- CodeMemoryManager.cpp - CodeMemoryManager Class -------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See external/llvm/LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 //  This file defines the CodeMemoryManager class.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #define LOG_TAG "bcc"
     15 #include <bcc/bcc_assert.h>
     16 
     17 #include <cutils/log.h>
     18 
     19 #include "CodeMemoryManager.h"
     20 #include "ExecutionEngine/OldJIT/ContextManager.h"
     21 
     22 #include "llvm/Support/ErrorHandling.h"
     23 
     24 #include <sys/mman.h>
     25 
     26 #include <stddef.h>
     27 
     28 #include <map>
     29 #include <string>
     30 #include <utility>
     31 
     32 
     33 namespace bcc {
     34 
     35 
     36 const unsigned int MaxCodeSize = ContextManager::ContextCodeSize;
     37 const unsigned int MaxGOTSize = 1 * 1024;
     38 const unsigned int MaxGlobalVarSize = ContextManager::ContextDataSize;
     39 
     40 
     41 CodeMemoryManager::CodeMemoryManager()
     42   : mpCodeMem(NULL), mpGVMem(NULL), mpGOTBase(NULL) {
     43 
     44   reset();
     45   std::string ErrMsg;
     46 
     47   mpCodeMem = ContextManager::get().allocateContext();
     48 
     49   if (!mpCodeMem) {
     50     LOGE("Unable to allocate mpCodeMem\n");
     51     llvm::report_fatal_error("Failed to allocate memory for emitting "
     52                              "codes\n" + ErrMsg);
     53   }
     54 
     55   // Set global variable pool
     56   mpGVMem = mpCodeMem + MaxCodeSize;
     57 
     58   return;
     59 }
     60 
     61 
     62 CodeMemoryManager::~CodeMemoryManager() {
     63   mpCodeMem = 0;
     64   mpGVMem = 0;
     65 }
     66 
     67 
     68 uint8_t *CodeMemoryManager::allocateSGMemory(uintptr_t Size,
     69                                              unsigned Alignment) {
     70 
     71   intptr_t FreeMemSize = getFreeCodeMemSize();
     72   if ((FreeMemSize < 0) || (static_cast<uintptr_t>(FreeMemSize) < Size))
     73     // The code size excesses our limit
     74     return NULL;
     75 
     76   if (Alignment == 0)
     77     Alignment = 1;
     78 
     79   uint8_t *result = getCodeMemBase() + mCurSGMemIdx - Size;
     80   result = (uint8_t*) (((intptr_t) result) & ~(intptr_t) (Alignment - 1));
     81 
     82   mCurSGMemIdx = result - getCodeMemBase();
     83 
     84   return result;
     85 }
     86 
     87 
     88 // setMemoryWritable - When code generation is in progress, the code pages
     89 //                     may need permissions changed.
     90 void CodeMemoryManager::setMemoryWritable() {
     91   mprotect(mpCodeMem, MaxCodeSize, PROT_READ | PROT_WRITE | PROT_EXEC);
     92 }
     93 
     94 
     95 // When code generation is done and we're ready to start execution, the
     96 // code pages may need permissions changed.
     97 void CodeMemoryManager::setMemoryExecutable() {
     98   mprotect(mpCodeMem, MaxCodeSize, PROT_READ | PROT_EXEC);
     99 }
    100 
    101 
    102 // Setting this flag to true makes the memory manager garbage values over
    103 // freed memory.  This is useful for testing and debugging, and is to be
    104 // turned on by default in debug mode.
    105 void CodeMemoryManager::setPoisonMemory(bool poison) {
    106   // no effect
    107 }
    108 
    109 
    110 // Global Offset Table Management
    111 
    112 // If the current table requires a Global Offset Table, this method is
    113 // invoked to allocate it.  This method is required to set HasGOT to true.
    114 void CodeMemoryManager::AllocateGOT() {
    115   bccAssert(mpGOTBase != NULL && "Cannot allocate the GOT multiple times");
    116   mpGOTBase = allocateSGMemory(MaxGOTSize);
    117   HasGOT = true;
    118 }
    119 
    120 
    121 // Main Allocation Functions
    122 
    123 // When we start JITing a function, the JIT calls this method to allocate a
    124 // block of free RWX memory, which returns a pointer to it. If the JIT wants
    125 // to request a block of memory of at least a certain size, it passes that
    126 // value as ActualSize, and this method returns a block with at least that
    127 // much space. If the JIT doesn't know ahead of time how much space it will
    128 // need to emit the function, it passes 0 for the ActualSize. In either
    129 // case, this method is required to pass back the size of the allocated
    130 // block through ActualSize. The JIT will be careful to not write more than
    131 // the returned ActualSize bytes of memory.
    132 uint8_t *CodeMemoryManager::startFunctionBody(const llvm::Function *F,
    133                                               uintptr_t &ActualSize) {
    134   intptr_t FreeMemSize = getFreeCodeMemSize();
    135   if ((FreeMemSize < 0) ||
    136       (static_cast<uintptr_t>(FreeMemSize) < ActualSize))
    137     // The code size excesses our limit
    138     return NULL;
    139 
    140   ActualSize = getFreeCodeMemSize();
    141   return (getCodeMemBase() + mCurFuncMemIdx);
    142 }
    143 
    144 // This method is called when the JIT is done codegen'ing the specified
    145 // function. At this point we know the size of the JIT compiled function.
    146 // This passes in FunctionStart (which was returned by the startFunctionBody
    147 // method) and FunctionEnd which is a pointer to the actual end of the
    148 // function. This method should mark the space allocated and remember where
    149 // it is in case the client wants to deallocate it.
    150 void CodeMemoryManager::endFunctionBody(const llvm::Function *F,
    151                                         uint8_t *FunctionStart,
    152                                         uint8_t *FunctionEnd) {
    153   bccAssert(FunctionEnd > FunctionStart);
    154   bccAssert(FunctionStart == (getCodeMemBase() + mCurFuncMemIdx) &&
    155             "Mismatched function start/end!");
    156 
    157   // Advance the pointer
    158   intptr_t FunctionCodeSize = FunctionEnd - FunctionStart;
    159   bccAssert(FunctionCodeSize <= getFreeCodeMemSize() &&
    160             "Code size excess the limitation!");
    161   mCurFuncMemIdx += FunctionCodeSize;
    162 
    163   // Record there's a function in our memory start from @FunctionStart
    164   bccAssert(mFunctionMap.find(F) == mFunctionMap.end() &&
    165             "Function already emitted!");
    166   mFunctionMap.insert(
    167       std::make_pair<const llvm::Function*, std::pair<void*, void*> >(
    168           F, std::make_pair(FunctionStart, FunctionEnd)));
    169 
    170   return;
    171 }
    172 
    173 // Allocate a (function code) memory block of the given size. This method
    174 // cannot be called between calls to startFunctionBody and endFunctionBody.
    175 uint8_t *CodeMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) {
    176   if (getFreeCodeMemSize() < Size) {
    177     // The code size excesses our limit
    178     return NULL;
    179   }
    180 
    181   if (Alignment == 0)
    182     Alignment = 1;
    183 
    184   uint8_t *result = getCodeMemBase() + mCurFuncMemIdx;
    185   result = (uint8_t*) (((intptr_t) result + Alignment - 1) &
    186                        ~(intptr_t) (Alignment - 1));
    187 
    188   mCurFuncMemIdx = (result + Size) - getCodeMemBase();
    189 
    190   return result;
    191 }
    192 
    193 // Allocate memory for a global variable.
    194 uint8_t *CodeMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) {
    195   if (getFreeGVMemSize() < Size) {
    196     // The code size excesses our limit
    197     LOGE("No Global Memory");
    198     return NULL;
    199   }
    200 
    201   if (Alignment == 0)
    202     Alignment = 1;
    203 
    204   uint8_t *result = getGVMemBase() + mCurGVMemIdx;
    205   result = (uint8_t*) (((intptr_t) result + Alignment - 1) &
    206                        ~(intptr_t) (Alignment - 1));
    207 
    208   mCurGVMemIdx = (result + Size) - getGVMemBase();
    209 
    210   return result;
    211 }
    212 
    213 // Free the specified function body. The argument must be the return value
    214 // from a call to startFunctionBody() that hasn't been deallocated yet. This
    215 // is never called when the JIT is currently emitting a function.
    216 void CodeMemoryManager::deallocateFunctionBody(void *Body) {
    217   // linear search
    218   uint8_t *FunctionStart = NULL, *FunctionEnd = NULL;
    219   for (FunctionMapTy::iterator I = mFunctionMap.begin(),
    220           E = mFunctionMap.end(); I != E; I++) {
    221     if (I->second.first == Body) {
    222       FunctionStart = reinterpret_cast<uint8_t*>(I->second.first);
    223       FunctionEnd = reinterpret_cast<uint8_t*>(I->second.second);
    224       break;
    225     }
    226   }
    227 
    228   bccAssert((FunctionStart == NULL) && "Memory is never allocated!");
    229 
    230   // free the memory
    231   intptr_t SizeNeedMove = (getCodeMemBase() + mCurFuncMemIdx) - FunctionEnd;
    232 
    233   bccAssert(SizeNeedMove >= 0 &&
    234             "Internal error: CodeMemoryManager::mCurFuncMemIdx may not"
    235             " be correctly calculated!");
    236 
    237   if (SizeNeedMove > 0) {
    238     // there's data behind deallocating function
    239     memmove(FunctionStart, FunctionEnd, SizeNeedMove);
    240   }
    241 
    242   mCurFuncMemIdx -= (FunctionEnd - FunctionStart);
    243 }
    244 
    245 // Below are the methods we create
    246 void CodeMemoryManager::reset() {
    247   mpGOTBase = NULL;
    248   HasGOT = false;
    249 
    250   mCurFuncMemIdx = 0;
    251   mCurSGMemIdx = MaxCodeSize - 1;
    252   mCurGVMemIdx = 0;
    253 
    254   mFunctionMap.clear();
    255 }
    256 
    257 } // namespace bcc
    258