Compiler.cpp revision fc519dc8f4444f6d93806ec15ce7445b322070fd
1ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng/*
2ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * Copyright (C) 2009 The Android Open Source Project
3ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng *
4ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * Licensed under the Apache License, Version 2.0 (the "License");
5ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * you may not use this file except in compliance with the License.
6ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * You may obtain a copy of the License at
7ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng *
8ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng *      http://www.apache.org/licenses/LICENSE-2.0
9ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng *
10ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * Unless required by applicable law or agreed to in writing, software
11ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * distributed under the License is distributed on an "AS IS" BASIS,
12ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * See the License for the specific language governing permissions and
14ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * limitations under the License.
15ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng */
16ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
17ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#include <sys/mman.h>
18ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#include <errno.h>
197c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng#include <cutils/ashmem.h>
20ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
21ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#include "Dalvik.h"
22ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#include "interp/Jit.h"
23ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#include "CompilerInternals.h"
24ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
25ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengstatic inline bool workQueueLength(void)
26ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng{
27ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    return gDvmJit.compilerQueueLength;
28ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng}
29ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
30ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengstatic CompilerWorkOrder workDequeue(void)
31ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng{
32ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    assert(gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex].kind
33ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng           != kWorkOrderInvalid);
34ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    CompilerWorkOrder work =
35ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex];
36ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex++].kind =
37ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        kWorkOrderInvalid;
38ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if (gDvmJit.compilerWorkDequeueIndex == COMPILER_WORK_QUEUE_SIZE) {
39ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        gDvmJit.compilerWorkDequeueIndex = 0;
40ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    }
41ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    gDvmJit.compilerQueueLength--;
42f9f33287693f9f9aa44318036b8aab627bd21a32Bill Buzbee    if (gDvmJit.compilerQueueLength == 0) {
43f9f33287693f9f9aa44318036b8aab627bd21a32Bill Buzbee        int cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
44f9f33287693f9f9aa44318036b8aab627bd21a32Bill Buzbee    }
45ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
46ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    /* Remember the high water mark of the queue length */
47ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if (gDvmJit.compilerQueueLength > gDvmJit.compilerMaxQueued)
48ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        gDvmJit.compilerMaxQueued = gDvmJit.compilerQueueLength;
49ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
50ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    return work;
51ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng}
52ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
53964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee/*
54964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee * Attempt to enqueue a work order, returning true if successful.
55964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee * This routine will not block, but simply return if it couldn't
56964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee * aquire the lock or if the queue is full.
571357e94efecd485bda933270a9181035f6a39e09Ben Cheng *
581357e94efecd485bda933270a9181035f6a39e09Ben Cheng * NOTE: Make sure that the caller frees the info pointer if the return value
591357e94efecd485bda933270a9181035f6a39e09Ben Cheng * is false.
60964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee */
61ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengbool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
62ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng{
63ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    int cc;
64ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    int i;
65ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    int numWork;
6660c24f436d603c564d5351a6f81821f12635733cBen Cheng    bool result = true;
67ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
68964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    if (dvmTryLockMutex(&gDvmJit.compilerLock)) {
693e5cd17e4a0306dc976e1dc37b39d19dee4451a7Ben Cheng        return false;  // Couldn't acquire the lock
70964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    }
71ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
727a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    /*
736999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng     * Return if queue or code cache is full.
747a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng     */
756999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE ||
766999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng        gDvmJit.codeCacheFull == true) {
7760c24f436d603c564d5351a6f81821f12635733cBen Cheng        result = false;
78964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee        goto unlockAndExit;
79ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    }
80ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
81ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    for (numWork = gDvmJit.compilerQueueLength,
82ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng           i = gDvmJit.compilerWorkDequeueIndex;
83ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng         numWork > 0;
84ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng         numWork--) {
85ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        /* Already enqueued */
86ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        if (gDvmJit.compilerWorkQueue[i++].pc == pc)
87964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee            goto unlockAndExit;
88ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        /* Wrap around */
89ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        if (i == COMPILER_WORK_QUEUE_SIZE)
90ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            i = 0;
91ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    }
92ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
93ccd6c0102d1f898aaea1c94761167fdd083b5275Ben Cheng    CompilerWorkOrder *newOrder =
94ccd6c0102d1f898aaea1c94761167fdd083b5275Ben Cheng        &gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex];
95ccd6c0102d1f898aaea1c94761167fdd083b5275Ben Cheng    newOrder->pc = pc;
96ccd6c0102d1f898aaea1c94761167fdd083b5275Ben Cheng    newOrder->kind = kind;
97ccd6c0102d1f898aaea1c94761167fdd083b5275Ben Cheng    newOrder->info = info;
98ccd6c0102d1f898aaea1c94761167fdd083b5275Ben Cheng    newOrder->result.codeAddress = NULL;
99ccd6c0102d1f898aaea1c94761167fdd083b5275Ben Cheng    newOrder->result.discardResult =
1001f74863d3e0f19930818398f375ebf1cf2d78969Bill Buzbee        (kind == kWorkOrderTraceDebug) ? true : false;
10133672456e19bff9913b4a3459e6b8472f4c26c84Ben Cheng    newOrder->result.requestingThread = dvmThreadSelf();
10233672456e19bff9913b4a3459e6b8472f4c26c84Ben Cheng
103ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    gDvmJit.compilerWorkEnqueueIndex++;
104ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
105ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        gDvmJit.compilerWorkEnqueueIndex = 0;
106ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    gDvmJit.compilerQueueLength++;
107ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
108ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    assert(cc == 0);
109ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
110964a7b06a9134947b5985c7f712d18d57ed665d2Bill BuzbeeunlockAndExit:
111ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    dvmUnlockMutex(&gDvmJit.compilerLock);
11260c24f436d603c564d5351a6f81821f12635733cBen Cheng    return result;
113ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng}
114ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
115ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng/* Block until queue length is 0 */
116ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengvoid dvmCompilerDrainQueue(void)
117ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng{
118d726991ba52466cde88e37aba4de2395b62477faBill Buzbee    int oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
119ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    dvmLockMutex(&gDvmJit.compilerLock);
120ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread) {
121ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        pthread_cond_wait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock);
122ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    }
123ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    dvmUnlockMutex(&gDvmJit.compilerLock);
124d726991ba52466cde88e37aba4de2395b62477faBill Buzbee    dvmChangeStatus(NULL, oldStatus);
125ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng}
126ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
12760c24f436d603c564d5351a6f81821f12635733cBen Chengbool dvmCompilerSetupCodeCache(void)
12860c24f436d603c564d5351a6f81821f12635733cBen Cheng{
12960c24f436d603c564d5351a6f81821f12635733cBen Cheng    extern void dvmCompilerTemplateStart(void);
13060c24f436d603c564d5351a6f81821f12635733cBen Cheng    extern void dmvCompilerTemplateEnd(void);
1317c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng    int fd;
13260c24f436d603c564d5351a6f81821f12635733cBen Cheng
13360c24f436d603c564d5351a6f81821f12635733cBen Cheng    /* Allocate the code cache */
1347c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng    fd = ashmem_create_region("dalvik-jit-code-cache", gDvmJit.codeCacheSize);
1357c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng    if (fd < 0) {
1367c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng        LOGE("Could not create %u-byte ashmem region for the JIT code cache",
1377c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng             gDvmJit.codeCacheSize);
1387c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng        return false;
1397c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng    }
1407c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng    gDvmJit.codeCache = mmap(NULL, gDvmJit.codeCacheSize,
1417c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng                             PROT_READ | PROT_WRITE | PROT_EXEC,
1427c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng                             MAP_PRIVATE , fd, 0);
1437c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng    close(fd);
14460c24f436d603c564d5351a6f81821f12635733cBen Cheng    if (gDvmJit.codeCache == MAP_FAILED) {
1457c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng        LOGE("Failed to mmap the JIT code cache: %s\n", strerror(errno));
14660c24f436d603c564d5351a6f81821f12635733cBen Cheng        return false;
14760c24f436d603c564d5351a6f81821f12635733cBen Cheng    }
14860c24f436d603c564d5351a6f81821f12635733cBen Cheng
1497c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng    /* This can be found through "dalvik-jit-code-cache" in /proc/<pid>/maps */
1507c4afdb7e96bb74909f111f08741aed261d191f8Ben Cheng    // LOGD("Code cache starts at %p", gDvmJit.codeCache);
1517a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng
15260c24f436d603c564d5351a6f81821f12635733cBen Cheng    /* Copy the template code into the beginning of the code cache */
15360c24f436d603c564d5351a6f81821f12635733cBen Cheng    int templateSize = (intptr_t) dmvCompilerTemplateEnd -
15460c24f436d603c564d5351a6f81821f12635733cBen Cheng                       (intptr_t) dvmCompilerTemplateStart;
15560c24f436d603c564d5351a6f81821f12635733cBen Cheng    memcpy((void *) gDvmJit.codeCache,
15660c24f436d603c564d5351a6f81821f12635733cBen Cheng           (void *) dvmCompilerTemplateStart,
15760c24f436d603c564d5351a6f81821f12635733cBen Cheng           templateSize);
15860c24f436d603c564d5351a6f81821f12635733cBen Cheng
15960c24f436d603c564d5351a6f81821f12635733cBen Cheng    gDvmJit.templateSize = templateSize;
16060c24f436d603c564d5351a6f81821f12635733cBen Cheng    gDvmJit.codeCacheByteUsed = templateSize;
16160c24f436d603c564d5351a6f81821f12635733cBen Cheng
16260c24f436d603c564d5351a6f81821f12635733cBen Cheng    /* Only flush the part in the code cache that is being used now */
16360c24f436d603c564d5351a6f81821f12635733cBen Cheng    cacheflush((intptr_t) gDvmJit.codeCache,
16460c24f436d603c564d5351a6f81821f12635733cBen Cheng               (intptr_t) gDvmJit.codeCache + templateSize, 0);
16560c24f436d603c564d5351a6f81821f12635733cBen Cheng    return true;
16660c24f436d603c564d5351a6f81821f12635733cBen Cheng}
16760c24f436d603c564d5351a6f81821f12635733cBen Cheng
1687a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Chengstatic void crawlDalvikStack(Thread *thread, bool print)
1697a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng{
1707a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    void *fp = thread->curFrame;
1717a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    StackSaveArea* saveArea = NULL;
1727a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    int stackLevel = 0;
1737a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng
1747a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    if (print) {
1757a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng        LOGD("Crawling tid %d (%s / %p %s)", thread->systemTid,
1767a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng             dvmGetThreadStatusStr(thread->status),
1777a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng             thread->inJitCodeCache,
1787a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng             thread->inJitCodeCache ? "jit" : "interp");
1797a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    }
1807a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    /* Crawl the Dalvik stack frames to clear the returnAddr field */
1817a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    while (fp != NULL) {
1827a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng        saveArea = SAVEAREA_FROM_FP(fp);
1837a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng
1847a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng        if (print) {
1857a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng            if (dvmIsBreakFrame(fp)) {
1867a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng                LOGD("  #%d: break frame (%p)",
1877a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng                     stackLevel, saveArea->returnAddr);
1887a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng            }
1897a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng            else {
1907a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng                LOGD("  #%d: %s.%s%s (%p)",
1917a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng                     stackLevel,
1927a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng                     saveArea->method->clazz->descriptor,
1937a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng                     saveArea->method->name,
1947a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng                     dvmIsNativeMethod(saveArea->method) ?
1957a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng                         " (native)" : "",
1967a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng                     saveArea->returnAddr);
1977a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng            }
1987a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng        }
1997a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng        stackLevel++;
2007a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng        saveArea->returnAddr = NULL;
2017a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng        assert(fp != saveArea->prevFrame);
2027a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng        fp = saveArea->prevFrame;
2037a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    }
2047a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    /* Make sure the stack is fully unwound to the bottom */
2057a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    assert(saveArea == NULL ||
2067a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng           (u1 *) (saveArea+1) == thread->interpStackStart);
2077a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng}
2087a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng
20960c24f436d603c564d5351a6f81821f12635733cBen Chengstatic void resetCodeCache(void)
21060c24f436d603c564d5351a6f81821f12635733cBen Cheng{
21160c24f436d603c564d5351a6f81821f12635733cBen Cheng    Thread* thread;
2127a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    u8 startTime = dvmGetRelativeTimeUsec();
2137a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    int inJit = 0;
2146999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    int byteUsed = gDvmJit.codeCacheByteUsed;
21560c24f436d603c564d5351a6f81821f12635733cBen Cheng
2167a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    /* If any thread is found stuck in the JIT state, don't reset the cache */
21760c24f436d603c564d5351a6f81821f12635733cBen Cheng    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
2186999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng        /*
2196999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng         * Crawl the stack to wipe out the returnAddr field so that
2206999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng         * 1) the soon-to-be-deleted code in the JIT cache won't be used
2216999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng         * 2) or the thread stuck in the JIT land will soon return
2226999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng         *    to the interpreter land
2236999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng         */
2246999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng        crawlDalvikStack(thread, false);
2257a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng        if (thread->inJitCodeCache) {
2267a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng            inJit++;
2277a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng        }
2287a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    }
22960c24f436d603c564d5351a6f81821f12635733cBen Cheng
2307a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    if (inJit) {
2316999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng        LOGD("JIT code cache reset delayed (%d bytes %d/%d)",
2326999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng             gDvmJit.codeCacheByteUsed, gDvmJit.numCodeCacheReset,
2336999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng             ++gDvmJit.numCodeCacheResetDelayed);
2346999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng        return;
2357a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    }
2367a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng
2376999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    /* Lock the mutex to clean up the work queue */
2386999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    dvmLockMutex(&gDvmJit.compilerLock);
2396999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng
2406999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    /* Drain the work queue to free the work orders */
2417a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    while (workQueueLength()) {
2427a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng        CompilerWorkOrder work = workDequeue();
2437a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng        free(work.info);
2447a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    }
2457a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng
24660c24f436d603c564d5351a6f81821f12635733cBen Cheng    /* Reset the JitEntry table contents to the initial unpopulated state */
24760c24f436d603c564d5351a6f81821f12635733cBen Cheng    dvmJitResetTable();
24860c24f436d603c564d5351a6f81821f12635733cBen Cheng
24960c24f436d603c564d5351a6f81821f12635733cBen Cheng    /*
25060c24f436d603c564d5351a6f81821f12635733cBen Cheng     * Wipe out the code cache content to force immediate crashes if
25160c24f436d603c564d5351a6f81821f12635733cBen Cheng     * stale JIT'ed code is invoked.
25260c24f436d603c564d5351a6f81821f12635733cBen Cheng     */
2537a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    memset((char *) gDvmJit.codeCache + gDvmJit.templateSize,
2547a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng           0,
2557a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng           gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
25660c24f436d603c564d5351a6f81821f12635733cBen Cheng    cacheflush((intptr_t) gDvmJit.codeCache,
25760c24f436d603c564d5351a6f81821f12635733cBen Cheng               (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed, 0);
25860c24f436d603c564d5351a6f81821f12635733cBen Cheng
25960c24f436d603c564d5351a6f81821f12635733cBen Cheng    /* Reset the current mark of used bytes to the end of template code */
26060c24f436d603c564d5351a6f81821f12635733cBen Cheng    gDvmJit.codeCacheByteUsed = gDvmJit.templateSize;
26160c24f436d603c564d5351a6f81821f12635733cBen Cheng    gDvmJit.numCompilations = 0;
26260c24f436d603c564d5351a6f81821f12635733cBen Cheng
26360c24f436d603c564d5351a6f81821f12635733cBen Cheng    /* Reset the work queue */
26460c24f436d603c564d5351a6f81821f12635733cBen Cheng    memset(gDvmJit.compilerWorkQueue, 0,
26560c24f436d603c564d5351a6f81821f12635733cBen Cheng           sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
26660c24f436d603c564d5351a6f81821f12635733cBen Cheng    gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
26760c24f436d603c564d5351a6f81821f12635733cBen Cheng    gDvmJit.compilerQueueLength = 0;
26860c24f436d603c564d5351a6f81821f12635733cBen Cheng
2696999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    /* Reset the IC patch work queue */
2706999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    dvmLockMutex(&gDvmJit.compilerICPatchLock);
2716999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    gDvmJit.compilerICPatchIndex = 0;
2726999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
2736999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng
27460c24f436d603c564d5351a6f81821f12635733cBen Cheng    /* All clear now */
27560c24f436d603c564d5351a6f81821f12635733cBen Cheng    gDvmJit.codeCacheFull = false;
27660c24f436d603c564d5351a6f81821f12635733cBen Cheng
2776999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    dvmUnlockMutex(&gDvmJit.compilerLock);
2787a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng
2796999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    LOGD("JIT code cache reset in %lld ms (%d bytes %d/%d)",
2806999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng         (dvmGetRelativeTimeUsec() - startTime) / 1000,
2816999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng         byteUsed, ++gDvmJit.numCodeCacheReset,
2826999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng         gDvmJit.numCodeCacheResetDelayed);
2836999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng}
2846999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng
2856999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng/*
2866999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng * Perform actions that are only safe when all threads are suspended. Currently
2876999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng * we do:
2886999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng * 1) Check if the code cache is full. If so reset it and restart populating it
2896999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng *    from scratch.
2906999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng * 2) Patch predicted chaining cells by consuming recorded work orders.
2916999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng */
2926999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Chengvoid dvmCompilerPerformSafePointChecks(void)
2936999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng{
2946999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    if (gDvmJit.codeCacheFull) {
2956999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng        resetCodeCache();
2966999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    }
2976999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    dvmCompilerPatchInlineCache();
29860c24f436d603c564d5351a6f81821f12635733cBen Cheng}
29960c24f436d603c564d5351a6f81821f12635733cBen Cheng
300964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbeebool compilerThreadStartup(void)
301964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee{
302964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    JitEntry *pJitTable = NULL;
303964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    unsigned char *pJitProfTable = NULL;
304964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    unsigned int i;
305964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
306964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    if (!dvmCompilerArchInit())
307964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee        goto fail;
308964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
309964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    /*
310964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee     * Setup the code cache if we have not inherited a valid code cache
311964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee     * from the zygote.
312964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee     */
313964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    if (gDvmJit.codeCache == NULL) {
314964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee        if (!dvmCompilerSetupCodeCache())
315964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee            goto fail;
316964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    }
317964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
318964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    /* Allocate the initial arena block */
319964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    if (dvmCompilerHeapInit() == false) {
320964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee        goto fail;
321964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    }
322964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
323964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    dvmLockMutex(&gDvmJit.compilerLock);
324964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
3251357e94efecd485bda933270a9181035f6a39e09Ben Cheng#if defined(WITH_JIT_TUNING)
326964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    /* Track method-level compilation statistics */
327964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    gDvmJit.methodStatsTable =  dvmHashTableCreate(32, NULL);
3281357e94efecd485bda933270a9181035f6a39e09Ben Cheng#endif
329964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
330964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    dvmUnlockMutex(&gDvmJit.compilerLock);
331964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
332964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    /* Set up the JitTable */
333964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
334964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    /* Power of 2? */
335964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    assert(gDvmJit.jitTableSize &&
336964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee           !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1)));
337964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
338964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    dvmInitMutex(&gDvmJit.tableLock);
339964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    dvmLockMutex(&gDvmJit.tableLock);
340964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    pJitTable = (JitEntry*)
341964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee                calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
342964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    if (!pJitTable) {
343964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee        LOGE("jit table allocation failed\n");
344964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee        dvmUnlockMutex(&gDvmJit.tableLock);
345964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee        goto fail;
346964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    }
347964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    /*
348964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee     * NOTE: the profile table must only be allocated once, globally.
349964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee     * Profiling is turned on and off by nulling out gDvm.pJitProfTable
350964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee     * and then restoring its original value.  However, this action
351964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee     * is not syncronized for speed so threads may continue to hold
352964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee     * and update the profile table after profiling has been turned
353964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee     * off by null'ng the global pointer.  Be aware.
354964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee     */
355964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE);
356964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    if (!pJitProfTable) {
357964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee        LOGE("jit prof table allocation failed\n");
358964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee        dvmUnlockMutex(&gDvmJit.tableLock);
359964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee        goto fail;
360964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    }
361964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE);
362964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    for (i=0; i < gDvmJit.jitTableSize; i++) {
363964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee       pJitTable[i].u.info.chain = gDvmJit.jitTableSize;
364964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    }
365964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    /* Is chain field wide enough for termination pattern? */
366964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize);
367964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
368964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    gDvmJit.pJitEntryTable = pJitTable;
369964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
370964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    gDvmJit.jitTableEntriesUsed = 0;
371964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    gDvmJit.compilerHighWater =
372964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee        COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
373964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    gDvmJit.pProfTable = pJitProfTable;
37406bb83906737fec543c86ab36f450cc62066b58aBill Buzbee    gDvmJit.pProfTableCopy = pJitProfTable;
375964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    dvmUnlockMutex(&gDvmJit.tableLock);
376964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
377964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    /* Signal running threads to refresh their cached pJitTable pointers */
378964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    dvmSuspendAllThreads(SUSPEND_FOR_REFRESH);
379964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    dvmResumeAllThreads(SUSPEND_FOR_REFRESH);
380964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    return true;
381964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
382964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbeefail:
383964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    return false;
384964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
385964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee}
386964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee
387ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengstatic void *compilerThreadStart(void *arg)
388ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng{
38994d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee    int ret;
39094d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee    struct timespec ts;
39194d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee
3925ccdf0be4b448c98b595444a77dbaa21471ad1b1Ben Cheng    dvmChangeStatus(NULL, THREAD_VMWAIT);
3935ccdf0be4b448c98b595444a77dbaa21471ad1b1Ben Cheng
394b1d8044ee3a7503b94eb54459f3077d7200cd675Bill Buzbee    /*
395eb695c6f814f6b0bdbba0e837555d3fe5ad23104Bill Buzbee     * If we're not running stand-alone, wait a little before
396eb695c6f814f6b0bdbba0e837555d3fe5ad23104Bill Buzbee     * recieving translation requests on the assumption that process start
397eb695c6f814f6b0bdbba0e837555d3fe5ad23104Bill Buzbee     * up code isn't worth compiling.  We'll resume when the framework
398eb695c6f814f6b0bdbba0e837555d3fe5ad23104Bill Buzbee     * signals us that the first screen draw has happened, or the timer
399eb695c6f814f6b0bdbba0e837555d3fe5ad23104Bill Buzbee     * below expires (to catch daemons).
400f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng     *
401f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng     * There is a theoretical race between the callback to
402f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng     * VMRuntime.startJitCompiation and when the compiler thread reaches this
403f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng     * point. In case the callback happens earlier, in order not to permanently
404f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng     * hold the system_server (which is not using the timed wait) in
405f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng     * interpreter-only mode we bypass the delay here.
406b1d8044ee3a7503b94eb54459f3077d7200cd675Bill Buzbee     */
407f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng    if (gDvmJit.runningInAndroidFramework &&
408f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng        !gDvmJit.alreadyEnabledViaFramework) {
409f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng        /*
410f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng         * If the current VM instance is the system server (detected by having
411f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng         * 0 in gDvm.systemServerPid), we will use the indefinite wait on the
412f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng         * conditional variable to determine whether to start the JIT or not.
413f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng         * If the system server detects that the whole system is booted in
414f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng         * safe mode, the conditional variable will never be signaled and the
415f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng         * system server will remain in the interpreter-only mode. All
416f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng         * subsequent apps will be started with the --enable-safemode flag
417f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng         * explicitly appended.
418f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng         */
419f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng        if (gDvm.systemServerPid == 0) {
420f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng            dvmLockMutex(&gDvmJit.compilerLock);
421f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng            pthread_cond_wait(&gDvmJit.compilerQueueActivity,
422f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng                              &gDvmJit.compilerLock);
423f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng            dvmUnlockMutex(&gDvmJit.compilerLock);
424f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng            LOGD("JIT started for system_server");
425f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng        } else {
426f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng            dvmLockMutex(&gDvmJit.compilerLock);
427f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng            /*
428f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng             * TUNING: experiment with the delay & perhaps make it
429f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng             * target-specific
430f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng             */
431f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng            dvmRelativeCondWait(&gDvmJit.compilerQueueActivity,
432f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng                                 &gDvmJit.compilerLock, 3000, 0);
433f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng            dvmUnlockMutex(&gDvmJit.compilerLock);
434f30acbb249b137b049500f136d2bb273c0b6221aBen Cheng        }
435eb695c6f814f6b0bdbba0e837555d3fe5ad23104Bill Buzbee        if (gDvmJit.haltCompilerThread) {
436eb695c6f814f6b0bdbba0e837555d3fe5ad23104Bill Buzbee             return NULL;
437eb695c6f814f6b0bdbba0e837555d3fe5ad23104Bill Buzbee        }
43894d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee    }
43994d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee
440964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    compilerThreadStartup();
441b1d8044ee3a7503b94eb54459f3077d7200cd675Bill Buzbee
442ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    dvmLockMutex(&gDvmJit.compilerLock);
443ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    /*
444ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng     * Since the compiler thread will not touch any objects on the heap once
445ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng     * being created, we just fake its state as VMWAIT so that it can be a
446ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng     * bit late when there is suspend request pending.
447ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng     */
448ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    while (!gDvmJit.haltCompilerThread) {
449ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        if (workQueueLength() == 0) {
450ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            int cc;
451ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
452ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            assert(cc == 0);
453ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            pthread_cond_wait(&gDvmJit.compilerQueueActivity,
454ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                              &gDvmJit.compilerLock);
455ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            continue;
456ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        } else {
457ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            do {
458ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                CompilerWorkOrder work = workDequeue();
459ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                dvmUnlockMutex(&gDvmJit.compilerLock);
46086717f79d9b018f4d69cc991075fa36611f234e5Ben Cheng#if defined(JIT_STATS)
46186717f79d9b018f4d69cc991075fa36611f234e5Ben Cheng                u8 startTime = dvmGetRelativeTimeUsec();
46286717f79d9b018f4d69cc991075fa36611f234e5Ben Cheng#endif
463964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee                /*
464964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee                 * Check whether there is a suspend request on me.  This
465964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee                 * is necessary to allow a clean shutdown.
466964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee                 */
467ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                dvmCheckSuspendPending(NULL);
4682717622484eb0f7ad537275f7260b2f93324eda2Bill Buzbee                /* Is JitTable filling up? */
4692717622484eb0f7ad537275f7260b2f93324eda2Bill Buzbee                if (gDvmJit.jitTableEntriesUsed >
4702717622484eb0f7ad537275f7260b2f93324eda2Bill Buzbee                    (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
4716999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng                    bool resizeFail =
4726999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng                        dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
4736999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng                    /*
4746999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng                     * If the jit table is full, consider it's time to reset
4756999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng                     * the code cache too.
4766999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng                     */
4776999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng                    gDvmJit.codeCacheFull |= resizeFail;
4782717622484eb0f7ad537275f7260b2f93324eda2Bill Buzbee                }
479ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                if (gDvmJit.haltCompilerThread) {
480ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                    LOGD("Compiler shutdown in progress - discarding request");
4816999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng                } else if (!gDvmJit.codeCacheFull) {
482fc519dc8f4444f6d93806ec15ce7445b322070fdBill Buzbee                    bool compileOK = false;
483fc519dc8f4444f6d93806ec15ce7445b322070fdBill Buzbee                    jmp_buf jmpBuf;
484fc519dc8f4444f6d93806ec15ce7445b322070fdBill Buzbee                    work.bailPtr = &jmpBuf;
485fc519dc8f4444f6d93806ec15ce7445b322070fdBill Buzbee                    bool aborted = setjmp(jmpBuf);
486fc519dc8f4444f6d93806ec15ce7445b322070fdBill Buzbee                    if (!aborted) {
487fc519dc8f4444f6d93806ec15ce7445b322070fdBill Buzbee                        compileOK = dvmCompilerDoWork(&work);
488ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                    }
489fc519dc8f4444f6d93806ec15ce7445b322070fdBill Buzbee                    if (aborted || !compileOK) {
490fc519dc8f4444f6d93806ec15ce7445b322070fdBill Buzbee                        dvmCompilerArenaReset();
491fc519dc8f4444f6d93806ec15ce7445b322070fdBill Buzbee                        work.result.codeAddress = gDvmJit.interpretTemplate;
492fc519dc8f4444f6d93806ec15ce7445b322070fdBill Buzbee                    } else if (!work.result.discardResult) {
49360c24f436d603c564d5351a6f81821f12635733cBen Cheng                        dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
49460c24f436d603c564d5351a6f81821f12635733cBen Cheng                                          work.result.instructionSet);
49560c24f436d603c564d5351a6f81821f12635733cBen Cheng                    }
496ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                }
497ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                free(work.info);
49886717f79d9b018f4d69cc991075fa36611f234e5Ben Cheng#if defined(JIT_STATS)
49986717f79d9b018f4d69cc991075fa36611f234e5Ben Cheng                gDvmJit.jitTime += dvmGetRelativeTimeUsec() - startTime;
50086717f79d9b018f4d69cc991075fa36611f234e5Ben Cheng#endif
501ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng                dvmLockMutex(&gDvmJit.compilerLock);
502ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng            } while (workQueueLength() != 0);
503ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        }
504ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    }
505ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
506ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    dvmUnlockMutex(&gDvmJit.compilerLock);
507ef00a85e7f148f044b14942aa09204e2d0d72738Ben Cheng
5085ccdf0be4b448c98b595444a77dbaa21471ad1b1Ben Cheng    /*
5095ccdf0be4b448c98b595444a77dbaa21471ad1b1Ben Cheng     * As part of detaching the thread we need to call into Java code to update
5105ccdf0be4b448c98b595444a77dbaa21471ad1b1Ben Cheng     * the ThreadGroup, and we should not be in VMWAIT state while executing
5115ccdf0be4b448c98b595444a77dbaa21471ad1b1Ben Cheng     * interpreted code.
5125ccdf0be4b448c98b595444a77dbaa21471ad1b1Ben Cheng     */
5135ccdf0be4b448c98b595444a77dbaa21471ad1b1Ben Cheng    dvmChangeStatus(NULL, THREAD_RUNNING);
5145ccdf0be4b448c98b595444a77dbaa21471ad1b1Ben Cheng
51543eb5015ca8bc0c859100b659d9c12934011a42eAndy McFadden    if (gDvm.verboseShutdown)
51643eb5015ca8bc0c859100b659d9c12934011a42eAndy McFadden        LOGD("Compiler thread shutting down\n");
517ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    return NULL;
518ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng}
519ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
520ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengbool dvmCompilerStartup(void)
521ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng{
52294d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee
52394d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee    dvmInitMutex(&gDvmJit.compilerLock);
5246999d84e2c55dc4a46a6c311b55bd5811336d9c4Ben Cheng    dvmInitMutex(&gDvmJit.compilerICPatchLock);
52594d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee    dvmLockMutex(&gDvmJit.compilerLock);
52694d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee    pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
52794d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee    pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
52894d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee
52994d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee    /* Reset the work queue */
53094d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee    gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
53194d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee    gDvmJit.compilerQueueLength = 0;
53294d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee    dvmUnlockMutex(&gDvmJit.compilerLock);
53394d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee
534ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    /*
53594d89f8016b6c305ab0df491874dcedb252ecfccBill Buzbee     * Defer rest of initialization until we're sure JIT'ng makes sense. Launch
536964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee     * the compiler thread, which will do the real initialization if and
537964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee     * when it is signalled to do so.
538ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng     */
539964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee    return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
540964a7b06a9134947b5985c7f712d18d57ed665d2Bill Buzbee                                   compilerThreadStart, NULL);
541ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng}
542ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
543ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Chengvoid dvmCompilerShutdown(void)
544ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng{
545ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    void *threadReturn;
546ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
54788a0f970e47dc0091d2c9965aa9bd06667e5f4b7Ben Cheng    if (gDvm.verboseShutdown) {
54888a0f970e47dc0091d2c9965aa9bd06667e5f4b7Ben Cheng        dvmCompilerDumpStats();
54988a0f970e47dc0091d2c9965aa9bd06667e5f4b7Ben Cheng        while (gDvmJit.compilerQueueLength)
55088a0f970e47dc0091d2c9965aa9bd06667e5f4b7Ben Cheng          sleep(5);
55188a0f970e47dc0091d2c9965aa9bd06667e5f4b7Ben Cheng    }
55288a0f970e47dc0091d2c9965aa9bd06667e5f4b7Ben Cheng
553ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    if (gDvmJit.compilerHandle) {
554ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
555ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        gDvmJit.haltCompilerThread = true;
556ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
557ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        dvmLockMutex(&gDvmJit.compilerLock);
558ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        pthread_cond_signal(&gDvmJit.compilerQueueActivity);
559ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        dvmUnlockMutex(&gDvmJit.compilerLock);
560ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
561ef00a85e7f148f044b14942aa09204e2d0d72738Ben Cheng        if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
562ef00a85e7f148f044b14942aa09204e2d0d72738Ben Cheng            LOGW("Compiler thread join failed\n");
56343eb5015ca8bc0c859100b659d9c12934011a42eAndy McFadden        else if (gDvm.verboseShutdown)
564ef00a85e7f148f044b14942aa09204e2d0d72738Ben Cheng            LOGD("Compiler thread has shut down\n");
565ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    }
56606bb83906737fec543c86ab36f450cc62066b58aBill Buzbee
56796cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee    dvmDestroyMutex(&gDvmJit.tableLock);
56896cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee    dvmDestroyMutex(&gDvmJit.compilerLock);
56996cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee    dvmDestroyMutex(&gDvmJit.compilerICPatchLock);
57096cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee
57196cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee    if (gDvmJit.pJitEntryTable) {
57296cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee        free(gDvmJit.pJitEntryTable);
57396cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee        gDvmJit.pJitEntryTable = NULL;
57496cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee    }
57596cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee
57696cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee    if (gDvmJit.pProfTable) {
57796cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee        free(gDvmJit.pProfTable);
57896cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee        gDvmJit.pProfTable = NULL;
57996cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee    }
58096cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee
58196cfe6c39b91dabc78182e2f7676b27b4012886aBill Buzbee}
58206bb83906737fec543c86ab36f450cc62066b58aBill Buzbee
58306bb83906737fec543c86ab36f450cc62066b58aBill Buzbeevoid dvmCompilerStateRefresh()
58406bb83906737fec543c86ab36f450cc62066b58aBill Buzbee{
58506bb83906737fec543c86ab36f450cc62066b58aBill Buzbee    bool jitActive;
58606bb83906737fec543c86ab36f450cc62066b58aBill Buzbee    bool jitActivate;
5873e392681fd57eaa64d4a65bd99d3576b8366569dBill Buzbee    bool needUnchain = false;
58806bb83906737fec543c86ab36f450cc62066b58aBill Buzbee
58906bb83906737fec543c86ab36f450cc62066b58aBill Buzbee    dvmLockMutex(&gDvmJit.tableLock);
59006bb83906737fec543c86ab36f450cc62066b58aBill Buzbee    jitActive = gDvmJit.pProfTable != NULL;
59106bb83906737fec543c86ab36f450cc62066b58aBill Buzbee    jitActivate = !(gDvm.debuggerActive || (gDvm.activeProfilers > 0));
59206bb83906737fec543c86ab36f450cc62066b58aBill Buzbee
59306bb83906737fec543c86ab36f450cc62066b58aBill Buzbee    if (jitActivate && !jitActive) {
59406bb83906737fec543c86ab36f450cc62066b58aBill Buzbee        gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
59506bb83906737fec543c86ab36f450cc62066b58aBill Buzbee    } else if (!jitActivate && jitActive) {
59606bb83906737fec543c86ab36f450cc62066b58aBill Buzbee        gDvmJit.pProfTable = NULL;
5973e392681fd57eaa64d4a65bd99d3576b8366569dBill Buzbee        needUnchain = true;
59806bb83906737fec543c86ab36f450cc62066b58aBill Buzbee    }
5993e392681fd57eaa64d4a65bd99d3576b8366569dBill Buzbee    dvmUnlockMutex(&gDvmJit.tableLock);
6003e392681fd57eaa64d4a65bd99d3576b8366569dBill Buzbee    if (needUnchain)
6013e392681fd57eaa64d4a65bd99d3576b8366569dBill Buzbee        dvmJitUnchainAll();
60206bb83906737fec543c86ab36f450cc62066b58aBill Buzbee}
603