blob: 0380e02d2ce6489c45e04aeedb2f09f7b66e0889 [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>
Ben Cheng7c4afdb2010-02-11 15:03:00 -080019#include <cutils/ashmem.h>
Ben Chengba4fc8b2009-06-01 13:00:29 -070020
21#include "Dalvik.h"
22#include "interp/Jit.h"
23#include "CompilerInternals.h"
24
Ben Chengba4fc8b2009-06-01 13:00:29 -070025static inline bool workQueueLength(void)
26{
27 return gDvmJit.compilerQueueLength;
28}
29
30static CompilerWorkOrder workDequeue(void)
31{
32 assert(gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex].kind
33 != kWorkOrderInvalid);
34 CompilerWorkOrder work =
35 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex];
36 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex++].kind =
37 kWorkOrderInvalid;
38 if (gDvmJit.compilerWorkDequeueIndex == COMPILER_WORK_QUEUE_SIZE) {
39 gDvmJit.compilerWorkDequeueIndex = 0;
40 }
41 gDvmJit.compilerQueueLength--;
Bill Buzbeef9f33282009-11-22 12:45:30 -080042 if (gDvmJit.compilerQueueLength == 0) {
43 int cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
44 }
Ben Chengba4fc8b2009-06-01 13:00:29 -070045
46 /* Remember the high water mark of the queue length */
47 if (gDvmJit.compilerQueueLength > gDvmJit.compilerMaxQueued)
48 gDvmJit.compilerMaxQueued = gDvmJit.compilerQueueLength;
49
50 return work;
51}
52
Bill Buzbee964a7b02010-01-28 12:54:19 -080053/*
54 * Attempt to enqueue a work order, returning true if successful.
55 * This routine will not block, but simply return if it couldn't
56 * aquire the lock or if the queue is full.
Ben Cheng1357e942010-02-10 17:21:39 -080057 *
58 * NOTE: Make sure that the caller frees the info pointer if the return value
59 * is false.
Bill Buzbee964a7b02010-01-28 12:54:19 -080060 */
Ben Chengba4fc8b2009-06-01 13:00:29 -070061bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
62{
63 int cc;
64 int i;
65 int numWork;
Ben Cheng60c24f42010-01-04 12:29:56 -080066 bool result = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -070067
Bill Buzbee964a7b02010-01-28 12:54:19 -080068 if (dvmTryLockMutex(&gDvmJit.compilerLock)) {
Ben Cheng3e5cd172010-02-08 20:57:59 -080069 return false; // Couldn't acquire the lock
Bill Buzbee964a7b02010-01-28 12:54:19 -080070 }
Ben Chengba4fc8b2009-06-01 13:00:29 -070071
Ben Cheng7a0bcd02010-01-22 16:45:45 -080072 /*
Ben Cheng6999d842010-01-26 16:46:15 -080073 * Return if queue or code cache is full.
Ben Cheng7a0bcd02010-01-22 16:45:45 -080074 */
Ben Cheng6999d842010-01-26 16:46:15 -080075 if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE ||
76 gDvmJit.codeCacheFull == true) {
Ben Cheng60c24f42010-01-04 12:29:56 -080077 result = false;
Bill Buzbee964a7b02010-01-28 12:54:19 -080078 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070079 }
80
81 for (numWork = gDvmJit.compilerQueueLength,
82 i = gDvmJit.compilerWorkDequeueIndex;
83 numWork > 0;
84 numWork--) {
85 /* Already enqueued */
86 if (gDvmJit.compilerWorkQueue[i++].pc == pc)
Bill Buzbee964a7b02010-01-28 12:54:19 -080087 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070088 /* Wrap around */
89 if (i == COMPILER_WORK_QUEUE_SIZE)
90 i = 0;
91 }
92
Ben Chengccd6c012009-10-15 14:52:45 -070093 CompilerWorkOrder *newOrder =
94 &gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex];
95 newOrder->pc = pc;
96 newOrder->kind = kind;
97 newOrder->info = info;
98 newOrder->result.codeAddress = NULL;
99 newOrder->result.discardResult =
Bill Buzbee1f748632010-03-02 16:14:41 -0800100 (kind == kWorkOrderTraceDebug) ? true : false;
Ben Cheng33672452010-01-12 14:59:30 -0800101 newOrder->result.requestingThread = dvmThreadSelf();
102
Ben Chengba4fc8b2009-06-01 13:00:29 -0700103 gDvmJit.compilerWorkEnqueueIndex++;
104 if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
105 gDvmJit.compilerWorkEnqueueIndex = 0;
106 gDvmJit.compilerQueueLength++;
107 cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
108 assert(cc == 0);
109
Bill Buzbee964a7b02010-01-28 12:54:19 -0800110unlockAndExit:
Ben Chengba4fc8b2009-06-01 13:00:29 -0700111 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng60c24f42010-01-04 12:29:56 -0800112 return result;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700113}
114
115/* Block until queue length is 0 */
116void dvmCompilerDrainQueue(void)
117{
Bill Buzbeed7269912009-11-10 14:31:32 -0800118 int oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700119 dvmLockMutex(&gDvmJit.compilerLock);
120 while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread) {
121 pthread_cond_wait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock);
122 }
123 dvmUnlockMutex(&gDvmJit.compilerLock);
Bill Buzbeed7269912009-11-10 14:31:32 -0800124 dvmChangeStatus(NULL, oldStatus);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700125}
126
Ben Cheng60c24f42010-01-04 12:29:56 -0800127bool dvmCompilerSetupCodeCache(void)
128{
129 extern void dvmCompilerTemplateStart(void);
130 extern void dmvCompilerTemplateEnd(void);
Ben Cheng7c4afdb2010-02-11 15:03:00 -0800131 int fd;
Ben Cheng60c24f42010-01-04 12:29:56 -0800132
133 /* Allocate the code cache */
Ben Cheng7c4afdb2010-02-11 15:03:00 -0800134 fd = ashmem_create_region("dalvik-jit-code-cache", gDvmJit.codeCacheSize);
135 if (fd < 0) {
136 LOGE("Could not create %u-byte ashmem region for the JIT code cache",
137 gDvmJit.codeCacheSize);
138 return false;
139 }
140 gDvmJit.codeCache = mmap(NULL, gDvmJit.codeCacheSize,
141 PROT_READ | PROT_WRITE | PROT_EXEC,
142 MAP_PRIVATE , fd, 0);
143 close(fd);
Ben Cheng60c24f42010-01-04 12:29:56 -0800144 if (gDvmJit.codeCache == MAP_FAILED) {
Ben Cheng7c4afdb2010-02-11 15:03:00 -0800145 LOGE("Failed to mmap the JIT code cache: %s\n", strerror(errno));
Ben Cheng60c24f42010-01-04 12:29:56 -0800146 return false;
147 }
148
Ben Cheng7c4afdb2010-02-11 15:03:00 -0800149 /* This can be found through "dalvik-jit-code-cache" in /proc/<pid>/maps */
150 // LOGD("Code cache starts at %p", gDvmJit.codeCache);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800151
Ben Cheng60c24f42010-01-04 12:29:56 -0800152 /* Copy the template code into the beginning of the code cache */
153 int templateSize = (intptr_t) dmvCompilerTemplateEnd -
154 (intptr_t) dvmCompilerTemplateStart;
155 memcpy((void *) gDvmJit.codeCache,
156 (void *) dvmCompilerTemplateStart,
157 templateSize);
158
Ben Cheng72621c92010-03-10 13:12:55 -0800159 /*
160 * Work around a CPU bug by keeping the 32-bit ARM handler code in its own
161 * page.
162 */
163 if (dvmCompilerInstructionSet() == DALVIK_JIT_THUMB2) {
164 templateSize = (templateSize + 4095) & ~4095;
165 }
166
Ben Cheng60c24f42010-01-04 12:29:56 -0800167 gDvmJit.templateSize = templateSize;
168 gDvmJit.codeCacheByteUsed = templateSize;
169
170 /* Only flush the part in the code cache that is being used now */
171 cacheflush((intptr_t) gDvmJit.codeCache,
172 (intptr_t) gDvmJit.codeCache + templateSize, 0);
173 return true;
174}
175
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800176static void crawlDalvikStack(Thread *thread, bool print)
177{
178 void *fp = thread->curFrame;
179 StackSaveArea* saveArea = NULL;
180 int stackLevel = 0;
181
182 if (print) {
183 LOGD("Crawling tid %d (%s / %p %s)", thread->systemTid,
184 dvmGetThreadStatusStr(thread->status),
185 thread->inJitCodeCache,
186 thread->inJitCodeCache ? "jit" : "interp");
187 }
188 /* Crawl the Dalvik stack frames to clear the returnAddr field */
189 while (fp != NULL) {
190 saveArea = SAVEAREA_FROM_FP(fp);
191
192 if (print) {
193 if (dvmIsBreakFrame(fp)) {
194 LOGD(" #%d: break frame (%p)",
195 stackLevel, saveArea->returnAddr);
196 }
197 else {
198 LOGD(" #%d: %s.%s%s (%p)",
199 stackLevel,
200 saveArea->method->clazz->descriptor,
201 saveArea->method->name,
202 dvmIsNativeMethod(saveArea->method) ?
203 " (native)" : "",
204 saveArea->returnAddr);
205 }
206 }
207 stackLevel++;
208 saveArea->returnAddr = NULL;
209 assert(fp != saveArea->prevFrame);
210 fp = saveArea->prevFrame;
211 }
212 /* Make sure the stack is fully unwound to the bottom */
213 assert(saveArea == NULL ||
214 (u1 *) (saveArea+1) == thread->interpStackStart);
215}
216
Ben Cheng60c24f42010-01-04 12:29:56 -0800217static void resetCodeCache(void)
218{
Ben Cheng60c24f42010-01-04 12:29:56 -0800219 Thread* thread;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800220 u8 startTime = dvmGetRelativeTimeUsec();
221 int inJit = 0;
Ben Cheng6999d842010-01-26 16:46:15 -0800222 int byteUsed = gDvmJit.codeCacheByteUsed;
Ben Cheng60c24f42010-01-04 12:29:56 -0800223
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800224 /* If any thread is found stuck in the JIT state, don't reset the cache */
225 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
Ben Cheng6999d842010-01-26 16:46:15 -0800226 /*
227 * Crawl the stack to wipe out the returnAddr field so that
228 * 1) the soon-to-be-deleted code in the JIT cache won't be used
229 * 2) or the thread stuck in the JIT land will soon return
230 * to the interpreter land
231 */
232 crawlDalvikStack(thread, false);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800233 if (thread->inJitCodeCache) {
234 inJit++;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800235 }
236 }
237
238 if (inJit) {
Ben Cheng6999d842010-01-26 16:46:15 -0800239 LOGD("JIT code cache reset delayed (%d bytes %d/%d)",
240 gDvmJit.codeCacheByteUsed, gDvmJit.numCodeCacheReset,
241 ++gDvmJit.numCodeCacheResetDelayed);
242 return;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800243 }
244
Ben Cheng6999d842010-01-26 16:46:15 -0800245 /* Lock the mutex to clean up the work queue */
246 dvmLockMutex(&gDvmJit.compilerLock);
247
248 /* Drain the work queue to free the work orders */
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800249 while (workQueueLength()) {
250 CompilerWorkOrder work = workDequeue();
251 free(work.info);
252 }
253
Ben Cheng60c24f42010-01-04 12:29:56 -0800254 /* Reset the JitEntry table contents to the initial unpopulated state */
255 dvmJitResetTable();
256
Ben Cheng60c24f42010-01-04 12:29:56 -0800257 /*
Ben Cheng60c24f42010-01-04 12:29:56 -0800258 * Wipe out the code cache content to force immediate crashes if
259 * stale JIT'ed code is invoked.
260 */
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800261 memset((char *) gDvmJit.codeCache + gDvmJit.templateSize,
262 0,
263 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
Ben Cheng60c24f42010-01-04 12:29:56 -0800264 cacheflush((intptr_t) gDvmJit.codeCache,
265 (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed, 0);
Ben Cheng60c24f42010-01-04 12:29:56 -0800266
267 /* Reset the current mark of used bytes to the end of template code */
268 gDvmJit.codeCacheByteUsed = gDvmJit.templateSize;
269 gDvmJit.numCompilations = 0;
270
271 /* Reset the work queue */
272 memset(gDvmJit.compilerWorkQueue, 0,
273 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
274 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
275 gDvmJit.compilerQueueLength = 0;
276
Ben Cheng6999d842010-01-26 16:46:15 -0800277 /* Reset the IC patch work queue */
278 dvmLockMutex(&gDvmJit.compilerICPatchLock);
279 gDvmJit.compilerICPatchIndex = 0;
280 dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
281
Ben Cheng60c24f42010-01-04 12:29:56 -0800282 /* All clear now */
283 gDvmJit.codeCacheFull = false;
284
Ben Cheng6999d842010-01-26 16:46:15 -0800285 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800286
Ben Cheng6999d842010-01-26 16:46:15 -0800287 LOGD("JIT code cache reset in %lld ms (%d bytes %d/%d)",
288 (dvmGetRelativeTimeUsec() - startTime) / 1000,
289 byteUsed, ++gDvmJit.numCodeCacheReset,
290 gDvmJit.numCodeCacheResetDelayed);
291}
292
293/*
294 * Perform actions that are only safe when all threads are suspended. Currently
295 * we do:
296 * 1) Check if the code cache is full. If so reset it and restart populating it
297 * from scratch.
298 * 2) Patch predicted chaining cells by consuming recorded work orders.
299 */
300void dvmCompilerPerformSafePointChecks(void)
301{
302 if (gDvmJit.codeCacheFull) {
303 resetCodeCache();
304 }
305 dvmCompilerPatchInlineCache();
Ben Cheng60c24f42010-01-04 12:29:56 -0800306}
307
Bill Buzbee964a7b02010-01-28 12:54:19 -0800308bool compilerThreadStartup(void)
309{
310 JitEntry *pJitTable = NULL;
311 unsigned char *pJitProfTable = NULL;
312 unsigned int i;
313
314 if (!dvmCompilerArchInit())
315 goto fail;
316
317 /*
318 * Setup the code cache if we have not inherited a valid code cache
319 * from the zygote.
320 */
321 if (gDvmJit.codeCache == NULL) {
322 if (!dvmCompilerSetupCodeCache())
323 goto fail;
324 }
325
326 /* Allocate the initial arena block */
327 if (dvmCompilerHeapInit() == false) {
328 goto fail;
329 }
330
Bill Buzbee964a7b02010-01-28 12:54:19 -0800331 dvmLockMutex(&gDvmJit.compilerLock);
332
Ben Cheng1357e942010-02-10 17:21:39 -0800333#if defined(WITH_JIT_TUNING)
Bill Buzbee964a7b02010-01-28 12:54:19 -0800334 /* Track method-level compilation statistics */
335 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
Ben Cheng1357e942010-02-10 17:21:39 -0800336#endif
Bill Buzbee964a7b02010-01-28 12:54:19 -0800337
338 dvmUnlockMutex(&gDvmJit.compilerLock);
339
340 /* Set up the JitTable */
341
342 /* Power of 2? */
343 assert(gDvmJit.jitTableSize &&
344 !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1)));
345
346 dvmInitMutex(&gDvmJit.tableLock);
347 dvmLockMutex(&gDvmJit.tableLock);
348 pJitTable = (JitEntry*)
349 calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
350 if (!pJitTable) {
351 LOGE("jit table allocation failed\n");
352 dvmUnlockMutex(&gDvmJit.tableLock);
353 goto fail;
354 }
355 /*
356 * NOTE: the profile table must only be allocated once, globally.
357 * Profiling is turned on and off by nulling out gDvm.pJitProfTable
358 * and then restoring its original value. However, this action
359 * is not syncronized for speed so threads may continue to hold
360 * and update the profile table after profiling has been turned
361 * off by null'ng the global pointer. Be aware.
362 */
363 pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE);
364 if (!pJitProfTable) {
365 LOGE("jit prof table allocation failed\n");
366 dvmUnlockMutex(&gDvmJit.tableLock);
367 goto fail;
368 }
369 memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE);
370 for (i=0; i < gDvmJit.jitTableSize; i++) {
371 pJitTable[i].u.info.chain = gDvmJit.jitTableSize;
372 }
373 /* Is chain field wide enough for termination pattern? */
374 assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize);
375
376 gDvmJit.pJitEntryTable = pJitTable;
377 gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
378 gDvmJit.jitTableEntriesUsed = 0;
379 gDvmJit.compilerHighWater =
380 COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
381 gDvmJit.pProfTable = pJitProfTable;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800382 gDvmJit.pProfTableCopy = pJitProfTable;
Bill Buzbee964a7b02010-01-28 12:54:19 -0800383 dvmUnlockMutex(&gDvmJit.tableLock);
384
385 /* Signal running threads to refresh their cached pJitTable pointers */
386 dvmSuspendAllThreads(SUSPEND_FOR_REFRESH);
387 dvmResumeAllThreads(SUSPEND_FOR_REFRESH);
388 return true;
389
390fail:
391 return false;
392
393}
394
Ben Chengba4fc8b2009-06-01 13:00:29 -0700395static void *compilerThreadStart(void *arg)
396{
Bill Buzbee94d89f82010-01-29 13:44:19 -0800397 int ret;
398 struct timespec ts;
399
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700400 dvmChangeStatus(NULL, THREAD_VMWAIT);
401
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800402 /*
Bill Buzbeeeb695c62010-02-04 16:09:55 -0800403 * If we're not running stand-alone, wait a little before
404 * recieving translation requests on the assumption that process start
405 * up code isn't worth compiling. We'll resume when the framework
406 * signals us that the first screen draw has happened, or the timer
407 * below expires (to catch daemons).
Ben Chengf30acbb2010-02-14 16:17:36 -0800408 *
409 * There is a theoretical race between the callback to
410 * VMRuntime.startJitCompiation and when the compiler thread reaches this
411 * point. In case the callback happens earlier, in order not to permanently
412 * hold the system_server (which is not using the timed wait) in
413 * interpreter-only mode we bypass the delay here.
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800414 */
Ben Chengf30acbb2010-02-14 16:17:36 -0800415 if (gDvmJit.runningInAndroidFramework &&
416 !gDvmJit.alreadyEnabledViaFramework) {
417 /*
418 * If the current VM instance is the system server (detected by having
419 * 0 in gDvm.systemServerPid), we will use the indefinite wait on the
420 * conditional variable to determine whether to start the JIT or not.
421 * If the system server detects that the whole system is booted in
422 * safe mode, the conditional variable will never be signaled and the
423 * system server will remain in the interpreter-only mode. All
424 * subsequent apps will be started with the --enable-safemode flag
425 * explicitly appended.
426 */
427 if (gDvm.systemServerPid == 0) {
428 dvmLockMutex(&gDvmJit.compilerLock);
429 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
430 &gDvmJit.compilerLock);
431 dvmUnlockMutex(&gDvmJit.compilerLock);
432 LOGD("JIT started for system_server");
433 } else {
434 dvmLockMutex(&gDvmJit.compilerLock);
435 /*
436 * TUNING: experiment with the delay & perhaps make it
437 * target-specific
438 */
439 dvmRelativeCondWait(&gDvmJit.compilerQueueActivity,
440 &gDvmJit.compilerLock, 3000, 0);
441 dvmUnlockMutex(&gDvmJit.compilerLock);
442 }
Bill Buzbeeeb695c62010-02-04 16:09:55 -0800443 if (gDvmJit.haltCompilerThread) {
444 return NULL;
445 }
Bill Buzbee94d89f82010-01-29 13:44:19 -0800446 }
447
Bill Buzbee964a7b02010-01-28 12:54:19 -0800448 compilerThreadStartup();
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800449
Ben Chengba4fc8b2009-06-01 13:00:29 -0700450 dvmLockMutex(&gDvmJit.compilerLock);
451 /*
452 * Since the compiler thread will not touch any objects on the heap once
453 * being created, we just fake its state as VMWAIT so that it can be a
454 * bit late when there is suspend request pending.
455 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700456 while (!gDvmJit.haltCompilerThread) {
457 if (workQueueLength() == 0) {
458 int cc;
459 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
460 assert(cc == 0);
461 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
462 &gDvmJit.compilerLock);
463 continue;
464 } else {
465 do {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700466 CompilerWorkOrder work = workDequeue();
467 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng86717f72010-03-05 15:27:21 -0800468#if defined(JIT_STATS)
469 u8 startTime = dvmGetRelativeTimeUsec();
470#endif
Bill Buzbee964a7b02010-01-28 12:54:19 -0800471 /*
472 * Check whether there is a suspend request on me. This
473 * is necessary to allow a clean shutdown.
474 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700475 dvmCheckSuspendPending(NULL);
Bill Buzbee27176222009-06-09 09:20:16 -0700476 /* Is JitTable filling up? */
477 if (gDvmJit.jitTableEntriesUsed >
478 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
Ben Cheng6999d842010-01-26 16:46:15 -0800479 bool resizeFail =
480 dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
481 /*
482 * If the jit table is full, consider it's time to reset
483 * the code cache too.
484 */
485 gDvmJit.codeCacheFull |= resizeFail;
Bill Buzbee27176222009-06-09 09:20:16 -0700486 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700487 if (gDvmJit.haltCompilerThread) {
488 LOGD("Compiler shutdown in progress - discarding request");
Ben Cheng6999d842010-01-26 16:46:15 -0800489 } else if (!gDvmJit.codeCacheFull) {
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800490 bool compileOK = false;
491 jmp_buf jmpBuf;
492 work.bailPtr = &jmpBuf;
493 bool aborted = setjmp(jmpBuf);
494 if (!aborted) {
495 compileOK = dvmCompilerDoWork(&work);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700496 }
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800497 if (aborted || !compileOK) {
498 dvmCompilerArenaReset();
499 work.result.codeAddress = gDvmJit.interpretTemplate;
500 } else if (!work.result.discardResult) {
Ben Cheng60c24f42010-01-04 12:29:56 -0800501 dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
502 work.result.instructionSet);
503 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700504 }
505 free(work.info);
Ben Cheng86717f72010-03-05 15:27:21 -0800506#if defined(JIT_STATS)
507 gDvmJit.jitTime += dvmGetRelativeTimeUsec() - startTime;
508#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700509 dvmLockMutex(&gDvmJit.compilerLock);
510 } while (workQueueLength() != 0);
511 }
512 }
513 pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
514 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Chengef00a852009-06-22 22:53:35 -0700515
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700516 /*
517 * As part of detaching the thread we need to call into Java code to update
518 * the ThreadGroup, and we should not be in VMWAIT state while executing
519 * interpreted code.
520 */
521 dvmChangeStatus(NULL, THREAD_RUNNING);
522
Andy McFadden43eb5012010-02-01 16:56:53 -0800523 if (gDvm.verboseShutdown)
524 LOGD("Compiler thread shutting down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700525 return NULL;
526}
527
Ben Chengba4fc8b2009-06-01 13:00:29 -0700528bool dvmCompilerStartup(void)
529{
Bill Buzbee94d89f82010-01-29 13:44:19 -0800530
531 dvmInitMutex(&gDvmJit.compilerLock);
Ben Cheng6999d842010-01-26 16:46:15 -0800532 dvmInitMutex(&gDvmJit.compilerICPatchLock);
Bill Buzbee94d89f82010-01-29 13:44:19 -0800533 dvmLockMutex(&gDvmJit.compilerLock);
534 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
535 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
536
537 /* Reset the work queue */
538 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
539 gDvmJit.compilerQueueLength = 0;
540 dvmUnlockMutex(&gDvmJit.compilerLock);
541
Ben Chengba4fc8b2009-06-01 13:00:29 -0700542 /*
Bill Buzbee94d89f82010-01-29 13:44:19 -0800543 * Defer rest of initialization until we're sure JIT'ng makes sense. Launch
Bill Buzbee964a7b02010-01-28 12:54:19 -0800544 * the compiler thread, which will do the real initialization if and
545 * when it is signalled to do so.
Ben Chengba4fc8b2009-06-01 13:00:29 -0700546 */
Bill Buzbee964a7b02010-01-28 12:54:19 -0800547 return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
548 compilerThreadStart, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700549}
550
551void dvmCompilerShutdown(void)
552{
553 void *threadReturn;
554
Bill Buzbee2fc03c32010-03-08 11:30:19 -0800555 /* Disable new translation requests */
556 gDvmJit.pProfTable = NULL;
557 gDvmJit.pProfTableCopy = NULL;
558
Ben Cheng88a0f972010-02-24 15:00:40 -0800559 if (gDvm.verboseShutdown) {
560 dvmCompilerDumpStats();
561 while (gDvmJit.compilerQueueLength)
562 sleep(5);
563 }
564
Ben Chengba4fc8b2009-06-01 13:00:29 -0700565 if (gDvmJit.compilerHandle) {
566
567 gDvmJit.haltCompilerThread = true;
568
569 dvmLockMutex(&gDvmJit.compilerLock);
570 pthread_cond_signal(&gDvmJit.compilerQueueActivity);
571 dvmUnlockMutex(&gDvmJit.compilerLock);
572
Ben Chengef00a852009-06-22 22:53:35 -0700573 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
574 LOGW("Compiler thread join failed\n");
Andy McFadden43eb5012010-02-01 16:56:53 -0800575 else if (gDvm.verboseShutdown)
Ben Chengef00a852009-06-22 22:53:35 -0700576 LOGD("Compiler thread has shut down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700577 }
Bill Buzbee06bb8392010-01-31 18:53:15 -0800578
Bill Buzbee2fc03c32010-03-08 11:30:19 -0800579 /* Break loops within the translation cache */
580 dvmJitUnchainAll();
Bill Buzbee96cfe6c2010-02-08 17:08:15 -0800581
Bill Buzbee2fc03c32010-03-08 11:30:19 -0800582 /*
583 * NOTE: our current implementatation doesn't allow for the compiler
584 * thread to be restarted after it exits here. We aren't freeing
585 * the JitTable or the ProfTable because threads which still may be
586 * running or in the process of shutting down may hold references to
587 * them.
588 */
Bill Buzbee96cfe6c2010-02-08 17:08:15 -0800589}
Bill Buzbee06bb8392010-01-31 18:53:15 -0800590
591void dvmCompilerStateRefresh()
592{
593 bool jitActive;
594 bool jitActivate;
Bill Buzbee3e392682010-02-03 18:13:57 -0800595 bool needUnchain = false;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800596
597 dvmLockMutex(&gDvmJit.tableLock);
598 jitActive = gDvmJit.pProfTable != NULL;
599 jitActivate = !(gDvm.debuggerActive || (gDvm.activeProfilers > 0));
600
601 if (jitActivate && !jitActive) {
602 gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800603 } else if (!jitActivate && jitActive) {
604 gDvmJit.pProfTable = NULL;
Bill Buzbee3e392682010-02-03 18:13:57 -0800605 needUnchain = true;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800606 }
Bill Buzbee3e392682010-02-03 18:13:57 -0800607 dvmUnlockMutex(&gDvmJit.tableLock);
608 if (needUnchain)
609 dvmJitUnchainAll();
Bill Buzbee06bb8392010-01-31 18:53:15 -0800610}