Home | History | Annotate | Download | only in CodeGen
      1 //===-- CodeMemoryManager.h - CodeMemoryManager Class -----------*- C++ -*-===//
      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 #ifndef BCC_CODEMEMORYMANAGER_H
     15 #define BCC_CODEMEMORYMANAGER_H
     16 
     17 #include "ExecutionEngine/Compiler.h"
     18 
     19 #include "llvm/ExecutionEngine/JITMemoryManager.h"
     20 
     21 #include <bcc/bcc_assert.h>
     22 
     23 #include <map>
     24 #include <utility>
     25 
     26 #include <stddef.h>
     27 #include <stdint.h>
     28 
     29 
     30 namespace llvm {
     31   // Forward Declaration
     32   class Function;
     33   class GlobalValue;
     34 };
     35 
     36 
     37 namespace bcc {
     38 
     39   //////////////////////////////////////////////////////////////////////////////
     40   // Memory manager for the code reside in memory
     41   //
     42   // The memory for our code emitter is very simple and is conforming to the
     43   // design decisions of Android RenderScript's Exection Environment:
     44   //   The code, data, and symbol sizes are limited (currently 100KB.)
     45   //
     46   // It's very different from typical compiler, which has no limitation
     47   // on the code size. How does code emitter know the size of the code
     48   // it is about to emit? It does not know beforehand. We want to solve
     49   // this without complicating the code emitter too much.
     50   //
     51   // We solve this by pre-allocating a certain amount of memory,
     52   // and then start the code emission. Once the buffer overflows, the emitter
     53   // simply discards all the subsequent emission but still has a counter
     54   // on how many bytes have been emitted.
     55   //
     56   // So once the whole emission is done, if there's a buffer overflow,
     57   // it re-allocates the buffer with enough size (based on the
     58   //  counter from previous emission) and re-emit again.
     59 
     60   extern const unsigned int MaxCodeSize;
     61   extern const unsigned int MaxGOTSize;
     62   extern const unsigned int MaxGlobalVarSize;
     63 
     64 
     65   class CodeMemoryManager : public llvm::JITMemoryManager {
     66   private:
     67     typedef std::map<const llvm::Function*,
     68                      std::pair<void * /* start address */,
     69                                void * /* end address */> > FunctionMapTy;
     70 
     71 
     72   private:
     73     //
     74     // Our memory layout is as follows:
     75     //
     76     //  The direction of arrows (-> and <-) shows memory's growth direction
     77     //  when more space is needed.
     78     //
     79     // @mpCodeMem:
     80     //  +--------------------------------------------------------------+
     81     //  | Function Memory ... ->                <- ...        Stub/GOT |
     82     //  +--------------------------------------------------------------+
     83     //  |<------------------ Total: @MaxCodeSize KiB ----------------->|
     84     //
     85     //  Where size of GOT is @MaxGOTSize KiB.
     86     //
     87     // @mpGVMem:
     88     //  +--------------------------------------------------------------+
     89     //  | Global variable ... ->                                       |
     90     //  +--------------------------------------------------------------+
     91     //  |<--------------- Total: @MaxGlobalVarSize KiB --------------->|
     92     //
     93     //
     94     // @mCurFuncMemIdx: The current index (starting from 0) of the last byte
     95     //                    of function code's memory usage
     96     // @mCurSGMemIdx: The current index (starting from tail) of the last byte
     97     //                    of stub/GOT's memory usage
     98     // @mCurGVMemIdx: The current index (starting from tail) of the last byte
     99     //                    of global variable's memory usage
    100     //
    101     uintptr_t mCurFuncMemIdx;
    102     uintptr_t mCurSGMemIdx;
    103     uintptr_t mCurGVMemIdx;
    104     char *mpCodeMem;
    105     char *mpGVMem;
    106 
    107     // GOT Base
    108     uint8_t *mpGOTBase;
    109 
    110     FunctionMapTy mFunctionMap;
    111 
    112 
    113   public:
    114     CodeMemoryManager();
    115 
    116     virtual ~CodeMemoryManager();
    117 
    118     uint8_t *getCodeMemBase() const {
    119       return reinterpret_cast<uint8_t*>(mpCodeMem);
    120     }
    121 
    122     // setMemoryWritable - When code generation is in progress, the code pages
    123     //                     may need permissions changed.
    124     virtual void setMemoryWritable();
    125 
    126     // When code generation is done and we're ready to start execution, the
    127     // code pages may need permissions changed.
    128     virtual void setMemoryExecutable();
    129 
    130     // Setting this flag to true makes the memory manager garbage values over
    131     // freed memory.  This is useful for testing and debugging, and is to be
    132     // turned on by default in debug mode.
    133     virtual void setPoisonMemory(bool poison);
    134 
    135 
    136     // Global Offset Table Management
    137 
    138     // If the current table requires a Global Offset Table, this method is
    139     // invoked to allocate it.  This method is required to set HasGOT to true.
    140     virtual void AllocateGOT();
    141 
    142     // If this is managing a Global Offset Table, this method should return a
    143     // pointer to its base.
    144     virtual uint8_t *getGOTBase() const {
    145       return mpGOTBase;
    146     }
    147 
    148     // Main Allocation Functions
    149 
    150     // When we start JITing a function, the JIT calls this method to allocate a
    151     // block of free RWX memory, which returns a pointer to it. If the JIT wants
    152     // to request a block of memory of at least a certain size, it passes that
    153     // value as ActualSize, and this method returns a block with at least that
    154     // much space. If the JIT doesn't know ahead of time how much space it will
    155     // need to emit the function, it passes 0 for the ActualSize. In either
    156     // case, this method is required to pass back the size of the allocated
    157     // block through ActualSize. The JIT will be careful to not write more than
    158     // the returned ActualSize bytes of memory.
    159     virtual uint8_t *startFunctionBody(const llvm::Function *F,
    160                                        uintptr_t &ActualSize);
    161 
    162     // This method is called by the JIT to allocate space for a function stub
    163     // (used to handle limited branch displacements) while it is JIT compiling a
    164     // function. For example, if foo calls bar, and if bar either needs to be
    165     // lazily compiled or is a native function that exists too far away from the
    166     // call site to work, this method will be used to make a thunk for it. The
    167     // stub should be "close" to the current function body, but should not be
    168     // included in the 'actualsize' returned by startFunctionBody.
    169     virtual uint8_t *allocateStub(const llvm::GlobalValue *F,
    170                                   unsigned StubSize,
    171                                   unsigned Alignment) {
    172       return allocateSGMemory(StubSize, Alignment);
    173     }
    174 
    175     // This method is called when the JIT is done codegen'ing the specified
    176     // function. At this point we know the size of the JIT compiled function.
    177     // This passes in FunctionStart (which was returned by the startFunctionBody
    178     // method) and FunctionEnd which is a pointer to the actual end of the
    179     // function. This method should mark the space allocated and remember where
    180     // it is in case the client wants to deallocate it.
    181     virtual void endFunctionBody(const llvm::Function *F,
    182                                  uint8_t *FunctionStart,
    183                                  uint8_t *FunctionEnd);
    184 
    185     // Allocate a (function code) memory block of the given size. This method
    186     // cannot be called between calls to startFunctionBody and endFunctionBody.
    187     virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment);
    188 
    189     // Allocate memory for a global variable.
    190     virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment);
    191 
    192     // Free the specified function body. The argument must be the return value
    193     // from a call to startFunctionBody() that hasn't been deallocated yet. This
    194     // is never called when the JIT is currently emitting a function.
    195     virtual void deallocateFunctionBody(void *Body);
    196 
    197     // When we finished JITing the function, if exception handling is set, we
    198     // emit the exception table.
    199     virtual uint8_t *startExceptionTable(const llvm::Function *F,
    200                                          uintptr_t &ActualSize) {
    201       bccAssert(false &&
    202                 "Exception is not allowed in our language specification");
    203       return NULL;
    204     }
    205 
    206     // This method is called when the JIT is done emitting the exception table.
    207     virtual void endExceptionTable(const llvm::Function *F, uint8_t *TableStart,
    208                                    uint8_t *TableEnd, uint8_t *FrameRegister) {
    209       bccAssert(false &&
    210                 "Exception is not allowed in our language specification");
    211     }
    212 
    213     // Free the specified exception table's memory. The argument must be the
    214     // return value from a call to startExceptionTable() that hasn't been
    215     // deallocated yet. This is never called when the JIT is currently emitting
    216     // an exception table.
    217     virtual void deallocateExceptionTable(void *ET) {
    218       bccAssert(false &&
    219                 "Exception is not allowed in our language specification");
    220     }
    221 
    222     // Below are the methods we create
    223     void reset();
    224 
    225 
    226   private:
    227     intptr_t getFreeCodeMemSize() const {
    228       return mCurSGMemIdx - mCurFuncMemIdx;
    229     }
    230 
    231     uint8_t *allocateSGMemory(uintptr_t Size,
    232                               unsigned Alignment = 1 /* no alignment */);
    233 
    234     uintptr_t getFreeGVMemSize() const {
    235       return MaxGlobalVarSize - mCurGVMemIdx;
    236     }
    237 
    238     uint8_t *getGVMemBase() const {
    239       return reinterpret_cast<uint8_t*>(mpGVMem);
    240     }
    241 
    242   };
    243 
    244 } // namespace bcc
    245 
    246 #endif  // BCC_CODEMEMORYMANAGER_H
    247