1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "Dalvik.h" 18 #include "CompilerInternals.h" 19 20 static ArenaMemBlock *arenaHead, *currentArena; 21 static int numArenaBlocks; 22 23 /* Allocate the initial memory block for arena-based allocation */ 24 bool dvmCompilerHeapInit(void) 25 { 26 assert(arenaHead == NULL); 27 arenaHead = 28 (ArenaMemBlock *) malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE); 29 if (arenaHead == NULL) { 30 LOGE("No memory left to create compiler heap memory\n"); 31 return false; 32 } 33 currentArena = arenaHead; 34 currentArena->bytesAllocated = 0; 35 currentArena->next = NULL; 36 numArenaBlocks = 1; 37 38 return true; 39 } 40 41 /* Arena-based malloc for compilation tasks */ 42 void * dvmCompilerNew(size_t size, bool zero) 43 { 44 size = (size + 3) & ~3; 45 retry: 46 /* Normal case - space is available in the current page */ 47 if (size + currentArena->bytesAllocated <= ARENA_DEFAULT_SIZE) { 48 void *ptr; 49 ptr = ¤tArena->ptr[currentArena->bytesAllocated]; 50 currentArena->bytesAllocated += size; 51 if (zero) { 52 memset(ptr, 0, size); 53 } 54 return ptr; 55 } else { 56 /* 57 * See if there are previously allocated arena blocks before the last 58 * reset 59 */ 60 if (currentArena->next) { 61 currentArena = currentArena->next; 62 goto retry; 63 } 64 /* 65 * If we allocate really large variable-sized data structures that 66 * could go above the limit we need to enhance the allocation 67 * mechanism. 68 */ 69 assert(size <= ARENA_DEFAULT_SIZE); 70 /* Time to allocate a new arena */ 71 ArenaMemBlock *newArena = (ArenaMemBlock *) 72 malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE); 73 newArena->bytesAllocated = 0; 74 newArena->next = NULL; 75 currentArena->next = newArena; 76 currentArena = newArena; 77 numArenaBlocks++; 78 if (numArenaBlocks > 10) 79 LOGI("Total arena pages for JIT: %d", numArenaBlocks); 80 goto retry; 81 } 82 return NULL; 83 } 84 85 /* Reclaim all the arena blocks allocated so far */ 86 void dvmCompilerArenaReset(void) 87 { 88 ArenaMemBlock *block; 89 90 for (block = arenaHead; block; block = block->next) { 91 block->bytesAllocated = 0; 92 } 93 currentArena = arenaHead; 94 } 95 96 /* Growable List initialization */ 97 void dvmInitGrowableList(GrowableList *gList, size_t initLength) 98 { 99 gList->numAllocated = initLength; 100 gList->numUsed = 0; 101 gList->elemList = (void **) dvmCompilerNew(sizeof(void *) * initLength, 102 true); 103 } 104 105 /* Expand the capacity of a growable list */ 106 static void expandGrowableList(GrowableList *gList) 107 { 108 int newLength = gList->numAllocated; 109 if (newLength < 128) { 110 newLength <<= 1; 111 } else { 112 newLength += 128; 113 } 114 void *newArray = dvmCompilerNew(sizeof(void *) * newLength, true); 115 memcpy(newArray, gList->elemList, sizeof(void *) * gList->numAllocated); 116 gList->numAllocated = newLength; 117 gList->elemList = newArray; 118 } 119 120 /* Insert a new element into the growable list */ 121 void dvmInsertGrowableList(GrowableList *gList, void *elem) 122 { 123 if (gList->numUsed == gList->numAllocated) { 124 expandGrowableList(gList); 125 } 126 gList->elemList[gList->numUsed++] = elem; 127 } 128 129 /* Debug Utility - dump a compilation unit */ 130 void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit) 131 { 132 int i; 133 BasicBlock *bb; 134 LOGD("%d blocks in total\n", cUnit->numBlocks); 135 136 for (i = 0; i < cUnit->numBlocks; i++) { 137 bb = cUnit->blockList[i]; 138 LOGD("Block %d (insn %04x - %04x%s)\n", 139 bb->id, bb->startOffset, 140 bb->lastMIRInsn ? bb->lastMIRInsn->offset : bb->startOffset, 141 bb->lastMIRInsn ? "" : " empty"); 142 if (bb->taken) { 143 LOGD(" Taken branch: block %d (%04x)\n", 144 bb->taken->id, bb->taken->startOffset); 145 } 146 if (bb->fallThrough) { 147 LOGD(" Fallthrough : block %d (%04x)\n", 148 bb->fallThrough->id, bb->fallThrough->startOffset); 149 } 150 } 151 } 152 153 /* 154 * dvmHashForeach callback. 155 */ 156 static int dumpMethodStats(void *compilerMethodStats, void *totalMethodStats) 157 { 158 CompilerMethodStats *methodStats = 159 (CompilerMethodStats *) compilerMethodStats; 160 CompilerMethodStats *totalStats = 161 (CompilerMethodStats *) totalMethodStats; 162 const Method *method = methodStats->method; 163 164 totalStats->dalvikSize += methodStats->dalvikSize; 165 totalStats->compiledDalvikSize += methodStats->compiledDalvikSize; 166 totalStats->nativeSize += methodStats->nativeSize; 167 168 /* Enable the following when fine-tuning the JIT performance */ 169 #if 0 170 int limit = (methodStats->dalvikSize >> 2) * 3; 171 172 /* If over 3/4 of the Dalvik code is compiled, print something */ 173 if (methodStats->compiledDalvikSize >= limit) { 174 LOGD("Method stats: %s%s, %d/%d (compiled/total Dalvik), %d (native)", 175 method->clazz->descriptor, method->name, 176 methodStats->compiledDalvikSize, 177 methodStats->dalvikSize, 178 methodStats->nativeSize); 179 } 180 #endif 181 return 0; 182 } 183 184 /* 185 * Dump the current stats of the compiler, including number of bytes used in 186 * the code cache, arena size, and work queue length, and various JIT stats. 187 */ 188 void dvmCompilerDumpStats(void) 189 { 190 CompilerMethodStats totalMethodStats; 191 192 memset(&totalMethodStats, 0, sizeof(CompilerMethodStats)); 193 LOGD("%d compilations using %d + %d bytes", 194 gDvmJit.numCompilations, 195 gDvmJit.templateSize, 196 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize); 197 LOGD("Compiler arena uses %d blocks (%d bytes each)", 198 numArenaBlocks, ARENA_DEFAULT_SIZE); 199 LOGD("Compiler work queue length is %d/%d", gDvmJit.compilerQueueLength, 200 gDvmJit.compilerMaxQueued); 201 dvmJitStats(); 202 dvmCompilerArchDump(); 203 if (gDvmJit.methodStatsTable) { 204 dvmHashForeach(gDvmJit.methodStatsTable, dumpMethodStats, 205 &totalMethodStats); 206 } 207 LOGD("Code size stats: %d/%d (compiled/total Dalvik), %d (native)", 208 totalMethodStats.compiledDalvikSize, 209 totalMethodStats.dalvikSize, 210 totalMethodStats.nativeSize); 211 } 212 213 /* 214 * Allocate a bit vector with enough space to hold at least the specified 215 * number of bits. 216 * 217 * NOTE: this is the sister implementation of dvmAllocBitVector. In this version 218 * memory is allocated from the compiler arena. 219 */ 220 BitVector* dvmCompilerAllocBitVector(int startBits, bool expandable) 221 { 222 BitVector* bv; 223 int count; 224 225 assert(sizeof(bv->storage[0]) == 4); /* assuming 32-bit units */ 226 assert(startBits >= 0); 227 228 bv = (BitVector*) dvmCompilerNew(sizeof(BitVector), false); 229 230 count = (startBits + 31) >> 5; 231 232 bv->storageSize = count; 233 bv->expandable = expandable; 234 bv->storage = (u4*) dvmCompilerNew(count * sizeof(u4), true); 235 return bv; 236 } 237 238 /* 239 * Mark the specified bit as "set". 240 * 241 * Returns "false" if the bit is outside the range of the vector and we're 242 * not allowed to expand. 243 * 244 * NOTE: this is the sister implementation of dvmSetBit. In this version 245 * memory is allocated from the compiler arena. 246 */ 247 bool dvmCompilerSetBit(BitVector *pBits, int num) 248 { 249 assert(num >= 0); 250 if (num >= pBits->storageSize * (int)sizeof(u4) * 8) { 251 if (!pBits->expandable) 252 return false; 253 254 int newSize = (num + 31) >> 5; 255 assert(newSize > pBits->storageSize); 256 u4 *newStorage = dvmCompilerNew(newSize * sizeof(u4), false); 257 memcpy(newStorage, pBits->storage, pBits->storageSize * sizeof(u4)); 258 memset(&newStorage[pBits->storageSize], 0, 259 (newSize - pBits->storageSize) * sizeof(u4)); 260 pBits->storage = newStorage; 261 pBits->storageSize = newSize; 262 } 263 264 pBits->storage[num >> 5] |= 1 << (num & 0x1f); 265 return true; 266 } 267 268 void dvmDebugBitVector(char *msg, const BitVector *bv, int length) 269 { 270 int i; 271 272 LOGE("%s", msg); 273 for (i = 0; i < length; i++) { 274 if (dvmIsBitSet(bv, i)) { 275 LOGE("Bit %d is set", i); 276 } 277 } 278 } 279 280 void dvmCompilerAbort(CompilationUnit *cUnit) 281 { 282 LOGE("Jit: aborting trace compilation, reverting to interpreter"); 283 /* Force a traceback in debug builds */ 284 assert(0); 285 /* 286 * Abort translation and force to interpret-only for this trace 287 * Matching setjmp in compiler thread work loop in Compiler.c. 288 */ 289 longjmp(*cUnit->bailPtr, 1); 290 } 291