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