2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include "interp/Jit.h"
22 #include "CompilerInternals.h"
24 static inline bool workQueueLength(void)
26 return gDvmJit.compilerQueueLength;
29 static CompilerWorkOrder workDequeue(void)
31 assert(gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex].kind
32 != kWorkOrderInvalid);
33 CompilerWorkOrder work =
34 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex];
35 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex++].kind =
37 if (gDvmJit.compilerWorkDequeueIndex == COMPILER_WORK_QUEUE_SIZE) {
38 gDvmJit.compilerWorkDequeueIndex = 0;
40 gDvmJit.compilerQueueLength--;
42 /* Remember the high water mark of the queue length */
43 if (gDvmJit.compilerQueueLength > gDvmJit.compilerMaxQueued)
44 gDvmJit.compilerMaxQueued = gDvmJit.compilerQueueLength;
49 bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
55 dvmLockMutex(&gDvmJit.compilerLock);
58 if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE ||
59 gDvmJit.codeCacheFull == true) {
60 dvmUnlockMutex(&gDvmJit.compilerLock);
64 for (numWork = gDvmJit.compilerQueueLength,
65 i = gDvmJit.compilerWorkDequeueIndex;
68 /* Already enqueued */
69 if (gDvmJit.compilerWorkQueue[i++].pc == pc)
72 if (i == COMPILER_WORK_QUEUE_SIZE)
76 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex].pc = pc;
77 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex].kind = kind;
78 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex].info = info;
79 gDvmJit.compilerWorkEnqueueIndex++;
80 if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
81 gDvmJit.compilerWorkEnqueueIndex = 0;
82 gDvmJit.compilerQueueLength++;
83 cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
87 dvmUnlockMutex(&gDvmJit.compilerLock);
91 /* Block until queue length is 0 */
92 void dvmCompilerDrainQueue(void)
94 dvmLockMutex(&gDvmJit.compilerLock);
95 while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread) {
96 pthread_cond_wait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock);
98 dvmUnlockMutex(&gDvmJit.compilerLock);
101 static void *compilerThreadStart(void *arg)
103 dvmChangeStatus(NULL, THREAD_VMWAIT);
105 dvmLockMutex(&gDvmJit.compilerLock);
107 * Since the compiler thread will not touch any objects on the heap once
108 * being created, we just fake its state as VMWAIT so that it can be a
109 * bit late when there is suspend request pending.
111 while (!gDvmJit.haltCompilerThread) {
112 if (workQueueLength() == 0) {
114 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
116 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
117 &gDvmJit.compilerLock);
121 CompilerWorkOrder work = workDequeue();
122 dvmUnlockMutex(&gDvmJit.compilerLock);
123 /* Check whether there is a suspend request on me */
124 dvmCheckSuspendPending(NULL);
125 /* Is JitTable filling up? */
126 if (gDvmJit.jitTableEntriesUsed >
127 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
128 dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
130 if (gDvmJit.haltCompilerThread) {
131 LOGD("Compiler shutdown in progress - discarding request");
133 /* Compilation is successful */
134 if (dvmCompilerDoWork(&work)) {
135 dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
136 work.result.instructionSet);
140 dvmLockMutex(&gDvmJit.compilerLock);
141 } while (workQueueLength() != 0);
144 pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
145 dvmUnlockMutex(&gDvmJit.compilerLock);
148 * As part of detaching the thread we need to call into Java code to update
149 * the ThreadGroup, and we should not be in VMWAIT state while executing
152 dvmChangeStatus(NULL, THREAD_RUNNING);
154 LOGD("Compiler thread shutting down\n");
158 bool dvmCompilerSetupCodeCache(void)
160 extern void dvmCompilerTemplateStart(void);
161 extern void dmvCompilerTemplateEnd(void);
163 /* Allocate the code cache */
164 gDvmJit.codeCache = mmap(0, CODE_CACHE_SIZE,
165 PROT_READ | PROT_WRITE | PROT_EXEC,
166 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
167 if (gDvmJit.codeCache == MAP_FAILED) {
168 LOGE("Failed to create the code cache: %s\n", strerror(errno));
172 /* Copy the template code into the beginning of the code cache */
173 int templateSize = (intptr_t) dmvCompilerTemplateEnd -
174 (intptr_t) dvmCompilerTemplateStart;
175 memcpy((void *) gDvmJit.codeCache,
176 (void *) dvmCompilerTemplateStart,
179 gDvmJit.templateSize = templateSize;
180 gDvmJit.codeCacheByteUsed = templateSize;
182 /* Flush dcache and invalidate the icache to maintain coherence */
183 cacheflush((intptr_t) gDvmJit.codeCache,
184 (intptr_t) gDvmJit.codeCache + CODE_CACHE_SIZE, 0);
188 bool dvmCompilerStartup(void)
190 /* Make sure the BBType enum is in sane state */
191 assert(CHAINING_CELL_NORMAL == 0);
193 /* Architecture-specific chores to initialize */
194 if (!dvmCompilerArchInit())
198 * Setup the code cache if it is not done so already. For apps it should be
199 * done by the Zygote already, but for command-line dalvikvm invocation we
200 * need to do it here.
202 if (gDvmJit.codeCache == NULL) {
203 if (!dvmCompilerSetupCodeCache())
207 /* Allocate the initial arena block */
208 if (dvmCompilerHeapInit() == false) {
212 dvmInitMutex(&gDvmJit.compilerLock);
213 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
214 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
216 dvmLockMutex(&gDvmJit.compilerLock);
218 gDvmJit.haltCompilerThread = false;
220 /* Reset the work queue */
221 memset(gDvmJit.compilerWorkQueue, 0,
222 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
223 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
224 gDvmJit.compilerQueueLength = 0;
225 gDvmJit.compilerHighWater =
226 COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
228 assert(gDvmJit.compilerHighWater < COMPILER_WORK_QUEUE_SIZE);
229 if (!dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
230 compilerThreadStart, NULL)) {
231 dvmUnlockMutex(&gDvmJit.compilerLock);
235 /* Track method-level compilation statistics */
236 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
238 dvmUnlockMutex(&gDvmJit.compilerLock);
246 void dvmCompilerShutdown(void)
250 if (gDvmJit.compilerHandle) {
252 gDvmJit.haltCompilerThread = true;
254 dvmLockMutex(&gDvmJit.compilerLock);
255 pthread_cond_signal(&gDvmJit.compilerQueueActivity);
256 dvmUnlockMutex(&gDvmJit.compilerLock);
258 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
259 LOGW("Compiler thread join failed\n");
261 LOGD("Compiler thread has shut down\n");