blob: 45d8317d0bc77f2a6c5da19986f0c91ec863f4a6 [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--;
Bill Buzbeef9f33282009-11-22 12:45:30 -080041 if (gDvmJit.compilerQueueLength == 0) {
42 int cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
43 }
Ben Chengba4fc8b2009-06-01 13:00:29 -070044
45 /* Remember the high water mark of the queue length */
46 if (gDvmJit.compilerQueueLength > gDvmJit.compilerMaxQueued)
47 gDvmJit.compilerMaxQueued = gDvmJit.compilerQueueLength;
48
49 return work;
50}
51
52bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
53{
54 int cc;
55 int i;
56 int numWork;
57
58 dvmLockMutex(&gDvmJit.compilerLock);
59
60 /* Queue full */
61 if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE ||
62 gDvmJit.codeCacheFull == true) {
63 dvmUnlockMutex(&gDvmJit.compilerLock);
64 return false;
65 }
66
67 for (numWork = gDvmJit.compilerQueueLength,
68 i = gDvmJit.compilerWorkDequeueIndex;
69 numWork > 0;
70 numWork--) {
71 /* Already enqueued */
72 if (gDvmJit.compilerWorkQueue[i++].pc == pc)
73 goto done;
74 /* Wrap around */
75 if (i == COMPILER_WORK_QUEUE_SIZE)
76 i = 0;
77 }
78
Ben Chengccd6c012009-10-15 14:52:45 -070079 CompilerWorkOrder *newOrder =
80 &gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex];
81 newOrder->pc = pc;
82 newOrder->kind = kind;
83 newOrder->info = info;
84 newOrder->result.codeAddress = NULL;
85 newOrder->result.discardResult =
86 (kind == kWorkOrderTraceDebug) ? true : false;
Ben Chengba4fc8b2009-06-01 13:00:29 -070087 gDvmJit.compilerWorkEnqueueIndex++;
88 if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
89 gDvmJit.compilerWorkEnqueueIndex = 0;
90 gDvmJit.compilerQueueLength++;
91 cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
92 assert(cc == 0);
93
94done:
95 dvmUnlockMutex(&gDvmJit.compilerLock);
96 return true;
97}
98
99/* Block until queue length is 0 */
100void dvmCompilerDrainQueue(void)
101{
Bill Buzbeed7269912009-11-10 14:31:32 -0800102 int oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700103 dvmLockMutex(&gDvmJit.compilerLock);
104 while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread) {
105 pthread_cond_wait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock);
106 }
107 dvmUnlockMutex(&gDvmJit.compilerLock);
Bill Buzbeed7269912009-11-10 14:31:32 -0800108 dvmChangeStatus(NULL, oldStatus);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700109}
110
111static void *compilerThreadStart(void *arg)
112{
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700113 dvmChangeStatus(NULL, THREAD_VMWAIT);
114
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800115 /*
116 * Wait a little before recieving translation requests on the assumption
117 * that process start-up code isn't worth compiling. The trace
118 * selector won't attempt to request a translation if the queue is
119 * filled, so we'll prevent by keeping the high water mark at zero
120 * for a shore time.
121 */
122 assert(gDvmJit.compilerHighWater == 0);
123 usleep(1000);
124 gDvmJit.compilerHighWater =
125 COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
126
Ben Chengba4fc8b2009-06-01 13:00:29 -0700127 dvmLockMutex(&gDvmJit.compilerLock);
128 /*
129 * Since the compiler thread will not touch any objects on the heap once
130 * being created, we just fake its state as VMWAIT so that it can be a
131 * bit late when there is suspend request pending.
132 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700133 while (!gDvmJit.haltCompilerThread) {
134 if (workQueueLength() == 0) {
135 int cc;
136 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
137 assert(cc == 0);
138 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
139 &gDvmJit.compilerLock);
140 continue;
141 } else {
142 do {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700143 CompilerWorkOrder work = workDequeue();
144 dvmUnlockMutex(&gDvmJit.compilerLock);
145 /* Check whether there is a suspend request on me */
146 dvmCheckSuspendPending(NULL);
Bill Buzbee27176222009-06-09 09:20:16 -0700147 /* Is JitTable filling up? */
148 if (gDvmJit.jitTableEntriesUsed >
149 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
150 dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
151 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700152 if (gDvmJit.haltCompilerThread) {
153 LOGD("Compiler shutdown in progress - discarding request");
154 } else {
Bill Buzbeed7269912009-11-10 14:31:32 -0800155 /* If compilation failed, use interpret-template */
156 if (!dvmCompilerDoWork(&work)) {
157 work.result.codeAddress = gDvmJit.interpretTemplate;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700158 }
Bill Buzbeed7269912009-11-10 14:31:32 -0800159 dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
160 work.result.instructionSet);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700161 }
162 free(work.info);
163 dvmLockMutex(&gDvmJit.compilerLock);
164 } while (workQueueLength() != 0);
165 }
166 }
167 pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
168 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Chengef00a852009-06-22 22:53:35 -0700169
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700170 /*
171 * As part of detaching the thread we need to call into Java code to update
172 * the ThreadGroup, and we should not be in VMWAIT state while executing
173 * interpreted code.
174 */
175 dvmChangeStatus(NULL, THREAD_RUNNING);
176
Ben Chengef00a852009-06-22 22:53:35 -0700177 LOGD("Compiler thread shutting down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700178 return NULL;
179}
180
181bool dvmCompilerSetupCodeCache(void)
182{
183 extern void dvmCompilerTemplateStart(void);
184 extern void dmvCompilerTemplateEnd(void);
185
186 /* Allocate the code cache */
187 gDvmJit.codeCache = mmap(0, CODE_CACHE_SIZE,
188 PROT_READ | PROT_WRITE | PROT_EXEC,
Dan Bornsteincede69b2009-10-07 17:33:46 -0700189 MAP_PRIVATE | MAP_ANON, -1, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700190 if (gDvmJit.codeCache == MAP_FAILED) {
191 LOGE("Failed to create the code cache: %s\n", strerror(errno));
192 return false;
193 }
194
195 /* Copy the template code into the beginning of the code cache */
196 int templateSize = (intptr_t) dmvCompilerTemplateEnd -
197 (intptr_t) dvmCompilerTemplateStart;
198 memcpy((void *) gDvmJit.codeCache,
199 (void *) dvmCompilerTemplateStart,
200 templateSize);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700201
202 gDvmJit.templateSize = templateSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700203 gDvmJit.codeCacheByteUsed = templateSize;
204
Ben Chengb28d3a82009-10-20 15:57:28 -0700205 /* Only flush the part in the code cache that is being used now */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700206 cacheflush((intptr_t) gDvmJit.codeCache,
Ben Chengb28d3a82009-10-20 15:57:28 -0700207 (intptr_t) gDvmJit.codeCache + templateSize, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700208 return true;
209}
210
211bool dvmCompilerStartup(void)
212{
213 /* Make sure the BBType enum is in sane state */
Bill Buzbee1465db52009-09-23 17:17:35 -0700214 assert(kChainingCellNormal == 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700215
216 /* Architecture-specific chores to initialize */
217 if (!dvmCompilerArchInit())
218 goto fail;
219
220 /*
221 * Setup the code cache if it is not done so already. For apps it should be
222 * done by the Zygote already, but for command-line dalvikvm invocation we
223 * need to do it here.
224 */
225 if (gDvmJit.codeCache == NULL) {
226 if (!dvmCompilerSetupCodeCache())
227 goto fail;
228 }
229
230 /* Allocate the initial arena block */
231 if (dvmCompilerHeapInit() == false) {
232 goto fail;
233 }
234
235 dvmInitMutex(&gDvmJit.compilerLock);
236 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
237 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
238
239 dvmLockMutex(&gDvmJit.compilerLock);
240
241 gDvmJit.haltCompilerThread = false;
242
243 /* Reset the work queue */
244 memset(gDvmJit.compilerWorkQueue, 0,
245 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
246 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
247 gDvmJit.compilerQueueLength = 0;
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800248 /* Block new entries via HighWater until compiler thread is ready */
249 gDvmJit.compilerHighWater = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700250
251 assert(gDvmJit.compilerHighWater < COMPILER_WORK_QUEUE_SIZE);
252 if (!dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
253 compilerThreadStart, NULL)) {
254 dvmUnlockMutex(&gDvmJit.compilerLock);
255 goto fail;
256 }
257
Ben Cheng8b258bf2009-06-24 17:27:07 -0700258 /* Track method-level compilation statistics */
259 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
260
Ben Chengba4fc8b2009-06-01 13:00:29 -0700261 dvmUnlockMutex(&gDvmJit.compilerLock);
262
263 return true;
264
265fail:
266 return false;
267}
268
269void dvmCompilerShutdown(void)
270{
271 void *threadReturn;
272
273 if (gDvmJit.compilerHandle) {
274
275 gDvmJit.haltCompilerThread = true;
276
277 dvmLockMutex(&gDvmJit.compilerLock);
278 pthread_cond_signal(&gDvmJit.compilerQueueActivity);
279 dvmUnlockMutex(&gDvmJit.compilerLock);
280
Ben Chengef00a852009-06-22 22:53:35 -0700281 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
282 LOGW("Compiler thread join failed\n");
283 else
284 LOGD("Compiler thread has shut down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700285 }
286}