blob: b53ebf8dfd7228372411c07ada71b4376a713bad [file] [log] [blame]
Ben Chengba4fc8b2009-06-01 13:00:29 -07001/*
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
20#include "Dalvik.h"
21#include "interp/Jit.h"
22#include "CompilerInternals.h"
23
Ben Chengba4fc8b2009-06-01 13:00:29 -070024static inline bool workQueueLength(void)
25{
26 return gDvmJit.compilerQueueLength;
27}
28
29static CompilerWorkOrder workDequeue(void)
30{
31 assert(gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex].kind
32 != kWorkOrderInvalid);
33 CompilerWorkOrder work =
34 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex];
35 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex++].kind =
36 kWorkOrderInvalid;
37 if (gDvmJit.compilerWorkDequeueIndex == COMPILER_WORK_QUEUE_SIZE) {
38 gDvmJit.compilerWorkDequeueIndex = 0;
39 }
40 gDvmJit.compilerQueueLength--;
41
42 /* Remember the high water mark of the queue length */
43 if (gDvmJit.compilerQueueLength > gDvmJit.compilerMaxQueued)
44 gDvmJit.compilerMaxQueued = gDvmJit.compilerQueueLength;
45
46 return work;
47}
48
49bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
50{
51 int cc;
52 int i;
53 int numWork;
54
55 dvmLockMutex(&gDvmJit.compilerLock);
56
57 /* Queue full */
58 if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE ||
59 gDvmJit.codeCacheFull == true) {
60 dvmUnlockMutex(&gDvmJit.compilerLock);
61 return false;
62 }
63
64 for (numWork = gDvmJit.compilerQueueLength,
65 i = gDvmJit.compilerWorkDequeueIndex;
66 numWork > 0;
67 numWork--) {
68 /* Already enqueued */
69 if (gDvmJit.compilerWorkQueue[i++].pc == pc)
70 goto done;
71 /* Wrap around */
72 if (i == COMPILER_WORK_QUEUE_SIZE)
73 i = 0;
74 }
75
Ben Chengccd6c012009-10-15 14:52:45 -070076 CompilerWorkOrder *newOrder =
77 &gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex];
78 newOrder->pc = pc;
79 newOrder->kind = kind;
80 newOrder->info = info;
81 newOrder->result.codeAddress = NULL;
82 newOrder->result.discardResult =
83 (kind == kWorkOrderTraceDebug) ? true : false;
Ben Chengba4fc8b2009-06-01 13:00:29 -070084 gDvmJit.compilerWorkEnqueueIndex++;
85 if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
86 gDvmJit.compilerWorkEnqueueIndex = 0;
87 gDvmJit.compilerQueueLength++;
88 cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
89 assert(cc == 0);
90
91done:
92 dvmUnlockMutex(&gDvmJit.compilerLock);
93 return true;
94}
95
96/* Block until queue length is 0 */
97void dvmCompilerDrainQueue(void)
98{
Bill Buzbeed7269912009-11-10 14:31:32 -080099 int oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700100 dvmLockMutex(&gDvmJit.compilerLock);
101 while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread) {
102 pthread_cond_wait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock);
103 }
104 dvmUnlockMutex(&gDvmJit.compilerLock);
Bill Buzbeed7269912009-11-10 14:31:32 -0800105 dvmChangeStatus(NULL, oldStatus);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700106}
107
108static void *compilerThreadStart(void *arg)
109{
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700110 dvmChangeStatus(NULL, THREAD_VMWAIT);
111
Ben Chengba4fc8b2009-06-01 13:00:29 -0700112 dvmLockMutex(&gDvmJit.compilerLock);
113 /*
114 * Since the compiler thread will not touch any objects on the heap once
115 * being created, we just fake its state as VMWAIT so that it can be a
116 * bit late when there is suspend request pending.
117 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700118 while (!gDvmJit.haltCompilerThread) {
119 if (workQueueLength() == 0) {
120 int cc;
121 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
122 assert(cc == 0);
123 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
124 &gDvmJit.compilerLock);
125 continue;
126 } else {
127 do {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700128 CompilerWorkOrder work = workDequeue();
129 dvmUnlockMutex(&gDvmJit.compilerLock);
130 /* Check whether there is a suspend request on me */
131 dvmCheckSuspendPending(NULL);
Bill Buzbee27176222009-06-09 09:20:16 -0700132 /* Is JitTable filling up? */
133 if (gDvmJit.jitTableEntriesUsed >
134 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
135 dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
136 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700137 if (gDvmJit.haltCompilerThread) {
138 LOGD("Compiler shutdown in progress - discarding request");
139 } else {
Bill Buzbeed7269912009-11-10 14:31:32 -0800140 /* If compilation failed, use interpret-template */
141 if (!dvmCompilerDoWork(&work)) {
142 work.result.codeAddress = gDvmJit.interpretTemplate;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700143 }
Bill Buzbeed7269912009-11-10 14:31:32 -0800144 dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
145 work.result.instructionSet);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700146 }
147 free(work.info);
148 dvmLockMutex(&gDvmJit.compilerLock);
149 } while (workQueueLength() != 0);
150 }
151 }
152 pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
153 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Chengef00a852009-06-22 22:53:35 -0700154
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700155 /*
156 * As part of detaching the thread we need to call into Java code to update
157 * the ThreadGroup, and we should not be in VMWAIT state while executing
158 * interpreted code.
159 */
160 dvmChangeStatus(NULL, THREAD_RUNNING);
161
Ben Chengef00a852009-06-22 22:53:35 -0700162 LOGD("Compiler thread shutting down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700163 return NULL;
164}
165
166bool dvmCompilerSetupCodeCache(void)
167{
168 extern void dvmCompilerTemplateStart(void);
169 extern void dmvCompilerTemplateEnd(void);
170
171 /* Allocate the code cache */
172 gDvmJit.codeCache = mmap(0, CODE_CACHE_SIZE,
173 PROT_READ | PROT_WRITE | PROT_EXEC,
Dan Bornsteincede69b2009-10-07 17:33:46 -0700174 MAP_PRIVATE | MAP_ANON, -1, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700175 if (gDvmJit.codeCache == MAP_FAILED) {
176 LOGE("Failed to create the code cache: %s\n", strerror(errno));
177 return false;
178 }
179
180 /* Copy the template code into the beginning of the code cache */
181 int templateSize = (intptr_t) dmvCompilerTemplateEnd -
182 (intptr_t) dvmCompilerTemplateStart;
183 memcpy((void *) gDvmJit.codeCache,
184 (void *) dvmCompilerTemplateStart,
185 templateSize);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700186
187 gDvmJit.templateSize = templateSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700188 gDvmJit.codeCacheByteUsed = templateSize;
189
Ben Chengb28d3a82009-10-20 15:57:28 -0700190 /* Only flush the part in the code cache that is being used now */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700191 cacheflush((intptr_t) gDvmJit.codeCache,
Ben Chengb28d3a82009-10-20 15:57:28 -0700192 (intptr_t) gDvmJit.codeCache + templateSize, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700193 return true;
194}
195
196bool dvmCompilerStartup(void)
197{
198 /* Make sure the BBType enum is in sane state */
Bill Buzbee1465db52009-09-23 17:17:35 -0700199 assert(kChainingCellNormal == 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700200
201 /* Architecture-specific chores to initialize */
202 if (!dvmCompilerArchInit())
203 goto fail;
204
205 /*
206 * Setup the code cache if it is not done so already. For apps it should be
207 * done by the Zygote already, but for command-line dalvikvm invocation we
208 * need to do it here.
209 */
210 if (gDvmJit.codeCache == NULL) {
211 if (!dvmCompilerSetupCodeCache())
212 goto fail;
213 }
214
215 /* Allocate the initial arena block */
216 if (dvmCompilerHeapInit() == false) {
217 goto fail;
218 }
219
220 dvmInitMutex(&gDvmJit.compilerLock);
221 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
222 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
223
224 dvmLockMutex(&gDvmJit.compilerLock);
225
226 gDvmJit.haltCompilerThread = false;
227
228 /* Reset the work queue */
229 memset(gDvmJit.compilerWorkQueue, 0,
230 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
231 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
232 gDvmJit.compilerQueueLength = 0;
233 gDvmJit.compilerHighWater =
234 COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
235
236 assert(gDvmJit.compilerHighWater < COMPILER_WORK_QUEUE_SIZE);
237 if (!dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
238 compilerThreadStart, NULL)) {
239 dvmUnlockMutex(&gDvmJit.compilerLock);
240 goto fail;
241 }
242
Ben Cheng8b258bf2009-06-24 17:27:07 -0700243 /* Track method-level compilation statistics */
244 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
245
Ben Chengba4fc8b2009-06-01 13:00:29 -0700246 dvmUnlockMutex(&gDvmJit.compilerLock);
247
248 return true;
249
250fail:
251 return false;
252}
253
254void dvmCompilerShutdown(void)
255{
256 void *threadReturn;
257
258 if (gDvmJit.compilerHandle) {
259
260 gDvmJit.haltCompilerThread = true;
261
262 dvmLockMutex(&gDvmJit.compilerLock);
263 pthread_cond_signal(&gDvmJit.compilerQueueActivity);
264 dvmUnlockMutex(&gDvmJit.compilerLock);
265
Ben Chengef00a852009-06-22 22:53:35 -0700266 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
267 LOGW("Compiler thread join failed\n");
268 else
269 LOGD("Compiler thread has shut down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700270 }
271}