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