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