• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 dmvCompilerTemplateEnd(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: %s", 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) dmvCompilerTemplateEnd -
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 
217     int result = mprotect(gDvmJit.codeCache, gDvmJit.codeCacheSize,
218                           PROTECT_CODE_CACHE_ATTRS);
219 
220     if (result == -1) {
221         ALOGE("Failed to remove the write permission for the code cache");
222         dvmAbort();
223     }
224 #else
225     gDvmJit.codeCacheByteUsed = 0;
226     stream = (char*)gDvmJit.codeCache + gDvmJit.codeCacheByteUsed;
227     ALOGV("codeCache = %p stream = %p before initJIT", gDvmJit.codeCache, stream);
228     streamStart = stream;
229     initJIT(NULL, NULL);
230     gDvmJit.templateSize = (stream - streamStart);
231     gDvmJit.codeCacheByteUsed = (stream - streamStart);
232     ALOGV("stream = %p after initJIT", stream);
233 #endif
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(pJitProfTable);
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         dvmUnlockMutex(&gDvmJit.tableLock);
468         goto fail;
469     }
470 
471     gDvmJit.pJitEntryTable = pJitTable;
472     gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
473     gDvmJit.jitTableEntriesUsed = 0;
474     gDvmJit.compilerHighWater =
475         COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
476     /*
477      * If the VM is launched with wait-on-the-debugger, we will need to hide
478      * the profile table here
479      */
480     gDvmJit.pProfTable = dvmDebuggerOrProfilerActive() ? NULL : pJitProfTable;
481     gDvmJit.pProfTableCopy = pJitProfTable;
482     gDvmJit.pJitTraceProfCounters = pJitTraceProfCounters;
483     dvmJitUpdateThreadStateAll();
484     dvmUnlockMutex(&gDvmJit.tableLock);
485 
486     /* Signal running threads to refresh their cached pJitTable pointers */
487     dvmSuspendAllThreads(SUSPEND_FOR_REFRESH);
488     dvmResumeAllThreads(SUSPEND_FOR_REFRESH);
489 
490     /* Enable signature breakpoints by customizing the following code */
491 #if defined(SIGNATURE_BREAKPOINT)
492     /*
493      * Suppose one sees the following native crash in the bugreport:
494      * I/DEBUG   ( 1638): Build fingerprint: 'unknown'
495      * I/DEBUG   ( 1638): pid: 2468, tid: 2507  >>> com.google.android.gallery3d
496      * I/DEBUG   ( 1638): signal 11 (SIGSEGV), fault addr 00001400
497      * I/DEBUG   ( 1638):  r0 44ea7190  r1 44e4f7b8  r2 44ebc710  r3 00000000
498      * I/DEBUG   ( 1638):  r4 00000a00  r5 41862dec  r6 4710dc10  r7 00000280
499      * I/DEBUG   ( 1638):  r8 ad010f40  r9 46a37a12  10 001116b0  fp 42a78208
500      * I/DEBUG   ( 1638):  ip 00000090  sp 4710dbc8  lr ad060e67  pc 46b90682
501      * cpsr 00000030
502      * I/DEBUG   ( 1638):  #00  pc 46b90682 /dev/ashmem/dalvik-jit-code-cache
503      * I/DEBUG   ( 1638):  #01  pc 00060e62  /system/lib/libdvm.so
504      *
505      * I/DEBUG   ( 1638): code around pc:
506      * I/DEBUG   ( 1638): 46b90660 6888d01c 34091dcc d2174287 4a186b68
507      * I/DEBUG   ( 1638): 46b90670 d0052800 68006809 28004790 6b68d00e
508      * I/DEBUG   ( 1638): 46b90680 512000bc 37016eaf 6ea866af 6f696028
509      * I/DEBUG   ( 1638): 46b90690 682a6069 429a686b e003da08 6df1480b
510      * I/DEBUG   ( 1638): 46b906a0 1c2d4788 47806d70 46a378fa 47806d70
511      *
512      * Clearly it is a JIT bug. To find out which translation contains the
513      * offending code, the content of the memory dump around the faulting PC
514      * can be pasted into the gDvmJit.signatureBreakpoint[] array and next time
515      * when a similar compilation is being created, the JIT compiler replay the
516      * trace in the verbose mode and one can investigate the instruction
517      * sequence in details.
518      *
519      * The length of the signature may need additional experiments to determine.
520      * The rule of thumb is don't include PC-relative instructions in the
521      * signature since it may be affected by the alignment of the compiled code.
522      * However, a signature that's too short might increase the chance of false
523      * positive matches. Using gdbjithelper to disassembly the memory content
524      * first might be a good companion approach.
525      *
526      * For example, if the next 4 words starting from 46b90680 is pasted into
527      * the data structure:
528      */
529 
530     gDvmJit.signatureBreakpointSize = 4;
531     gDvmJit.signatureBreakpoint =
532         malloc(sizeof(u4) * gDvmJit.signatureBreakpointSize);
533     gDvmJit.signatureBreakpoint[0] = 0x512000bc;
534     gDvmJit.signatureBreakpoint[1] = 0x37016eaf;
535     gDvmJit.signatureBreakpoint[2] = 0x6ea866af;
536     gDvmJit.signatureBreakpoint[3] = 0x6f696028;
537 
538     /*
539      * The following log will be printed when a match is found in subsequent
540      * testings:
541      *
542      * D/dalvikvm( 2468): Signature match starting from offset 0x34 (4 words)
543      * D/dalvikvm( 2468): --------
544      * D/dalvikvm( 2468): Compiler: Building trace for computeVisibleItems,
545      * offset 0x1f7
546      * D/dalvikvm( 2468): 0x46a37a12: 0x0090 add-int v42, v5, v26
547      * D/dalvikvm( 2468): 0x46a37a16: 0x004d aput-object v13, v14, v42
548      * D/dalvikvm( 2468): 0x46a37a1a: 0x0028 goto, (#0), (#0)
549      * D/dalvikvm( 2468): 0x46a3794e: 0x00d8 add-int/lit8 v26, v26, (#1)
550      * D/dalvikvm( 2468): 0x46a37952: 0x0028 goto, (#0), (#0)
551      * D/dalvikvm( 2468): 0x46a378ee: 0x0002 move/from16 v0, v26, (#0)
552      * D/dalvikvm( 2468): 0x46a378f2: 0x0002 move/from16 v1, v29, (#0)
553      * D/dalvikvm( 2468): 0x46a378f6: 0x0035 if-ge v0, v1, (#10)
554      * D/dalvikvm( 2468): TRACEINFO (554): 0x46a37624
555      * Lcom/cooliris/media/GridLayer;computeVisibleItems 0x1f7 14 of 934, 8
556      * blocks
557      *     :
558      *     :
559      * D/dalvikvm( 2468): 0x20 (0020): ldr     r0, [r5, #52]
560      * D/dalvikvm( 2468): 0x22 (0022): ldr     r2, [pc, #96]
561      * D/dalvikvm( 2468): 0x24 (0024): cmp     r0, #0
562      * D/dalvikvm( 2468): 0x26 (0026): beq     0x00000034
563      * D/dalvikvm( 2468): 0x28 (0028): ldr     r1, [r1, #0]
564      * D/dalvikvm( 2468): 0x2a (002a): ldr     r0, [r0, #0]
565      * D/dalvikvm( 2468): 0x2c (002c): blx     r2
566      * D/dalvikvm( 2468): 0x2e (002e): cmp     r0, #0
567      * D/dalvikvm( 2468): 0x30 (0030): beq     0x00000050
568      * D/dalvikvm( 2468): 0x32 (0032): ldr     r0, [r5, #52]
569      * D/dalvikvm( 2468): 0x34 (0034): lsls    r4, r7, #2
570      * D/dalvikvm( 2468): 0x36 (0036): str     r0, [r4, r4]
571      * D/dalvikvm( 2468): -------- dalvik offset: 0x01fb @ goto, (#0), (#0)
572      * D/dalvikvm( 2468): L0x0195:
573      * D/dalvikvm( 2468): -------- dalvik offset: 0x0195 @ add-int/lit8 v26,
574      * v26, (#1)
575      * D/dalvikvm( 2468): 0x38 (0038): ldr     r7, [r5, #104]
576      * D/dalvikvm( 2468): 0x3a (003a): adds    r7, r7, #1
577      * D/dalvikvm( 2468): 0x3c (003c): str     r7, [r5, #104]
578      * D/dalvikvm( 2468): -------- dalvik offset: 0x0197 @ goto, (#0), (#0)
579      * D/dalvikvm( 2468): L0x0165:
580      * D/dalvikvm( 2468): -------- dalvik offset: 0x0165 @ move/from16 v0, v26,
581      * (#0)
582      * D/dalvikvm( 2468): 0x3e (003e): ldr     r0, [r5, #104]
583      * D/dalvikvm( 2468): 0x40 (0040): str     r0, [r5, #0]
584      *
585      * The "str r0, [r4, r4]" is indeed the culprit of the native crash.
586      */
587 #endif
588 
589     return true;
590 
591 fail:
592     return false;
593 
594 }
595 
compilerThreadStart(void * arg)596 static void *compilerThreadStart(void *arg)
597 {
598     dvmChangeStatus(NULL, THREAD_VMWAIT);
599 
600     /*
601      * If we're not running stand-alone, wait a little before
602      * recieving translation requests on the assumption that process start
603      * up code isn't worth compiling.  We'll resume when the framework
604      * signals us that the first screen draw has happened, or the timer
605      * below expires (to catch daemons).
606      *
607      * There is a theoretical race between the callback to
608      * VMRuntime.startJitCompiation and when the compiler thread reaches this
609      * point. In case the callback happens earlier, in order not to permanently
610      * hold the system_server (which is not using the timed wait) in
611      * interpreter-only mode we bypass the delay here.
612      */
613     if (gDvmJit.runningInAndroidFramework &&
614         !gDvmJit.alreadyEnabledViaFramework) {
615         /*
616          * If the current VM instance is the system server (detected by having
617          * 0 in gDvm.systemServerPid), we will use the indefinite wait on the
618          * conditional variable to determine whether to start the JIT or not.
619          * If the system server detects that the whole system is booted in
620          * safe mode, the conditional variable will never be signaled and the
621          * system server will remain in the interpreter-only mode. All
622          * subsequent apps will be started with the --enable-safemode flag
623          * explicitly appended.
624          */
625         if (gDvm.systemServerPid == 0) {
626             dvmLockMutex(&gDvmJit.compilerLock);
627             pthread_cond_wait(&gDvmJit.compilerQueueActivity,
628                               &gDvmJit.compilerLock);
629             dvmUnlockMutex(&gDvmJit.compilerLock);
630             ALOGD("JIT started for system_server");
631         } else {
632             dvmLockMutex(&gDvmJit.compilerLock);
633             /*
634              * TUNING: experiment with the delay & perhaps make it
635              * target-specific
636              */
637             dvmRelativeCondWait(&gDvmJit.compilerQueueActivity,
638                                  &gDvmJit.compilerLock, 3000, 0);
639             dvmUnlockMutex(&gDvmJit.compilerLock);
640         }
641         if (gDvmJit.haltCompilerThread) {
642              return NULL;
643         }
644     }
645 
646     compilerThreadStartup();
647 
648     dvmLockMutex(&gDvmJit.compilerLock);
649     /*
650      * Since the compiler thread will not touch any objects on the heap once
651      * being created, we just fake its state as VMWAIT so that it can be a
652      * bit late when there is suspend request pending.
653      */
654     while (!gDvmJit.haltCompilerThread) {
655         if (workQueueLength() == 0) {
656             int cc;
657             cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
658             assert(cc == 0);
659             pthread_cond_wait(&gDvmJit.compilerQueueActivity,
660                               &gDvmJit.compilerLock);
661             continue;
662         } else {
663             do {
664                 CompilerWorkOrder work = workDequeue();
665                 dvmUnlockMutex(&gDvmJit.compilerLock);
666 #if defined(WITH_JIT_TUNING)
667                 /*
668                  * This is live across setjmp().  Mark it volatile to suppress
669                  * a gcc warning.  We should not need this since it is assigned
670                  * only once but gcc is not smart enough.
671                  */
672                 volatile u8 startTime = dvmGetRelativeTimeUsec();
673 #endif
674                 /*
675                  * Check whether there is a suspend request on me.  This
676                  * is necessary to allow a clean shutdown.
677                  *
678                  * However, in the blocking stress testing mode, let the
679                  * compiler thread continue doing compilations to unblock
680                  * other requesting threads. This may occasionally cause
681                  * shutdown from proceeding cleanly in the standalone invocation
682                  * of the vm but this should be acceptable.
683                  */
684                 if (!gDvmJit.blockingMode)
685                     dvmCheckSuspendPending(dvmThreadSelf());
686                 /* Is JitTable filling up? */
687                 if (gDvmJit.jitTableEntriesUsed >
688                     (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
689                     bool resizeFail =
690                         dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
691                     /*
692                      * If the jit table is full, consider it's time to reset
693                      * the code cache too.
694                      */
695                     gDvmJit.codeCacheFull |= resizeFail;
696                 }
697                 if (gDvmJit.haltCompilerThread) {
698                     ALOGD("Compiler shutdown in progress - discarding request");
699                 } else if (!gDvmJit.codeCacheFull) {
700                     jmp_buf jmpBuf;
701                     work.bailPtr = &jmpBuf;
702                     bool aborted = setjmp(jmpBuf);
703                     if (!aborted) {
704                         bool codeCompiled = dvmCompilerDoWork(&work);
705                         /*
706                          * Make sure we are still operating with the
707                          * same translation cache version.  See
708                          * Issue 4271784 for details.
709                          */
710                         dvmLockMutex(&gDvmJit.compilerLock);
711                         if ((work.result.cacheVersion ==
712                              gDvmJit.cacheVersion) &&
713                              codeCompiled &&
714                              !work.result.discardResult &&
715                              work.result.codeAddress) {
716                             dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
717                                               work.result.instructionSet,
718                                               false, /* not method entry */
719                                               work.result.profileCodeSize);
720                         }
721                         dvmUnlockMutex(&gDvmJit.compilerLock);
722                     }
723                     dvmCompilerArenaReset();
724                 }
725                 free(work.info);
726 #if defined(WITH_JIT_TUNING)
727                 gDvmJit.jitTime += dvmGetRelativeTimeUsec() - startTime;
728 #endif
729                 dvmLockMutex(&gDvmJit.compilerLock);
730             } while (workQueueLength() != 0);
731         }
732     }
733     pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
734     dvmUnlockMutex(&gDvmJit.compilerLock);
735 
736     /*
737      * As part of detaching the thread we need to call into Java code to update
738      * the ThreadGroup, and we should not be in VMWAIT state while executing
739      * interpreted code.
740      */
741     dvmChangeStatus(NULL, THREAD_RUNNING);
742 
743     if (gDvm.verboseShutdown)
744         ALOGD("Compiler thread shutting down");
745     return NULL;
746 }
747 
dvmCompilerStartup(void)748 bool dvmCompilerStartup(void)
749 {
750 
751     dvmInitMutex(&gDvmJit.compilerLock);
752     dvmInitMutex(&gDvmJit.compilerICPatchLock);
753     dvmInitMutex(&gDvmJit.codeCacheProtectionLock);
754     dvmLockMutex(&gDvmJit.compilerLock);
755     pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
756     pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
757 
758     /* Reset the work queue */
759     gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
760     gDvmJit.compilerQueueLength = 0;
761     dvmUnlockMutex(&gDvmJit.compilerLock);
762 
763     /*
764      * Defer rest of initialization until we're sure JIT'ng makes sense. Launch
765      * the compiler thread, which will do the real initialization if and
766      * when it is signalled to do so.
767      */
768     return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
769                                    compilerThreadStart, NULL);
770 }
771 
dvmCompilerShutdown(void)772 void dvmCompilerShutdown(void)
773 {
774     void *threadReturn;
775 
776     /* Disable new translation requests */
777     gDvmJit.pProfTable = NULL;
778     gDvmJit.pProfTableCopy = NULL;
779     dvmJitUpdateThreadStateAll();
780 
781     if (gDvm.verboseShutdown ||
782             gDvmJit.profileMode == kTraceProfilingContinuous) {
783         dvmCompilerDumpStats();
784         while (gDvmJit.compilerQueueLength)
785           sleep(5);
786     }
787 
788     if (gDvmJit.compilerHandle) {
789 
790         gDvmJit.haltCompilerThread = true;
791 
792         dvmLockMutex(&gDvmJit.compilerLock);
793         pthread_cond_signal(&gDvmJit.compilerQueueActivity);
794         dvmUnlockMutex(&gDvmJit.compilerLock);
795 
796         if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
797             ALOGW("Compiler thread join failed");
798         else if (gDvm.verboseShutdown)
799             ALOGD("Compiler thread has shut down");
800     }
801 
802     /* Break loops within the translation cache */
803     dvmJitUnchainAll();
804 
805     /*
806      * NOTE: our current implementatation doesn't allow for the compiler
807      * thread to be restarted after it exits here.  We aren't freeing
808      * the JitTable or the ProfTable because threads which still may be
809      * running or in the process of shutting down may hold references to
810      * them.
811      */
812 }
813 
dvmCompilerUpdateGlobalState()814 void dvmCompilerUpdateGlobalState()
815 {
816     bool jitActive;
817     bool jitActivate;
818     bool needUnchain = false;
819 
820     /*
821      * The tableLock might not be initialized yet by the compiler thread if
822      * debugger is attached from the very beginning of the VM launch. If
823      * pProfTableCopy is NULL, the lock is not initialized yet and we don't
824      * need to refresh anything either.
825      */
826     if (gDvmJit.pProfTableCopy == NULL) {
827         return;
828     }
829 
830     /*
831      * On the first enabling of method tracing, switch the compiler
832      * into a mode that includes trace support for invokes and returns.
833      * If there are any existing translations, flush them.  NOTE:  we
834      * can't blindly flush the translation cache because this code
835      * may be executed before the compiler thread has finished
836      * initialization.
837      */
838     if ((gDvm.activeProfilers != 0) &&
839         !gDvmJit.methodTraceSupport) {
840         bool resetRequired;
841         /*
842          * compilerLock will prevent new compilations from being
843          * installed while we are working.
844          */
845         dvmLockMutex(&gDvmJit.compilerLock);
846         gDvmJit.cacheVersion++; // invalidate compilations in flight
847         gDvmJit.methodTraceSupport = true;
848         resetRequired = (gDvmJit.numCompilations != 0);
849         dvmUnlockMutex(&gDvmJit.compilerLock);
850         if (resetRequired) {
851             dvmSuspendAllThreads(SUSPEND_FOR_CC_RESET);
852             resetCodeCache();
853             dvmResumeAllThreads(SUSPEND_FOR_CC_RESET);
854         }
855     }
856 
857     dvmLockMutex(&gDvmJit.tableLock);
858     jitActive = gDvmJit.pProfTable != NULL;
859     jitActivate = !dvmDebuggerOrProfilerActive();
860 
861     if (jitActivate && !jitActive) {
862         gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
863     } else if (!jitActivate && jitActive) {
864         gDvmJit.pProfTable = NULL;
865         needUnchain = true;
866     }
867     dvmUnlockMutex(&gDvmJit.tableLock);
868     if (needUnchain)
869         dvmJitUnchainAll();
870     // Make sure all threads have current values
871     dvmJitUpdateThreadStateAll();
872 }
873