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
33namespace bcc {
34
35
36const unsigned int MaxCodeSize = ContextManager::ContextCodeSize;
37const unsigned int MaxGOTSize = 1 * 1024;
38const unsigned int MaxGlobalVarSize = ContextManager::ContextDataSize;
39
40
41CodeMemoryManager::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
62CodeMemoryManager::~CodeMemoryManager() {
63  mpCodeMem = 0;
64  mpGVMem = 0;
65}
66
67
68uint8_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.
90void 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.
97void 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.
105void 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.
114void 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.
132uint8_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.
150void 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.
175uint8_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.
194uint8_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.
216void 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
246void 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