blob: b2654c407e98e8093462f9a2928cf3416874709d [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 }
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 */
42void * dvmCompilerNew(size_t size, bool zero)
43{
44 size = (size + 3) & ~3;
45retry:
46 /* Normal case - space is available in the current page */
47 if (size + currentArena->bytesAllocated <= ARENA_DEFAULT_SIZE) {
48 void *ptr;
49 ptr = &currentArena->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 */
Bill Buzbeefc519dc2010-03-06 23:30:57 -080069 assert(size <= ARENA_DEFAULT_SIZE);
Ben Chengba4fc8b2009-06-01 13:00:29 -070070 /* 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++;
Ben Cheng60c24f42010-01-04 12:29:56 -080078 if (numArenaBlocks > 10)
Ben Chenga4973592010-03-31 11:59:18 -070079 LOGI("Total arena pages for JIT: %d", numArenaBlocks);
Ben Chengba4fc8b2009-06-01 13:00:29 -070080 goto retry;
81 }
82 return NULL;
83}
84
85/* Reclaim all the arena blocks allocated so far */
86void 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 */
97void 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 */
106static 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 */
121void 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 */
130void 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/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700154 * dvmHashForeach callback.
155 */
156static 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
Ben Chenge80cd942009-07-17 15:54:23 -0700168 /* Enable the following when fine-tuning the JIT performance */
169#if 0
Ben Cheng8b258bf2009-06-24 17:27:07 -0700170 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 }
Ben Chenge80cd942009-07-17 15:54:23 -0700180#endif
Ben Cheng8b258bf2009-06-24 17:27:07 -0700181 return 0;
182}
183
184/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700185 * 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 */
188void dvmCompilerDumpStats(void)
189{
Ben Cheng8b258bf2009-06-24 17:27:07 -0700190 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);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700197 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();
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700203 if (gDvmJit.methodStatsTable) {
204 dvmHashForeach(gDvmJit.methodStatsTable, dumpMethodStats,
205 &totalMethodStats);
206 }
Ben Cheng8b258bf2009-06-24 17:27:07 -0700207 LOGD("Code size stats: %d/%d (compiled/total Dalvik), %d (native)",
208 totalMethodStats.compiledDalvikSize,
209 totalMethodStats.dalvikSize,
210 totalMethodStats.nativeSize);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700211}
Ben Cheng4238ec22009-08-24 16:32:22 -0700212
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 */
220BitVector* 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 */
247bool 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/* FIXME */
269void dvmDebugBitVector(char *msg, const BitVector *bv, int length)
270{
271 int i;
272
273 LOGE("%s", msg);
274 for (i = 0; i < length; i++) {
275 if (dvmIsBitSet(bv, i)) {
276 LOGE("Bit %d is set", i);
277 }
278 }
279}
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800280
281void dvmCompilerAbort(CompilationUnit *cUnit)
282{
283 LOGE("Jit: aborting trace compilation, reverting to interpreter");
284 /* Force a traceback in debug builds */
285 assert(0);
286 /*
287 * Abort translation and force to interpret-only for this trace
288 * Matching setjmp in compiler thread work loop in Compiler.c.
289 */
290 longjmp(*cUnit->bailPtr, 1);
291}