blob: c16e78c04d7ea5e756c5f64800832b2af8e86840 [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
Bill Buzbee964a7b02010-01-28 12:54:19 -080052/*
53 * Attempt to enqueue a work order, returning true if successful.
54 * This routine will not block, but simply return if it couldn't
55 * aquire the lock or if the queue is full.
56 */
Ben Chengba4fc8b2009-06-01 13:00:29 -070057bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
58{
59 int cc;
60 int i;
61 int numWork;
Ben Cheng60c24f42010-01-04 12:29:56 -080062 bool result = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -070063
Bill Buzbee964a7b02010-01-28 12:54:19 -080064 if (dvmTryLockMutex(&gDvmJit.compilerLock)) {
65 return false; // Couldn't aquire the lock
66 }
Ben Chengba4fc8b2009-06-01 13:00:29 -070067
Ben Cheng7a0bcd02010-01-22 16:45:45 -080068 /*
Ben Cheng6999d842010-01-26 16:46:15 -080069 * Return if queue or code cache is full.
Ben Cheng7a0bcd02010-01-22 16:45:45 -080070 */
Ben Cheng6999d842010-01-26 16:46:15 -080071 if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE ||
72 gDvmJit.codeCacheFull == true) {
Ben Cheng60c24f42010-01-04 12:29:56 -080073 result = false;
Bill Buzbee964a7b02010-01-28 12:54:19 -080074 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070075 }
76
77 for (numWork = gDvmJit.compilerQueueLength,
78 i = gDvmJit.compilerWorkDequeueIndex;
79 numWork > 0;
80 numWork--) {
81 /* Already enqueued */
82 if (gDvmJit.compilerWorkQueue[i++].pc == pc)
Bill Buzbee964a7b02010-01-28 12:54:19 -080083 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070084 /* Wrap around */
85 if (i == COMPILER_WORK_QUEUE_SIZE)
86 i = 0;
87 }
88
Ben Chengccd6c012009-10-15 14:52:45 -070089 CompilerWorkOrder *newOrder =
90 &gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex];
91 newOrder->pc = pc;
92 newOrder->kind = kind;
93 newOrder->info = info;
94 newOrder->result.codeAddress = NULL;
95 newOrder->result.discardResult =
Ben Cheng6999d842010-01-26 16:46:15 -080096 (kind == kWorkOrderTraceDebug) ? true : false;
Ben Cheng33672452010-01-12 14:59:30 -080097 newOrder->result.requestingThread = dvmThreadSelf();
98
Ben Chengba4fc8b2009-06-01 13:00:29 -070099 gDvmJit.compilerWorkEnqueueIndex++;
100 if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
101 gDvmJit.compilerWorkEnqueueIndex = 0;
102 gDvmJit.compilerQueueLength++;
103 cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
104 assert(cc == 0);
105
Bill Buzbee964a7b02010-01-28 12:54:19 -0800106unlockAndExit:
Ben Chengba4fc8b2009-06-01 13:00:29 -0700107 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng60c24f42010-01-04 12:29:56 -0800108 return result;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700109}
110
111/* Block until queue length is 0 */
112void dvmCompilerDrainQueue(void)
113{
Bill Buzbeed7269912009-11-10 14:31:32 -0800114 int oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700115 dvmLockMutex(&gDvmJit.compilerLock);
116 while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread) {
117 pthread_cond_wait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock);
118 }
119 dvmUnlockMutex(&gDvmJit.compilerLock);
Bill Buzbeed7269912009-11-10 14:31:32 -0800120 dvmChangeStatus(NULL, oldStatus);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700121}
122
Ben Cheng60c24f42010-01-04 12:29:56 -0800123bool dvmCompilerSetupCodeCache(void)
124{
125 extern void dvmCompilerTemplateStart(void);
126 extern void dmvCompilerTemplateEnd(void);
127
128 /* Allocate the code cache */
129 gDvmJit.codeCache = mmap(0, CODE_CACHE_SIZE,
130 PROT_READ | PROT_WRITE | PROT_EXEC,
131 MAP_PRIVATE | MAP_ANON, -1, 0);
132 if (gDvmJit.codeCache == MAP_FAILED) {
133 LOGE("Failed to create the code cache: %s\n", strerror(errno));
134 return false;
135 }
136
Ben Cheng6999d842010-01-26 16:46:15 -0800137 // STOPSHIP - for debugging only
138 LOGD("Code cache starts at %p", gDvmJit.codeCache);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800139
Ben Cheng60c24f42010-01-04 12:29:56 -0800140 /* Copy the template code into the beginning of the code cache */
141 int templateSize = (intptr_t) dmvCompilerTemplateEnd -
142 (intptr_t) dvmCompilerTemplateStart;
143 memcpy((void *) gDvmJit.codeCache,
144 (void *) dvmCompilerTemplateStart,
145 templateSize);
146
147 gDvmJit.templateSize = templateSize;
148 gDvmJit.codeCacheByteUsed = templateSize;
149
150 /* Only flush the part in the code cache that is being used now */
151 cacheflush((intptr_t) gDvmJit.codeCache,
152 (intptr_t) gDvmJit.codeCache + templateSize, 0);
153 return true;
154}
155
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800156static void crawlDalvikStack(Thread *thread, bool print)
157{
158 void *fp = thread->curFrame;
159 StackSaveArea* saveArea = NULL;
160 int stackLevel = 0;
161
162 if (print) {
163 LOGD("Crawling tid %d (%s / %p %s)", thread->systemTid,
164 dvmGetThreadStatusStr(thread->status),
165 thread->inJitCodeCache,
166 thread->inJitCodeCache ? "jit" : "interp");
167 }
168 /* Crawl the Dalvik stack frames to clear the returnAddr field */
169 while (fp != NULL) {
170 saveArea = SAVEAREA_FROM_FP(fp);
171
172 if (print) {
173 if (dvmIsBreakFrame(fp)) {
174 LOGD(" #%d: break frame (%p)",
175 stackLevel, saveArea->returnAddr);
176 }
177 else {
178 LOGD(" #%d: %s.%s%s (%p)",
179 stackLevel,
180 saveArea->method->clazz->descriptor,
181 saveArea->method->name,
182 dvmIsNativeMethod(saveArea->method) ?
183 " (native)" : "",
184 saveArea->returnAddr);
185 }
186 }
187 stackLevel++;
188 saveArea->returnAddr = NULL;
189 assert(fp != saveArea->prevFrame);
190 fp = saveArea->prevFrame;
191 }
192 /* Make sure the stack is fully unwound to the bottom */
193 assert(saveArea == NULL ||
194 (u1 *) (saveArea+1) == thread->interpStackStart);
195}
196
Ben Cheng60c24f42010-01-04 12:29:56 -0800197static void resetCodeCache(void)
198{
Ben Cheng60c24f42010-01-04 12:29:56 -0800199 Thread* thread;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800200 u8 startTime = dvmGetRelativeTimeUsec();
201 int inJit = 0;
Ben Cheng6999d842010-01-26 16:46:15 -0800202 int byteUsed = gDvmJit.codeCacheByteUsed;
Ben Cheng60c24f42010-01-04 12:29:56 -0800203
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800204 /* If any thread is found stuck in the JIT state, don't reset the cache */
205 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
Ben Cheng6999d842010-01-26 16:46:15 -0800206 /*
207 * Crawl the stack to wipe out the returnAddr field so that
208 * 1) the soon-to-be-deleted code in the JIT cache won't be used
209 * 2) or the thread stuck in the JIT land will soon return
210 * to the interpreter land
211 */
212 crawlDalvikStack(thread, false);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800213 if (thread->inJitCodeCache) {
214 inJit++;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800215 }
216 }
217
218 if (inJit) {
Ben Cheng6999d842010-01-26 16:46:15 -0800219 LOGD("JIT code cache reset delayed (%d bytes %d/%d)",
220 gDvmJit.codeCacheByteUsed, gDvmJit.numCodeCacheReset,
221 ++gDvmJit.numCodeCacheResetDelayed);
222 return;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800223 }
224
Ben Cheng6999d842010-01-26 16:46:15 -0800225 /* Lock the mutex to clean up the work queue */
226 dvmLockMutex(&gDvmJit.compilerLock);
227
228 /* Drain the work queue to free the work orders */
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800229 while (workQueueLength()) {
230 CompilerWorkOrder work = workDequeue();
231 free(work.info);
232 }
233
Ben Cheng60c24f42010-01-04 12:29:56 -0800234 /* Reset the JitEntry table contents to the initial unpopulated state */
235 dvmJitResetTable();
236
Ben Cheng60c24f42010-01-04 12:29:56 -0800237 /*
Ben Cheng60c24f42010-01-04 12:29:56 -0800238 * Wipe out the code cache content to force immediate crashes if
239 * stale JIT'ed code is invoked.
240 */
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800241 memset((char *) gDvmJit.codeCache + gDvmJit.templateSize,
242 0,
243 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
Ben Cheng60c24f42010-01-04 12:29:56 -0800244 cacheflush((intptr_t) gDvmJit.codeCache,
245 (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed, 0);
Ben Cheng60c24f42010-01-04 12:29:56 -0800246
247 /* Reset the current mark of used bytes to the end of template code */
248 gDvmJit.codeCacheByteUsed = gDvmJit.templateSize;
249 gDvmJit.numCompilations = 0;
250
251 /* Reset the work queue */
252 memset(gDvmJit.compilerWorkQueue, 0,
253 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
254 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
255 gDvmJit.compilerQueueLength = 0;
256
Ben Cheng6999d842010-01-26 16:46:15 -0800257 /* Reset the IC patch work queue */
258 dvmLockMutex(&gDvmJit.compilerICPatchLock);
259 gDvmJit.compilerICPatchIndex = 0;
260 dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
261
Ben Cheng60c24f42010-01-04 12:29:56 -0800262 /* All clear now */
263 gDvmJit.codeCacheFull = false;
264
Ben Cheng6999d842010-01-26 16:46:15 -0800265 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800266
Ben Cheng6999d842010-01-26 16:46:15 -0800267 LOGD("JIT code cache reset in %lld ms (%d bytes %d/%d)",
268 (dvmGetRelativeTimeUsec() - startTime) / 1000,
269 byteUsed, ++gDvmJit.numCodeCacheReset,
270 gDvmJit.numCodeCacheResetDelayed);
271}
272
273/*
274 * Perform actions that are only safe when all threads are suspended. Currently
275 * we do:
276 * 1) Check if the code cache is full. If so reset it and restart populating it
277 * from scratch.
278 * 2) Patch predicted chaining cells by consuming recorded work orders.
279 */
280void dvmCompilerPerformSafePointChecks(void)
281{
282 if (gDvmJit.codeCacheFull) {
283 resetCodeCache();
284 }
285 dvmCompilerPatchInlineCache();
Ben Cheng60c24f42010-01-04 12:29:56 -0800286}
287
Bill Buzbee964a7b02010-01-28 12:54:19 -0800288bool compilerThreadStartup(void)
289{
290 JitEntry *pJitTable = NULL;
291 unsigned char *pJitProfTable = NULL;
292 unsigned int i;
293
294 if (!dvmCompilerArchInit())
295 goto fail;
296
297 /*
298 * Setup the code cache if we have not inherited a valid code cache
299 * from the zygote.
300 */
301 if (gDvmJit.codeCache == NULL) {
302 if (!dvmCompilerSetupCodeCache())
303 goto fail;
304 }
305
306 /* Allocate the initial arena block */
307 if (dvmCompilerHeapInit() == false) {
308 goto fail;
309 }
310
Bill Buzbee964a7b02010-01-28 12:54:19 -0800311 dvmLockMutex(&gDvmJit.compilerLock);
312
Bill Buzbee964a7b02010-01-28 12:54:19 -0800313 /* Track method-level compilation statistics */
314 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
315
316 dvmUnlockMutex(&gDvmJit.compilerLock);
317
318 /* Set up the JitTable */
319
320 /* Power of 2? */
321 assert(gDvmJit.jitTableSize &&
322 !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1)));
323
324 dvmInitMutex(&gDvmJit.tableLock);
325 dvmLockMutex(&gDvmJit.tableLock);
326 pJitTable = (JitEntry*)
327 calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
328 if (!pJitTable) {
329 LOGE("jit table allocation failed\n");
330 dvmUnlockMutex(&gDvmJit.tableLock);
331 goto fail;
332 }
333 /*
334 * NOTE: the profile table must only be allocated once, globally.
335 * Profiling is turned on and off by nulling out gDvm.pJitProfTable
336 * and then restoring its original value. However, this action
337 * is not syncronized for speed so threads may continue to hold
338 * and update the profile table after profiling has been turned
339 * off by null'ng the global pointer. Be aware.
340 */
341 pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE);
342 if (!pJitProfTable) {
343 LOGE("jit prof table allocation failed\n");
344 dvmUnlockMutex(&gDvmJit.tableLock);
345 goto fail;
346 }
347 memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE);
348 for (i=0; i < gDvmJit.jitTableSize; i++) {
349 pJitTable[i].u.info.chain = gDvmJit.jitTableSize;
350 }
351 /* Is chain field wide enough for termination pattern? */
352 assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize);
353
354 gDvmJit.pJitEntryTable = pJitTable;
355 gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
356 gDvmJit.jitTableEntriesUsed = 0;
357 gDvmJit.compilerHighWater =
358 COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
359 gDvmJit.pProfTable = pJitProfTable;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800360 gDvmJit.pProfTableCopy = pJitProfTable;
Bill Buzbee964a7b02010-01-28 12:54:19 -0800361 dvmUnlockMutex(&gDvmJit.tableLock);
362
363 /* Signal running threads to refresh their cached pJitTable pointers */
364 dvmSuspendAllThreads(SUSPEND_FOR_REFRESH);
365 dvmResumeAllThreads(SUSPEND_FOR_REFRESH);
366 return true;
367
368fail:
369 return false;
370
371}
372
Ben Chengba4fc8b2009-06-01 13:00:29 -0700373static void *compilerThreadStart(void *arg)
374{
Bill Buzbee94d89f82010-01-29 13:44:19 -0800375 int ret;
376 struct timespec ts;
377
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700378 dvmChangeStatus(NULL, THREAD_VMWAIT);
379
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800380 /*
381 * Wait a little before recieving translation requests on the assumption
Bill Buzbee964a7b02010-01-28 12:54:19 -0800382 * that process start-up code isn't worth compiling.
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800383 */
Bill Buzbee94d89f82010-01-29 13:44:19 -0800384
385 dvmLockMutex(&gDvmJit.compilerLock);
386 /*
387 * TUNING: once framework is calling VMRuntime.startJitCompilation,
388 * experiment with the delay time (and perhaps have target-dependent
389 * values?
390 */
391 dvmAbsoluteTime(1000, 0, &ts);
392#if defined(HAVE_TIMEDWAIT_MONOTONIC)
393 ret = pthread_cond_timedwait_monotonic(&gDvmJit.compilerQueueActivity,
394 &gDvmJit.compilerLock, &ts);
395#else
396 ret = pthread_cond_timedwait(&gDvmJit.compilerQueueActivity,
397 &gDvmJit.compilerLock, &ts);
398#endif
399 assert(ret == 0 || ret == ETIMEDOUT);
400
401 if (gDvmJit.haltCompilerThread) {
402 dvmUnlockMutex(&gDvmJit.compilerLock);
403 return NULL;
404 }
405
406 dvmUnlockMutex(&gDvmJit.compilerLock);
407
Bill Buzbee964a7b02010-01-28 12:54:19 -0800408 compilerThreadStartup();
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800409
Ben Chengba4fc8b2009-06-01 13:00:29 -0700410 dvmLockMutex(&gDvmJit.compilerLock);
411 /*
412 * Since the compiler thread will not touch any objects on the heap once
413 * being created, we just fake its state as VMWAIT so that it can be a
414 * bit late when there is suspend request pending.
415 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700416 while (!gDvmJit.haltCompilerThread) {
417 if (workQueueLength() == 0) {
418 int cc;
419 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
420 assert(cc == 0);
421 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
422 &gDvmJit.compilerLock);
423 continue;
424 } else {
425 do {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700426 CompilerWorkOrder work = workDequeue();
427 dvmUnlockMutex(&gDvmJit.compilerLock);
Bill Buzbee964a7b02010-01-28 12:54:19 -0800428 /*
429 * Check whether there is a suspend request on me. This
430 * is necessary to allow a clean shutdown.
431 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700432 dvmCheckSuspendPending(NULL);
Bill Buzbee27176222009-06-09 09:20:16 -0700433 /* Is JitTable filling up? */
434 if (gDvmJit.jitTableEntriesUsed >
435 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
Ben Cheng6999d842010-01-26 16:46:15 -0800436 bool resizeFail =
437 dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
438 /*
439 * If the jit table is full, consider it's time to reset
440 * the code cache too.
441 */
442 gDvmJit.codeCacheFull |= resizeFail;
Bill Buzbee27176222009-06-09 09:20:16 -0700443 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700444 if (gDvmJit.haltCompilerThread) {
445 LOGD("Compiler shutdown in progress - discarding request");
Ben Cheng6999d842010-01-26 16:46:15 -0800446 } else if (!gDvmJit.codeCacheFull) {
Bill Buzbeed7269912009-11-10 14:31:32 -0800447 /* If compilation failed, use interpret-template */
448 if (!dvmCompilerDoWork(&work)) {
449 work.result.codeAddress = gDvmJit.interpretTemplate;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700450 }
Ben Cheng60c24f42010-01-04 12:29:56 -0800451 if (!work.result.discardResult) {
452 dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
453 work.result.instructionSet);
454 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700455 }
456 free(work.info);
457 dvmLockMutex(&gDvmJit.compilerLock);
458 } while (workQueueLength() != 0);
459 }
460 }
461 pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
462 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Chengef00a852009-06-22 22:53:35 -0700463
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700464 /*
465 * As part of detaching the thread we need to call into Java code to update
466 * the ThreadGroup, and we should not be in VMWAIT state while executing
467 * interpreted code.
468 */
469 dvmChangeStatus(NULL, THREAD_RUNNING);
470
Andy McFadden43eb5012010-02-01 16:56:53 -0800471 if (gDvm.verboseShutdown)
472 LOGD("Compiler thread shutting down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700473 return NULL;
474}
475
Ben Chengba4fc8b2009-06-01 13:00:29 -0700476bool dvmCompilerStartup(void)
477{
Bill Buzbee94d89f82010-01-29 13:44:19 -0800478
479 dvmInitMutex(&gDvmJit.compilerLock);
Ben Cheng6999d842010-01-26 16:46:15 -0800480 dvmInitMutex(&gDvmJit.compilerICPatchLock);
Bill Buzbee94d89f82010-01-29 13:44:19 -0800481 dvmLockMutex(&gDvmJit.compilerLock);
482 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
483 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
484
485 /* Reset the work queue */
486 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
487 gDvmJit.compilerQueueLength = 0;
488 dvmUnlockMutex(&gDvmJit.compilerLock);
489
Ben Chengba4fc8b2009-06-01 13:00:29 -0700490 /*
Bill Buzbee94d89f82010-01-29 13:44:19 -0800491 * Defer rest of initialization until we're sure JIT'ng makes sense. Launch
Bill Buzbee964a7b02010-01-28 12:54:19 -0800492 * the compiler thread, which will do the real initialization if and
493 * when it is signalled to do so.
Ben Chengba4fc8b2009-06-01 13:00:29 -0700494 */
Bill Buzbee964a7b02010-01-28 12:54:19 -0800495 return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
496 compilerThreadStart, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700497}
498
499void dvmCompilerShutdown(void)
500{
501 void *threadReturn;
502
503 if (gDvmJit.compilerHandle) {
504
505 gDvmJit.haltCompilerThread = true;
506
507 dvmLockMutex(&gDvmJit.compilerLock);
508 pthread_cond_signal(&gDvmJit.compilerQueueActivity);
509 dvmUnlockMutex(&gDvmJit.compilerLock);
510
Ben Chengef00a852009-06-22 22:53:35 -0700511 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
512 LOGW("Compiler thread join failed\n");
Andy McFadden43eb5012010-02-01 16:56:53 -0800513 else if (gDvm.verboseShutdown)
Ben Chengef00a852009-06-22 22:53:35 -0700514 LOGD("Compiler thread has shut down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700515 }
516}
Bill Buzbee06bb8392010-01-31 18:53:15 -0800517
518
519void dvmCompilerStateRefresh()
520{
521 bool jitActive;
522 bool jitActivate;
Bill Buzbee3e392682010-02-03 18:13:57 -0800523 bool needUnchain = false;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800524
525 dvmLockMutex(&gDvmJit.tableLock);
526 jitActive = gDvmJit.pProfTable != NULL;
527 jitActivate = !(gDvm.debuggerActive || (gDvm.activeProfilers > 0));
528
529 if (jitActivate && !jitActive) {
530 gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800531 } else if (!jitActivate && jitActive) {
532 gDvmJit.pProfTable = NULL;
Bill Buzbee3e392682010-02-03 18:13:57 -0800533 needUnchain = true;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800534 }
Bill Buzbee3e392682010-02-03 18:13:57 -0800535 dvmUnlockMutex(&gDvmJit.tableLock);
536 if (needUnchain)
537 dvmJitUnchainAll();
Bill Buzbee06bb8392010-01-31 18:53:15 -0800538}