1 /*
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>
19 #include <cutils/ashmem.h>
20
21 #include "Dalvik.h"
22 #include "interp/Jit.h"
23 #include "CompilerInternals.h"
24 #ifdef ARCH_IA32
25 #include "codegen/x86/Translator.h"
26 #include "codegen/x86/Lower.h"
27 #endif
28
29 extern "C" void dvmCompilerTemplateStart(void);
30 extern "C" void dvmCompilerTemplateEnd(void);
31
workQueueLength(void)32 static inline bool workQueueLength(void)
33 {
34 return gDvmJit.compilerQueueLength;
35 }
36
workDequeue(void)37 static CompilerWorkOrder workDequeue(void)
38 {
39 assert(gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex].kind
40 != kWorkOrderInvalid);
41 CompilerWorkOrder work =
42 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex];
43 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex++].kind =
44 kWorkOrderInvalid;
45 if (gDvmJit.compilerWorkDequeueIndex == COMPILER_WORK_QUEUE_SIZE) {
46 gDvmJit.compilerWorkDequeueIndex = 0;
47 }
48 gDvmJit.compilerQueueLength--;
49 if (gDvmJit.compilerQueueLength == 0) {
50 dvmSignalCond(&gDvmJit.compilerQueueEmpty);
51 }
52
53 /* Remember the high water mark of the queue length */
54 if (gDvmJit.compilerQueueLength > gDvmJit.compilerMaxQueued)
55 gDvmJit.compilerMaxQueued = gDvmJit.compilerQueueLength;
56
57 return work;
58 }
59
60 /*
61 * Enqueue a work order - retrying until successful. If attempt to enqueue
62 * is repeatedly unsuccessful, assume the JIT is in a bad state and force a
63 * code cache reset.
64 */
65 #define ENQUEUE_MAX_RETRIES 20
dvmCompilerForceWorkEnqueue(const u2 * pc,WorkOrderKind kind,void * info)66 void dvmCompilerForceWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
67 {
68 bool success;
69 int retries = 0;
70 do {
71 success = dvmCompilerWorkEnqueue(pc, kind, info);
72 if (!success) {
73 retries++;
74 if (retries > ENQUEUE_MAX_RETRIES) {
75 ALOGE("JIT: compiler queue wedged - forcing reset");
76 gDvmJit.codeCacheFull = true; // Force reset
77 success = true; // Because we'll drop the order now anyway
78 } else {
79 dvmLockMutex(&gDvmJit.compilerLock);
80 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
81 &gDvmJit.compilerLock);
82 dvmUnlockMutex(&gDvmJit.compilerLock);
83
84 }
85 }
86 } while (!success);
87 }
88
89 /*
90 * Attempt to enqueue a work order, returning true if successful.
91 *
92 * NOTE: Make sure that the caller frees the info pointer if the return value
93 * is false.
94 */
dvmCompilerWorkEnqueue(const u2 * pc,WorkOrderKind kind,void * info)95 bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
96 {
97 int cc;
98 int i;
99 int numWork;
100 bool result = true;
101
102 dvmLockMutex(&gDvmJit.compilerLock);
103
104 /*
105 * Return if queue or code cache is full.
106 */
107 if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE ||
108 gDvmJit.codeCacheFull == true) {
109 dvmUnlockMutex(&gDvmJit.compilerLock);
110 return false;
111 }
112
113 for (numWork = gDvmJit.compilerQueueLength,
114 i = gDvmJit.compilerWorkDequeueIndex;
115 numWork > 0;
116 numWork--) {
117 /* Already enqueued */
118 if (gDvmJit.compilerWorkQueue[i++].pc == pc) {
119 dvmUnlockMutex(&gDvmJit.compilerLock);
120 return true;
121 }
122 /* Wrap around */
123 if (i == COMPILER_WORK_QUEUE_SIZE)
124 i = 0;
125 }
126
127 CompilerWorkOrder *newOrder =
128 &gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex];
129 newOrder->pc = pc;
130 newOrder->kind = kind;
131 newOrder->info = info;
132 newOrder->result.methodCompilationAborted = NULL;
133 newOrder->result.codeAddress = NULL;
134 newOrder->result.discardResult =
135 (kind == kWorkOrderTraceDebug) ? true : false;
136 newOrder->result.cacheVersion = gDvmJit.cacheVersion;
137 newOrder->result.requestingThread = dvmThreadSelf();
138
139 gDvmJit.compilerWorkEnqueueIndex++;
140 if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
141 gDvmJit.compilerWorkEnqueueIndex = 0;
142 gDvmJit.compilerQueueLength++;
143 cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
144 assert(cc == 0);
145
146 dvmUnlockMutex(&gDvmJit.compilerLock);
147 return result;
148 }
149
150 /* Block until the queue length is 0, or there is a pending suspend request */
dvmCompilerDrainQueue(void)151 void dvmCompilerDrainQueue(void)
152 {
153 Thread *self = dvmThreadSelf();
154
155 dvmLockMutex(&gDvmJit.compilerLock);
156 while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread &&
157 self->suspendCount == 0) {
158 /*
159 * Use timed wait here - more than one mutator threads may be blocked
160 * but the compiler thread will only signal once when the queue is
161 * emptied. Furthermore, the compiler thread may have been shutdown
162 * so the blocked thread may never get the wakeup signal.
163 */
164 dvmRelativeCondWait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock, 1000, 0);
165 }
166 dvmUnlockMutex(&gDvmJit.compilerLock);
167 }
168
dvmCompilerSetupCodeCache(void)169 bool dvmCompilerSetupCodeCache(void)
170 {
171 int fd;
172
173 /* Allocate the code cache */
174 fd = ashmem_create_region("dalvik-jit-code-cache", gDvmJit.codeCacheSize);
175 if (fd < 0) {
176 ALOGE("Could not create %u-byte ashmem region for the JIT code cache",
177 gDvmJit.codeCacheSize);
178 return false;
179 }
180 gDvmJit.codeCache = mmap(NULL, gDvmJit.codeCacheSize,
181 PROT_READ | PROT_WRITE | PROT_EXEC,
182 MAP_PRIVATE , fd, 0);
183 close(fd);
184 if (gDvmJit.codeCache == MAP_FAILED) {
185 ALOGE("Failed to mmap the JIT code cache of size %d: %s", gDvmJit.codeCacheSize, strerror(errno));
186 return false;
187 }
188
189 gDvmJit.pageSizeMask = getpagesize() - 1;
190
191 /* This can be found through "dalvik-jit-code-cache" in /proc/<pid>/maps */
192 // ALOGD("Code cache starts at %p", gDvmJit.codeCache);
193
194 #ifndef ARCH_IA32
195 /* Copy the template code into the beginning of the code cache */
196 int templateSize = (intptr_t) dvmCompilerTemplateEnd -
197 (intptr_t) dvmCompilerTemplateStart;
198 memcpy((void *) gDvmJit.codeCache,
199 (void *) dvmCompilerTemplateStart,
200 templateSize);
201
202 /*
203 * Work around a CPU bug by keeping the 32-bit ARM handler code in its own
204 * page.
205 */
206 if (dvmCompilerInstructionSet() == DALVIK_JIT_THUMB2) {
207 templateSize = (templateSize + 4095) & ~4095;
208 }
209
210 gDvmJit.templateSize = templateSize;
211 gDvmJit.codeCacheByteUsed = templateSize;
212
213 /* Only flush the part in the code cache that is being used now */
214 dvmCompilerCacheFlush((intptr_t) gDvmJit.codeCache,
215 (intptr_t) gDvmJit.codeCache + templateSize, 0);
216 #else
217 gDvmJit.codeCacheByteUsed = 0;
218 stream = (char*)gDvmJit.codeCache + gDvmJit.codeCacheByteUsed;
219 ALOGV("codeCache = %p stream = %p before initJIT", gDvmJit.codeCache, stream);
220 streamStart = stream;
221 initJIT(NULL, NULL);
222 gDvmJit.templateSize = (stream - streamStart);
223 gDvmJit.codeCacheByteUsed = (stream - streamStart);
224 ALOGV("stream = %p after initJIT", stream);
225 #endif
226
227 int result = mprotect(gDvmJit.codeCache, gDvmJit.codeCacheSize,
228 PROTECT_CODE_CACHE_ATTRS);
229
230 if (result == -1) {
231 ALOGE("Failed to remove the write permission for the code cache");
232 dvmAbort();
233 }
234
235 return true;
236 }
237
crawlDalvikStack(Thread * thread,bool print)238 static void crawlDalvikStack(Thread *thread, bool print)
239 {
240 void *fp = thread->interpSave.curFrame;
241 StackSaveArea* saveArea = NULL;
242 int stackLevel = 0;
243
244 if (print) {
245 ALOGD("Crawling tid %d (%s / %p %s)", thread->systemTid,
246 dvmGetThreadStatusStr(thread->status),
247 thread->inJitCodeCache,
248 thread->inJitCodeCache ? "jit" : "interp");
249 }
250 /* Crawl the Dalvik stack frames to clear the returnAddr field */
251 while (fp != NULL) {
252 saveArea = SAVEAREA_FROM_FP(fp);
253
254 if (print) {
255 if (dvmIsBreakFrame((u4*)fp)) {
256 ALOGD(" #%d: break frame (%p)",
257 stackLevel, saveArea->returnAddr);
258 }
259 else {
260 ALOGD(" #%d: %s.%s%s (%p)",
261 stackLevel,
262 saveArea->method->clazz->descriptor,
263 saveArea->method->name,
264 dvmIsNativeMethod(saveArea->method) ?
265 " (native)" : "",
266 saveArea->returnAddr);
267 }
268 }
269 stackLevel++;
270 saveArea->returnAddr = NULL;
271 assert(fp != saveArea->prevFrame);
272 fp = saveArea->prevFrame;
273 }
274 /* Make sure the stack is fully unwound to the bottom */
275 assert(saveArea == NULL ||
276 (u1 *) (saveArea+1) == thread->interpStackStart);
277 }
278
resetCodeCache(void)279 static void resetCodeCache(void)
280 {
281 Thread* thread;
282 u8 startTime = dvmGetRelativeTimeUsec();
283 int inJit = 0;
284 int byteUsed = gDvmJit.codeCacheByteUsed;
285
286 /* If any thread is found stuck in the JIT state, don't reset the cache */
287 dvmLockThreadList(NULL);
288 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
289 /*
290 * Crawl the stack to wipe out the returnAddr field so that
291 * 1) the soon-to-be-deleted code in the JIT cache won't be used
292 * 2) or the thread stuck in the JIT land will soon return
293 * to the interpreter land
294 */
295 crawlDalvikStack(thread, false);
296 if (thread->inJitCodeCache) {
297 inJit++;
298 }
299 /* Cancel any ongoing trace selection */
300 dvmDisableSubMode(thread, kSubModeJitTraceBuild);
301 }
302 dvmUnlockThreadList();
303
304 if (inJit) {
305 ALOGD("JIT code cache reset delayed (%d bytes %d/%d)",
306 gDvmJit.codeCacheByteUsed, gDvmJit.numCodeCacheReset,
307 ++gDvmJit.numCodeCacheResetDelayed);
308 return;
309 }
310
311 /* Lock the mutex to clean up the work queue */
312 dvmLockMutex(&gDvmJit.compilerLock);
313
314 /* Update the translation cache version */
315 gDvmJit.cacheVersion++;
316
317 /* Drain the work queue to free the work orders */
318 while (workQueueLength()) {
319 CompilerWorkOrder work = workDequeue();
320 free(work.info);
321 }
322
323 /* Reset the JitEntry table contents to the initial unpopulated state */
324 dvmJitResetTable();
325
326 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
327 /*
328 * Wipe out the code cache content to force immediate crashes if
329 * stale JIT'ed code is invoked.
330 */
331 dvmCompilerCacheClear((char *) gDvmJit.codeCache + gDvmJit.templateSize,
332 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
333
334 dvmCompilerCacheFlush((intptr_t) gDvmJit.codeCache,
335 (intptr_t) gDvmJit.codeCache +
336 gDvmJit.codeCacheByteUsed, 0);
337
338 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
339
340 /* Reset the current mark of used bytes to the end of template code */
341 gDvmJit.codeCacheByteUsed = gDvmJit.templateSize;
342 gDvmJit.numCompilations = 0;
343
344 /* Reset the work queue */
345 memset(gDvmJit.compilerWorkQueue, 0,
346 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
347 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
348 gDvmJit.compilerQueueLength = 0;
349
350 /* Reset the IC patch work queue */
351 dvmLockMutex(&gDvmJit.compilerICPatchLock);
352 gDvmJit.compilerICPatchIndex = 0;
353 dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
354
355 /*
356 * Reset the inflight compilation address (can only be done in safe points
357 * or by the compiler thread when its thread state is RUNNING).
358 */
359 gDvmJit.inflightBaseAddr = NULL;
360
361 /* All clear now */
362 gDvmJit.codeCacheFull = false;
363
364 dvmUnlockMutex(&gDvmJit.compilerLock);
365
366 ALOGD("JIT code cache reset in %lld ms (%d bytes %d/%d)",
367 (dvmGetRelativeTimeUsec() - startTime) / 1000,
368 byteUsed, ++gDvmJit.numCodeCacheReset,
369 gDvmJit.numCodeCacheResetDelayed);
370 }
371
372 /*
373 * Perform actions that are only safe when all threads are suspended. Currently
374 * we do:
375 * 1) Check if the code cache is full. If so reset it and restart populating it
376 * from scratch.
377 * 2) Patch predicted chaining cells by consuming recorded work orders.
378 */
dvmCompilerPerformSafePointChecks(void)379 void dvmCompilerPerformSafePointChecks(void)
380 {
381 if (gDvmJit.codeCacheFull) {
382 resetCodeCache();
383 }
384 dvmCompilerPatchInlineCache();
385 }
386
compilerThreadStartup(void)387 static bool compilerThreadStartup(void)
388 {
389 JitEntry *pJitTable = NULL;
390 unsigned char *pJitProfTable = NULL;
391 JitTraceProfCounters *pJitTraceProfCounters = NULL;
392 unsigned int i;
393
394 if (!dvmCompilerArchInit())
395 goto fail;
396
397 /*
398 * Setup the code cache if we have not inherited a valid code cache
399 * from the zygote.
400 */
401 if (gDvmJit.codeCache == NULL) {
402 if (!dvmCompilerSetupCodeCache())
403 goto fail;
404 }
405
406 /* Allocate the initial arena block */
407 if (dvmCompilerHeapInit() == false) {
408 goto fail;
409 }
410
411 /* Cache the thread pointer */
412 gDvmJit.compilerThread = dvmThreadSelf();
413
414 dvmLockMutex(&gDvmJit.compilerLock);
415
416 /* Track method-level compilation statistics */
417 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
418
419 #if defined(WITH_JIT_TUNING)
420 gDvm.verboseShutdown = true;
421 #endif
422
423 dvmUnlockMutex(&gDvmJit.compilerLock);
424
425 /* Set up the JitTable */
426
427 /* Power of 2? */
428 assert(gDvmJit.jitTableSize &&
429 !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1)));
430
431 dvmInitMutex(&gDvmJit.tableLock);
432 dvmLockMutex(&gDvmJit.tableLock);
433 pJitTable = (JitEntry*)
434 calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
435 if (!pJitTable) {
436 ALOGE("jit table allocation failed");
437 dvmUnlockMutex(&gDvmJit.tableLock);
438 goto fail;
439 }
440 /*
441 * NOTE: the profile table must only be allocated once, globally.
442 * Profiling is turned on and off by nulling out gDvm.pJitProfTable
443 * and then restoring its original value. However, this action
444 * is not synchronized for speed so threads may continue to hold
445 * and update the profile table after profiling has been turned
446 * off by null'ng the global pointer. Be aware.
447 */
448 pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE);
449 if (!pJitProfTable) {
450 ALOGE("jit prof table allocation failed");
451 free(pJitTable);
452 dvmUnlockMutex(&gDvmJit.tableLock);
453 goto fail;
454 }
455 memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE);
456 for (i=0; i < gDvmJit.jitTableSize; i++) {
457 pJitTable[i].u.info.chain = gDvmJit.jitTableSize;
458 }
459 /* Is chain field wide enough for termination pattern? */
460 assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize);
461
462 /* Allocate the trace profiling structure */
463 pJitTraceProfCounters = (JitTraceProfCounters*)
464 calloc(1, sizeof(*pJitTraceProfCounters));
465 if (!pJitTraceProfCounters) {
466 ALOGE("jit trace prof counters allocation failed");
467 free(pJitTable);
468 free(pJitProfTable);
469 dvmUnlockMutex(&gDvmJit.tableLock);
470 goto fail;
471 }
472
473 gDvmJit.pJitEntryTable = pJitTable;
474 gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
475 gDvmJit.jitTableEntriesUsed = 0;
476 gDvmJit.compilerHighWater =
477 COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
478 /*
479 * If the VM is launched with wait-on-the-debugger, we will need to hide
480 * the profile table here
481 */
482 gDvmJit.pProfTable = dvmDebuggerOrProfilerActive() ? NULL : pJitProfTable;
483 gDvmJit.pProfTableCopy = pJitProfTable;
484 gDvmJit.pJitTraceProfCounters = pJitTraceProfCounters;
485 dvmJitUpdateThreadStateAll();
486 dvmUnlockMutex(&gDvmJit.tableLock);
487
488 /* Signal running threads to refresh their cached pJitTable pointers */
489 dvmSuspendAllThreads(SUSPEND_FOR_REFRESH);
490 dvmResumeAllThreads(SUSPEND_FOR_REFRESH);
491
492 /* Enable signature breakpoints by customizing the following code */
493 #if defined(SIGNATURE_BREAKPOINT)
494 /*
495 * Suppose one sees the following native crash in the bugreport:
496 * I/DEBUG ( 1638): Build fingerprint: 'unknown'
497 * I/DEBUG ( 1638): pid: 2468, tid: 2507 >>> com.google.android.gallery3d
498 * I/DEBUG ( 1638): signal 11 (SIGSEGV), fault addr 00001400
499 * I/DEBUG ( 1638): r0 44ea7190 r1 44e4f7b8 r2 44ebc710 r3 00000000
500 * I/DEBUG ( 1638): r4 00000a00 r5 41862dec r6 4710dc10 r7 00000280
501 * I/DEBUG ( 1638): r8 ad010f40 r9 46a37a12 10 001116b0 fp 42a78208
502 * I/DEBUG ( 1638): ip 00000090 sp 4710dbc8 lr ad060e67 pc 46b90682
503 * cpsr 00000030
504 * I/DEBUG ( 1638): #00 pc 46b90682 /dev/ashmem/dalvik-jit-code-cache
505 * I/DEBUG ( 1638): #01 pc 00060e62 /system/lib/libdvm.so
506 *
507 * I/DEBUG ( 1638): code around pc:
508 * I/DEBUG ( 1638): 46b90660 6888d01c 34091dcc d2174287 4a186b68
509 * I/DEBUG ( 1638): 46b90670 d0052800 68006809 28004790 6b68d00e
510 * I/DEBUG ( 1638): 46b90680 512000bc 37016eaf 6ea866af 6f696028
511 * I/DEBUG ( 1638): 46b90690 682a6069 429a686b e003da08 6df1480b
512 * I/DEBUG ( 1638): 46b906a0 1c2d4788 47806d70 46a378fa 47806d70
513 *
514 * Clearly it is a JIT bug. To find out which translation contains the
515 * offending code, the content of the memory dump around the faulting PC
516 * can be pasted into the gDvmJit.signatureBreakpoint[] array and next time
517 * when a similar compilation is being created, the JIT compiler replay the
518 * trace in the verbose mode and one can investigate the instruction
519 * sequence in details.
520 *
521 * The length of the signature may need additional experiments to determine.
522 * The rule of thumb is don't include PC-relative instructions in the
523 * signature since it may be affected by the alignment of the compiled code.
524 * However, a signature that's too short might increase the chance of false
525 * positive matches. Using gdbjithelper to disassembly the memory content
526 * first might be a good companion approach.
527 *
528 * For example, if the next 4 words starting from 46b90680 is pasted into
529 * the data structure:
530 */
531
532 gDvmJit.signatureBreakpointSize = 4;
533 gDvmJit.signatureBreakpoint =
534 malloc(sizeof(u4) * gDvmJit.signatureBreakpointSize);
535 gDvmJit.signatureBreakpoint[0] = 0x512000bc;
536 gDvmJit.signatureBreakpoint[1] = 0x37016eaf;
537 gDvmJit.signatureBreakpoint[2] = 0x6ea866af;
538 gDvmJit.signatureBreakpoint[3] = 0x6f696028;
539
540 /*
541 * The following log will be printed when a match is found in subsequent
542 * testings:
543 *
544 * D/dalvikvm( 2468): Signature match starting from offset 0x34 (4 words)
545 * D/dalvikvm( 2468): --------
546 * D/dalvikvm( 2468): Compiler: Building trace for computeVisibleItems,
547 * offset 0x1f7
548 * D/dalvikvm( 2468): 0x46a37a12: 0x0090 add-int v42, v5, v26
549 * D/dalvikvm( 2468): 0x46a37a16: 0x004d aput-object v13, v14, v42
550 * D/dalvikvm( 2468): 0x46a37a1a: 0x0028 goto, (#0), (#0)
551 * D/dalvikvm( 2468): 0x46a3794e: 0x00d8 add-int/lit8 v26, v26, (#1)
552 * D/dalvikvm( 2468): 0x46a37952: 0x0028 goto, (#0), (#0)
553 * D/dalvikvm( 2468): 0x46a378ee: 0x0002 move/from16 v0, v26, (#0)
554 * D/dalvikvm( 2468): 0x46a378f2: 0x0002 move/from16 v1, v29, (#0)
555 * D/dalvikvm( 2468): 0x46a378f6: 0x0035 if-ge v0, v1, (#10)
556 * D/dalvikvm( 2468): TRACEINFO (554): 0x46a37624
557 * Lcom/cooliris/media/GridLayer;computeVisibleItems 0x1f7 14 of 934, 8
558 * blocks
559 * :
560 * :
561 * D/dalvikvm( 2468): 0x20 (0020): ldr r0, [r5, #52]
562 * D/dalvikvm( 2468): 0x22 (0022): ldr r2, [pc, #96]
563 * D/dalvikvm( 2468): 0x24 (0024): cmp r0, #0
564 * D/dalvikvm( 2468): 0x26 (0026): beq 0x00000034
565 * D/dalvikvm( 2468): 0x28 (0028): ldr r1, [r1, #0]
566 * D/dalvikvm( 2468): 0x2a (002a): ldr r0, [r0, #0]
567 * D/dalvikvm( 2468): 0x2c (002c): blx r2
568 * D/dalvikvm( 2468): 0x2e (002e): cmp r0, #0
569 * D/dalvikvm( 2468): 0x30 (0030): beq 0x00000050
570 * D/dalvikvm( 2468): 0x32 (0032): ldr r0, [r5, #52]
571 * D/dalvikvm( 2468): 0x34 (0034): lsls r4, r7, #2
572 * D/dalvikvm( 2468): 0x36 (0036): str r0, [r4, r4]
573 * D/dalvikvm( 2468): -------- dalvik offset: 0x01fb @ goto, (#0), (#0)
574 * D/dalvikvm( 2468): L0x0195:
575 * D/dalvikvm( 2468): -------- dalvik offset: 0x0195 @ add-int/lit8 v26,
576 * v26, (#1)
577 * D/dalvikvm( 2468): 0x38 (0038): ldr r7, [r5, #104]
578 * D/dalvikvm( 2468): 0x3a (003a): adds r7, r7, #1
579 * D/dalvikvm( 2468): 0x3c (003c): str r7, [r5, #104]
580 * D/dalvikvm( 2468): -------- dalvik offset: 0x0197 @ goto, (#0), (#0)
581 * D/dalvikvm( 2468): L0x0165:
582 * D/dalvikvm( 2468): -------- dalvik offset: 0x0165 @ move/from16 v0, v26,
583 * (#0)
584 * D/dalvikvm( 2468): 0x3e (003e): ldr r0, [r5, #104]
585 * D/dalvikvm( 2468): 0x40 (0040): str r0, [r5, #0]
586 *
587 * The "str r0, [r4, r4]" is indeed the culprit of the native crash.
588 */
589 #endif
590
591 return true;
592
593 fail:
594 return false;
595
596 }
597
compilerThreadStart(void * arg)598 static void *compilerThreadStart(void *arg)
599 {
600 dvmChangeStatus(NULL, THREAD_VMWAIT);
601
602 /*
603 * If we're not running stand-alone, wait a little before
604 * recieving translation requests on the assumption that process start
605 * up code isn't worth compiling. We'll resume when the framework
606 * signals us that the first screen draw has happened, or the timer
607 * below expires (to catch daemons).
608 *
609 * There is a theoretical race between the callback to
610 * VMRuntime.startJitCompiation and when the compiler thread reaches this
611 * point. In case the callback happens earlier, in order not to permanently
612 * hold the system_server (which is not using the timed wait) in
613 * interpreter-only mode we bypass the delay here.
614 */
615 if (gDvmJit.runningInAndroidFramework &&
616 !gDvmJit.alreadyEnabledViaFramework) {
617 /*
618 * If the current VM instance is the system server (detected by having
619 * 0 in gDvm.systemServerPid), we will use the indefinite wait on the
620 * conditional variable to determine whether to start the JIT or not.
621 * If the system server detects that the whole system is booted in
622 * safe mode, the conditional variable will never be signaled and the
623 * system server will remain in the interpreter-only mode. All
624 * subsequent apps will be started with the --enable-safemode flag
625 * explicitly appended.
626 */
627 if (gDvm.systemServerPid == 0) {
628 dvmLockMutex(&gDvmJit.compilerLock);
629 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
630 &gDvmJit.compilerLock);
631 dvmUnlockMutex(&gDvmJit.compilerLock);
632 ALOGD("JIT started for system_server");
633 } else {
634 dvmLockMutex(&gDvmJit.compilerLock);
635 /*
636 * TUNING: experiment with the delay & perhaps make it
637 * target-specific
638 */
639 dvmRelativeCondWait(&gDvmJit.compilerQueueActivity,
640 &gDvmJit.compilerLock, 3000, 0);
641 dvmUnlockMutex(&gDvmJit.compilerLock);
642 }
643 if (gDvmJit.haltCompilerThread) {
644 return NULL;
645 }
646 }
647
648 compilerThreadStartup();
649
650 dvmLockMutex(&gDvmJit.compilerLock);
651 /*
652 * Since the compiler thread will not touch any objects on the heap once
653 * being created, we just fake its state as VMWAIT so that it can be a
654 * bit late when there is suspend request pending.
655 */
656 while (!gDvmJit.haltCompilerThread) {
657 if (workQueueLength() == 0) {
658 int cc;
659 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
660 assert(cc == 0);
661 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
662 &gDvmJit.compilerLock);
663 continue;
664 } else {
665 do {
666 CompilerWorkOrder work = workDequeue();
667 dvmUnlockMutex(&gDvmJit.compilerLock);
668 #if defined(WITH_JIT_TUNING)
669 /*
670 * This is live across setjmp(). Mark it volatile to suppress
671 * a gcc warning. We should not need this since it is assigned
672 * only once but gcc is not smart enough.
673 */
674 volatile u8 startTime = dvmGetRelativeTimeUsec();
675 #endif
676 /*
677 * Check whether there is a suspend request on me. This
678 * is necessary to allow a clean shutdown.
679 *
680 * However, in the blocking stress testing mode, let the
681 * compiler thread continue doing compilations to unblock
682 * other requesting threads. This may occasionally cause
683 * shutdown from proceeding cleanly in the standalone invocation
684 * of the vm but this should be acceptable.
685 */
686 if (!gDvmJit.blockingMode)
687 dvmCheckSuspendPending(dvmThreadSelf());
688 /* Is JitTable filling up? */
689 if (gDvmJit.jitTableEntriesUsed >
690 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
691 bool resizeFail =
692 dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
693 /*
694 * If the jit table is full, consider it's time to reset
695 * the code cache too.
696 */
697 gDvmJit.codeCacheFull |= resizeFail;
698 }
699 if (gDvmJit.haltCompilerThread) {
700 ALOGD("Compiler shutdown in progress - discarding request");
701 } else if (!gDvmJit.codeCacheFull) {
702 jmp_buf jmpBuf;
703 work.bailPtr = &jmpBuf;
704 bool aborted = setjmp(jmpBuf);
705 if (!aborted) {
706 bool codeCompiled = dvmCompilerDoWork(&work);
707 /*
708 * Make sure we are still operating with the
709 * same translation cache version. See
710 * Issue 4271784 for details.
711 */
712 dvmLockMutex(&gDvmJit.compilerLock);
713 if ((work.result.cacheVersion ==
714 gDvmJit.cacheVersion) &&
715 codeCompiled &&
716 !work.result.discardResult &&
717 work.result.codeAddress) {
718 dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
719 work.result.instructionSet,
720 false, /* not method entry */
721 work.result.profileCodeSize);
722 }
723 dvmUnlockMutex(&gDvmJit.compilerLock);
724 }
725 dvmCompilerArenaReset();
726 }
727 free(work.info);
728 #if defined(WITH_JIT_TUNING)
729 gDvmJit.jitTime += dvmGetRelativeTimeUsec() - startTime;
730 #endif
731 dvmLockMutex(&gDvmJit.compilerLock);
732 } while (workQueueLength() != 0);
733 }
734 }
735 pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
736 dvmUnlockMutex(&gDvmJit.compilerLock);
737
738 /*
739 * As part of detaching the thread we need to call into Java code to update
740 * the ThreadGroup, and we should not be in VMWAIT state while executing
741 * interpreted code.
742 */
743 dvmChangeStatus(NULL, THREAD_RUNNING);
744
745 if (gDvm.verboseShutdown)
746 ALOGD("Compiler thread shutting down");
747 return NULL;
748 }
749
dvmCompilerStartup(void)750 bool dvmCompilerStartup(void)
751 {
752
753 dvmInitMutex(&gDvmJit.compilerLock);
754 dvmInitMutex(&gDvmJit.compilerICPatchLock);
755 dvmInitMutex(&gDvmJit.codeCacheProtectionLock);
756 dvmLockMutex(&gDvmJit.compilerLock);
757 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
758 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
759
760 /* Reset the work queue */
761 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
762 gDvmJit.compilerQueueLength = 0;
763 dvmUnlockMutex(&gDvmJit.compilerLock);
764
765 /*
766 * Defer rest of initialization until we're sure JIT'ng makes sense. Launch
767 * the compiler thread, which will do the real initialization if and
768 * when it is signalled to do so.
769 */
770 return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
771 compilerThreadStart, NULL);
772 }
773
dvmCompilerShutdown(void)774 void dvmCompilerShutdown(void)
775 {
776 void *threadReturn;
777
778 /* Disable new translation requests */
779 gDvmJit.pProfTable = NULL;
780 gDvmJit.pProfTableCopy = NULL;
781 dvmJitUpdateThreadStateAll();
782
783 if (gDvm.verboseShutdown ||
784 gDvmJit.profileMode == kTraceProfilingContinuous) {
785 dvmCompilerDumpStats();
786 while (gDvmJit.compilerQueueLength)
787 sleep(5);
788 }
789
790 if (gDvmJit.compilerHandle) {
791
792 gDvmJit.haltCompilerThread = true;
793
794 dvmLockMutex(&gDvmJit.compilerLock);
795 pthread_cond_signal(&gDvmJit.compilerQueueActivity);
796 dvmUnlockMutex(&gDvmJit.compilerLock);
797
798 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
799 ALOGW("Compiler thread join failed");
800 else if (gDvm.verboseShutdown)
801 ALOGD("Compiler thread has shut down");
802 }
803
804 /* Break loops within the translation cache */
805 dvmJitUnchainAll();
806
807 /*
808 * NOTE: our current implementatation doesn't allow for the compiler
809 * thread to be restarted after it exits here. We aren't freeing
810 * the JitTable or the ProfTable because threads which still may be
811 * running or in the process of shutting down may hold references to
812 * them.
813 */
814 }
815
dvmCompilerUpdateGlobalState()816 void dvmCompilerUpdateGlobalState()
817 {
818 bool jitActive;
819 bool jitActivate;
820 bool needUnchain = false;
821
822 /*
823 * The tableLock might not be initialized yet by the compiler thread if
824 * debugger is attached from the very beginning of the VM launch. If
825 * pProfTableCopy is NULL, the lock is not initialized yet and we don't
826 * need to refresh anything either.
827 */
828 if (gDvmJit.pProfTableCopy == NULL) {
829 return;
830 }
831
832 /*
833 * On the first enabling of method tracing, switch the compiler
834 * into a mode that includes trace support for invokes and returns.
835 * If there are any existing translations, flush them. NOTE: we
836 * can't blindly flush the translation cache because this code
837 * may be executed before the compiler thread has finished
838 * initialization.
839 */
840 if ((gDvm.activeProfilers != 0) &&
841 !gDvmJit.methodTraceSupport) {
842 bool resetRequired;
843 /*
844 * compilerLock will prevent new compilations from being
845 * installed while we are working.
846 */
847 dvmLockMutex(&gDvmJit.compilerLock);
848 gDvmJit.cacheVersion++; // invalidate compilations in flight
849 gDvmJit.methodTraceSupport = true;
850 resetRequired = (gDvmJit.numCompilations != 0);
851 dvmUnlockMutex(&gDvmJit.compilerLock);
852 if (resetRequired) {
853 dvmSuspendAllThreads(SUSPEND_FOR_CC_RESET);
854 resetCodeCache();
855 dvmResumeAllThreads(SUSPEND_FOR_CC_RESET);
856 }
857 }
858
859 dvmLockMutex(&gDvmJit.tableLock);
860 jitActive = gDvmJit.pProfTable != NULL;
861 jitActivate = !dvmDebuggerOrProfilerActive();
862
863 if (jitActivate && !jitActive) {
864 gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
865 } else if (!jitActivate && jitActive) {
866 gDvmJit.pProfTable = NULL;
867 needUnchain = true;
868 }
869 dvmUnlockMutex(&gDvmJit.tableLock);
870 if (needUnchain)
871 dvmJitUnchainAll();
872 // Make sure all threads have current values
873 dvmJitUpdateThreadStateAll();
874 }
875