blob: 6cd7eb583c5b4f4d11844cc0d368e1ddc1c818ff [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 <sys/mman.h>
18#include <errno.h>
Ben Cheng7c4afdb2010-02-11 15:03:00 -080019#include <cutils/ashmem.h>
Ben Chengba4fc8b2009-06-01 13:00:29 -070020
21#include "Dalvik.h"
22#include "interp/Jit.h"
23#include "CompilerInternals.h"
24
Ben Chengba4fc8b2009-06-01 13:00:29 -070025static inline bool workQueueLength(void)
26{
27 return gDvmJit.compilerQueueLength;
28}
29
30static CompilerWorkOrder workDequeue(void)
31{
32 assert(gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex].kind
33 != kWorkOrderInvalid);
34 CompilerWorkOrder work =
35 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex];
36 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex++].kind =
37 kWorkOrderInvalid;
38 if (gDvmJit.compilerWorkDequeueIndex == COMPILER_WORK_QUEUE_SIZE) {
39 gDvmJit.compilerWorkDequeueIndex = 0;
40 }
41 gDvmJit.compilerQueueLength--;
Bill Buzbeef9f33282009-11-22 12:45:30 -080042 if (gDvmJit.compilerQueueLength == 0) {
Carl Shapirob31b3012010-05-25 18:35:37 -070043 dvmSignalCond(&gDvmJit.compilerQueueEmpty);
Bill Buzbeef9f33282009-11-22 12:45:30 -080044 }
Ben Chengba4fc8b2009-06-01 13:00:29 -070045
46 /* Remember the high water mark of the queue length */
47 if (gDvmJit.compilerQueueLength > gDvmJit.compilerMaxQueued)
48 gDvmJit.compilerMaxQueued = gDvmJit.compilerQueueLength;
49
50 return work;
51}
52
Bill Buzbee964a7b02010-01-28 12:54:19 -080053/*
54 * Attempt to enqueue a work order, returning true if successful.
55 * This routine will not block, but simply return if it couldn't
56 * aquire the lock or if the queue is full.
Ben Cheng1357e942010-02-10 17:21:39 -080057 *
58 * NOTE: Make sure that the caller frees the info pointer if the return value
59 * is false.
Bill Buzbee964a7b02010-01-28 12:54:19 -080060 */
Ben Chengba4fc8b2009-06-01 13:00:29 -070061bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
62{
63 int cc;
64 int i;
65 int numWork;
Ben Cheng60c24f42010-01-04 12:29:56 -080066 bool result = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -070067
Bill Buzbee964a7b02010-01-28 12:54:19 -080068 if (dvmTryLockMutex(&gDvmJit.compilerLock)) {
Ben Cheng3e5cd172010-02-08 20:57:59 -080069 return false; // Couldn't acquire the lock
Bill Buzbee964a7b02010-01-28 12:54:19 -080070 }
Ben Chengba4fc8b2009-06-01 13:00:29 -070071
Ben Cheng7a0bcd02010-01-22 16:45:45 -080072 /*
Ben Cheng6999d842010-01-26 16:46:15 -080073 * Return if queue or code cache is full.
Ben Cheng7a0bcd02010-01-22 16:45:45 -080074 */
Ben Cheng6999d842010-01-26 16:46:15 -080075 if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE ||
76 gDvmJit.codeCacheFull == true) {
Ben Cheng60c24f42010-01-04 12:29:56 -080077 result = false;
Bill Buzbee964a7b02010-01-28 12:54:19 -080078 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070079 }
80
81 for (numWork = gDvmJit.compilerQueueLength,
82 i = gDvmJit.compilerWorkDequeueIndex;
83 numWork > 0;
84 numWork--) {
85 /* Already enqueued */
86 if (gDvmJit.compilerWorkQueue[i++].pc == pc)
Bill Buzbee964a7b02010-01-28 12:54:19 -080087 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070088 /* Wrap around */
89 if (i == COMPILER_WORK_QUEUE_SIZE)
90 i = 0;
91 }
92
Ben Chengccd6c012009-10-15 14:52:45 -070093 CompilerWorkOrder *newOrder =
94 &gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex];
95 newOrder->pc = pc;
96 newOrder->kind = kind;
97 newOrder->info = info;
Ben Cheng7a2697d2010-06-07 13:44:23 -070098 newOrder->result.methodCompilationAborted = NULL;
Ben Chengccd6c012009-10-15 14:52:45 -070099 newOrder->result.codeAddress = NULL;
100 newOrder->result.discardResult =
Bill Buzbee1f748632010-03-02 16:14:41 -0800101 (kind == kWorkOrderTraceDebug) ? true : false;
buzbee18fba342011-01-19 15:31:15 -0800102 newOrder->result.cacheVersion = gDvmJit.cacheVersion;
Ben Cheng33672452010-01-12 14:59:30 -0800103 newOrder->result.requestingThread = dvmThreadSelf();
104
Ben Chengba4fc8b2009-06-01 13:00:29 -0700105 gDvmJit.compilerWorkEnqueueIndex++;
106 if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
107 gDvmJit.compilerWorkEnqueueIndex = 0;
108 gDvmJit.compilerQueueLength++;
109 cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
110 assert(cc == 0);
111
Bill Buzbee964a7b02010-01-28 12:54:19 -0800112unlockAndExit:
Ben Chengba4fc8b2009-06-01 13:00:29 -0700113 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng60c24f42010-01-04 12:29:56 -0800114 return result;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700115}
116
Ben Cheng11d8f142010-03-24 15:24:19 -0700117/* Block until the queue length is 0, or there is a pending suspend request */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700118void dvmCompilerDrainQueue(void)
119{
Ben Cheng11d8f142010-03-24 15:24:19 -0700120 Thread *self = dvmThreadSelf();
121
Ben Chengba4fc8b2009-06-01 13:00:29 -0700122 dvmLockMutex(&gDvmJit.compilerLock);
Ben Cheng11d8f142010-03-24 15:24:19 -0700123 while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread &&
124 self->suspendCount == 0) {
Ben Cheng812e6b12010-03-15 15:19:06 -0700125 /*
126 * Use timed wait here - more than one mutator threads may be blocked
127 * but the compiler thread will only signal once when the queue is
128 * emptied. Furthermore, the compiler thread may have been shutdown
129 * so the blocked thread may never get the wakeup signal.
130 */
131 dvmRelativeCondWait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock, 1000, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700132 }
133 dvmUnlockMutex(&gDvmJit.compilerLock);
134}
135
Ben Cheng60c24f42010-01-04 12:29:56 -0800136bool dvmCompilerSetupCodeCache(void)
137{
138 extern void dvmCompilerTemplateStart(void);
139 extern void dmvCompilerTemplateEnd(void);
Ben Cheng7c4afdb2010-02-11 15:03:00 -0800140 int fd;
Ben Cheng60c24f42010-01-04 12:29:56 -0800141
142 /* Allocate the code cache */
Ben Cheng7c4afdb2010-02-11 15:03:00 -0800143 fd = ashmem_create_region("dalvik-jit-code-cache", gDvmJit.codeCacheSize);
144 if (fd < 0) {
145 LOGE("Could not create %u-byte ashmem region for the JIT code cache",
146 gDvmJit.codeCacheSize);
147 return false;
148 }
149 gDvmJit.codeCache = mmap(NULL, gDvmJit.codeCacheSize,
150 PROT_READ | PROT_WRITE | PROT_EXEC,
151 MAP_PRIVATE , fd, 0);
152 close(fd);
Ben Cheng60c24f42010-01-04 12:29:56 -0800153 if (gDvmJit.codeCache == MAP_FAILED) {
Ben Cheng7c4afdb2010-02-11 15:03:00 -0800154 LOGE("Failed to mmap the JIT code cache: %s\n", strerror(errno));
Ben Cheng60c24f42010-01-04 12:29:56 -0800155 return false;
156 }
157
Ben Chengb88ec3c2010-05-17 12:50:33 -0700158 gDvmJit.pageSizeMask = getpagesize() - 1;
159
Ben Cheng7c4afdb2010-02-11 15:03:00 -0800160 /* This can be found through "dalvik-jit-code-cache" in /proc/<pid>/maps */
161 // LOGD("Code cache starts at %p", gDvmJit.codeCache);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800162
Ben Cheng60c24f42010-01-04 12:29:56 -0800163 /* Copy the template code into the beginning of the code cache */
164 int templateSize = (intptr_t) dmvCompilerTemplateEnd -
165 (intptr_t) dvmCompilerTemplateStart;
166 memcpy((void *) gDvmJit.codeCache,
167 (void *) dvmCompilerTemplateStart,
168 templateSize);
169
Ben Cheng72621c92010-03-10 13:12:55 -0800170 /*
171 * Work around a CPU bug by keeping the 32-bit ARM handler code in its own
172 * page.
173 */
174 if (dvmCompilerInstructionSet() == DALVIK_JIT_THUMB2) {
175 templateSize = (templateSize + 4095) & ~4095;
176 }
177
Ben Cheng60c24f42010-01-04 12:29:56 -0800178 gDvmJit.templateSize = templateSize;
179 gDvmJit.codeCacheByteUsed = templateSize;
180
181 /* Only flush the part in the code cache that is being used now */
buzbee13fbc2e2010-12-14 11:06:25 -0800182 dvmCompilerCacheFlush((intptr_t) gDvmJit.codeCache,
183 (intptr_t) gDvmJit.codeCache + templateSize, 0);
Ben Chengb88ec3c2010-05-17 12:50:33 -0700184
Ben Cheng1f3da0b2010-06-03 13:52:42 -0700185 int result = mprotect(gDvmJit.codeCache, gDvmJit.codeCacheSize,
186 PROTECT_CODE_CACHE_ATTRS);
187
188 if (result == -1) {
189 LOGE("Failed to remove the write permission for the code cache");
190 dvmAbort();
191 }
Ben Chengb88ec3c2010-05-17 12:50:33 -0700192
Ben Cheng60c24f42010-01-04 12:29:56 -0800193 return true;
194}
195
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800196static void crawlDalvikStack(Thread *thread, bool print)
197{
198 void *fp = thread->curFrame;
199 StackSaveArea* saveArea = NULL;
200 int stackLevel = 0;
201
202 if (print) {
203 LOGD("Crawling tid %d (%s / %p %s)", thread->systemTid,
204 dvmGetThreadStatusStr(thread->status),
205 thread->inJitCodeCache,
206 thread->inJitCodeCache ? "jit" : "interp");
207 }
208 /* Crawl the Dalvik stack frames to clear the returnAddr field */
209 while (fp != NULL) {
210 saveArea = SAVEAREA_FROM_FP(fp);
211
212 if (print) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800213 if (dvmIsBreakFrame((u4*)fp)) {
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800214 LOGD(" #%d: break frame (%p)",
215 stackLevel, saveArea->returnAddr);
216 }
217 else {
218 LOGD(" #%d: %s.%s%s (%p)",
219 stackLevel,
220 saveArea->method->clazz->descriptor,
221 saveArea->method->name,
222 dvmIsNativeMethod(saveArea->method) ?
223 " (native)" : "",
224 saveArea->returnAddr);
225 }
226 }
227 stackLevel++;
228 saveArea->returnAddr = NULL;
229 assert(fp != saveArea->prevFrame);
230 fp = saveArea->prevFrame;
231 }
232 /* Make sure the stack is fully unwound to the bottom */
233 assert(saveArea == NULL ||
234 (u1 *) (saveArea+1) == thread->interpStackStart);
235}
236
Ben Cheng60c24f42010-01-04 12:29:56 -0800237static void resetCodeCache(void)
238{
Ben Cheng60c24f42010-01-04 12:29:56 -0800239 Thread* thread;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800240 u8 startTime = dvmGetRelativeTimeUsec();
241 int inJit = 0;
Ben Cheng6999d842010-01-26 16:46:15 -0800242 int byteUsed = gDvmJit.codeCacheByteUsed;
Ben Cheng60c24f42010-01-04 12:29:56 -0800243
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800244 /* If any thread is found stuck in the JIT state, don't reset the cache */
245 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
Ben Cheng6999d842010-01-26 16:46:15 -0800246 /*
247 * Crawl the stack to wipe out the returnAddr field so that
248 * 1) the soon-to-be-deleted code in the JIT cache won't be used
249 * 2) or the thread stuck in the JIT land will soon return
250 * to the interpreter land
251 */
252 crawlDalvikStack(thread, false);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800253 if (thread->inJitCodeCache) {
254 inJit++;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800255 }
256 }
257
258 if (inJit) {
Ben Cheng6999d842010-01-26 16:46:15 -0800259 LOGD("JIT code cache reset delayed (%d bytes %d/%d)",
260 gDvmJit.codeCacheByteUsed, gDvmJit.numCodeCacheReset,
261 ++gDvmJit.numCodeCacheResetDelayed);
262 return;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800263 }
264
Ben Cheng6999d842010-01-26 16:46:15 -0800265 /* Lock the mutex to clean up the work queue */
266 dvmLockMutex(&gDvmJit.compilerLock);
267
buzbee18fba342011-01-19 15:31:15 -0800268 /* Update the translation cache version */
269 gDvmJit.cacheVersion++;
270
Ben Cheng6999d842010-01-26 16:46:15 -0800271 /* Drain the work queue to free the work orders */
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800272 while (workQueueLength()) {
273 CompilerWorkOrder work = workDequeue();
274 free(work.info);
275 }
276
Ben Cheng60c24f42010-01-04 12:29:56 -0800277 /* Reset the JitEntry table contents to the initial unpopulated state */
278 dvmJitResetTable();
279
Ben Chengb88ec3c2010-05-17 12:50:33 -0700280 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
Ben Cheng60c24f42010-01-04 12:29:56 -0800281 /*
Ben Cheng60c24f42010-01-04 12:29:56 -0800282 * Wipe out the code cache content to force immediate crashes if
283 * stale JIT'ed code is invoked.
284 */
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800285 memset((char *) gDvmJit.codeCache + gDvmJit.templateSize,
286 0,
287 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
buzbee13fbc2e2010-12-14 11:06:25 -0800288 dvmCompilerCacheFlush((intptr_t) gDvmJit.codeCache,
289 (intptr_t) gDvmJit.codeCache +
290 gDvmJit.codeCacheByteUsed, 0);
Ben Cheng60c24f42010-01-04 12:29:56 -0800291
Ben Chengb88ec3c2010-05-17 12:50:33 -0700292 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
293
Ben Cheng60c24f42010-01-04 12:29:56 -0800294 /* Reset the current mark of used bytes to the end of template code */
295 gDvmJit.codeCacheByteUsed = gDvmJit.templateSize;
296 gDvmJit.numCompilations = 0;
297
298 /* Reset the work queue */
299 memset(gDvmJit.compilerWorkQueue, 0,
300 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
301 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
302 gDvmJit.compilerQueueLength = 0;
303
Ben Cheng6999d842010-01-26 16:46:15 -0800304 /* Reset the IC patch work queue */
305 dvmLockMutex(&gDvmJit.compilerICPatchLock);
306 gDvmJit.compilerICPatchIndex = 0;
307 dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
308
Ben Cheng60c24f42010-01-04 12:29:56 -0800309 /* All clear now */
310 gDvmJit.codeCacheFull = false;
311
Ben Cheng6999d842010-01-26 16:46:15 -0800312 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800313
Ben Cheng6999d842010-01-26 16:46:15 -0800314 LOGD("JIT code cache reset in %lld ms (%d bytes %d/%d)",
315 (dvmGetRelativeTimeUsec() - startTime) / 1000,
316 byteUsed, ++gDvmJit.numCodeCacheReset,
317 gDvmJit.numCodeCacheResetDelayed);
318}
319
320/*
321 * Perform actions that are only safe when all threads are suspended. Currently
322 * we do:
323 * 1) Check if the code cache is full. If so reset it and restart populating it
324 * from scratch.
325 * 2) Patch predicted chaining cells by consuming recorded work orders.
326 */
327void dvmCompilerPerformSafePointChecks(void)
328{
329 if (gDvmJit.codeCacheFull) {
330 resetCodeCache();
331 }
332 dvmCompilerPatchInlineCache();
Ben Cheng60c24f42010-01-04 12:29:56 -0800333}
334
Andy McFadden953a0ed2010-09-17 15:48:38 -0700335static bool compilerThreadStartup(void)
Bill Buzbee964a7b02010-01-28 12:54:19 -0800336{
337 JitEntry *pJitTable = NULL;
338 unsigned char *pJitProfTable = NULL;
buzbee2e152ba2010-12-15 16:32:35 -0800339 JitTraceProfCounters *pJitTraceProfCounters = NULL;
Bill Buzbee964a7b02010-01-28 12:54:19 -0800340 unsigned int i;
341
342 if (!dvmCompilerArchInit())
343 goto fail;
344
345 /*
346 * Setup the code cache if we have not inherited a valid code cache
347 * from the zygote.
348 */
349 if (gDvmJit.codeCache == NULL) {
350 if (!dvmCompilerSetupCodeCache())
351 goto fail;
352 }
353
354 /* Allocate the initial arena block */
355 if (dvmCompilerHeapInit() == false) {
356 goto fail;
357 }
358
Bill Buzbee964a7b02010-01-28 12:54:19 -0800359 dvmLockMutex(&gDvmJit.compilerLock);
360
Bill Buzbee964a7b02010-01-28 12:54:19 -0800361 /* Track method-level compilation statistics */
362 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700363
364#if defined(WITH_JIT_TUNING)
Ben Cheng452efba2010-04-30 15:14:00 -0700365 gDvm.verboseShutdown = true;
Ben Cheng1357e942010-02-10 17:21:39 -0800366#endif
Bill Buzbee964a7b02010-01-28 12:54:19 -0800367
368 dvmUnlockMutex(&gDvmJit.compilerLock);
369
370 /* Set up the JitTable */
371
372 /* Power of 2? */
373 assert(gDvmJit.jitTableSize &&
374 !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1)));
375
376 dvmInitMutex(&gDvmJit.tableLock);
377 dvmLockMutex(&gDvmJit.tableLock);
378 pJitTable = (JitEntry*)
379 calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
380 if (!pJitTable) {
381 LOGE("jit table allocation failed\n");
382 dvmUnlockMutex(&gDvmJit.tableLock);
383 goto fail;
384 }
385 /*
386 * NOTE: the profile table must only be allocated once, globally.
387 * Profiling is turned on and off by nulling out gDvm.pJitProfTable
388 * and then restoring its original value. However, this action
389 * is not syncronized for speed so threads may continue to hold
390 * and update the profile table after profiling has been turned
391 * off by null'ng the global pointer. Be aware.
392 */
393 pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE);
394 if (!pJitProfTable) {
395 LOGE("jit prof table allocation failed\n");
396 dvmUnlockMutex(&gDvmJit.tableLock);
397 goto fail;
398 }
399 memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE);
400 for (i=0; i < gDvmJit.jitTableSize; i++) {
401 pJitTable[i].u.info.chain = gDvmJit.jitTableSize;
402 }
403 /* Is chain field wide enough for termination pattern? */
404 assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize);
405
buzbee2e152ba2010-12-15 16:32:35 -0800406 /* Allocate the trace profiling structure */
407 pJitTraceProfCounters = (JitTraceProfCounters*)
408 calloc(1, sizeof(*pJitTraceProfCounters));
409 if (!pJitTraceProfCounters) {
410 LOGE("jit trace prof counters allocation failed\n");
411 dvmUnlockMutex(&gDvmJit.tableLock);
412 goto fail;
413 }
414
Bill Buzbee964a7b02010-01-28 12:54:19 -0800415 gDvmJit.pJitEntryTable = pJitTable;
416 gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
417 gDvmJit.jitTableEntriesUsed = 0;
418 gDvmJit.compilerHighWater =
419 COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
Ben Chenga4973592010-03-31 11:59:18 -0700420 /*
421 * If the VM is launched with wait-on-the-debugger, we will need to hide
422 * the profile table here
423 */
424 gDvmJit.pProfTable = dvmDebuggerOrProfilerActive() ? NULL : pJitProfTable;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800425 gDvmJit.pProfTableCopy = pJitProfTable;
buzbee2e152ba2010-12-15 16:32:35 -0800426 gDvmJit.pJitTraceProfCounters = pJitTraceProfCounters;
Bill Buzbee964a7b02010-01-28 12:54:19 -0800427 dvmUnlockMutex(&gDvmJit.tableLock);
428
429 /* Signal running threads to refresh their cached pJitTable pointers */
430 dvmSuspendAllThreads(SUSPEND_FOR_REFRESH);
431 dvmResumeAllThreads(SUSPEND_FOR_REFRESH);
Ben Chengdca71432010-03-16 16:04:11 -0700432
433 /* Enable signature breakpoints by customizing the following code */
434#if defined(SIGNATURE_BREAKPOINT)
435 /*
436 * Suppose one sees the following native crash in the bugreport:
437 * I/DEBUG ( 1638): Build fingerprint: 'unknown'
438 * I/DEBUG ( 1638): pid: 2468, tid: 2507 >>> com.google.android.gallery3d
439 * I/DEBUG ( 1638): signal 11 (SIGSEGV), fault addr 00001400
440 * I/DEBUG ( 1638): r0 44ea7190 r1 44e4f7b8 r2 44ebc710 r3 00000000
441 * I/DEBUG ( 1638): r4 00000a00 r5 41862dec r6 4710dc10 r7 00000280
442 * I/DEBUG ( 1638): r8 ad010f40 r9 46a37a12 10 001116b0 fp 42a78208
443 * I/DEBUG ( 1638): ip 00000090 sp 4710dbc8 lr ad060e67 pc 46b90682
444 * cpsr 00000030
445 * I/DEBUG ( 1638): #00 pc 46b90682 /dev/ashmem/dalvik-jit-code-cache
446 * I/DEBUG ( 1638): #01 pc 00060e62 /system/lib/libdvm.so
447 *
448 * I/DEBUG ( 1638): code around pc:
449 * I/DEBUG ( 1638): 46b90660 6888d01c 34091dcc d2174287 4a186b68
450 * I/DEBUG ( 1638): 46b90670 d0052800 68006809 28004790 6b68d00e
451 * I/DEBUG ( 1638): 46b90680 512000bc 37016eaf 6ea866af 6f696028
452 * I/DEBUG ( 1638): 46b90690 682a6069 429a686b e003da08 6df1480b
453 * I/DEBUG ( 1638): 46b906a0 1c2d4788 47806d70 46a378fa 47806d70
454 *
455 * Clearly it is a JIT bug. To find out which translation contains the
456 * offending code, the content of the memory dump around the faulting PC
457 * can be pasted into the gDvmJit.signatureBreakpoint[] array and next time
458 * when a similar compilation is being created, the JIT compiler replay the
459 * trace in the verbose mode and one can investigate the instruction
460 * sequence in details.
461 *
462 * The length of the signature may need additional experiments to determine.
463 * The rule of thumb is don't include PC-relative instructions in the
464 * signature since it may be affected by the alignment of the compiled code.
465 * However, a signature that's too short might increase the chance of false
466 * positive matches. Using gdbjithelper to disassembly the memory content
467 * first might be a good companion approach.
468 *
469 * For example, if the next 4 words starting from 46b90680 is pasted into
470 * the data structure:
471 */
472
473 gDvmJit.signatureBreakpointSize = 4;
474 gDvmJit.signatureBreakpoint =
475 malloc(sizeof(u4) * gDvmJit.signatureBreakpointSize);
476 gDvmJit.signatureBreakpoint[0] = 0x512000bc;
477 gDvmJit.signatureBreakpoint[1] = 0x37016eaf;
478 gDvmJit.signatureBreakpoint[2] = 0x6ea866af;
479 gDvmJit.signatureBreakpoint[3] = 0x6f696028;
480
481 /*
482 * The following log will be printed when a match is found in subsequent
483 * testings:
484 *
485 * D/dalvikvm( 2468): Signature match starting from offset 0x34 (4 words)
486 * D/dalvikvm( 2468): --------
487 * D/dalvikvm( 2468): Compiler: Building trace for computeVisibleItems,
488 * offset 0x1f7
489 * D/dalvikvm( 2468): 0x46a37a12: 0x0090 add-int v42, v5, v26
490 * D/dalvikvm( 2468): 0x46a37a16: 0x004d aput-object v13, v14, v42
491 * D/dalvikvm( 2468): 0x46a37a1a: 0x0028 goto, (#0), (#0)
492 * D/dalvikvm( 2468): 0x46a3794e: 0x00d8 add-int/lit8 v26, v26, (#1)
493 * D/dalvikvm( 2468): 0x46a37952: 0x0028 goto, (#0), (#0)
494 * D/dalvikvm( 2468): 0x46a378ee: 0x0002 move/from16 v0, v26, (#0)
495 * D/dalvikvm( 2468): 0x46a378f2: 0x0002 move/from16 v1, v29, (#0)
496 * D/dalvikvm( 2468): 0x46a378f6: 0x0035 if-ge v0, v1, (#10)
497 * D/dalvikvm( 2468): TRACEINFO (554): 0x46a37624
498 * Lcom/cooliris/media/GridLayer;computeVisibleItems 0x1f7 14 of 934, 8
499 * blocks
500 * :
501 * :
502 * D/dalvikvm( 2468): 0x20 (0020): ldr r0, [r5, #52]
503 * D/dalvikvm( 2468): 0x22 (0022): ldr r2, [pc, #96]
504 * D/dalvikvm( 2468): 0x24 (0024): cmp r0, #0
505 * D/dalvikvm( 2468): 0x26 (0026): beq 0x00000034
506 * D/dalvikvm( 2468): 0x28 (0028): ldr r1, [r1, #0]
507 * D/dalvikvm( 2468): 0x2a (002a): ldr r0, [r0, #0]
508 * D/dalvikvm( 2468): 0x2c (002c): blx r2
509 * D/dalvikvm( 2468): 0x2e (002e): cmp r0, #0
510 * D/dalvikvm( 2468): 0x30 (0030): beq 0x00000050
511 * D/dalvikvm( 2468): 0x32 (0032): ldr r0, [r5, #52]
512 * D/dalvikvm( 2468): 0x34 (0034): lsls r4, r7, #2
513 * D/dalvikvm( 2468): 0x36 (0036): str r0, [r4, r4]
514 * D/dalvikvm( 2468): -------- dalvik offset: 0x01fb @ goto, (#0), (#0)
515 * D/dalvikvm( 2468): L0x0195:
516 * D/dalvikvm( 2468): -------- dalvik offset: 0x0195 @ add-int/lit8 v26,
517 * v26, (#1)
518 * D/dalvikvm( 2468): 0x38 (0038): ldr r7, [r5, #104]
519 * D/dalvikvm( 2468): 0x3a (003a): adds r7, r7, #1
520 * D/dalvikvm( 2468): 0x3c (003c): str r7, [r5, #104]
521 * D/dalvikvm( 2468): -------- dalvik offset: 0x0197 @ goto, (#0), (#0)
522 * D/dalvikvm( 2468): L0x0165:
523 * D/dalvikvm( 2468): -------- dalvik offset: 0x0165 @ move/from16 v0, v26,
524 * (#0)
525 * D/dalvikvm( 2468): 0x3e (003e): ldr r0, [r5, #104]
526 * D/dalvikvm( 2468): 0x40 (0040): str r0, [r5, #0]
527 *
528 * The "str r0, [r4, r4]" is indeed the culprit of the native crash.
529 */
530#endif
531
Bill Buzbee964a7b02010-01-28 12:54:19 -0800532 return true;
533
534fail:
535 return false;
536
537}
538
Ben Chengba4fc8b2009-06-01 13:00:29 -0700539static void *compilerThreadStart(void *arg)
540{
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700541 dvmChangeStatus(NULL, THREAD_VMWAIT);
542
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800543 /*
Bill Buzbeeeb695c62010-02-04 16:09:55 -0800544 * If we're not running stand-alone, wait a little before
545 * recieving translation requests on the assumption that process start
546 * up code isn't worth compiling. We'll resume when the framework
547 * signals us that the first screen draw has happened, or the timer
548 * below expires (to catch daemons).
Ben Chengf30acbb2010-02-14 16:17:36 -0800549 *
550 * There is a theoretical race between the callback to
551 * VMRuntime.startJitCompiation and when the compiler thread reaches this
552 * point. In case the callback happens earlier, in order not to permanently
553 * hold the system_server (which is not using the timed wait) in
554 * interpreter-only mode we bypass the delay here.
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800555 */
Ben Chengf30acbb2010-02-14 16:17:36 -0800556 if (gDvmJit.runningInAndroidFramework &&
557 !gDvmJit.alreadyEnabledViaFramework) {
558 /*
559 * If the current VM instance is the system server (detected by having
560 * 0 in gDvm.systemServerPid), we will use the indefinite wait on the
561 * conditional variable to determine whether to start the JIT or not.
562 * If the system server detects that the whole system is booted in
563 * safe mode, the conditional variable will never be signaled and the
564 * system server will remain in the interpreter-only mode. All
565 * subsequent apps will be started with the --enable-safemode flag
566 * explicitly appended.
567 */
568 if (gDvm.systemServerPid == 0) {
569 dvmLockMutex(&gDvmJit.compilerLock);
570 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
571 &gDvmJit.compilerLock);
572 dvmUnlockMutex(&gDvmJit.compilerLock);
573 LOGD("JIT started for system_server");
574 } else {
575 dvmLockMutex(&gDvmJit.compilerLock);
576 /*
577 * TUNING: experiment with the delay & perhaps make it
578 * target-specific
579 */
580 dvmRelativeCondWait(&gDvmJit.compilerQueueActivity,
581 &gDvmJit.compilerLock, 3000, 0);
582 dvmUnlockMutex(&gDvmJit.compilerLock);
583 }
Bill Buzbeeeb695c62010-02-04 16:09:55 -0800584 if (gDvmJit.haltCompilerThread) {
585 return NULL;
586 }
Bill Buzbee94d89f82010-01-29 13:44:19 -0800587 }
588
Bill Buzbee964a7b02010-01-28 12:54:19 -0800589 compilerThreadStartup();
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800590
Ben Chengba4fc8b2009-06-01 13:00:29 -0700591 dvmLockMutex(&gDvmJit.compilerLock);
592 /*
593 * Since the compiler thread will not touch any objects on the heap once
594 * being created, we just fake its state as VMWAIT so that it can be a
595 * bit late when there is suspend request pending.
596 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700597 while (!gDvmJit.haltCompilerThread) {
598 if (workQueueLength() == 0) {
599 int cc;
600 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
601 assert(cc == 0);
602 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
603 &gDvmJit.compilerLock);
604 continue;
605 } else {
606 do {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700607 CompilerWorkOrder work = workDequeue();
608 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng978738d2010-05-13 13:45:57 -0700609#if defined(WITH_JIT_TUNING)
Ben Cheng86717f72010-03-05 15:27:21 -0800610 u8 startTime = dvmGetRelativeTimeUsec();
611#endif
Bill Buzbee964a7b02010-01-28 12:54:19 -0800612 /*
613 * Check whether there is a suspend request on me. This
614 * is necessary to allow a clean shutdown.
Ben Cheng11d8f142010-03-24 15:24:19 -0700615 *
616 * However, in the blocking stress testing mode, let the
617 * compiler thread continue doing compilations to unblock
618 * other requesting threads. This may occasionally cause
619 * shutdown from proceeding cleanly in the standalone invocation
620 * of the vm but this should be acceptable.
Bill Buzbee964a7b02010-01-28 12:54:19 -0800621 */
Ben Cheng11d8f142010-03-24 15:24:19 -0700622 if (!gDvmJit.blockingMode)
Andy McFaddenab227f72010-04-06 12:37:48 -0700623 dvmCheckSuspendPending(dvmThreadSelf());
Bill Buzbee27176222009-06-09 09:20:16 -0700624 /* Is JitTable filling up? */
625 if (gDvmJit.jitTableEntriesUsed >
626 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
Ben Cheng6999d842010-01-26 16:46:15 -0800627 bool resizeFail =
628 dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
629 /*
630 * If the jit table is full, consider it's time to reset
631 * the code cache too.
632 */
633 gDvmJit.codeCacheFull |= resizeFail;
Bill Buzbee27176222009-06-09 09:20:16 -0700634 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700635 if (gDvmJit.haltCompilerThread) {
636 LOGD("Compiler shutdown in progress - discarding request");
Ben Cheng6999d842010-01-26 16:46:15 -0800637 } else if (!gDvmJit.codeCacheFull) {
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800638 jmp_buf jmpBuf;
639 work.bailPtr = &jmpBuf;
640 bool aborted = setjmp(jmpBuf);
641 if (!aborted) {
buzbee2e152ba2010-12-15 16:32:35 -0800642 bool codeCompiled = dvmCompilerDoWork(&work);
643 if (codeCompiled && !work.result.discardResult &&
644 work.result.codeAddress) {
645 dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
646 work.result.instructionSet,
Ben Chengcfdeca32011-01-14 11:36:46 -0800647 false, /* not method entry */
buzbee2e152ba2010-12-15 16:32:35 -0800648 work.result.profileCodeSize);
649 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700650 }
buzbee2e152ba2010-12-15 16:32:35 -0800651 dvmCompilerArenaReset();
Ben Chengba4fc8b2009-06-01 13:00:29 -0700652 }
653 free(work.info);
Ben Cheng978738d2010-05-13 13:45:57 -0700654#if defined(WITH_JIT_TUNING)
Ben Cheng86717f72010-03-05 15:27:21 -0800655 gDvmJit.jitTime += dvmGetRelativeTimeUsec() - startTime;
656#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700657 dvmLockMutex(&gDvmJit.compilerLock);
658 } while (workQueueLength() != 0);
659 }
660 }
661 pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
662 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Chengef00a852009-06-22 22:53:35 -0700663
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700664 /*
665 * As part of detaching the thread we need to call into Java code to update
666 * the ThreadGroup, and we should not be in VMWAIT state while executing
667 * interpreted code.
668 */
669 dvmChangeStatus(NULL, THREAD_RUNNING);
670
Andy McFadden43eb5012010-02-01 16:56:53 -0800671 if (gDvm.verboseShutdown)
672 LOGD("Compiler thread shutting down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700673 return NULL;
674}
675
Ben Chengba4fc8b2009-06-01 13:00:29 -0700676bool dvmCompilerStartup(void)
677{
Bill Buzbee94d89f82010-01-29 13:44:19 -0800678
679 dvmInitMutex(&gDvmJit.compilerLock);
Ben Cheng6999d842010-01-26 16:46:15 -0800680 dvmInitMutex(&gDvmJit.compilerICPatchLock);
Ben Chengb88ec3c2010-05-17 12:50:33 -0700681 dvmInitMutex(&gDvmJit.codeCacheProtectionLock);
Bill Buzbee94d89f82010-01-29 13:44:19 -0800682 dvmLockMutex(&gDvmJit.compilerLock);
683 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
684 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
685
686 /* Reset the work queue */
687 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
688 gDvmJit.compilerQueueLength = 0;
689 dvmUnlockMutex(&gDvmJit.compilerLock);
690
Ben Chengba4fc8b2009-06-01 13:00:29 -0700691 /*
Bill Buzbee94d89f82010-01-29 13:44:19 -0800692 * Defer rest of initialization until we're sure JIT'ng makes sense. Launch
Bill Buzbee964a7b02010-01-28 12:54:19 -0800693 * the compiler thread, which will do the real initialization if and
694 * when it is signalled to do so.
Ben Chengba4fc8b2009-06-01 13:00:29 -0700695 */
Bill Buzbee964a7b02010-01-28 12:54:19 -0800696 return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
697 compilerThreadStart, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700698}
699
700void dvmCompilerShutdown(void)
701{
702 void *threadReturn;
703
Bill Buzbee2fc03c32010-03-08 11:30:19 -0800704 /* Disable new translation requests */
705 gDvmJit.pProfTable = NULL;
706 gDvmJit.pProfTableCopy = NULL;
707
buzbee2e152ba2010-12-15 16:32:35 -0800708 if (gDvm.verboseShutdown ||
709 gDvmJit.profileMode == kTraceProfilingContinuous) {
Ben Cheng88a0f972010-02-24 15:00:40 -0800710 dvmCompilerDumpStats();
711 while (gDvmJit.compilerQueueLength)
712 sleep(5);
713 }
714
Ben Chengba4fc8b2009-06-01 13:00:29 -0700715 if (gDvmJit.compilerHandle) {
716
717 gDvmJit.haltCompilerThread = true;
718
719 dvmLockMutex(&gDvmJit.compilerLock);
720 pthread_cond_signal(&gDvmJit.compilerQueueActivity);
721 dvmUnlockMutex(&gDvmJit.compilerLock);
722
Ben Chengef00a852009-06-22 22:53:35 -0700723 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
724 LOGW("Compiler thread join failed\n");
Andy McFadden43eb5012010-02-01 16:56:53 -0800725 else if (gDvm.verboseShutdown)
Ben Chengef00a852009-06-22 22:53:35 -0700726 LOGD("Compiler thread has shut down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700727 }
Bill Buzbee06bb8392010-01-31 18:53:15 -0800728
Bill Buzbee2fc03c32010-03-08 11:30:19 -0800729 /* Break loops within the translation cache */
730 dvmJitUnchainAll();
Bill Buzbee96cfe6c2010-02-08 17:08:15 -0800731
Bill Buzbee2fc03c32010-03-08 11:30:19 -0800732 /*
733 * NOTE: our current implementatation doesn't allow for the compiler
734 * thread to be restarted after it exits here. We aren't freeing
735 * the JitTable or the ProfTable because threads which still may be
736 * running or in the process of shutting down may hold references to
737 * them.
738 */
Bill Buzbee96cfe6c2010-02-08 17:08:15 -0800739}
Bill Buzbee06bb8392010-01-31 18:53:15 -0800740
741void dvmCompilerStateRefresh()
742{
743 bool jitActive;
744 bool jitActivate;
Bill Buzbee3e392682010-02-03 18:13:57 -0800745 bool needUnchain = false;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800746
Ben Chenga4973592010-03-31 11:59:18 -0700747 /*
748 * The tableLock might not be initialized yet by the compiler thread if
749 * debugger is attached from the very beginning of the VM launch. If
750 * pProfTableCopy is NULL, the lock is not initialized yet and we don't
751 * need to refresh anything either.
752 */
753 if (gDvmJit.pProfTableCopy == NULL) {
754 return;
755 }
756
buzbee18fba342011-01-19 15:31:15 -0800757 /*
758 * On the first enabling of method tracing, switch the compiler
759 * into a mode that includes trace support for invokes and returns.
760 * If there are any existing translations, flush them. NOTE: we
761 * can't blindly flush the translation cache because this code
762 * may be executed before the compiler thread has finished
763 * initialization.
764 */
765 if ((gDvm.interpBreak & kSubModeMethodTrace) &&
766 !gDvmJit.methodTraceSupport) {
767 bool resetRequired;
768 /*
769 * compilerLock will prevent new compilations from being
770 * installed while we are working.
771 */
772 dvmLockMutex(&gDvmJit.compilerLock);
773 gDvmJit.cacheVersion++; // invalidate compilations in flight
774 gDvmJit.methodTraceSupport = true;
775 resetRequired = (gDvmJit.numCompilations != 0);
776 dvmUnlockMutex(&gDvmJit.compilerLock);
777 if (resetRequired) {
778 dvmSuspendAllThreads(SUSPEND_FOR_CC_RESET);
779 resetCodeCache();
780 dvmResumeAllThreads(SUSPEND_FOR_CC_RESET);
781 }
782 }
783
Bill Buzbee06bb8392010-01-31 18:53:15 -0800784 dvmLockMutex(&gDvmJit.tableLock);
785 jitActive = gDvmJit.pProfTable != NULL;
buzbeecb3081f2011-01-14 13:37:31 -0800786 jitActivate = !dvmDebuggerOrProfilerActive();
Bill Buzbee06bb8392010-01-31 18:53:15 -0800787
788 if (jitActivate && !jitActive) {
789 gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800790 } else if (!jitActivate && jitActive) {
791 gDvmJit.pProfTable = NULL;
Bill Buzbee3e392682010-02-03 18:13:57 -0800792 needUnchain = true;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800793 }
Bill Buzbee3e392682010-02-03 18:13:57 -0800794 dvmUnlockMutex(&gDvmJit.tableLock);
795 if (needUnchain)
796 dvmJitUnchainAll();
Bill Buzbee06bb8392010-01-31 18:53:15 -0800797}