blob: 7be57efa2b08343f3b5a3726e57e7bfc698c4d58 [file] [log] [blame]
Ben Chengba4fc8b2009-06-01 13:00:29 -07001/*
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
20static ArenaMemBlock *arenaHead, *currentArena;
21static int numArenaBlocks;
22
23/* Allocate the initial memory block for arena-based allocation */
24bool 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 }
Ben Cheng7a2697d2010-06-07 13:44:23 -070033 arenaHead->blockSize = ARENA_DEFAULT_SIZE;
Ben Chengba4fc8b2009-06-01 13:00:29 -070034 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 */
43void * dvmCompilerNew(size_t size, bool zero)
44{
45 size = (size + 3) & ~3;
46retry:
47 /* Normal case - space is available in the current page */
Ben Cheng7a2697d2010-06-07 13:44:23 -070048 if (size + currentArena->bytesAllocated <= currentArena->blockSize) {
Ben Chengba4fc8b2009-06-01 13:00:29 -070049 void *ptr;
50 ptr = &currentArena->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 }
Ben Cheng7a2697d2010-06-07 13:44:23 -070065
66 size_t blockSize = (size < ARENA_DEFAULT_SIZE) ?
67 ARENA_DEFAULT_SIZE : size;
Ben Chengba4fc8b2009-06-01 13:00:29 -070068 /* Time to allocate a new arena */
69 ArenaMemBlock *newArena = (ArenaMemBlock *)
Ben Cheng7a2697d2010-06-07 13:44:23 -070070 malloc(sizeof(ArenaMemBlock) + blockSize);
71 if (newArena == NULL) {
72 LOGE("Arena allocation failure");
73 dvmAbort();
74 }
75 newArena->blockSize = blockSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -070076 newArena->bytesAllocated = 0;
77 newArena->next = NULL;
78 currentArena->next = newArena;
79 currentArena = newArena;
80 numArenaBlocks++;
Ben Cheng60c24f42010-01-04 12:29:56 -080081 if (numArenaBlocks > 10)
Ben Chenga4973592010-03-31 11:59:18 -070082 LOGI("Total arena pages for JIT: %d", numArenaBlocks);
Ben Chengba4fc8b2009-06-01 13:00:29 -070083 goto retry;
84 }
Ben Cheng00603072010-10-28 11:13:58 -070085 /* Should not reach here */
86 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -070087}
88
89/* Reclaim all the arena blocks allocated so far */
90void 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 */
101void dvmInitGrowableList(GrowableList *gList, size_t initLength)
102{
103 gList->numAllocated = initLength;
104 gList->numUsed = 0;
Ben Cheng00603072010-10-28 11:13:58 -0700105 gList->elemList = (intptr_t *) dvmCompilerNew(sizeof(intptr_t) * initLength,
106 true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700107}
108
109/* Expand the capacity of a growable list */
110static void expandGrowableList(GrowableList *gList)
111{
112 int newLength = gList->numAllocated;
113 if (newLength < 128) {
114 newLength <<= 1;
115 } else {
116 newLength += 128;
117 }
Ben Cheng00603072010-10-28 11:13:58 -0700118 intptr_t *newArray =
119 (intptr_t *) dvmCompilerNew(sizeof(intptr_t) * newLength, true);
120 memcpy(newArray, gList->elemList, sizeof(intptr_t) * gList->numAllocated);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700121 gList->numAllocated = newLength;
Ben Cheng00603072010-10-28 11:13:58 -0700122 gList->elemList = newArray;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700123}
124
125/* Insert a new element into the growable list */
Ben Cheng00603072010-10-28 11:13:58 -0700126void dvmInsertGrowableList(GrowableList *gList, intptr_t elem)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700127{
Ben Cheng7a2697d2010-06-07 13:44:23 -0700128 assert(gList->numAllocated != 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700129 if (gList->numUsed == gList->numAllocated) {
130 expandGrowableList(gList);
131 }
132 gList->elemList[gList->numUsed++] = elem;
133}
134
Ben Cheng00603072010-10-28 11:13:58 -0700135void dvmGrowableListIteratorInit(GrowableList *gList,
136 GrowableListIterator *iterator)
137{
138 iterator->list = gList;
139 iterator->idx = 0;
140 iterator->size = gList->numUsed;
141}
142
143intptr_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
150intptr_t dvmGrowableListGetElement(const GrowableList *gList, size_t idx)
151{
152 assert(idx < gList->numUsed);
153 return gList->elemList[idx];
154}
155
Ben Chengba4fc8b2009-06-01 13:00:29 -0700156/* Debug Utility - dump a compilation unit */
157void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit)
158{
Ben Chengba4fc8b2009-06-01 13:00:29 -0700159 BasicBlock *bb;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700160 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 "Method Entry Block",
169 "Trace Entry Block",
170 "Code Block",
171 "Trace Exit Block",
172 "Method Exit Block",
173 "PC Reconstruction",
174 "Exception Handling",
175 };
176
177 LOGD("Compiling %s %s", cUnit->method->clazz->descriptor,
178 cUnit->method->name);
179 LOGD("%d insns", dvmGetMethodInsnsSize(cUnit->method));
180 LOGD("%d blocks in total", cUnit->numBlocks);
Ben Cheng00603072010-10-28 11:13:58 -0700181 GrowableListIterator iterator;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700182
Ben Cheng00603072010-10-28 11:13:58 -0700183 dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
184
185 while (true) {
186 bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
187 if (bb == NULL) break;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700188 LOGD("Block %d (%s) (insn %04x - %04x%s)\n",
189 bb->id,
190 blockTypeNames[bb->blockType],
191 bb->startOffset,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700192 bb->lastMIRInsn ? bb->lastMIRInsn->offset : bb->startOffset,
193 bb->lastMIRInsn ? "" : " empty");
194 if (bb->taken) {
195 LOGD(" Taken branch: block %d (%04x)\n",
196 bb->taken->id, bb->taken->startOffset);
197 }
198 if (bb->fallThrough) {
199 LOGD(" Fallthrough : block %d (%04x)\n",
200 bb->fallThrough->id, bb->fallThrough->startOffset);
201 }
202 }
203}
204
205/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700206 * dvmHashForeach callback.
207 */
208static int dumpMethodStats(void *compilerMethodStats, void *totalMethodStats)
209{
210 CompilerMethodStats *methodStats =
211 (CompilerMethodStats *) compilerMethodStats;
212 CompilerMethodStats *totalStats =
213 (CompilerMethodStats *) totalMethodStats;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700214
215 totalStats->dalvikSize += methodStats->dalvikSize;
216 totalStats->compiledDalvikSize += methodStats->compiledDalvikSize;
217 totalStats->nativeSize += methodStats->nativeSize;
218
Ben Chenge80cd942009-07-17 15:54:23 -0700219 /* Enable the following when fine-tuning the JIT performance */
220#if 0
Ben Cheng8b258bf2009-06-24 17:27:07 -0700221 int limit = (methodStats->dalvikSize >> 2) * 3;
222
223 /* If over 3/4 of the Dalvik code is compiled, print something */
224 if (methodStats->compiledDalvikSize >= limit) {
225 LOGD("Method stats: %s%s, %d/%d (compiled/total Dalvik), %d (native)",
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700226 methodStats->method->clazz->descriptor,
227 methodStats->method->name,
Ben Cheng8b258bf2009-06-24 17:27:07 -0700228 methodStats->compiledDalvikSize,
229 methodStats->dalvikSize,
230 methodStats->nativeSize);
231 }
Ben Chenge80cd942009-07-17 15:54:23 -0700232#endif
Ben Cheng8b258bf2009-06-24 17:27:07 -0700233 return 0;
234}
235
236/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700237 * Dump the current stats of the compiler, including number of bytes used in
238 * the code cache, arena size, and work queue length, and various JIT stats.
239 */
240void dvmCompilerDumpStats(void)
241{
Ben Cheng8b258bf2009-06-24 17:27:07 -0700242 CompilerMethodStats totalMethodStats;
243
244 memset(&totalMethodStats, 0, sizeof(CompilerMethodStats));
245 LOGD("%d compilations using %d + %d bytes",
246 gDvmJit.numCompilations,
247 gDvmJit.templateSize,
248 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700249 LOGD("Compiler arena uses %d blocks (%d bytes each)",
250 numArenaBlocks, ARENA_DEFAULT_SIZE);
251 LOGD("Compiler work queue length is %d/%d", gDvmJit.compilerQueueLength,
252 gDvmJit.compilerMaxQueued);
253 dvmJitStats();
254 dvmCompilerArchDump();
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700255 if (gDvmJit.methodStatsTable) {
256 dvmHashForeach(gDvmJit.methodStatsTable, dumpMethodStats,
257 &totalMethodStats);
Ben Cheng978738d2010-05-13 13:45:57 -0700258 LOGD("Code size stats: %d/%d (compiled/total Dalvik), %d (native)",
259 totalMethodStats.compiledDalvikSize,
260 totalMethodStats.dalvikSize,
261 totalMethodStats.nativeSize);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700262 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700263}
Ben Cheng4238ec22009-08-24 16:32:22 -0700264
265/*
266 * Allocate a bit vector with enough space to hold at least the specified
267 * number of bits.
268 *
269 * NOTE: this is the sister implementation of dvmAllocBitVector. In this version
270 * memory is allocated from the compiler arena.
271 */
Andy McFadden9fd527f2010-12-10 15:34:00 -0800272BitVector* dvmCompilerAllocBitVector(unsigned int startBits, bool expandable)
Ben Cheng4238ec22009-08-24 16:32:22 -0700273{
274 BitVector* bv;
Andy McFadden9fd527f2010-12-10 15:34:00 -0800275 unsigned int count;
Ben Cheng4238ec22009-08-24 16:32:22 -0700276
277 assert(sizeof(bv->storage[0]) == 4); /* assuming 32-bit units */
Ben Cheng4238ec22009-08-24 16:32:22 -0700278
279 bv = (BitVector*) dvmCompilerNew(sizeof(BitVector), false);
280
281 count = (startBits + 31) >> 5;
282
283 bv->storageSize = count;
284 bv->expandable = expandable;
285 bv->storage = (u4*) dvmCompilerNew(count * sizeof(u4), true);
286 return bv;
287}
288
289/*
290 * Mark the specified bit as "set".
291 *
292 * Returns "false" if the bit is outside the range of the vector and we're
293 * not allowed to expand.
294 *
295 * NOTE: this is the sister implementation of dvmSetBit. In this version
296 * memory is allocated from the compiler arena.
297 */
Andy McFadden9fd527f2010-12-10 15:34:00 -0800298bool dvmCompilerSetBit(BitVector *pBits, unsigned int num)
Ben Cheng4238ec22009-08-24 16:32:22 -0700299{
Andy McFadden9fd527f2010-12-10 15:34:00 -0800300 if (num >= pBits->storageSize * sizeof(u4) * 8) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700301 if (!pBits->expandable)
Ben Cheng00603072010-10-28 11:13:58 -0700302 dvmAbort();
Ben Cheng4238ec22009-08-24 16:32:22 -0700303
Ben Chengabf3ef82010-11-23 11:55:16 -0800304 /* Round up to word boundaries for "num+1" bits */
Andy McFadden9fd527f2010-12-10 15:34:00 -0800305 unsigned int newSize = (num + 1 + 31) >> 5;
Ben Cheng4238ec22009-08-24 16:32:22 -0700306 assert(newSize > pBits->storageSize);
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800307 u4 *newStorage = (u4*)dvmCompilerNew(newSize * sizeof(u4), false);
Ben Cheng4238ec22009-08-24 16:32:22 -0700308 memcpy(newStorage, pBits->storage, pBits->storageSize * sizeof(u4));
309 memset(&newStorage[pBits->storageSize], 0,
310 (newSize - pBits->storageSize) * sizeof(u4));
311 pBits->storage = newStorage;
312 pBits->storageSize = newSize;
313 }
314
315 pBits->storage[num >> 5] |= 1 << (num & 0x1f);
316 return true;
317}
318
Ben Cheng00603072010-10-28 11:13:58 -0700319/*
320 * Mark the specified bit as "unset".
321 *
322 * Returns "false" if the bit is outside the range of the vector and we're
323 * not allowed to expand.
324 *
325 * NOTE: this is the sister implementation of dvmClearBit. In this version
326 * memory is allocated from the compiler arena.
327 */
Andy McFadden9fd527f2010-12-10 15:34:00 -0800328bool dvmCompilerClearBit(BitVector *pBits, unsigned int num)
Ben Cheng00603072010-10-28 11:13:58 -0700329{
Andy McFadden9fd527f2010-12-10 15:34:00 -0800330 if (num >= pBits->storageSize * sizeof(u4) * 8) {
Ben Cheng00603072010-10-28 11:13:58 -0700331 LOGE("Trying to clear a bit that is not set in the vector yet!");
332 dvmAbort();
333 }
334
335 pBits->storage[num >> 5] &= ~(1 << (num & 0x1f));
336 return true;
337}
338
339/*
340 * If set is true, mark all bits as 1. Otherwise mark all bits as 0.
341 */
342void dvmCompilerMarkAllBits(BitVector *pBits, bool set)
343{
344 int value = set ? -1 : 0;
345 memset(pBits->storage, value, pBits->storageSize * (int)sizeof(u4));
346}
347
Ben Cheng4238ec22009-08-24 16:32:22 -0700348void dvmDebugBitVector(char *msg, const BitVector *bv, int length)
349{
350 int i;
351
352 LOGE("%s", msg);
353 for (i = 0; i < length; i++) {
354 if (dvmIsBitSet(bv, i)) {
355 LOGE("Bit %d is set", i);
356 }
357 }
358}
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800359
360void dvmCompilerAbort(CompilationUnit *cUnit)
361{
362 LOGE("Jit: aborting trace compilation, reverting to interpreter");
363 /* Force a traceback in debug builds */
364 assert(0);
365 /*
366 * Abort translation and force to interpret-only for this trace
367 * Matching setjmp in compiler thread work loop in Compiler.c.
368 */
369 longjmp(*cUnit->bailPtr, 1);
370}
Ben Cheng00603072010-10-28 11:13:58 -0700371
372void dvmDumpBlockBitVector(const GrowableList *blocks, char *msg,
373 const BitVector *bv, int length)
374{
375 int i;
376
377 LOGE("%s", msg);
378 for (i = 0; i < length; i++) {
379 if (dvmIsBitSet(bv, i)) {
380 BasicBlock *bb =
381 (BasicBlock *) dvmGrowableListGetElement(blocks, i);
382 char blockName[BLOCK_NAME_LEN];
383 dvmGetBlockName(bb, blockName);
384 LOGE("Bit %d / %s is set", i, blockName);
385 }
386 }
387}
388
389void dvmGetBlockName(BasicBlock *bb, char *name)
390{
391 switch (bb->blockType) {
392 case kMethodEntryBlock:
393 snprintf(name, BLOCK_NAME_LEN, "entry");
394 break;
395 case kMethodExitBlock:
396 snprintf(name, BLOCK_NAME_LEN, "exit");
397 break;
398 case kDalvikByteCode:
399 snprintf(name, BLOCK_NAME_LEN, "block%04x", bb->startOffset);
400 break;
401 case kExceptionHandling:
402 snprintf(name, BLOCK_NAME_LEN, "exception%04x", bb->startOffset);
403 break;
404 default:
405 snprintf(name, BLOCK_NAME_LEN, "??");
406 break;
407 }
408}