• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CodeMemoryManager()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 
~CodeMemoryManager()62 CodeMemoryManager::~CodeMemoryManager() {
63   mpCodeMem = 0;
64   mpGVMem = 0;
65 }
66 
67 
allocateSGMemory(uintptr_t Size,unsigned Alignment)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.
setMemoryWritable()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.
setMemoryExecutable()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.
setPoisonMemory(bool poison)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.
AllocateGOT()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.
startFunctionBody(const llvm::Function * F,uintptr_t & ActualSize)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.
endFunctionBody(const llvm::Function * F,uint8_t * FunctionStart,uint8_t * FunctionEnd)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.
allocateSpace(intptr_t Size,unsigned Alignment)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.
allocateGlobal(uintptr_t Size,unsigned Alignment)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.
deallocateFunctionBody(void * Body)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
reset()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