blob: 705333b85bfee1335dd8aac56a4da2aafb1ab1b5 [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 */
Ben Cheng7b133ef2010-02-04 16:15:59 -0800129 gDvmJit.codeCache = mmap(0, gDvmJit.codeCacheSize,
Ben Cheng60c24f42010-01-04 12:29:56 -0800130 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 /*
Bill Buzbeeeb695c62010-02-04 16:09:55 -0800381 * If we're not running stand-alone, wait a little before
382 * recieving translation requests on the assumption that process start
383 * up code isn't worth compiling. We'll resume when the framework
384 * signals us that the first screen draw has happened, or the timer
385 * below expires (to catch daemons).
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800386 */
Bill Buzbeeeb695c62010-02-04 16:09:55 -0800387 if (gDvmJit.runningInAndroidFramework) {
388 dvmLockMutex(&gDvmJit.compilerLock);
389 // TUNING: experiment with the delay & perhaps make it target-specific
390 dvmRelativeCondWait(&gDvmJit.compilerQueueActivity,
391 &gDvmJit.compilerLock, 3000, 0);
Bill Buzbee94d89f82010-01-29 13:44:19 -0800392 dvmUnlockMutex(&gDvmJit.compilerLock);
Bill Buzbeeeb695c62010-02-04 16:09:55 -0800393 if (gDvmJit.haltCompilerThread) {
394 return NULL;
395 }
Bill Buzbee94d89f82010-01-29 13:44:19 -0800396 }
397
Bill Buzbee964a7b02010-01-28 12:54:19 -0800398 compilerThreadStartup();
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800399
Ben Chengba4fc8b2009-06-01 13:00:29 -0700400 dvmLockMutex(&gDvmJit.compilerLock);
401 /*
402 * Since the compiler thread will not touch any objects on the heap once
403 * being created, we just fake its state as VMWAIT so that it can be a
404 * bit late when there is suspend request pending.
405 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700406 while (!gDvmJit.haltCompilerThread) {
407 if (workQueueLength() == 0) {
408 int cc;
409 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
410 assert(cc == 0);
411 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
412 &gDvmJit.compilerLock);
413 continue;
414 } else {
415 do {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700416 CompilerWorkOrder work = workDequeue();
417 dvmUnlockMutex(&gDvmJit.compilerLock);
Bill Buzbee964a7b02010-01-28 12:54:19 -0800418 /*
419 * Check whether there is a suspend request on me. This
420 * is necessary to allow a clean shutdown.
421 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700422 dvmCheckSuspendPending(NULL);
Bill Buzbee27176222009-06-09 09:20:16 -0700423 /* Is JitTable filling up? */
424 if (gDvmJit.jitTableEntriesUsed >
425 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
Ben Cheng6999d842010-01-26 16:46:15 -0800426 bool resizeFail =
427 dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
428 /*
429 * If the jit table is full, consider it's time to reset
430 * the code cache too.
431 */
432 gDvmJit.codeCacheFull |= resizeFail;
Bill Buzbee27176222009-06-09 09:20:16 -0700433 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700434 if (gDvmJit.haltCompilerThread) {
435 LOGD("Compiler shutdown in progress - discarding request");
Ben Cheng6999d842010-01-26 16:46:15 -0800436 } else if (!gDvmJit.codeCacheFull) {
Bill Buzbeed7269912009-11-10 14:31:32 -0800437 /* If compilation failed, use interpret-template */
438 if (!dvmCompilerDoWork(&work)) {
439 work.result.codeAddress = gDvmJit.interpretTemplate;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700440 }
Ben Cheng60c24f42010-01-04 12:29:56 -0800441 if (!work.result.discardResult) {
442 dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
443 work.result.instructionSet);
444 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700445 }
446 free(work.info);
447 dvmLockMutex(&gDvmJit.compilerLock);
448 } while (workQueueLength() != 0);
449 }
450 }
451 pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
452 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Chengef00a852009-06-22 22:53:35 -0700453
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700454 /*
455 * As part of detaching the thread we need to call into Java code to update
456 * the ThreadGroup, and we should not be in VMWAIT state while executing
457 * interpreted code.
458 */
459 dvmChangeStatus(NULL, THREAD_RUNNING);
460
Andy McFadden43eb5012010-02-01 16:56:53 -0800461 if (gDvm.verboseShutdown)
462 LOGD("Compiler thread shutting down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700463 return NULL;
464}
465
Ben Chengba4fc8b2009-06-01 13:00:29 -0700466bool dvmCompilerStartup(void)
467{
Bill Buzbee94d89f82010-01-29 13:44:19 -0800468
469 dvmInitMutex(&gDvmJit.compilerLock);
Ben Cheng6999d842010-01-26 16:46:15 -0800470 dvmInitMutex(&gDvmJit.compilerICPatchLock);
Bill Buzbee94d89f82010-01-29 13:44:19 -0800471 dvmLockMutex(&gDvmJit.compilerLock);
472 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
473 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
474
475 /* Reset the work queue */
476 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
477 gDvmJit.compilerQueueLength = 0;
478 dvmUnlockMutex(&gDvmJit.compilerLock);
479
Ben Chengba4fc8b2009-06-01 13:00:29 -0700480 /*
Bill Buzbee94d89f82010-01-29 13:44:19 -0800481 * Defer rest of initialization until we're sure JIT'ng makes sense. Launch
Bill Buzbee964a7b02010-01-28 12:54:19 -0800482 * the compiler thread, which will do the real initialization if and
483 * when it is signalled to do so.
Ben Chengba4fc8b2009-06-01 13:00:29 -0700484 */
Bill Buzbee964a7b02010-01-28 12:54:19 -0800485 return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
486 compilerThreadStart, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700487}
488
489void dvmCompilerShutdown(void)
490{
491 void *threadReturn;
492
493 if (gDvmJit.compilerHandle) {
494
495 gDvmJit.haltCompilerThread = true;
496
497 dvmLockMutex(&gDvmJit.compilerLock);
498 pthread_cond_signal(&gDvmJit.compilerQueueActivity);
499 dvmUnlockMutex(&gDvmJit.compilerLock);
500
Ben Chengef00a852009-06-22 22:53:35 -0700501 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
502 LOGW("Compiler thread join failed\n");
Andy McFadden43eb5012010-02-01 16:56:53 -0800503 else if (gDvm.verboseShutdown)
Ben Chengef00a852009-06-22 22:53:35 -0700504 LOGD("Compiler thread has shut down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700505 }
Bill Buzbee06bb8392010-01-31 18:53:15 -0800506
Bill Buzbee96cfe6c2010-02-08 17:08:15 -0800507 if (gDvm.verboseShutdown)
508 dvmCompilerDumpStats();
509
510 dvmDestroyMutex(&gDvmJit.tableLock);
511 dvmDestroyMutex(&gDvmJit.compilerLock);
512 dvmDestroyMutex(&gDvmJit.compilerICPatchLock);
513
514 if (gDvmJit.pJitEntryTable) {
515 free(gDvmJit.pJitEntryTable);
516 gDvmJit.pJitEntryTable = NULL;
517 }
518
519 if (gDvmJit.pProfTable) {
520 free(gDvmJit.pProfTable);
521 gDvmJit.pProfTable = NULL;
522 }
523
524}
Bill Buzbee06bb8392010-01-31 18:53:15 -0800525
526void dvmCompilerStateRefresh()
527{
528 bool jitActive;
529 bool jitActivate;
Bill Buzbee3e392682010-02-03 18:13:57 -0800530 bool needUnchain = false;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800531
532 dvmLockMutex(&gDvmJit.tableLock);
533 jitActive = gDvmJit.pProfTable != NULL;
534 jitActivate = !(gDvm.debuggerActive || (gDvm.activeProfilers > 0));
535
536 if (jitActivate && !jitActive) {
537 gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800538 } else if (!jitActivate && jitActive) {
539 gDvmJit.pProfTable = NULL;
Bill Buzbee3e392682010-02-03 18:13:57 -0800540 needUnchain = true;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800541 }
Bill Buzbee3e392682010-02-03 18:13:57 -0800542 dvmUnlockMutex(&gDvmJit.tableLock);
543 if (needUnchain)
544 dvmJitUnchainAll();
Bill Buzbee06bb8392010-01-31 18:53:15 -0800545}