blob: dfcd88f34af262293cf65f47aaa68e933a98c19e [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 /*
69 * Return if queue is full.
70 * If the code cache is full, we will allow the work order to be added and
71 * we use that to trigger code cache reset.
72 */
73 if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE) {
Ben Cheng60c24f42010-01-04 12:29:56 -080074 result = false;
Bill Buzbee964a7b02010-01-28 12:54:19 -080075 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070076 }
77
78 for (numWork = gDvmJit.compilerQueueLength,
79 i = gDvmJit.compilerWorkDequeueIndex;
80 numWork > 0;
81 numWork--) {
82 /* Already enqueued */
83 if (gDvmJit.compilerWorkQueue[i++].pc == pc)
Bill Buzbee964a7b02010-01-28 12:54:19 -080084 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070085 /* Wrap around */
86 if (i == COMPILER_WORK_QUEUE_SIZE)
87 i = 0;
88 }
89
Ben Chengccd6c012009-10-15 14:52:45 -070090 CompilerWorkOrder *newOrder =
91 &gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex];
92 newOrder->pc = pc;
93 newOrder->kind = kind;
94 newOrder->info = info;
95 newOrder->result.codeAddress = NULL;
96 newOrder->result.discardResult =
Ben Cheng60c24f42010-01-04 12:29:56 -080097 (kind == kWorkOrderTraceDebug || kind == kWorkOrderICPatch) ?
98 true : false;
Ben Cheng33672452010-01-12 14:59:30 -080099 newOrder->result.requestingThread = dvmThreadSelf();
100
Ben Chengba4fc8b2009-06-01 13:00:29 -0700101 gDvmJit.compilerWorkEnqueueIndex++;
102 if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
103 gDvmJit.compilerWorkEnqueueIndex = 0;
104 gDvmJit.compilerQueueLength++;
105 cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
106 assert(cc == 0);
107
Bill Buzbee964a7b02010-01-28 12:54:19 -0800108unlockAndExit:
Ben Chengba4fc8b2009-06-01 13:00:29 -0700109 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng60c24f42010-01-04 12:29:56 -0800110 return result;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700111}
112
113/* Block until queue length is 0 */
114void dvmCompilerDrainQueue(void)
115{
Bill Buzbeed7269912009-11-10 14:31:32 -0800116 int oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700117 dvmLockMutex(&gDvmJit.compilerLock);
118 while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread) {
119 pthread_cond_wait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock);
120 }
121 dvmUnlockMutex(&gDvmJit.compilerLock);
Bill Buzbeed7269912009-11-10 14:31:32 -0800122 dvmChangeStatus(NULL, oldStatus);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700123}
124
Ben Cheng60c24f42010-01-04 12:29:56 -0800125bool dvmCompilerSetupCodeCache(void)
126{
127 extern void dvmCompilerTemplateStart(void);
128 extern void dmvCompilerTemplateEnd(void);
129
130 /* Allocate the code cache */
131 gDvmJit.codeCache = mmap(0, CODE_CACHE_SIZE,
132 PROT_READ | PROT_WRITE | PROT_EXEC,
133 MAP_PRIVATE | MAP_ANON, -1, 0);
134 if (gDvmJit.codeCache == MAP_FAILED) {
135 LOGE("Failed to create the code cache: %s\n", strerror(errno));
136 return false;
137 }
138
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800139 // For debugging only
140 // LOGD("Code cache starts at %p", gDvmJit.codeCache);
141
Ben Cheng60c24f42010-01-04 12:29:56 -0800142 /* Copy the template code into the beginning of the code cache */
143 int templateSize = (intptr_t) dmvCompilerTemplateEnd -
144 (intptr_t) dvmCompilerTemplateStart;
145 memcpy((void *) gDvmJit.codeCache,
146 (void *) dvmCompilerTemplateStart,
147 templateSize);
148
149 gDvmJit.templateSize = templateSize;
150 gDvmJit.codeCacheByteUsed = templateSize;
151
152 /* Only flush the part in the code cache that is being used now */
153 cacheflush((intptr_t) gDvmJit.codeCache,
154 (intptr_t) gDvmJit.codeCache + templateSize, 0);
155 return true;
156}
157
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800158static void crawlDalvikStack(Thread *thread, bool print)
159{
160 void *fp = thread->curFrame;
161 StackSaveArea* saveArea = NULL;
162 int stackLevel = 0;
163
164 if (print) {
165 LOGD("Crawling tid %d (%s / %p %s)", thread->systemTid,
166 dvmGetThreadStatusStr(thread->status),
167 thread->inJitCodeCache,
168 thread->inJitCodeCache ? "jit" : "interp");
169 }
170 /* Crawl the Dalvik stack frames to clear the returnAddr field */
171 while (fp != NULL) {
172 saveArea = SAVEAREA_FROM_FP(fp);
173
174 if (print) {
175 if (dvmIsBreakFrame(fp)) {
176 LOGD(" #%d: break frame (%p)",
177 stackLevel, saveArea->returnAddr);
178 }
179 else {
180 LOGD(" #%d: %s.%s%s (%p)",
181 stackLevel,
182 saveArea->method->clazz->descriptor,
183 saveArea->method->name,
184 dvmIsNativeMethod(saveArea->method) ?
185 " (native)" : "",
186 saveArea->returnAddr);
187 }
188 }
189 stackLevel++;
190 saveArea->returnAddr = NULL;
191 assert(fp != saveArea->prevFrame);
192 fp = saveArea->prevFrame;
193 }
194 /* Make sure the stack is fully unwound to the bottom */
195 assert(saveArea == NULL ||
196 (u1 *) (saveArea+1) == thread->interpStackStart);
197}
198
Ben Cheng60c24f42010-01-04 12:29:56 -0800199static void resetCodeCache(void)
200{
Ben Cheng60c24f42010-01-04 12:29:56 -0800201 Thread* thread;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800202 u8 startTime = dvmGetRelativeTimeUsec();
203 int inJit = 0;
Ben Cheng60c24f42010-01-04 12:29:56 -0800204
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800205 LOGD("Reset the JIT code cache (%d bytes used / %d time(s))",
206 gDvmJit.codeCacheByteUsed, ++gDvmJit.numCodeCacheReset);
Ben Cheng60c24f42010-01-04 12:29:56 -0800207
208 /* Stop the world */
209 dvmSuspendAllThreads(SUSPEND_FOR_CC_RESET);
210
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800211 /* If any thread is found stuck in the JIT state, don't reset the cache */
212 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
213 if (thread->inJitCodeCache) {
214 inJit++;
215 /*
216 * STOPSHIP
217 * Change the verbose mode to false after the new code receives
218 * more QA love.
219 */
220 crawlDalvikStack(thread, true);
221 }
222 }
223
224 if (inJit) {
225 /* Wait a while for the busy threads to rest and try again */
226 gDvmJit.delayCodeCacheReset = 256;
227 goto done;
228 }
229
230 /* Drain the work queue to free the work order */
231 while (workQueueLength()) {
232 CompilerWorkOrder work = workDequeue();
233 free(work.info);
234 }
235
Ben Cheng60c24f42010-01-04 12:29:56 -0800236 /* Wipe out the returnAddr field that soon will point to stale code */
237 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800238 crawlDalvikStack(thread, false);
Ben Cheng60c24f42010-01-04 12:29:56 -0800239 }
240
241 /* Reset the JitEntry table contents to the initial unpopulated state */
242 dvmJitResetTable();
243
Ben Cheng60c24f42010-01-04 12:29:56 -0800244 /*
Ben Cheng60c24f42010-01-04 12:29:56 -0800245 * Wipe out the code cache content to force immediate crashes if
246 * stale JIT'ed code is invoked.
247 */
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800248 memset((char *) gDvmJit.codeCache + gDvmJit.templateSize,
249 0,
250 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
Ben Cheng60c24f42010-01-04 12:29:56 -0800251 cacheflush((intptr_t) gDvmJit.codeCache,
252 (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed, 0);
Ben Cheng60c24f42010-01-04 12:29:56 -0800253
254 /* Reset the current mark of used bytes to the end of template code */
255 gDvmJit.codeCacheByteUsed = gDvmJit.templateSize;
256 gDvmJit.numCompilations = 0;
257
258 /* Reset the work queue */
259 memset(gDvmJit.compilerWorkQueue, 0,
260 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
261 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
262 gDvmJit.compilerQueueLength = 0;
263
264 /* All clear now */
265 gDvmJit.codeCacheFull = false;
266
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800267 LOGD("Code cache reset takes %lld usec",
268 dvmGetRelativeTimeUsec() - startTime);
269
270done:
Ben Cheng60c24f42010-01-04 12:29:56 -0800271 /* Resume all threads */
272 dvmResumeAllThreads(SUSPEND_FOR_CC_RESET);
273}
274
Bill Buzbee964a7b02010-01-28 12:54:19 -0800275bool compilerThreadStartup(void)
276{
277 JitEntry *pJitTable = NULL;
278 unsigned char *pJitProfTable = NULL;
279 unsigned int i;
280
281 if (!dvmCompilerArchInit())
282 goto fail;
283
284 /*
285 * Setup the code cache if we have not inherited a valid code cache
286 * from the zygote.
287 */
288 if (gDvmJit.codeCache == NULL) {
289 if (!dvmCompilerSetupCodeCache())
290 goto fail;
291 }
292
293 /* Allocate the initial arena block */
294 if (dvmCompilerHeapInit() == false) {
295 goto fail;
296 }
297
Bill Buzbee964a7b02010-01-28 12:54:19 -0800298 dvmLockMutex(&gDvmJit.compilerLock);
299
Bill Buzbee964a7b02010-01-28 12:54:19 -0800300 /* Track method-level compilation statistics */
301 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
302
303 dvmUnlockMutex(&gDvmJit.compilerLock);
304
305 /* Set up the JitTable */
306
307 /* Power of 2? */
308 assert(gDvmJit.jitTableSize &&
309 !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1)));
310
311 dvmInitMutex(&gDvmJit.tableLock);
312 dvmLockMutex(&gDvmJit.tableLock);
313 pJitTable = (JitEntry*)
314 calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
315 if (!pJitTable) {
316 LOGE("jit table allocation failed\n");
317 dvmUnlockMutex(&gDvmJit.tableLock);
318 goto fail;
319 }
320 /*
321 * NOTE: the profile table must only be allocated once, globally.
322 * Profiling is turned on and off by nulling out gDvm.pJitProfTable
323 * and then restoring its original value. However, this action
324 * is not syncronized for speed so threads may continue to hold
325 * and update the profile table after profiling has been turned
326 * off by null'ng the global pointer. Be aware.
327 */
328 pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE);
329 if (!pJitProfTable) {
330 LOGE("jit prof table allocation failed\n");
331 dvmUnlockMutex(&gDvmJit.tableLock);
332 goto fail;
333 }
334 memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE);
335 for (i=0; i < gDvmJit.jitTableSize; i++) {
336 pJitTable[i].u.info.chain = gDvmJit.jitTableSize;
337 }
338 /* Is chain field wide enough for termination pattern? */
339 assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize);
340
341 gDvmJit.pJitEntryTable = pJitTable;
342 gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
343 gDvmJit.jitTableEntriesUsed = 0;
344 gDvmJit.compilerHighWater =
345 COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
346 gDvmJit.pProfTable = pJitProfTable;
Bill Buzbee06bb8392010-01-31 18:53:15 -0800347 gDvmJit.pProfTableCopy = pJitProfTable;
Bill Buzbee964a7b02010-01-28 12:54:19 -0800348 dvmUnlockMutex(&gDvmJit.tableLock);
349
350 /* Signal running threads to refresh their cached pJitTable pointers */
351 dvmSuspendAllThreads(SUSPEND_FOR_REFRESH);
352 dvmResumeAllThreads(SUSPEND_FOR_REFRESH);
353 return true;
354
355fail:
356 return false;
357
358}
359
Ben Chengba4fc8b2009-06-01 13:00:29 -0700360static void *compilerThreadStart(void *arg)
361{
Bill Buzbee94d89f82010-01-29 13:44:19 -0800362 int ret;
363 struct timespec ts;
364
Ben Cheng5ccdf0b2009-10-08 16:09:49 -0700365 dvmChangeStatus(NULL, THREAD_VMWAIT);
366
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800367 /*
368 * Wait a little before recieving translation requests on the assumption
Bill Buzbee964a7b02010-01-28 12:54:19 -0800369 * that process start-up code isn't worth compiling.
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800370 */
Bill Buzbee94d89f82010-01-29 13:44:19 -0800371
372 dvmLockMutex(&gDvmJit.compilerLock);
373 /*
374 * TUNING: once framework is calling VMRuntime.startJitCompilation,
375 * experiment with the delay time (and perhaps have target-dependent
376 * values?
377 */
378 dvmAbsoluteTime(1000, 0, &ts);
379#if defined(HAVE_TIMEDWAIT_MONOTONIC)
380 ret = pthread_cond_timedwait_monotonic(&gDvmJit.compilerQueueActivity,
381 &gDvmJit.compilerLock, &ts);
382#else
383 ret = pthread_cond_timedwait(&gDvmJit.compilerQueueActivity,
384 &gDvmJit.compilerLock, &ts);
385#endif
386 assert(ret == 0 || ret == ETIMEDOUT);
387
388 if (gDvmJit.haltCompilerThread) {
389 dvmUnlockMutex(&gDvmJit.compilerLock);
390 return NULL;
391 }
392
393 dvmUnlockMutex(&gDvmJit.compilerLock);
394
Bill Buzbee964a7b02010-01-28 12:54:19 -0800395 compilerThreadStartup();
Bill Buzbeeb1d80442009-12-17 14:55:21 -0800396
Ben Chengba4fc8b2009-06-01 13:00:29 -0700397 dvmLockMutex(&gDvmJit.compilerLock);
398 /*
399 * Since the compiler thread will not touch any objects on the heap once
400 * being created, we just fake its state as VMWAIT so that it can be a
401 * bit late when there is suspend request pending.
402 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700403 while (!gDvmJit.haltCompilerThread) {
404 if (workQueueLength() == 0) {
405 int cc;
406 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
407 assert(cc == 0);
408 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
409 &gDvmJit.compilerLock);
410 continue;
411 } else {
412 do {
Bill Buzbee964a7b02010-01-28 12:54:19 -0800413 bool resizeFail = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700414 CompilerWorkOrder work = workDequeue();
415 dvmUnlockMutex(&gDvmJit.compilerLock);
Bill Buzbee964a7b02010-01-28 12:54:19 -0800416 /*
417 * Check whether there is a suspend request on me. This
418 * is necessary to allow a clean shutdown.
419 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700420 dvmCheckSuspendPending(NULL);
Bill Buzbee27176222009-06-09 09:20:16 -0700421 /* Is JitTable filling up? */
422 if (gDvmJit.jitTableEntriesUsed >
423 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
Bill Buzbee964a7b02010-01-28 12:54:19 -0800424 resizeFail = dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
Bill Buzbee27176222009-06-09 09:20:16 -0700425 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700426 if (gDvmJit.haltCompilerThread) {
427 LOGD("Compiler shutdown in progress - discarding request");
Bill Buzbee964a7b02010-01-28 12:54:19 -0800428 } else if (!resizeFail) {
Bill Buzbeed7269912009-11-10 14:31:32 -0800429 /* If compilation failed, use interpret-template */
430 if (!dvmCompilerDoWork(&work)) {
431 work.result.codeAddress = gDvmJit.interpretTemplate;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700432 }
Ben Cheng60c24f42010-01-04 12:29:56 -0800433 if (!work.result.discardResult) {
434 dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
435 work.result.instructionSet);
436 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700437 }
438 free(work.info);
439 dvmLockMutex(&gDvmJit.compilerLock);
Ben Cheng60c24f42010-01-04 12:29:56 -0800440
Ben Cheng49ca7862010-01-20 12:03:51 -0800441 /*
442 * FIXME - temporarily disable code cache reset until
443 * stale code stops leaking.
444 */
445#if 0
Bill Buzbee964a7b02010-01-28 12:54:19 -0800446 if (gDvmJit.codeCacheFull == true || resizeFail) {
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800447 if (gDvmJit.delayCodeCacheReset == 0) {
448 resetCodeCache();
449 assert(workQueueLength() == 0 ||
450 gDvmJit.delayCodeCacheReset != 0);
451 } else {
452 LOGD("Delay the next %d tries to reset code cache",
453 gDvmJit.delayCodeCacheReset);
454 gDvmJit.delayCodeCacheReset--;
455 }
Ben Cheng60c24f42010-01-04 12:29:56 -0800456 }
Ben Cheng49ca7862010-01-20 12:03:51 -0800457#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700458 } 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
Ben Chengef00a852009-06-22 22:53:35 -0700471 LOGD("Compiler thread shutting down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700472 return NULL;
473}
474
Ben Chengba4fc8b2009-06-01 13:00:29 -0700475bool dvmCompilerStartup(void)
476{
Bill Buzbee94d89f82010-01-29 13:44:19 -0800477
478 dvmInitMutex(&gDvmJit.compilerLock);
479 dvmLockMutex(&gDvmJit.compilerLock);
480 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
481 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
482
483 /* Reset the work queue */
484 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
485 gDvmJit.compilerQueueLength = 0;
486 dvmUnlockMutex(&gDvmJit.compilerLock);
487
Ben Chengba4fc8b2009-06-01 13:00:29 -0700488 /*
Bill Buzbee94d89f82010-01-29 13:44:19 -0800489 * Defer rest of initialization until we're sure JIT'ng makes sense. Launch
Bill Buzbee964a7b02010-01-28 12:54:19 -0800490 * the compiler thread, which will do the real initialization if and
491 * when it is signalled to do so.
Ben Chengba4fc8b2009-06-01 13:00:29 -0700492 */
Bill Buzbee964a7b02010-01-28 12:54:19 -0800493 return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
494 compilerThreadStart, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700495}
496
497void dvmCompilerShutdown(void)
498{
499 void *threadReturn;
500
501 if (gDvmJit.compilerHandle) {
502
503 gDvmJit.haltCompilerThread = true;
504
505 dvmLockMutex(&gDvmJit.compilerLock);
506 pthread_cond_signal(&gDvmJit.compilerQueueActivity);
507 dvmUnlockMutex(&gDvmJit.compilerLock);
508
Ben Chengef00a852009-06-22 22:53:35 -0700509 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
510 LOGW("Compiler thread join failed\n");
511 else
512 LOGD("Compiler thread has shut down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700513 }
514}
Bill Buzbee06bb8392010-01-31 18:53:15 -0800515
516
517void dvmCompilerStateRefresh()
518{
519 bool jitActive;
520 bool jitActivate;
521
522 dvmLockMutex(&gDvmJit.tableLock);
523 jitActive = gDvmJit.pProfTable != NULL;
524 jitActivate = !(gDvm.debuggerActive || (gDvm.activeProfilers > 0));
525
526 if (jitActivate && !jitActive) {
527 gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
528 dvmUnlockMutex(&gDvmJit.tableLock);
529 } else if (!jitActivate && jitActive) {
530 gDvmJit.pProfTable = NULL;
531 dvmUnlockMutex(&gDvmJit.tableLock);
532 dvmJitUnchainAll();
533 }
534}