blob: e01ca894a555260bdfaac707b2d8410f0e6ac157 [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)) {
Ben Cheng3e5cd172010-02-08 20:57:59 -080065 /*
66 * Make sure the memory associated with the info pointer is freed for
67 * dropped work orders.
68 */
69 free(info);
70 return false; // Couldn't acquire the lock
Bill Buzbee964a7b02010-01-28 12:54:19 -080071 }
Ben Chengba4fc8b2009-06-01 13:00:29 -070072
Ben Cheng7a0bcd02010-01-22 16:45:45 -080073 /*
Ben Cheng6999d842010-01-26 16:46:15 -080074 * Return if queue or code cache is full.
Ben Cheng7a0bcd02010-01-22 16:45:45 -080075 */
Ben Cheng6999d842010-01-26 16:46:15 -080076 if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE ||
77 gDvmJit.codeCacheFull == true) {
Ben Cheng60c24f42010-01-04 12:29:56 -080078 result = false;
Bill Buzbee964a7b02010-01-28 12:54:19 -080079 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070080 }
81
82 for (numWork = gDvmJit.compilerQueueLength,
83 i = gDvmJit.compilerWorkDequeueIndex;
84 numWork > 0;
85 numWork--) {
86 /* Already enqueued */
87 if (gDvmJit.compilerWorkQueue[i++].pc == pc)
Bill Buzbee964a7b02010-01-28 12:54:19 -080088 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070089 /* Wrap around */
90 if (i == COMPILER_WORK_QUEUE_SIZE)
91 i = 0;
92 }
93
Ben Chengccd6c012009-10-15 14:52:45 -070094 CompilerWorkOrder *newOrder =
95 &gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex];
96 newOrder->pc = pc;
97 newOrder->kind = kind;
98 newOrder->info = info;
99 newOrder->result.codeAddress = NULL;
100 newOrder->result.discardResult =
Ben Cheng6999d842010-01-26 16:46:15 -0800101 (kind == kWorkOrderTraceDebug) ? true : false;
Ben Cheng33672452010-01-12 14:59:30 -0800102 newOrder->result.requestingThread = dvmThreadSelf();
103
Ben Chengba4fc8b2009-06-01 13:00:29 -0700104 gDvmJit.compilerWorkEnqueueIndex++;
105 if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
106 gDvmJit.compilerWorkEnqueueIndex = 0;
107 gDvmJit.compilerQueueLength++;
108 cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
109 assert(cc == 0);
110
Bill Buzbee964a7b02010-01-28 12:54:19 -0800111unlockAndExit:
Ben Chengba4fc8b2009-06-01 13:00:29 -0700112 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng60c24f42010-01-04 12:29:56 -0800113 return result;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700114}
115
116/* Block until queue length is 0 */
117void dvmCompilerDrainQueue(void)
118{
Bill Buzbeed7269912009-11-10 14:31:32 -0800119 int oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700120 dvmLockMutex(&gDvmJit.compilerLock);
121 while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread) {
122 pthread_cond_wait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock);
123 }
124 dvmUnlockMutex(&gDvmJit.compilerLock);
Bill Buzbeed7269912009-11-10 14:31:32 -0800125 dvmChangeStatus(NULL, oldStatus);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700126}
127
Ben Cheng60c24f42010-01-04 12:29:56 -0800128bool dvmCompilerSetupCodeCache(void)
129{
130 extern void dvmCompilerTemplateStart(void);
131 extern void dmvCompilerTemplateEnd(void);
132
133 /* Allocate the code cache */
Ben Cheng7b133ef2010-02-04 16:15:59 -0800134 gDvmJit.codeCache = mmap(0, gDvmJit.codeCacheSize,
Ben Cheng60c24f42010-01-04 12:29:56 -0800135 PROT_READ | PROT_WRITE | PROT_EXEC,
136 MAP_PRIVATE | MAP_ANON, -1, 0);
137 if (gDvmJit.codeCache == MAP_FAILED) {
138 LOGE("Failed to create the code cache: %s\n", strerror(errno));
139 return false;
140 }
141
Ben Cheng6999d842010-01-26 16:46:15 -0800142 // STOPSHIP - for debugging only
143 LOGD("Code cache starts at %p", gDvmJit.codeCache);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800144
Ben Cheng60c24f42010-01-04 12:29:56 -0800145 /* Copy the template code into the beginning of the code cache */
146 int templateSize = (intptr_t) dmvCompilerTemplateEnd -
147 (intptr_t) dvmCompilerTemplateStart;
148 memcpy((void *) gDvmJit.codeCache,
149 (void *) dvmCompilerTemplateStart,
150 templateSize);
151
152 gDvmJit.templateSize = templateSize;
153 gDvmJit.codeCacheByteUsed = templateSize;
154
155 /* Only flush the part in the code cache that is being used now */
156 cacheflush((intptr_t) gDvmJit.codeCache,
157 (intptr_t) gDvmJit.codeCache + templateSize, 0);
158 return true;
159}
160
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800161static void crawlDalvikStack(Thread *thread, bool print)
162{
163 void *fp = thread->curFrame;
164 StackSaveArea* saveArea = NULL;
165 int stackLevel = 0;
166
167 if (print) {
168 LOGD("Crawling tid %d (%s / %p %s)", thread->systemTid,
169 dvmGetThreadStatusStr(thread->status),
170 thread->inJitCodeCache,
171 thread->inJitCodeCache ? "jit" : "interp");
172 }
173 /* Crawl the Dalvik stack frames to clear the returnAddr field */
174 while (fp != NULL) {
175 saveArea = SAVEAREA_FROM_FP(fp);
176
177 if (print) {
178 if (dvmIsBreakFrame(fp)) {
179 LOGD(" #%d: break frame (%p)",
180 stackLevel, saveArea->returnAddr);
181 }
182 else {
183 LOGD(" #%d: %s.%s%s (%p)",
184 stackLevel,
185 saveArea->method->clazz->descriptor,
186 saveArea->method->name,
187 dvmIsNativeMethod(saveArea->method) ?
188 " (native)" : "",
189 saveArea->returnAddr);
190 }
191 }
192 stackLevel++;
193 saveArea->returnAddr = NULL;
194 assert(fp != saveArea->prevFrame);
195 fp = saveArea->prevFrame;
196 }
197 /* Make sure the stack is fully unwound to the bottom */
198 assert(saveArea == NULL ||
199 (u1 *) (saveArea+1) == thread->interpStackStart);
200}
201
Ben Cheng60c24f42010-01-04 12:29:56 -0800202static void resetCodeCache(void)
203{
Ben Cheng60c24f42010-01-04 12:29:56 -0800204 Thread* thread;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800205 u8 startTime = dvmGetRelativeTimeUsec();
206 int inJit = 0;
Ben Cheng6999d842010-01-26 16:46:15 -0800207 int byteUsed = gDvmJit.codeCacheByteUsed;
Ben Cheng60c24f42010-01-04 12:29:56 -0800208
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800209 /* If any thread is found stuck in the JIT state, don't reset the cache */
210 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
Ben Cheng6999d842010-01-26 16:46:15 -0800211 /*
212 * Crawl the stack to wipe out the returnAddr field so that
213 * 1) the soon-to-be-deleted code in the JIT cache won't be used
214 * 2) or the thread stuck in the JIT land will soon return
215 * to the interpreter land
216 */
217 crawlDalvikStack(thread, false);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800218 if (thread->inJitCodeCache) {
219 inJit++;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800220 }
221 }
222
223 if (inJit) {
Ben Cheng6999d842010-01-26 16:46:15 -0800224 LOGD("JIT code cache reset delayed (%d bytes %d/%d)",
225 gDvmJit.codeCacheByteUsed, gDvmJit.numCodeCacheReset,
226 ++gDvmJit.numCodeCacheResetDelayed);
227 return;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800228 }
229
Ben Cheng6999d842010-01-26 16:46:15 -0800230 /* Lock the mutex to clean up the work queue */
231 dvmLockMutex(&gDvmJit.compilerLock);
232
233 /* Drain the work queue to free the work orders */
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800234 while (workQueueLength()) {
235 CompilerWorkOrder work = workDequeue();
236 free(work.info);
237 }
238
Ben Cheng60c24f42010-01-04 12:29:56 -0800239 /* Reset the JitEntry table contents to the initial unpopulated state */
240 dvmJitResetTable();
241
Ben Cheng60c24f42010-01-04 12:29:56 -0800242 /*
Ben Cheng60c24f42010-01-04 12:29:56 -0800243 * Wipe out the code cache content to force immediate crashes if
244 * stale JIT'ed code is invoked.
245 */
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800246 memset((char *) gDvmJit.codeCache + gDvmJit.templateSize,
247 0,
248 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
Ben Cheng60c24f42010-01-04 12:29:56 -0800249 cacheflush((intptr_t) gDvmJit.codeCache,
250 (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed, 0);
Ben Cheng60c24f42010-01-04 12:29:56 -0800251
252 /* Reset the current mark of used bytes to the end of template code */
253 gDvmJit.codeCacheByteUsed = gDvmJit.templateSize;
254 gDvmJit.numCompilations = 0;
255
256 /* Reset the work queue */
257 memset(gDvmJit.compilerWorkQueue, 0,
258 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
259 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
260 gDvmJit.compilerQueueLength = 0;
261
Ben Cheng6999d842010-01-26 16:46:15 -0800262 /* Reset the IC patch work queue */
263 dvmLockMutex(&gDvmJit.compilerICPatchLock);
264 gDvmJit.compilerICPatchIndex = 0;
265 dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
266
Ben Cheng60c24f42010-01-04 12:29:56 -0800267 /* All clear now */
268 gDvmJit.codeCacheFull = false;
269
Ben Cheng6999d842010-01-26 16:46:15 -0800270 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800271
Ben Cheng6999d842010-01-26 16:46:15 -0800272 LOGD("JIT code cache reset in %lld ms (%d bytes %d/%d)",
273 (dvmGetRelativeTimeUsec() - startTime) / 1000,
274 byteUsed, ++gDvmJit.numCodeCacheReset,
275 gDvmJit.numCodeCacheResetDelayed);
276}
277
278/*
279 * Perform actions that are only safe when all threads are suspended. Currently
280 * we do:
281 * 1) Check if the code cache is full. If so reset it and restart populating it
282 * from scratch.
283 * 2) Patch predicted chaining cells by consuming recorded work orders.
284 */
285void dvmCompilerPerformSafePointChecks(void)
286{
287 if (gDvmJit.codeCacheFull) {
288 resetCodeCache();
289 }
290 dvmCompilerPatchInlineCache();
Ben Cheng60c24f42010-01-04 12:29:56 -0800291}
292
Bill Buzbee964a7b02010-01-28 12:54:19 -0800293bool compilerThreadStartup(void)
294{
295 JitEntry *pJitTable = NULL;
296 unsigned char *pJitProfTable = NULL;
297 unsigned int i;
298
299 if (!dvmCompilerArchInit())
300 goto fail;
301
302 /*
303 * Setup the code cache if we have not inherited a valid code cache
304 * from the zygote.
305 */
306 if (gDvmJit.codeCache == NULL) {
307 if (!dvmCompilerSetupCodeCache())
308 goto fail;
309 }
310
311 /* Allocate the initial arena block */
312 if (dvmCompilerHeapInit() == false) {
313 goto fail;
314 }
315
Bill Buzbee964a7b02010-01-28 12:54:19 -0800316 dvmLockMutex(&gDvmJit.compilerLock);
317
Bill Buzbee964a7b02010-01-28 12:54:19 -0800318 /* Track method-level compilation statistics */
319 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
320
321 dvmUnlockMutex(&gDvmJit.compilerLock);
322
323 /* Set up the JitTable */
324
325 /* Power of 2? */
326 assert(gDvmJit.jitTableSize &&
327 !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1)));
328
329 dvmInitMutex(&gDvmJit.tableLock);
330 dvmLockMutex(&gDvmJit.tableLock);
331 pJitTable = (JitEntry*)
332 calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
333 if (!pJitTable) {
334 LOGE("jit table allocation failed\n");
335 dvmUnlockMutex(&gDvmJit.tableLock);
336 goto fail;
337 }
338 /*
339 * NOTE: the profile table must only be allocated once, globally.
340 * Profiling is turned on and off by nulling out gDvm.pJitProfTable
341 * and then restoring its original value. However, this action
342 * is not syncronized for speed so threads may continue to hold
343 * and update the profile table after profiling has been turned
344 * off by null'ng the global pointer. Be aware.
345 */
346 pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE);
347 if (!pJitProfTable) {
348 LOGE("jit prof table allocation failed\n");
349 dvmUnlockMutex(&gDvmJit.tableLock);
350 goto fail;
351 }
352 memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE);
353 for (i=0; i < gDvmJit.jitTableSize; i++) {
354 pJitTable[i].u.info.chain = gDvmJit.jitTableSize;
355 }
356 /* Is chain field wide enough for termination pattern? */
357 assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize);
358
359 gDvmJit.pJitEntryTable = pJitTable;
360 gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
361 gDvmJit.jitTableEntriesUsed = 0;
362 gDvmJit.compilerHighWater =
363 COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
364 gDvmJit.pProfTable = pJitProfTable;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800365 gDvmJit.pProfTableCopy = pJitProfTable;
Bill Buzbee964a7b02010-01-28 12:54:19 -0800366 dvmUnlockMutex(&gDvmJit.tableLock);
367
368 /* Signal running threads to refresh their cached pJitTable pointers */
369 dvmSuspendAllThreads(SUSPEND_FOR_REFRESH);
370 dvmResumeAllThreads(SUSPEND_FOR_REFRESH);
371 return true;
372
373fail:
374 return false;
375
376}
377
Ben Chengba4fc8b2009-06-01 13:00:29 -0700378static void *compilerThreadStart(void *arg)
379{
Bill Buzbee94d89f82010-01-29 13:44:19 -0800380 int ret;
381 struct timespec ts;
382
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700383 dvmChangeStatus(NULL, THREAD_VMWAIT);
384
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800385 /*
Bill Buzbeeeb695c62010-02-04 16:09:55 -0800386 * If we're not running stand-alone, wait a little before
387 * recieving translation requests on the assumption that process start
388 * up code isn't worth compiling. We'll resume when the framework
389 * signals us that the first screen draw has happened, or the timer
390 * below expires (to catch daemons).
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800391 */
Bill Buzbeeeb695c62010-02-04 16:09:55 -0800392 if (gDvmJit.runningInAndroidFramework) {
393 dvmLockMutex(&gDvmJit.compilerLock);
394 // TUNING: experiment with the delay & perhaps make it target-specific
395 dvmRelativeCondWait(&gDvmJit.compilerQueueActivity,
396 &gDvmJit.compilerLock, 3000, 0);
Bill Buzbee94d89f82010-01-29 13:44:19 -0800397 dvmUnlockMutex(&gDvmJit.compilerLock);
Bill Buzbeeeb695c62010-02-04 16:09:55 -0800398 if (gDvmJit.haltCompilerThread) {
399 return NULL;
400 }
Bill Buzbee94d89f82010-01-29 13:44:19 -0800401 }
402
Bill Buzbee964a7b02010-01-28 12:54:19 -0800403 compilerThreadStartup();
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800404
Ben Chengba4fc8b2009-06-01 13:00:29 -0700405 dvmLockMutex(&gDvmJit.compilerLock);
406 /*
407 * Since the compiler thread will not touch any objects on the heap once
408 * being created, we just fake its state as VMWAIT so that it can be a
409 * bit late when there is suspend request pending.
410 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700411 while (!gDvmJit.haltCompilerThread) {
412 if (workQueueLength() == 0) {
413 int cc;
414 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
415 assert(cc == 0);
416 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
417 &gDvmJit.compilerLock);
418 continue;
419 } else {
420 do {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700421 CompilerWorkOrder work = workDequeue();
422 dvmUnlockMutex(&gDvmJit.compilerLock);
Bill Buzbee964a7b02010-01-28 12:54:19 -0800423 /*
424 * Check whether there is a suspend request on me. This
425 * is necessary to allow a clean shutdown.
426 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700427 dvmCheckSuspendPending(NULL);
Bill Buzbee27176222009-06-09 09:20:16 -0700428 /* Is JitTable filling up? */
429 if (gDvmJit.jitTableEntriesUsed >
430 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
Ben Cheng6999d842010-01-26 16:46:15 -0800431 bool resizeFail =
432 dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
433 /*
434 * If the jit table is full, consider it's time to reset
435 * the code cache too.
436 */
437 gDvmJit.codeCacheFull |= resizeFail;
Bill Buzbee27176222009-06-09 09:20:16 -0700438 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700439 if (gDvmJit.haltCompilerThread) {
440 LOGD("Compiler shutdown in progress - discarding request");
Ben Cheng6999d842010-01-26 16:46:15 -0800441 } else if (!gDvmJit.codeCacheFull) {
Bill Buzbeed7269912009-11-10 14:31:32 -0800442 /* If compilation failed, use interpret-template */
443 if (!dvmCompilerDoWork(&work)) {
444 work.result.codeAddress = gDvmJit.interpretTemplate;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700445 }
Ben Cheng60c24f42010-01-04 12:29:56 -0800446 if (!work.result.discardResult) {
447 dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
448 work.result.instructionSet);
449 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700450 }
451 free(work.info);
452 dvmLockMutex(&gDvmJit.compilerLock);
453 } while (workQueueLength() != 0);
454 }
455 }
456 pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
457 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Chengef00a852009-06-22 22:53:35 -0700458
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700459 /*
460 * As part of detaching the thread we need to call into Java code to update
461 * the ThreadGroup, and we should not be in VMWAIT state while executing
462 * interpreted code.
463 */
464 dvmChangeStatus(NULL, THREAD_RUNNING);
465
Andy McFadden43eb5012010-02-01 16:56:53 -0800466 if (gDvm.verboseShutdown)
467 LOGD("Compiler thread shutting down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700468 return NULL;
469}
470
Ben Chengba4fc8b2009-06-01 13:00:29 -0700471bool dvmCompilerStartup(void)
472{
Bill Buzbee94d89f82010-01-29 13:44:19 -0800473
474 dvmInitMutex(&gDvmJit.compilerLock);
Ben Cheng6999d842010-01-26 16:46:15 -0800475 dvmInitMutex(&gDvmJit.compilerICPatchLock);
Bill Buzbee94d89f82010-01-29 13:44:19 -0800476 dvmLockMutex(&gDvmJit.compilerLock);
477 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
478 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
479
480 /* Reset the work queue */
481 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
482 gDvmJit.compilerQueueLength = 0;
483 dvmUnlockMutex(&gDvmJit.compilerLock);
484
Ben Chengba4fc8b2009-06-01 13:00:29 -0700485 /*
Bill Buzbee94d89f82010-01-29 13:44:19 -0800486 * Defer rest of initialization until we're sure JIT'ng makes sense. Launch
Bill Buzbee964a7b02010-01-28 12:54:19 -0800487 * the compiler thread, which will do the real initialization if and
488 * when it is signalled to do so.
Ben Chengba4fc8b2009-06-01 13:00:29 -0700489 */
Bill Buzbee964a7b02010-01-28 12:54:19 -0800490 return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
491 compilerThreadStart, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700492}
493
494void dvmCompilerShutdown(void)
495{
496 void *threadReturn;
497
498 if (gDvmJit.compilerHandle) {
499
500 gDvmJit.haltCompilerThread = true;
501
502 dvmLockMutex(&gDvmJit.compilerLock);
503 pthread_cond_signal(&gDvmJit.compilerQueueActivity);
504 dvmUnlockMutex(&gDvmJit.compilerLock);
505
Ben Chengef00a852009-06-22 22:53:35 -0700506 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
507 LOGW("Compiler thread join failed\n");
Andy McFadden43eb5012010-02-01 16:56:53 -0800508 else if (gDvm.verboseShutdown)
Ben Chengef00a852009-06-22 22:53:35 -0700509 LOGD("Compiler thread has shut down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700510 }
Bill Buzbee06bb8392010-01-31 18:53:15 -0800511
Bill Buzbee96cfe6c2010-02-08 17:08:15 -0800512 if (gDvm.verboseShutdown)
513 dvmCompilerDumpStats();
514
515 dvmDestroyMutex(&gDvmJit.tableLock);
516 dvmDestroyMutex(&gDvmJit.compilerLock);
517 dvmDestroyMutex(&gDvmJit.compilerICPatchLock);
518
519 if (gDvmJit.pJitEntryTable) {
520 free(gDvmJit.pJitEntryTable);
521 gDvmJit.pJitEntryTable = NULL;
522 }
523
524 if (gDvmJit.pProfTable) {
525 free(gDvmJit.pProfTable);
526 gDvmJit.pProfTable = NULL;
527 }
528
529}
Bill Buzbee06bb8392010-01-31 18:53:15 -0800530
531void dvmCompilerStateRefresh()
532{
533 bool jitActive;
534 bool jitActivate;
Bill Buzbee3e392682010-02-03 18:13:57 -0800535 bool needUnchain = false;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800536
537 dvmLockMutex(&gDvmJit.tableLock);
538 jitActive = gDvmJit.pProfTable != NULL;
539 jitActivate = !(gDvm.debuggerActive || (gDvm.activeProfilers > 0));
540
541 if (jitActivate && !jitActive) {
542 gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800543 } else if (!jitActivate && jitActive) {
544 gDvmJit.pProfTable = NULL;
Bill Buzbee3e392682010-02-03 18:13:57 -0800545 needUnchain = true;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800546 }
Bill Buzbee3e392682010-02-03 18:13:57 -0800547 dvmUnlockMutex(&gDvmJit.tableLock);
548 if (needUnchain)
549 dvmJitUnchainAll();
Bill Buzbee06bb8392010-01-31 18:53:15 -0800550}