Ejemplo n.º 1
0
/* Block until the queue length is 0, or there is a pending suspend request */
void dvmCompilerDrainQueue(void)
{
    Thread *self = dvmThreadSelf();

    dvmLockMutex(&gDvmJit.compilerLock);
    while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread &&
           self->suspendCount == 0) {
        /*
         * Use timed wait here - more than one mutator threads may be blocked
         * but the compiler thread will only signal once when the queue is
         * emptied. Furthermore, the compiler thread may have been shutdown
         * so the blocked thread may never get the wakeup signal.
         */
        dvmRelativeCondWait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock,                             1000, 0);
    }
    dvmUnlockMutex(&gDvmJit.compilerLock);
}
Ejemplo n.º 2
0
/**
 * @brief 丢弃编译队列
 */
void dvmCompilerDrainQueue(void)
{
    Thread *self = dvmThreadSelf();

    dvmLockMutex(&gDvmJit.compilerLock);
	/* 遍历整个队列,并不停的检测编译线程是否终止,并且自身线程没有被挂起 */
    while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread &&
           self->suspendCount == 0) {
        /*
         * Use timed wait here - more than one mutator threads may be blocked
         * but the compiler thread will only signal once when the queue is
         * emptied. Furthermore, the compiler thread may have been shutdown
         * so the blocked thread may never get the wakeup signal.
         */
		/* 使用等待时间 - 超过一个mutator线程被阻塞但是编译器线程将
		 * 仅有一条一次当队列被提交,编译器线程不关闭,阻塞线程将永远不会唤醒*/
        dvmRelativeCondWait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock,                             1000, 0);
    }
    dvmUnlockMutex(&gDvmJit.compilerLock);
}
Ejemplo n.º 3
0
static void *compilerThreadStart(void *arg)
{
    dvmChangeStatus(NULL, THREAD_VMWAIT);

    /*
     * If we're not running stand-alone, wait a little before
     * recieving translation requests on the assumption that process start
     * up code isn't worth compiling.  We'll resume when the framework
     * signals us that the first screen draw has happened, or the timer
     * below expires (to catch daemons).
     *
     * There is a theoretical race between the callback to
     * VMRuntime.startJitCompiation and when the compiler thread reaches this
     * point. In case the callback happens earlier, in order not to permanently
     * hold the system_server (which is not using the timed wait) in
     * interpreter-only mode we bypass the delay here.
     */
    if (gDvmJit.runningInAndroidFramework &&
        !gDvmJit.alreadyEnabledViaFramework) {
        /*
         * If the current VM instance is the system server (detected by having
         * 0 in gDvm.systemServerPid), we will use the indefinite wait on the
         * conditional variable to determine whether to start the JIT or not.
         * If the system server detects that the whole system is booted in
         * safe mode, the conditional variable will never be signaled and the
         * system server will remain in the interpreter-only mode. All
         * subsequent apps will be started with the --enable-safemode flag
         * explicitly appended.
         */
        if (gDvm.systemServerPid == 0) {
            dvmLockMutex(&gDvmJit.compilerLock);
            pthread_cond_wait(&gDvmJit.compilerQueueActivity,
                              &gDvmJit.compilerLock);
            dvmUnlockMutex(&gDvmJit.compilerLock);
            ALOGD("JIT started for system_server");
        } else {
            dvmLockMutex(&gDvmJit.compilerLock);
            /*
             * TUNING: experiment with the delay & perhaps make it
             * target-specific
             */
            dvmRelativeCondWait(&gDvmJit.compilerQueueActivity,
                                 &gDvmJit.compilerLock, 3000, 0);
            dvmUnlockMutex(&gDvmJit.compilerLock);
        }
        if (gDvmJit.haltCompilerThread) {
             return NULL;
        }
    }

    compilerThreadStartup();

    dvmLockMutex(&gDvmJit.compilerLock);
    /*
     * Since the compiler thread will not touch any objects on the heap once
     * being created, we just fake its state as VMWAIT so that it can be a
     * bit late when there is suspend request pending.
     */
    while (!gDvmJit.haltCompilerThread) {
        if (workQueueLength() == 0) {
            int cc;
            cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
            assert(cc == 0);
            pthread_cond_wait(&gDvmJit.compilerQueueActivity,
                              &gDvmJit.compilerLock);
            continue;
        } else {
            do {
                CompilerWorkOrder work = workDequeue();
                dvmUnlockMutex(&gDvmJit.compilerLock);
#if defined(WITH_JIT_TUNING)
                /*
                 * This is live across setjmp().  Mark it volatile to suppress
                 * a gcc warning.  We should not need this since it is assigned
                 * only once but gcc is not smart enough.
                 */
                volatile u8 startTime = dvmGetRelativeTimeUsec();
#endif
                /*
                 * Check whether there is a suspend request on me.  This
                 * is necessary to allow a clean shutdown.
                 *
                 * However, in the blocking stress testing mode, let the
                 * compiler thread continue doing compilations to unblock
                 * other requesting threads. This may occasionally cause
                 * shutdown from proceeding cleanly in the standalone invocation
                 * of the vm but this should be acceptable.
                 */
                if (!gDvmJit.blockingMode)
                    dvmCheckSuspendPending(dvmThreadSelf());
                /* Is JitTable filling up? */
                if (gDvmJit.jitTableEntriesUsed >
                    (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
                    bool resizeFail =
                        dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
                    /*
                     * If the jit table is full, consider it's time to reset
                     * the code cache too.
                     */
                    gDvmJit.codeCacheFull |= resizeFail;
                }
                if (gDvmJit.haltCompilerThread) {
                    ALOGD("Compiler shutdown in progress - discarding request");
                } else if (!gDvmJit.codeCacheFull) {
                    jmp_buf jmpBuf;
                    work.bailPtr = &jmpBuf;
                    bool aborted = setjmp(jmpBuf);
                    if (!aborted) {
                        bool codeCompiled = dvmCompilerDoWork(&work);
                        /*
                         * Make sure we are still operating with the
                         * same translation cache version.  See
                         * Issue 4271784 for details.
                         */
                        dvmLockMutex(&gDvmJit.compilerLock);
                        if ((work.result.cacheVersion ==
                             gDvmJit.cacheVersion) &&
                             codeCompiled &&
                             !work.result.discardResult &&
                             work.result.codeAddress) {
                            dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
                                              work.result.instructionSet,
                                              false, /* not method entry */
                                              work.result.profileCodeSize);
                        }
                        dvmUnlockMutex(&gDvmJit.compilerLock);
                    }
                    dvmCompilerArenaReset();
                }
                free(work.info);
#if defined(WITH_JIT_TUNING)
                gDvmJit.jitTime += dvmGetRelativeTimeUsec() - startTime;
#endif
                dvmLockMutex(&gDvmJit.compilerLock);
            } while (workQueueLength() != 0);
        }
    }
    pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
    dvmUnlockMutex(&gDvmJit.compilerLock);

    /*
     * As part of detaching the thread we need to call into Java code to update
     * the ThreadGroup, and we should not be in VMWAIT state while executing
     * interpreted code.
     */
    dvmChangeStatus(NULL, THREAD_RUNNING);

    if (gDvm.verboseShutdown)
        ALOGD("Compiler thread shutting down");
    return NULL;
}
Ejemplo n.º 4
0
static void resetCodeCache(void)
{
    Thread* thread;
    u8 startTime = dvmGetRelativeTimeUsec();
    int inJit = 0;
    int byteUsed = gDvmJit.codeCacheByteUsed;

    /* If any thread is found stuck in the JIT state, don't reset the cache  */
    dvmLockThreadList(NULL);
    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
        /*
         * Crawl the stack to wipe out the returnAddr field so that
         * 1) the soon-to-be-deleted code in the JIT cache won't be used
         * 2) or the thread stuck in the JIT land will soon return
         *    to the interpreter land
         */
        crawlDalvikStack(thread, false);
        if (thread->inJitCodeCache) {
            inJit++;
        }
        /* Cancel any ongoing trace selection */
        dvmDisableSubMode(thread, kSubModeJitTraceBuild);
    }
    dvmUnlockThreadList();

    if (inJit) {
        ALOGD("JIT code cache reset delayed (%d bytes %d/%d)",
             gDvmJit.codeCacheByteUsed, gDvmJit.numCodeCacheReset,
             ++gDvmJit.numCodeCacheResetDelayed);
        return;
    }

    /* Lock the mutex to clean up the work queue */
    dvmLockMutex(&gDvmJit.compilerLock);

    /* Update the translation cache version */
    gDvmJit.cacheVersion++;

    /* Drain the work queue to free the work orders */
    while (workQueueLength()) {
        CompilerWorkOrder work = workDequeue();
        free(work.info);
    }

    /* Reset the JitEntry table contents to the initial unpopulated state */
    dvmJitResetTable();

    UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
    /*
     * Wipe out the code cache content to force immediate crashes if
     * stale JIT'ed code is invoked.
     */
    dvmCompilerCacheClear((char *) gDvmJit.codeCache + gDvmJit.templateSize,
                          gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);

    dvmCompilerCacheFlush((intptr_t) gDvmJit.codeCache,
                          (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed);

    PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);

    /* Reset the current mark of used bytes to the end of template code */
    gDvmJit.codeCacheByteUsed = gDvmJit.templateSize;
    gDvmJit.numCompilations = 0;

    /* Reset the work queue */
    memset(gDvmJit.compilerWorkQueue, 0,
           sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
    gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
    gDvmJit.compilerQueueLength = 0;

    /* Reset the IC patch work queue */
    dvmLockMutex(&gDvmJit.compilerICPatchLock);
    gDvmJit.compilerICPatchIndex = 0;
    dvmUnlockMutex(&gDvmJit.compilerICPatchLock);

    /*
     * Reset the inflight compilation address (can only be done in safe points
     * or by the compiler thread when its thread state is RUNNING).
     */
    gDvmJit.inflightBaseAddr = NULL;

    /* All clear now */
    gDvmJit.codeCacheFull = false;

    dvmUnlockMutex(&gDvmJit.compilerLock);

    ALOGD("JIT code cache reset in %lld ms (%d bytes %d/%d)",
         (dvmGetRelativeTimeUsec() - startTime) / 1000,
         byteUsed, ++gDvmJit.numCodeCacheReset,
         gDvmJit.numCodeCacheResetDelayed);
}