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 */
dvmCompilerHeapInit(void)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");
31 return false;
32 }
33 arenaHead->blockSize = ARENA_DEFAULT_SIZE;
34 currentArena = arenaHead;
35 currentArena->bytesAllocated = 0;
36 currentArena->next = NULL;
37 numArenaBlocks = 1;
38
39 return true;
40 }
41
42 /* Arena-based malloc for compilation tasks */
dvmCompilerNew(size_t size,bool zero)43 void * dvmCompilerNew(size_t size, bool zero)
44 {
45 size = (size + 3) & ~3;
46 retry:
47 /* Normal case - space is available in the current page */
48 if (size + currentArena->bytesAllocated <= currentArena->blockSize) {
49 void *ptr;
50 ptr = ¤tArena->ptr[currentArena->bytesAllocated];
51 currentArena->bytesAllocated += size;
52 if (zero) {
53 memset(ptr, 0, size);
54 }
55 return ptr;
56 } else {
57 /*
58 * See if there are previously allocated arena blocks before the last
59 * reset
60 */
61 if (currentArena->next) {
62 currentArena = currentArena->next;
63 goto retry;
64 }
65
66 size_t blockSize = (size < ARENA_DEFAULT_SIZE) ?
67 ARENA_DEFAULT_SIZE : size;
68 /* Time to allocate a new arena */
69 ArenaMemBlock *newArena = (ArenaMemBlock *)
70 malloc(sizeof(ArenaMemBlock) + blockSize);
71 if (newArena == NULL) {
72 LOGE("Arena allocation failure");
73 dvmAbort();
74 }
75 newArena->blockSize = blockSize;
76 newArena->bytesAllocated = 0;
77 newArena->next = NULL;
78 currentArena->next = newArena;
79 currentArena = newArena;
80 numArenaBlocks++;
81 if (numArenaBlocks > 10)
82 LOGI("Total arena pages for JIT: %d", numArenaBlocks);
83 goto retry;
84 }
85 /* Should not reach here */
86 dvmAbort();
87 }
88
89 /* Reclaim all the arena blocks allocated so far */
dvmCompilerArenaReset(void)90 void dvmCompilerArenaReset(void)
91 {
92 ArenaMemBlock *block;
93
94 for (block = arenaHead; block; block = block->next) {
95 block->bytesAllocated = 0;
96 }
97 currentArena = arenaHead;
98 }
99
100 /* Growable List initialization */
dvmInitGrowableList(GrowableList * gList,size_t initLength)101 void dvmInitGrowableList(GrowableList *gList, size_t initLength)
102 {
103 gList->numAllocated = initLength;
104 gList->numUsed = 0;
105 gList->elemList = (intptr_t *) dvmCompilerNew(sizeof(intptr_t) * initLength,
106 true);
107 }
108
109 /* Expand the capacity of a growable list */
expandGrowableList(GrowableList * gList)110 static void expandGrowableList(GrowableList *gList)
111 {
112 int newLength = gList->numAllocated;
113 if (newLength < 128) {
114 newLength <<= 1;
115 } else {
116 newLength += 128;
117 }
118 intptr_t *newArray =
119 (intptr_t *) dvmCompilerNew(sizeof(intptr_t) * newLength, true);
120 memcpy(newArray, gList->elemList, sizeof(intptr_t) * gList->numAllocated);
121 gList->numAllocated = newLength;
122 gList->elemList = newArray;
123 }
124
125 /* Insert a new element into the growable list */
dvmInsertGrowableList(GrowableList * gList,intptr_t elem)126 void dvmInsertGrowableList(GrowableList *gList, intptr_t elem)
127 {
128 assert(gList->numAllocated != 0);
129 if (gList->numUsed == gList->numAllocated) {
130 expandGrowableList(gList);
131 }
132 gList->elemList[gList->numUsed++] = elem;
133 }
134
dvmGrowableListIteratorInit(GrowableList * gList,GrowableListIterator * iterator)135 void dvmGrowableListIteratorInit(GrowableList *gList,
136 GrowableListIterator *iterator)
137 {
138 iterator->list = gList;
139 iterator->idx = 0;
140 iterator->size = gList->numUsed;
141 }
142
dvmGrowableListIteratorNext(GrowableListIterator * iterator)143 intptr_t dvmGrowableListIteratorNext(GrowableListIterator *iterator)
144 {
145 assert(iterator->size == iterator->list->numUsed);
146 if (iterator->idx == iterator->size) return 0;
147 return iterator->list->elemList[iterator->idx++];
148 }
149
dvmGrowableListGetElement(const GrowableList * gList,size_t idx)150 intptr_t dvmGrowableListGetElement(const GrowableList *gList, size_t idx)
151 {
152 assert(idx < gList->numUsed);
153 return gList->elemList[idx];
154 }
155
156 /* Debug Utility - dump a compilation unit */
dvmCompilerDumpCompilationUnit(CompilationUnit * cUnit)157 void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit)
158 {
159 BasicBlock *bb;
160 const char *blockTypeNames[] = {
161 "Normal Chaining Cell",
162 "Hot Chaining Cell",
163 "Singleton Chaining Cell",
164 "Predicted Chaining Cell",
165 "Backward Branch",
166 "Chaining Cell Gap",
167 "N/A",
168 "Entry Block",
169 "Code Block",
170 "Exit Block",
171 "PC Reconstruction",
172 "Exception Handling",
173 };
174
175 LOGD("Compiling %s %s", cUnit->method->clazz->descriptor,
176 cUnit->method->name);
177 LOGD("%d insns", dvmGetMethodInsnsSize(cUnit->method));
178 LOGD("%d blocks in total", cUnit->numBlocks);
179 GrowableListIterator iterator;
180
181 dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
182
183 while (true) {
184 bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
185 if (bb == NULL) break;
186 LOGD("Block %d (%s) (insn %04x - %04x%s)",
187 bb->id,
188 blockTypeNames[bb->blockType],
189 bb->startOffset,
190 bb->lastMIRInsn ? bb->lastMIRInsn->offset : bb->startOffset,
191 bb->lastMIRInsn ? "" : " empty");
192 if (bb->taken) {
193 LOGD(" Taken branch: block %d (%04x)",
194 bb->taken->id, bb->taken->startOffset);
195 }
196 if (bb->fallThrough) {
197 LOGD(" Fallthrough : block %d (%04x)",
198 bb->fallThrough->id, bb->fallThrough->startOffset);
199 }
200 }
201 }
202
203 /*
204 * dvmHashForeach callback.
205 */
dumpMethodStats(void * compilerMethodStats,void * totalMethodStats)206 static int dumpMethodStats(void *compilerMethodStats, void *totalMethodStats)
207 {
208 CompilerMethodStats *methodStats =
209 (CompilerMethodStats *) compilerMethodStats;
210 CompilerMethodStats *totalStats =
211 (CompilerMethodStats *) totalMethodStats;
212
213 totalStats->dalvikSize += methodStats->dalvikSize;
214 totalStats->compiledDalvikSize += methodStats->compiledDalvikSize;
215 totalStats->nativeSize += methodStats->nativeSize;
216
217 /* Enable the following when fine-tuning the JIT performance */
218 #if 0
219 int limit = (methodStats->dalvikSize >> 2) * 3;
220
221 /* If over 3/4 of the Dalvik code is compiled, print something */
222 if (methodStats->compiledDalvikSize >= limit) {
223 LOGD("Method stats: %s%s, %d/%d (compiled/total Dalvik), %d (native)",
224 methodStats->method->clazz->descriptor,
225 methodStats->method->name,
226 methodStats->compiledDalvikSize,
227 methodStats->dalvikSize,
228 methodStats->nativeSize);
229 }
230 #endif
231 return 0;
232 }
233
234 /*
235 * Dump the current stats of the compiler, including number of bytes used in
236 * the code cache, arena size, and work queue length, and various JIT stats.
237 */
dvmCompilerDumpStats(void)238 void dvmCompilerDumpStats(void)
239 {
240 CompilerMethodStats totalMethodStats;
241
242 memset(&totalMethodStats, 0, sizeof(CompilerMethodStats));
243 LOGD("%d compilations using %d + %d bytes",
244 gDvmJit.numCompilations,
245 gDvmJit.templateSize,
246 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
247 LOGD("Compiler arena uses %d blocks (%d bytes each)",
248 numArenaBlocks, ARENA_DEFAULT_SIZE);
249 LOGD("Compiler work queue length is %d/%d", gDvmJit.compilerQueueLength,
250 gDvmJit.compilerMaxQueued);
251 dvmJitStats();
252 dvmCompilerArchDump();
253 if (gDvmJit.methodStatsTable) {
254 dvmHashForeach(gDvmJit.methodStatsTable, dumpMethodStats,
255 &totalMethodStats);
256 LOGD("Code size stats: %d/%d (compiled/total Dalvik), %d (native)",
257 totalMethodStats.compiledDalvikSize,
258 totalMethodStats.dalvikSize,
259 totalMethodStats.nativeSize);
260 }
261 }
262
263 /*
264 * Allocate a bit vector with enough space to hold at least the specified
265 * number of bits.
266 *
267 * NOTE: this is the sister implementation of dvmAllocBitVector. In this version
268 * memory is allocated from the compiler arena.
269 */
dvmCompilerAllocBitVector(unsigned int startBits,bool expandable)270 BitVector* dvmCompilerAllocBitVector(unsigned int startBits, bool expandable)
271 {
272 BitVector* bv;
273 unsigned int count;
274
275 assert(sizeof(bv->storage[0]) == 4); /* assuming 32-bit units */
276
277 bv = (BitVector*) dvmCompilerNew(sizeof(BitVector), false);
278
279 count = (startBits + 31) >> 5;
280
281 bv->storageSize = count;
282 bv->expandable = expandable;
283 bv->storage = (u4*) dvmCompilerNew(count * sizeof(u4), true);
284 return bv;
285 }
286
287 /*
288 * Mark the specified bit as "set".
289 *
290 * Returns "false" if the bit is outside the range of the vector and we're
291 * not allowed to expand.
292 *
293 * NOTE: this is the sister implementation of dvmSetBit. In this version
294 * memory is allocated from the compiler arena.
295 */
dvmCompilerSetBit(BitVector * pBits,unsigned int num)296 bool dvmCompilerSetBit(BitVector *pBits, unsigned int num)
297 {
298 if (num >= pBits->storageSize * sizeof(u4) * 8) {
299 if (!pBits->expandable)
300 dvmAbort();
301
302 /* Round up to word boundaries for "num+1" bits */
303 unsigned int newSize = (num + 1 + 31) >> 5;
304 assert(newSize > pBits->storageSize);
305 u4 *newStorage = (u4*)dvmCompilerNew(newSize * sizeof(u4), false);
306 memcpy(newStorage, pBits->storage, pBits->storageSize * sizeof(u4));
307 memset(&newStorage[pBits->storageSize], 0,
308 (newSize - pBits->storageSize) * sizeof(u4));
309 pBits->storage = newStorage;
310 pBits->storageSize = newSize;
311 }
312
313 pBits->storage[num >> 5] |= 1 << (num & 0x1f);
314 return true;
315 }
316
317 /*
318 * Mark the specified bit as "unset".
319 *
320 * Returns "false" if the bit is outside the range of the vector and we're
321 * not allowed to expand.
322 *
323 * NOTE: this is the sister implementation of dvmClearBit. In this version
324 * memory is allocated from the compiler arena.
325 */
dvmCompilerClearBit(BitVector * pBits,unsigned int num)326 bool dvmCompilerClearBit(BitVector *pBits, unsigned int num)
327 {
328 if (num >= pBits->storageSize * sizeof(u4) * 8) {
329 LOGE("Trying to clear a bit that is not set in the vector yet!");
330 dvmAbort();
331 }
332
333 pBits->storage[num >> 5] &= ~(1 << (num & 0x1f));
334 return true;
335 }
336
337 /*
338 * If set is true, mark all bits as 1. Otherwise mark all bits as 0.
339 */
dvmCompilerMarkAllBits(BitVector * pBits,bool set)340 void dvmCompilerMarkAllBits(BitVector *pBits, bool set)
341 {
342 int value = set ? -1 : 0;
343 memset(pBits->storage, value, pBits->storageSize * (int)sizeof(u4));
344 }
345
dvmDebugBitVector(char * msg,const BitVector * bv,int length)346 void dvmDebugBitVector(char *msg, const BitVector *bv, int length)
347 {
348 int i;
349
350 LOGE("%s", msg);
351 for (i = 0; i < length; i++) {
352 if (dvmIsBitSet(bv, i)) {
353 LOGE(" Bit %d is set", i);
354 }
355 }
356 }
357
dvmCompilerAbort(CompilationUnit * cUnit)358 void dvmCompilerAbort(CompilationUnit *cUnit)
359 {
360 LOGE("Jit: aborting trace compilation, reverting to interpreter");
361 /* Force a traceback in debug builds */
362 assert(0);
363 /*
364 * Abort translation and force to interpret-only for this trace
365 * Matching setjmp in compiler thread work loop in Compiler.c.
366 */
367 longjmp(*cUnit->bailPtr, 1);
368 }
369
dvmDumpBlockBitVector(const GrowableList * blocks,char * msg,const BitVector * bv,int length)370 void dvmDumpBlockBitVector(const GrowableList *blocks, char *msg,
371 const BitVector *bv, int length)
372 {
373 int i;
374
375 LOGE("%s", msg);
376 for (i = 0; i < length; i++) {
377 if (dvmIsBitSet(bv, i)) {
378 BasicBlock *bb =
379 (BasicBlock *) dvmGrowableListGetElement(blocks, i);
380 char blockName[BLOCK_NAME_LEN];
381 dvmGetBlockName(bb, blockName);
382 LOGE("Bit %d / %s is set", i, blockName);
383 }
384 }
385 }
386
dvmGetBlockName(BasicBlock * bb,char * name)387 void dvmGetBlockName(BasicBlock *bb, char *name)
388 {
389 switch (bb->blockType) {
390 case kEntryBlock:
391 snprintf(name, BLOCK_NAME_LEN, "entry");
392 break;
393 case kExitBlock:
394 snprintf(name, BLOCK_NAME_LEN, "exit");
395 break;
396 case kDalvikByteCode:
397 snprintf(name, BLOCK_NAME_LEN, "block%04x", bb->startOffset);
398 break;
399 case kChainingCellNormal:
400 snprintf(name, BLOCK_NAME_LEN, "chain%04x", bb->startOffset);
401 break;
402 case kExceptionHandling:
403 snprintf(name, BLOCK_NAME_LEN, "exception%04x", bb->startOffset);
404 break;
405 default:
406 snprintf(name, BLOCK_NAME_LEN, "??");
407 break;
408 }
409 }
410