blob: 26bb3d082c97539be69f74d7721897583774d082 [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 */
69 if (size > ARENA_DEFAULT_SIZE) {
70 LOGE("Requesting %d bytes which exceed the maximal size allowed\n",
71 size);
Ben Cheng6c10a972009-10-29 14:39:18 -070072 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -070073 }
74 /* Time to allocate a new arena */
75 ArenaMemBlock *newArena = (ArenaMemBlock *)
76 malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE);
77 newArena->bytesAllocated = 0;
78 newArena->next = NULL;
79 currentArena->next = newArena;
80 currentArena = newArena;
81 numArenaBlocks++;
Ben Cheng60c24f42010-01-04 12:29:56 -080082 if (numArenaBlocks > 10)
83 LOGD("Total arena pages for JIT: %d", numArenaBlocks);
Ben Chengba4fc8b2009-06-01 13:00:29 -070084 goto retry;
85 }
86 return NULL;
87}
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;
105 gList->elemList = (void **) dvmCompilerNew(sizeof(void *) * initLength,
106 true);
107}
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 }
118 void *newArray = dvmCompilerNew(sizeof(void *) * newLength, true);
119 memcpy(newArray, gList->elemList, sizeof(void *) * gList->numAllocated);
120 gList->numAllocated = newLength;
121 gList->elemList = newArray;
122}
123
124/* Insert a new element into the growable list */
125void dvmInsertGrowableList(GrowableList *gList, void *elem)
126{
127 if (gList->numUsed == gList->numAllocated) {
128 expandGrowableList(gList);
129 }
130 gList->elemList[gList->numUsed++] = elem;
131}
132
133/* Debug Utility - dump a compilation unit */
134void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit)
135{
136 int i;
137 BasicBlock *bb;
138 LOGD("%d blocks in total\n", cUnit->numBlocks);
139
140 for (i = 0; i < cUnit->numBlocks; i++) {
141 bb = cUnit->blockList[i];
142 LOGD("Block %d (insn %04x - %04x%s)\n",
143 bb->id, bb->startOffset,
144 bb->lastMIRInsn ? bb->lastMIRInsn->offset : bb->startOffset,
145 bb->lastMIRInsn ? "" : " empty");
146 if (bb->taken) {
147 LOGD(" Taken branch: block %d (%04x)\n",
148 bb->taken->id, bb->taken->startOffset);
149 }
150 if (bb->fallThrough) {
151 LOGD(" Fallthrough : block %d (%04x)\n",
152 bb->fallThrough->id, bb->fallThrough->startOffset);
153 }
154 }
155}
156
157/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700158 * dvmHashForeach callback.
159 */
160static int dumpMethodStats(void *compilerMethodStats, void *totalMethodStats)
161{
162 CompilerMethodStats *methodStats =
163 (CompilerMethodStats *) compilerMethodStats;
164 CompilerMethodStats *totalStats =
165 (CompilerMethodStats *) totalMethodStats;
166 const Method *method = methodStats->method;
167
168 totalStats->dalvikSize += methodStats->dalvikSize;
169 totalStats->compiledDalvikSize += methodStats->compiledDalvikSize;
170 totalStats->nativeSize += methodStats->nativeSize;
171
Ben Chenge80cd942009-07-17 15:54:23 -0700172 /* Enable the following when fine-tuning the JIT performance */
173#if 0
Ben Cheng8b258bf2009-06-24 17:27:07 -0700174 int limit = (methodStats->dalvikSize >> 2) * 3;
175
176 /* If over 3/4 of the Dalvik code is compiled, print something */
177 if (methodStats->compiledDalvikSize >= limit) {
178 LOGD("Method stats: %s%s, %d/%d (compiled/total Dalvik), %d (native)",
179 method->clazz->descriptor, method->name,
180 methodStats->compiledDalvikSize,
181 methodStats->dalvikSize,
182 methodStats->nativeSize);
183 }
Ben Chenge80cd942009-07-17 15:54:23 -0700184#endif
Ben Cheng8b258bf2009-06-24 17:27:07 -0700185 return 0;
186}
187
188/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700189 * Dump the current stats of the compiler, including number of bytes used in
190 * the code cache, arena size, and work queue length, and various JIT stats.
191 */
192void dvmCompilerDumpStats(void)
193{
Ben Cheng8b258bf2009-06-24 17:27:07 -0700194 CompilerMethodStats totalMethodStats;
195
196 memset(&totalMethodStats, 0, sizeof(CompilerMethodStats));
197 LOGD("%d compilations using %d + %d bytes",
198 gDvmJit.numCompilations,
199 gDvmJit.templateSize,
200 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700201 LOGD("Compiler arena uses %d blocks (%d bytes each)",
202 numArenaBlocks, ARENA_DEFAULT_SIZE);
203 LOGD("Compiler work queue length is %d/%d", gDvmJit.compilerQueueLength,
204 gDvmJit.compilerMaxQueued);
205 dvmJitStats();
206 dvmCompilerArchDump();
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700207 if (gDvmJit.methodStatsTable) {
208 dvmHashForeach(gDvmJit.methodStatsTable, dumpMethodStats,
209 &totalMethodStats);
210 }
Ben Cheng8b258bf2009-06-24 17:27:07 -0700211 LOGD("Code size stats: %d/%d (compiled/total Dalvik), %d (native)",
212 totalMethodStats.compiledDalvikSize,
213 totalMethodStats.dalvikSize,
214 totalMethodStats.nativeSize);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700215}
Ben Cheng4238ec22009-08-24 16:32:22 -0700216
217/*
218 * Allocate a bit vector with enough space to hold at least the specified
219 * number of bits.
220 *
221 * NOTE: this is the sister implementation of dvmAllocBitVector. In this version
222 * memory is allocated from the compiler arena.
223 */
224BitVector* dvmCompilerAllocBitVector(int startBits, bool expandable)
225{
226 BitVector* bv;
227 int count;
228
229 assert(sizeof(bv->storage[0]) == 4); /* assuming 32-bit units */
230 assert(startBits >= 0);
231
232 bv = (BitVector*) dvmCompilerNew(sizeof(BitVector), false);
233
234 count = (startBits + 31) >> 5;
235
236 bv->storageSize = count;
237 bv->expandable = expandable;
238 bv->storage = (u4*) dvmCompilerNew(count * sizeof(u4), true);
239 return bv;
240}
241
242/*
243 * Mark the specified bit as "set".
244 *
245 * Returns "false" if the bit is outside the range of the vector and we're
246 * not allowed to expand.
247 *
248 * NOTE: this is the sister implementation of dvmSetBit. In this version
249 * memory is allocated from the compiler arena.
250 */
251bool dvmCompilerSetBit(BitVector *pBits, int num)
252{
253 assert(num >= 0);
254 if (num >= pBits->storageSize * (int)sizeof(u4) * 8) {
255 if (!pBits->expandable)
256 return false;
257
258 int newSize = (num + 31) >> 5;
259 assert(newSize > pBits->storageSize);
260 u4 *newStorage = dvmCompilerNew(newSize * sizeof(u4), false);
261 memcpy(newStorage, pBits->storage, pBits->storageSize * sizeof(u4));
262 memset(&newStorage[pBits->storageSize], 0,
263 (newSize - pBits->storageSize) * sizeof(u4));
264 pBits->storage = newStorage;
265 pBits->storageSize = newSize;
266 }
267
268 pBits->storage[num >> 5] |= 1 << (num & 0x1f);
269 return true;
270}
271
272/* FIXME */
273void dvmDebugBitVector(char *msg, const BitVector *bv, int length)
274{
275 int i;
276
277 LOGE("%s", msg);
278 for (i = 0; i < length; i++) {
279 if (dvmIsBitSet(bv, i)) {
280 LOGE("Bit %d is set", i);
281 }
282 }
283}