Compiler.cpp revision 062bf509a77fce9dfcb7e7b2e401cf2a124d83d5
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
25extern "C" void dvmCompilerTemplateStart(void);
26extern "C" void dmvCompilerTemplateEnd(void);
27
28static inline bool workQueueLength(void)
29{
30    return gDvmJit.compilerQueueLength;
31}
32
33static 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
62void 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 */
91bool 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 */
147void 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
165bool 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    // ALOGD("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
223static 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        ALOGD("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                ALOGD("  #%d: break frame (%p)",
242                     stackLevel, saveArea->returnAddr);
243            }
244            else {
245                ALOGD("  #%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
264static 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        ALOGD("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    ALOGD("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 */
364void dvmCompilerPerformSafePointChecks(void)
365{
366    if (gDvmJit.codeCacheFull) {
367        resetCodeCache();
368    }
369    dvmCompilerPatchInlineCache();
370}
371
372static 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
576fail:
577    return false;
578
579}
580
581static 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            ALOGD("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                    ALOGD("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        ALOGD("Compiler thread shutting down");
730    return NULL;
731}
732
733bool 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
757void 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            ALOGD("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
799void 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