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 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 62 CodeMemoryManager::~CodeMemoryManager() { 63 mpCodeMem = 0; 64 mpGVMem = 0; 65 } 66 67 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. 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. 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. 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. 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. 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. 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. 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. 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. 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 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