blob: 63f751245f7373a5f746f95cc06eec2d9fcfd6f7 [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) {
43 int cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
Carl Shapiroe3c01da2010-05-20 22:54:18 -070044 assert(cc == 0);
Bill Buzbeef9f33282009-11-22 12:45:30 -080045 }
Ben Chengba4fc8b2009-06-01 13:00:29 -070046
47 /* Remember the high water mark of the queue length */
48 if (gDvmJit.compilerQueueLength > gDvmJit.compilerMaxQueued)
49 gDvmJit.compilerMaxQueued = gDvmJit.compilerQueueLength;
50
51 return work;
52}
53
Bill Buzbee964a7b02010-01-28 12:54:19 -080054/*
55 * Attempt to enqueue a work order, returning true if successful.
56 * This routine will not block, but simply return if it couldn't
57 * aquire the lock or if the queue is full.
Ben Cheng1357e942010-02-10 17:21:39 -080058 *
59 * NOTE: Make sure that the caller frees the info pointer if the return value
60 * is false.
Bill Buzbee964a7b02010-01-28 12:54:19 -080061 */
Ben Chengba4fc8b2009-06-01 13:00:29 -070062bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
63{
64 int cc;
65 int i;
66 int numWork;
Ben Cheng60c24f42010-01-04 12:29:56 -080067 bool result = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -070068
Bill Buzbee964a7b02010-01-28 12:54:19 -080069 if (dvmTryLockMutex(&gDvmJit.compilerLock)) {
Ben Cheng3e5cd172010-02-08 20:57:59 -080070 return false; // Couldn't acquire the lock
Bill Buzbee964a7b02010-01-28 12:54:19 -080071 }
Ben Chengba4fc8b2009-06-01 13:00:29 -070072
Ben Cheng7a0bcd02010-01-22 16:45:45 -080073 /*
Ben Cheng6999d842010-01-26 16:46:15 -080074 * Return if queue or code cache is full.
Ben Cheng7a0bcd02010-01-22 16:45:45 -080075 */
Ben Cheng6999d842010-01-26 16:46:15 -080076 if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE ||
77 gDvmJit.codeCacheFull == true) {
Ben Cheng60c24f42010-01-04 12:29:56 -080078 result = false;
Bill Buzbee964a7b02010-01-28 12:54:19 -080079 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070080 }
81
82 for (numWork = gDvmJit.compilerQueueLength,
83 i = gDvmJit.compilerWorkDequeueIndex;
84 numWork > 0;
85 numWork--) {
86 /* Already enqueued */
87 if (gDvmJit.compilerWorkQueue[i++].pc == pc)
Bill Buzbee964a7b02010-01-28 12:54:19 -080088 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070089 /* Wrap around */
90 if (i == COMPILER_WORK_QUEUE_SIZE)
91 i = 0;
92 }
93
Ben Chengccd6c012009-10-15 14:52:45 -070094 CompilerWorkOrder *newOrder =
95 &gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex];
96 newOrder->pc = pc;
97 newOrder->kind = kind;
98 newOrder->info = info;
99 newOrder->result.codeAddress = NULL;
100 newOrder->result.discardResult =
Bill Buzbee1f748632010-03-02 16:14:41 -0800101 (kind == kWorkOrderTraceDebug) ? true : false;
Ben Cheng33672452010-01-12 14:59:30 -0800102 newOrder->result.requestingThread = dvmThreadSelf();
103
Ben Chengba4fc8b2009-06-01 13:00:29 -0700104 gDvmJit.compilerWorkEnqueueIndex++;
105 if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
106 gDvmJit.compilerWorkEnqueueIndex = 0;
107 gDvmJit.compilerQueueLength++;
108 cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
109 assert(cc == 0);
110
Bill Buzbee964a7b02010-01-28 12:54:19 -0800111unlockAndExit:
Ben Chengba4fc8b2009-06-01 13:00:29 -0700112 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng60c24f42010-01-04 12:29:56 -0800113 return result;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700114}
115
Ben Cheng11d8f142010-03-24 15:24:19 -0700116/* Block until the queue length is 0, or there is a pending suspend request */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700117void dvmCompilerDrainQueue(void)
118{
Ben Cheng11d8f142010-03-24 15:24:19 -0700119 Thread *self = dvmThreadSelf();
120
Ben Chengba4fc8b2009-06-01 13:00:29 -0700121 dvmLockMutex(&gDvmJit.compilerLock);
Ben Cheng11d8f142010-03-24 15:24:19 -0700122 while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread &&
123 self->suspendCount == 0) {
Ben Cheng812e6b12010-03-15 15:19:06 -0700124 /*
125 * Use timed wait here - more than one mutator threads may be blocked
126 * but the compiler thread will only signal once when the queue is
127 * emptied. Furthermore, the compiler thread may have been shutdown
128 * so the blocked thread may never get the wakeup signal.
129 */
130 dvmRelativeCondWait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock, 1000, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700131 }
132 dvmUnlockMutex(&gDvmJit.compilerLock);
133}
134
Ben Cheng60c24f42010-01-04 12:29:56 -0800135bool dvmCompilerSetupCodeCache(void)
136{
137 extern void dvmCompilerTemplateStart(void);
138 extern void dmvCompilerTemplateEnd(void);
Ben Cheng7c4afdb2010-02-11 15:03:00 -0800139 int fd;
Ben Cheng60c24f42010-01-04 12:29:56 -0800140
141 /* Allocate the code cache */
Ben Cheng7c4afdb2010-02-11 15:03:00 -0800142 fd = ashmem_create_region("dalvik-jit-code-cache", gDvmJit.codeCacheSize);
143 if (fd < 0) {
144 LOGE("Could not create %u-byte ashmem region for the JIT code cache",
145 gDvmJit.codeCacheSize);
146 return false;
147 }
148 gDvmJit.codeCache = mmap(NULL, gDvmJit.codeCacheSize,
149 PROT_READ | PROT_WRITE | PROT_EXEC,
150 MAP_PRIVATE , fd, 0);
151 close(fd);
Ben Cheng60c24f42010-01-04 12:29:56 -0800152 if (gDvmJit.codeCache == MAP_FAILED) {
Ben Cheng7c4afdb2010-02-11 15:03:00 -0800153 LOGE("Failed to mmap the JIT code cache: %s\n", strerror(errno));
Ben Cheng60c24f42010-01-04 12:29:56 -0800154 return false;
155 }
156
Ben Cheng7c4afdb2010-02-11 15:03:00 -0800157 /* This can be found through "dalvik-jit-code-cache" in /proc/<pid>/maps */
158 // LOGD("Code cache starts at %p", gDvmJit.codeCache);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800159
Ben Cheng60c24f42010-01-04 12:29:56 -0800160 /* Copy the template code into the beginning of the code cache */
161 int templateSize = (intptr_t) dmvCompilerTemplateEnd -
162 (intptr_t) dvmCompilerTemplateStart;
163 memcpy((void *) gDvmJit.codeCache,
164 (void *) dvmCompilerTemplateStart,
165 templateSize);
166
Ben Cheng72621c92010-03-10 13:12:55 -0800167 /*
168 * Work around a CPU bug by keeping the 32-bit ARM handler code in its own
169 * page.
170 */
171 if (dvmCompilerInstructionSet() == DALVIK_JIT_THUMB2) {
172 templateSize = (templateSize + 4095) & ~4095;
173 }
174
Ben Cheng60c24f42010-01-04 12:29:56 -0800175 gDvmJit.templateSize = templateSize;
176 gDvmJit.codeCacheByteUsed = templateSize;
177
178 /* Only flush the part in the code cache that is being used now */
179 cacheflush((intptr_t) gDvmJit.codeCache,
180 (intptr_t) gDvmJit.codeCache + templateSize, 0);
181 return true;
182}
183
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800184static void crawlDalvikStack(Thread *thread, bool print)
185{
186 void *fp = thread->curFrame;
187 StackSaveArea* saveArea = NULL;
188 int stackLevel = 0;
189
190 if (print) {
191 LOGD("Crawling tid %d (%s / %p %s)", thread->systemTid,
192 dvmGetThreadStatusStr(thread->status),
193 thread->inJitCodeCache,
194 thread->inJitCodeCache ? "jit" : "interp");
195 }
196 /* Crawl the Dalvik stack frames to clear the returnAddr field */
197 while (fp != NULL) {
198 saveArea = SAVEAREA_FROM_FP(fp);
199
200 if (print) {
201 if (dvmIsBreakFrame(fp)) {
202 LOGD(" #%d: break frame (%p)",
203 stackLevel, saveArea->returnAddr);
204 }
205 else {
206 LOGD(" #%d: %s.%s%s (%p)",
207 stackLevel,
208 saveArea->method->clazz->descriptor,
209 saveArea->method->name,
210 dvmIsNativeMethod(saveArea->method) ?
211 " (native)" : "",
212 saveArea->returnAddr);
213 }
214 }
215 stackLevel++;
216 saveArea->returnAddr = NULL;
217 assert(fp != saveArea->prevFrame);
218 fp = saveArea->prevFrame;
219 }
220 /* Make sure the stack is fully unwound to the bottom */
221 assert(saveArea == NULL ||
222 (u1 *) (saveArea+1) == thread->interpStackStart);
223}
224
Ben Cheng60c24f42010-01-04 12:29:56 -0800225static void resetCodeCache(void)
226{
Ben Cheng60c24f42010-01-04 12:29:56 -0800227 Thread* thread;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800228 u8 startTime = dvmGetRelativeTimeUsec();
229 int inJit = 0;
Ben Cheng6999d842010-01-26 16:46:15 -0800230 int byteUsed = gDvmJit.codeCacheByteUsed;
Ben Cheng60c24f42010-01-04 12:29:56 -0800231
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800232 /* If any thread is found stuck in the JIT state, don't reset the cache */
233 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
Ben Cheng6999d842010-01-26 16:46:15 -0800234 /*
235 * Crawl the stack to wipe out the returnAddr field so that
236 * 1) the soon-to-be-deleted code in the JIT cache won't be used
237 * 2) or the thread stuck in the JIT land will soon return
238 * to the interpreter land
239 */
240 crawlDalvikStack(thread, false);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800241 if (thread->inJitCodeCache) {
242 inJit++;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800243 }
244 }
245
246 if (inJit) {
Ben Cheng6999d842010-01-26 16:46:15 -0800247 LOGD("JIT code cache reset delayed (%d bytes %d/%d)",
248 gDvmJit.codeCacheByteUsed, gDvmJit.numCodeCacheReset,
249 ++gDvmJit.numCodeCacheResetDelayed);
250 return;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800251 }
252
Ben Cheng6999d842010-01-26 16:46:15 -0800253 /* Lock the mutex to clean up the work queue */
254 dvmLockMutex(&gDvmJit.compilerLock);
255
256 /* Drain the work queue to free the work orders */
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800257 while (workQueueLength()) {
258 CompilerWorkOrder work = workDequeue();
259 free(work.info);
260 }
261
Ben Cheng60c24f42010-01-04 12:29:56 -0800262 /* Reset the JitEntry table contents to the initial unpopulated state */
263 dvmJitResetTable();
264
Ben Cheng60c24f42010-01-04 12:29:56 -0800265 /*
Ben Cheng60c24f42010-01-04 12:29:56 -0800266 * Wipe out the code cache content to force immediate crashes if
267 * stale JIT'ed code is invoked.
268 */
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800269 memset((char *) gDvmJit.codeCache + gDvmJit.templateSize,
270 0,
271 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
Ben Cheng60c24f42010-01-04 12:29:56 -0800272 cacheflush((intptr_t) gDvmJit.codeCache,
273 (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed, 0);
Ben Cheng60c24f42010-01-04 12:29:56 -0800274
275 /* Reset the current mark of used bytes to the end of template code */
276 gDvmJit.codeCacheByteUsed = gDvmJit.templateSize;
277 gDvmJit.numCompilations = 0;
278
279 /* Reset the work queue */
280 memset(gDvmJit.compilerWorkQueue, 0,
281 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
282 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
283 gDvmJit.compilerQueueLength = 0;
284
Ben Cheng6999d842010-01-26 16:46:15 -0800285 /* Reset the IC patch work queue */
286 dvmLockMutex(&gDvmJit.compilerICPatchLock);
287 gDvmJit.compilerICPatchIndex = 0;
288 dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
289
Ben Cheng60c24f42010-01-04 12:29:56 -0800290 /* All clear now */
291 gDvmJit.codeCacheFull = false;
292
Ben Cheng6999d842010-01-26 16:46:15 -0800293 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800294
Ben Cheng6999d842010-01-26 16:46:15 -0800295 LOGD("JIT code cache reset in %lld ms (%d bytes %d/%d)",
296 (dvmGetRelativeTimeUsec() - startTime) / 1000,
297 byteUsed, ++gDvmJit.numCodeCacheReset,
298 gDvmJit.numCodeCacheResetDelayed);
299}
300
301/*
302 * Perform actions that are only safe when all threads are suspended. Currently
303 * we do:
304 * 1) Check if the code cache is full. If so reset it and restart populating it
305 * from scratch.
306 * 2) Patch predicted chaining cells by consuming recorded work orders.
307 */
308void dvmCompilerPerformSafePointChecks(void)
309{
310 if (gDvmJit.codeCacheFull) {
311 resetCodeCache();
312 }
313 dvmCompilerPatchInlineCache();
Ben Cheng60c24f42010-01-04 12:29:56 -0800314}
315
Bill Buzbee964a7b02010-01-28 12:54:19 -0800316bool compilerThreadStartup(void)
317{
318 JitEntry *pJitTable = NULL;
319 unsigned char *pJitProfTable = NULL;
320 unsigned int i;
321
322 if (!dvmCompilerArchInit())
323 goto fail;
324
325 /*
326 * Setup the code cache if we have not inherited a valid code cache
327 * from the zygote.
328 */
329 if (gDvmJit.codeCache == NULL) {
330 if (!dvmCompilerSetupCodeCache())
331 goto fail;
332 }
333
334 /* Allocate the initial arena block */
335 if (dvmCompilerHeapInit() == false) {
336 goto fail;
337 }
338
Bill Buzbee964a7b02010-01-28 12:54:19 -0800339 dvmLockMutex(&gDvmJit.compilerLock);
340
Ben Cheng1357e942010-02-10 17:21:39 -0800341#if defined(WITH_JIT_TUNING)
Bill Buzbee964a7b02010-01-28 12:54:19 -0800342 /* Track method-level compilation statistics */
343 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
Ben Cheng452efba2010-04-30 15:14:00 -0700344 gDvm.verboseShutdown = true;
Ben Cheng1357e942010-02-10 17:21:39 -0800345#endif
Bill Buzbee964a7b02010-01-28 12:54:19 -0800346
347 dvmUnlockMutex(&gDvmJit.compilerLock);
348
349 /* Set up the JitTable */
350
351 /* Power of 2? */
352 assert(gDvmJit.jitTableSize &&
353 !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1)));
354
355 dvmInitMutex(&gDvmJit.tableLock);
356 dvmLockMutex(&gDvmJit.tableLock);
357 pJitTable = (JitEntry*)
358 calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
359 if (!pJitTable) {
360 LOGE("jit table allocation failed\n");
361 dvmUnlockMutex(&gDvmJit.tableLock);
362 goto fail;
363 }
364 /*
365 * NOTE: the profile table must only be allocated once, globally.
366 * Profiling is turned on and off by nulling out gDvm.pJitProfTable
367 * and then restoring its original value. However, this action
368 * is not syncronized for speed so threads may continue to hold
369 * and update the profile table after profiling has been turned
370 * off by null'ng the global pointer. Be aware.
371 */
372 pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE);
373 if (!pJitProfTable) {
374 LOGE("jit prof table allocation failed\n");
375 dvmUnlockMutex(&gDvmJit.tableLock);
376 goto fail;
377 }
378 memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE);
379 for (i=0; i < gDvmJit.jitTableSize; i++) {
380 pJitTable[i].u.info.chain = gDvmJit.jitTableSize;
381 }
382 /* Is chain field wide enough for termination pattern? */
383 assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize);
384
385 gDvmJit.pJitEntryTable = pJitTable;
386 gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
387 gDvmJit.jitTableEntriesUsed = 0;
388 gDvmJit.compilerHighWater =
389 COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
Ben Chenga4973592010-03-31 11:59:18 -0700390 /*
391 * If the VM is launched with wait-on-the-debugger, we will need to hide
392 * the profile table here
393 */
394 gDvmJit.pProfTable = dvmDebuggerOrProfilerActive() ? NULL : pJitProfTable;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800395 gDvmJit.pProfTableCopy = pJitProfTable;
Bill Buzbee964a7b02010-01-28 12:54:19 -0800396 dvmUnlockMutex(&gDvmJit.tableLock);
397
398 /* Signal running threads to refresh their cached pJitTable pointers */
399 dvmSuspendAllThreads(SUSPEND_FOR_REFRESH);
400 dvmResumeAllThreads(SUSPEND_FOR_REFRESH);
Ben Chengdca71432010-03-16 16:04:11 -0700401
402 /* Enable signature breakpoints by customizing the following code */
403#if defined(SIGNATURE_BREAKPOINT)
404 /*
405 * Suppose one sees the following native crash in the bugreport:
406 * I/DEBUG ( 1638): Build fingerprint: 'unknown'
407 * I/DEBUG ( 1638): pid: 2468, tid: 2507 >>> com.google.android.gallery3d
408 * I/DEBUG ( 1638): signal 11 (SIGSEGV), fault addr 00001400
409 * I/DEBUG ( 1638): r0 44ea7190 r1 44e4f7b8 r2 44ebc710 r3 00000000
410 * I/DEBUG ( 1638): r4 00000a00 r5 41862dec r6 4710dc10 r7 00000280
411 * I/DEBUG ( 1638): r8 ad010f40 r9 46a37a12 10 001116b0 fp 42a78208
412 * I/DEBUG ( 1638): ip 00000090 sp 4710dbc8 lr ad060e67 pc 46b90682
413 * cpsr 00000030
414 * I/DEBUG ( 1638): #00 pc 46b90682 /dev/ashmem/dalvik-jit-code-cache
415 * I/DEBUG ( 1638): #01 pc 00060e62 /system/lib/libdvm.so
416 *
417 * I/DEBUG ( 1638): code around pc:
418 * I/DEBUG ( 1638): 46b90660 6888d01c 34091dcc d2174287 4a186b68
419 * I/DEBUG ( 1638): 46b90670 d0052800 68006809 28004790 6b68d00e
420 * I/DEBUG ( 1638): 46b90680 512000bc 37016eaf 6ea866af 6f696028
421 * I/DEBUG ( 1638): 46b90690 682a6069 429a686b e003da08 6df1480b
422 * I/DEBUG ( 1638): 46b906a0 1c2d4788 47806d70 46a378fa 47806d70
423 *
424 * Clearly it is a JIT bug. To find out which translation contains the
425 * offending code, the content of the memory dump around the faulting PC
426 * can be pasted into the gDvmJit.signatureBreakpoint[] array and next time
427 * when a similar compilation is being created, the JIT compiler replay the
428 * trace in the verbose mode and one can investigate the instruction
429 * sequence in details.
430 *
431 * The length of the signature may need additional experiments to determine.
432 * The rule of thumb is don't include PC-relative instructions in the
433 * signature since it may be affected by the alignment of the compiled code.
434 * However, a signature that's too short might increase the chance of false
435 * positive matches. Using gdbjithelper to disassembly the memory content
436 * first might be a good companion approach.
437 *
438 * For example, if the next 4 words starting from 46b90680 is pasted into
439 * the data structure:
440 */
441
442 gDvmJit.signatureBreakpointSize = 4;
443 gDvmJit.signatureBreakpoint =
444 malloc(sizeof(u4) * gDvmJit.signatureBreakpointSize);
445 gDvmJit.signatureBreakpoint[0] = 0x512000bc;
446 gDvmJit.signatureBreakpoint[1] = 0x37016eaf;
447 gDvmJit.signatureBreakpoint[2] = 0x6ea866af;
448 gDvmJit.signatureBreakpoint[3] = 0x6f696028;
449
450 /*
451 * The following log will be printed when a match is found in subsequent
452 * testings:
453 *
454 * D/dalvikvm( 2468): Signature match starting from offset 0x34 (4 words)
455 * D/dalvikvm( 2468): --------
456 * D/dalvikvm( 2468): Compiler: Building trace for computeVisibleItems,
457 * offset 0x1f7
458 * D/dalvikvm( 2468): 0x46a37a12: 0x0090 add-int v42, v5, v26
459 * D/dalvikvm( 2468): 0x46a37a16: 0x004d aput-object v13, v14, v42
460 * D/dalvikvm( 2468): 0x46a37a1a: 0x0028 goto, (#0), (#0)
461 * D/dalvikvm( 2468): 0x46a3794e: 0x00d8 add-int/lit8 v26, v26, (#1)
462 * D/dalvikvm( 2468): 0x46a37952: 0x0028 goto, (#0), (#0)
463 * D/dalvikvm( 2468): 0x46a378ee: 0x0002 move/from16 v0, v26, (#0)
464 * D/dalvikvm( 2468): 0x46a378f2: 0x0002 move/from16 v1, v29, (#0)
465 * D/dalvikvm( 2468): 0x46a378f6: 0x0035 if-ge v0, v1, (#10)
466 * D/dalvikvm( 2468): TRACEINFO (554): 0x46a37624
467 * Lcom/cooliris/media/GridLayer;computeVisibleItems 0x1f7 14 of 934, 8
468 * blocks
469 * :
470 * :
471 * D/dalvikvm( 2468): 0x20 (0020): ldr r0, [r5, #52]
472 * D/dalvikvm( 2468): 0x22 (0022): ldr r2, [pc, #96]
473 * D/dalvikvm( 2468): 0x24 (0024): cmp r0, #0
474 * D/dalvikvm( 2468): 0x26 (0026): beq 0x00000034
475 * D/dalvikvm( 2468): 0x28 (0028): ldr r1, [r1, #0]
476 * D/dalvikvm( 2468): 0x2a (002a): ldr r0, [r0, #0]
477 * D/dalvikvm( 2468): 0x2c (002c): blx r2
478 * D/dalvikvm( 2468): 0x2e (002e): cmp r0, #0
479 * D/dalvikvm( 2468): 0x30 (0030): beq 0x00000050
480 * D/dalvikvm( 2468): 0x32 (0032): ldr r0, [r5, #52]
481 * D/dalvikvm( 2468): 0x34 (0034): lsls r4, r7, #2
482 * D/dalvikvm( 2468): 0x36 (0036): str r0, [r4, r4]
483 * D/dalvikvm( 2468): -------- dalvik offset: 0x01fb @ goto, (#0), (#0)
484 * D/dalvikvm( 2468): L0x0195:
485 * D/dalvikvm( 2468): -------- dalvik offset: 0x0195 @ add-int/lit8 v26,
486 * v26, (#1)
487 * D/dalvikvm( 2468): 0x38 (0038): ldr r7, [r5, #104]
488 * D/dalvikvm( 2468): 0x3a (003a): adds r7, r7, #1
489 * D/dalvikvm( 2468): 0x3c (003c): str r7, [r5, #104]
490 * D/dalvikvm( 2468): -------- dalvik offset: 0x0197 @ goto, (#0), (#0)
491 * D/dalvikvm( 2468): L0x0165:
492 * D/dalvikvm( 2468): -------- dalvik offset: 0x0165 @ move/from16 v0, v26,
493 * (#0)
494 * D/dalvikvm( 2468): 0x3e (003e): ldr r0, [r5, #104]
495 * D/dalvikvm( 2468): 0x40 (0040): str r0, [r5, #0]
496 *
497 * The "str r0, [r4, r4]" is indeed the culprit of the native crash.
498 */
499#endif
500
Bill Buzbee964a7b02010-01-28 12:54:19 -0800501 return true;
502
503fail:
504 return false;
505
506}
507
Ben Chengba4fc8b2009-06-01 13:00:29 -0700508static void *compilerThreadStart(void *arg)
509{
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700510 dvmChangeStatus(NULL, THREAD_VMWAIT);
511
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800512 /*
Bill Buzbeeeb695c62010-02-04 16:09:55 -0800513 * If we're not running stand-alone, wait a little before
514 * recieving translation requests on the assumption that process start
515 * up code isn't worth compiling. We'll resume when the framework
516 * signals us that the first screen draw has happened, or the timer
517 * below expires (to catch daemons).
Ben Chengf30acbb2010-02-14 16:17:36 -0800518 *
519 * There is a theoretical race between the callback to
520 * VMRuntime.startJitCompiation and when the compiler thread reaches this
521 * point. In case the callback happens earlier, in order not to permanently
522 * hold the system_server (which is not using the timed wait) in
523 * interpreter-only mode we bypass the delay here.
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800524 */
Ben Chengf30acbb2010-02-14 16:17:36 -0800525 if (gDvmJit.runningInAndroidFramework &&
526 !gDvmJit.alreadyEnabledViaFramework) {
527 /*
528 * If the current VM instance is the system server (detected by having
529 * 0 in gDvm.systemServerPid), we will use the indefinite wait on the
530 * conditional variable to determine whether to start the JIT or not.
531 * If the system server detects that the whole system is booted in
532 * safe mode, the conditional variable will never be signaled and the
533 * system server will remain in the interpreter-only mode. All
534 * subsequent apps will be started with the --enable-safemode flag
535 * explicitly appended.
536 */
537 if (gDvm.systemServerPid == 0) {
538 dvmLockMutex(&gDvmJit.compilerLock);
539 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
540 &gDvmJit.compilerLock);
541 dvmUnlockMutex(&gDvmJit.compilerLock);
542 LOGD("JIT started for system_server");
543 } else {
544 dvmLockMutex(&gDvmJit.compilerLock);
545 /*
546 * TUNING: experiment with the delay & perhaps make it
547 * target-specific
548 */
549 dvmRelativeCondWait(&gDvmJit.compilerQueueActivity,
550 &gDvmJit.compilerLock, 3000, 0);
551 dvmUnlockMutex(&gDvmJit.compilerLock);
552 }
Bill Buzbeeeb695c62010-02-04 16:09:55 -0800553 if (gDvmJit.haltCompilerThread) {
554 return NULL;
555 }
Bill Buzbee94d89f82010-01-29 13:44:19 -0800556 }
557
Bill Buzbee964a7b02010-01-28 12:54:19 -0800558 compilerThreadStartup();
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800559
Ben Chengba4fc8b2009-06-01 13:00:29 -0700560 dvmLockMutex(&gDvmJit.compilerLock);
561 /*
562 * Since the compiler thread will not touch any objects on the heap once
563 * being created, we just fake its state as VMWAIT so that it can be a
564 * bit late when there is suspend request pending.
565 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700566 while (!gDvmJit.haltCompilerThread) {
567 if (workQueueLength() == 0) {
568 int cc;
569 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
570 assert(cc == 0);
571 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
572 &gDvmJit.compilerLock);
573 continue;
574 } else {
575 do {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700576 CompilerWorkOrder work = workDequeue();
577 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng978738d2010-05-13 13:45:57 -0700578#if defined(WITH_JIT_TUNING)
Ben Cheng86717f72010-03-05 15:27:21 -0800579 u8 startTime = dvmGetRelativeTimeUsec();
580#endif
Bill Buzbee964a7b02010-01-28 12:54:19 -0800581 /*
582 * Check whether there is a suspend request on me. This
583 * is necessary to allow a clean shutdown.
Ben Cheng11d8f142010-03-24 15:24:19 -0700584 *
585 * However, in the blocking stress testing mode, let the
586 * compiler thread continue doing compilations to unblock
587 * other requesting threads. This may occasionally cause
588 * shutdown from proceeding cleanly in the standalone invocation
589 * of the vm but this should be acceptable.
Bill Buzbee964a7b02010-01-28 12:54:19 -0800590 */
Ben Cheng11d8f142010-03-24 15:24:19 -0700591 if (!gDvmJit.blockingMode)
Andy McFaddenab227f72010-04-06 12:37:48 -0700592 dvmCheckSuspendPending(dvmThreadSelf());
Bill Buzbee27176222009-06-09 09:20:16 -0700593 /* Is JitTable filling up? */
594 if (gDvmJit.jitTableEntriesUsed >
595 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
Ben Cheng6999d842010-01-26 16:46:15 -0800596 bool resizeFail =
597 dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
598 /*
599 * If the jit table is full, consider it's time to reset
600 * the code cache too.
601 */
602 gDvmJit.codeCacheFull |= resizeFail;
Bill Buzbee27176222009-06-09 09:20:16 -0700603 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700604 if (gDvmJit.haltCompilerThread) {
605 LOGD("Compiler shutdown in progress - discarding request");
Ben Cheng6999d842010-01-26 16:46:15 -0800606 } else if (!gDvmJit.codeCacheFull) {
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800607 bool compileOK = false;
608 jmp_buf jmpBuf;
609 work.bailPtr = &jmpBuf;
610 bool aborted = setjmp(jmpBuf);
611 if (!aborted) {
612 compileOK = dvmCompilerDoWork(&work);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700613 }
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800614 if (aborted || !compileOK) {
615 dvmCompilerArenaReset();
Bill Buzbeebd047242010-05-13 13:02:53 -0700616 work.result.codeAddress = dvmCompilerGetInterpretTemplate();
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800617 } else if (!work.result.discardResult) {
Ben Cheng60c24f42010-01-04 12:29:56 -0800618 dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
619 work.result.instructionSet);
620 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700621 }
622 free(work.info);
Ben Cheng978738d2010-05-13 13:45:57 -0700623#if defined(WITH_JIT_TUNING)
Ben Cheng86717f72010-03-05 15:27:21 -0800624 gDvmJit.jitTime += dvmGetRelativeTimeUsec() - startTime;
625#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700626 dvmLockMutex(&gDvmJit.compilerLock);
627 } while (workQueueLength() != 0);
628 }
629 }
630 pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
631 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Chengef00a852009-06-22 22:53:35 -0700632
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700633 /*
634 * As part of detaching the thread we need to call into Java code to update
635 * the ThreadGroup, and we should not be in VMWAIT state while executing
636 * interpreted code.
637 */
638 dvmChangeStatus(NULL, THREAD_RUNNING);
639
Andy McFadden43eb5012010-02-01 16:56:53 -0800640 if (gDvm.verboseShutdown)
641 LOGD("Compiler thread shutting down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700642 return NULL;
643}
644
Ben Chengba4fc8b2009-06-01 13:00:29 -0700645bool dvmCompilerStartup(void)
646{
Bill Buzbee94d89f82010-01-29 13:44:19 -0800647
648 dvmInitMutex(&gDvmJit.compilerLock);
Ben Cheng6999d842010-01-26 16:46:15 -0800649 dvmInitMutex(&gDvmJit.compilerICPatchLock);
Bill Buzbee94d89f82010-01-29 13:44:19 -0800650 dvmLockMutex(&gDvmJit.compilerLock);
651 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
652 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
653
654 /* Reset the work queue */
655 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
656 gDvmJit.compilerQueueLength = 0;
657 dvmUnlockMutex(&gDvmJit.compilerLock);
658
Ben Chengba4fc8b2009-06-01 13:00:29 -0700659 /*
Bill Buzbee94d89f82010-01-29 13:44:19 -0800660 * Defer rest of initialization until we're sure JIT'ng makes sense. Launch
Bill Buzbee964a7b02010-01-28 12:54:19 -0800661 * the compiler thread, which will do the real initialization if and
662 * when it is signalled to do so.
Ben Chengba4fc8b2009-06-01 13:00:29 -0700663 */
Bill Buzbee964a7b02010-01-28 12:54:19 -0800664 return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
665 compilerThreadStart, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700666}
667
668void dvmCompilerShutdown(void)
669{
670 void *threadReturn;
671
Bill Buzbee2fc03c32010-03-08 11:30:19 -0800672 /* Disable new translation requests */
673 gDvmJit.pProfTable = NULL;
674 gDvmJit.pProfTableCopy = NULL;
675
Ben Cheng88a0f972010-02-24 15:00:40 -0800676 if (gDvm.verboseShutdown) {
677 dvmCompilerDumpStats();
678 while (gDvmJit.compilerQueueLength)
679 sleep(5);
680 }
681
Ben Chengba4fc8b2009-06-01 13:00:29 -0700682 if (gDvmJit.compilerHandle) {
683
684 gDvmJit.haltCompilerThread = true;
685
686 dvmLockMutex(&gDvmJit.compilerLock);
687 pthread_cond_signal(&gDvmJit.compilerQueueActivity);
688 dvmUnlockMutex(&gDvmJit.compilerLock);
689
Ben Chengef00a852009-06-22 22:53:35 -0700690 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
691 LOGW("Compiler thread join failed\n");
Andy McFadden43eb5012010-02-01 16:56:53 -0800692 else if (gDvm.verboseShutdown)
Ben Chengef00a852009-06-22 22:53:35 -0700693 LOGD("Compiler thread has shut down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700694 }
Bill Buzbee06bb8392010-01-31 18:53:15 -0800695
Bill Buzbee2fc03c32010-03-08 11:30:19 -0800696 /* Break loops within the translation cache */
697 dvmJitUnchainAll();
Bill Buzbee96cfe6c2010-02-08 17:08:15 -0800698
Bill Buzbee2fc03c32010-03-08 11:30:19 -0800699 /*
700 * NOTE: our current implementatation doesn't allow for the compiler
701 * thread to be restarted after it exits here. We aren't freeing
702 * the JitTable or the ProfTable because threads which still may be
703 * running or in the process of shutting down may hold references to
704 * them.
705 */
Bill Buzbee96cfe6c2010-02-08 17:08:15 -0800706}
Bill Buzbee06bb8392010-01-31 18:53:15 -0800707
708void dvmCompilerStateRefresh()
709{
710 bool jitActive;
711 bool jitActivate;
Bill Buzbee3e392682010-02-03 18:13:57 -0800712 bool needUnchain = false;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800713
Ben Chenga4973592010-03-31 11:59:18 -0700714 /*
715 * The tableLock might not be initialized yet by the compiler thread if
716 * debugger is attached from the very beginning of the VM launch. If
717 * pProfTableCopy is NULL, the lock is not initialized yet and we don't
718 * need to refresh anything either.
719 */
720 if (gDvmJit.pProfTableCopy == NULL) {
721 return;
722 }
723
Bill Buzbee06bb8392010-01-31 18:53:15 -0800724 dvmLockMutex(&gDvmJit.tableLock);
725 jitActive = gDvmJit.pProfTable != NULL;
Andy McFaddenc95e0fb2010-04-29 14:13:01 -0700726
727#if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
Bill Buzbee06bb8392010-01-31 18:53:15 -0800728 jitActivate = !(gDvm.debuggerActive || (gDvm.activeProfilers > 0));
Andy McFaddenc95e0fb2010-04-29 14:13:01 -0700729#elif defined(WITH_DEBUGGER)
730 jitActivate = !gDvm.debuggerActive;
731#elif defined(WITH_PROFILER)
732 jitActivate = !(gDvm.activeProfilers > 0);
733#else
734 jitActivate = true;
735#endif
Bill Buzbee06bb8392010-01-31 18:53:15 -0800736
737 if (jitActivate && !jitActive) {
738 gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800739 } else if (!jitActivate && jitActive) {
740 gDvmJit.pProfTable = NULL;
Bill Buzbee3e392682010-02-03 18:13:57 -0800741 needUnchain = true;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800742 }
Bill Buzbee3e392682010-02-03 18:13:57 -0800743 dvmUnlockMutex(&gDvmJit.tableLock);
744 if (needUnchain)
745 dvmJitUnchainAll();
Bill Buzbee06bb8392010-01-31 18:53:15 -0800746}