blob: 032b8594e947981e472c64505a99f3d5291ee331 [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.
Ben Cheng1357e942010-02-10 17:21:39 -080056 *
57 * NOTE: Make sure that the caller frees the info pointer if the return value
58 * is false.
Bill Buzbee964a7b02010-01-28 12:54:19 -080059 */
Ben Chengba4fc8b2009-06-01 13:00:29 -070060bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
61{
62 int cc;
63 int i;
64 int numWork;
Ben Cheng60c24f42010-01-04 12:29:56 -080065 bool result = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -070066
Bill Buzbee964a7b02010-01-28 12:54:19 -080067 if (dvmTryLockMutex(&gDvmJit.compilerLock)) {
Ben Cheng3e5cd172010-02-08 20:57:59 -080068 return false; // Couldn't acquire the lock
Bill Buzbee964a7b02010-01-28 12:54:19 -080069 }
Ben Chengba4fc8b2009-06-01 13:00:29 -070070
Ben Cheng7a0bcd02010-01-22 16:45:45 -080071 /*
Ben Cheng6999d842010-01-26 16:46:15 -080072 * Return if queue or code cache is full.
Ben Cheng7a0bcd02010-01-22 16:45:45 -080073 */
Ben Cheng6999d842010-01-26 16:46:15 -080074 if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE ||
75 gDvmJit.codeCacheFull == true) {
Ben Cheng60c24f42010-01-04 12:29:56 -080076 result = false;
Bill Buzbee964a7b02010-01-28 12:54:19 -080077 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070078 }
79
80 for (numWork = gDvmJit.compilerQueueLength,
81 i = gDvmJit.compilerWorkDequeueIndex;
82 numWork > 0;
83 numWork--) {
84 /* Already enqueued */
85 if (gDvmJit.compilerWorkQueue[i++].pc == pc)
Bill Buzbee964a7b02010-01-28 12:54:19 -080086 goto unlockAndExit;
Ben Chengba4fc8b2009-06-01 13:00:29 -070087 /* Wrap around */
88 if (i == COMPILER_WORK_QUEUE_SIZE)
89 i = 0;
90 }
91
Ben Chengccd6c012009-10-15 14:52:45 -070092 CompilerWorkOrder *newOrder =
93 &gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex];
94 newOrder->pc = pc;
95 newOrder->kind = kind;
96 newOrder->info = info;
97 newOrder->result.codeAddress = NULL;
98 newOrder->result.discardResult =
Ben Cheng6999d842010-01-26 16:46:15 -080099 (kind == kWorkOrderTraceDebug) ? true : false;
Ben Cheng33672452010-01-12 14:59:30 -0800100 newOrder->result.requestingThread = dvmThreadSelf();
101
Ben Chengba4fc8b2009-06-01 13:00:29 -0700102 gDvmJit.compilerWorkEnqueueIndex++;
103 if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
104 gDvmJit.compilerWorkEnqueueIndex = 0;
105 gDvmJit.compilerQueueLength++;
106 cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
107 assert(cc == 0);
108
Bill Buzbee964a7b02010-01-28 12:54:19 -0800109unlockAndExit:
Ben Chengba4fc8b2009-06-01 13:00:29 -0700110 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng60c24f42010-01-04 12:29:56 -0800111 return result;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700112}
113
114/* Block until queue length is 0 */
115void dvmCompilerDrainQueue(void)
116{
Bill Buzbeed7269912009-11-10 14:31:32 -0800117 int oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700118 dvmLockMutex(&gDvmJit.compilerLock);
119 while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread) {
120 pthread_cond_wait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock);
121 }
122 dvmUnlockMutex(&gDvmJit.compilerLock);
Bill Buzbeed7269912009-11-10 14:31:32 -0800123 dvmChangeStatus(NULL, oldStatus);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700124}
125
Ben Cheng60c24f42010-01-04 12:29:56 -0800126bool dvmCompilerSetupCodeCache(void)
127{
128 extern void dvmCompilerTemplateStart(void);
129 extern void dmvCompilerTemplateEnd(void);
130
131 /* Allocate the code cache */
Ben Cheng7b133ef2010-02-04 16:15:59 -0800132 gDvmJit.codeCache = mmap(0, gDvmJit.codeCacheSize,
Ben Cheng60c24f42010-01-04 12:29:56 -0800133 PROT_READ | PROT_WRITE | PROT_EXEC,
134 MAP_PRIVATE | MAP_ANON, -1, 0);
135 if (gDvmJit.codeCache == MAP_FAILED) {
136 LOGE("Failed to create the code cache: %s\n", strerror(errno));
137 return false;
138 }
139
Ben Cheng6999d842010-01-26 16:46:15 -0800140 // STOPSHIP - for debugging only
141 LOGD("Code cache starts at %p", gDvmJit.codeCache);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800142
Ben Cheng60c24f42010-01-04 12:29:56 -0800143 /* Copy the template code into the beginning of the code cache */
144 int templateSize = (intptr_t) dmvCompilerTemplateEnd -
145 (intptr_t) dvmCompilerTemplateStart;
146 memcpy((void *) gDvmJit.codeCache,
147 (void *) dvmCompilerTemplateStart,
148 templateSize);
149
150 gDvmJit.templateSize = templateSize;
151 gDvmJit.codeCacheByteUsed = templateSize;
152
153 /* Only flush the part in the code cache that is being used now */
154 cacheflush((intptr_t) gDvmJit.codeCache,
155 (intptr_t) gDvmJit.codeCache + templateSize, 0);
156 return true;
157}
158
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800159static void crawlDalvikStack(Thread *thread, bool print)
160{
161 void *fp = thread->curFrame;
162 StackSaveArea* saveArea = NULL;
163 int stackLevel = 0;
164
165 if (print) {
166 LOGD("Crawling tid %d (%s / %p %s)", thread->systemTid,
167 dvmGetThreadStatusStr(thread->status),
168 thread->inJitCodeCache,
169 thread->inJitCodeCache ? "jit" : "interp");
170 }
171 /* Crawl the Dalvik stack frames to clear the returnAddr field */
172 while (fp != NULL) {
173 saveArea = SAVEAREA_FROM_FP(fp);
174
175 if (print) {
176 if (dvmIsBreakFrame(fp)) {
177 LOGD(" #%d: break frame (%p)",
178 stackLevel, saveArea->returnAddr);
179 }
180 else {
181 LOGD(" #%d: %s.%s%s (%p)",
182 stackLevel,
183 saveArea->method->clazz->descriptor,
184 saveArea->method->name,
185 dvmIsNativeMethod(saveArea->method) ?
186 " (native)" : "",
187 saveArea->returnAddr);
188 }
189 }
190 stackLevel++;
191 saveArea->returnAddr = NULL;
192 assert(fp != saveArea->prevFrame);
193 fp = saveArea->prevFrame;
194 }
195 /* Make sure the stack is fully unwound to the bottom */
196 assert(saveArea == NULL ||
197 (u1 *) (saveArea+1) == thread->interpStackStart);
198}
199
Ben Cheng60c24f42010-01-04 12:29:56 -0800200static void resetCodeCache(void)
201{
Ben Cheng60c24f42010-01-04 12:29:56 -0800202 Thread* thread;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800203 u8 startTime = dvmGetRelativeTimeUsec();
204 int inJit = 0;
Ben Cheng6999d842010-01-26 16:46:15 -0800205 int byteUsed = gDvmJit.codeCacheByteUsed;
Ben Cheng60c24f42010-01-04 12:29:56 -0800206
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800207 /* If any thread is found stuck in the JIT state, don't reset the cache */
208 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
Ben Cheng6999d842010-01-26 16:46:15 -0800209 /*
210 * Crawl the stack to wipe out the returnAddr field so that
211 * 1) the soon-to-be-deleted code in the JIT cache won't be used
212 * 2) or the thread stuck in the JIT land will soon return
213 * to the interpreter land
214 */
215 crawlDalvikStack(thread, false);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800216 if (thread->inJitCodeCache) {
217 inJit++;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800218 }
219 }
220
221 if (inJit) {
Ben Cheng6999d842010-01-26 16:46:15 -0800222 LOGD("JIT code cache reset delayed (%d bytes %d/%d)",
223 gDvmJit.codeCacheByteUsed, gDvmJit.numCodeCacheReset,
224 ++gDvmJit.numCodeCacheResetDelayed);
225 return;
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800226 }
227
Ben Cheng6999d842010-01-26 16:46:15 -0800228 /* Lock the mutex to clean up the work queue */
229 dvmLockMutex(&gDvmJit.compilerLock);
230
231 /* Drain the work queue to free the work orders */
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800232 while (workQueueLength()) {
233 CompilerWorkOrder work = workDequeue();
234 free(work.info);
235 }
236
Ben Cheng60c24f42010-01-04 12:29:56 -0800237 /* Reset the JitEntry table contents to the initial unpopulated state */
238 dvmJitResetTable();
239
Ben Cheng60c24f42010-01-04 12:29:56 -0800240 /*
Ben Cheng60c24f42010-01-04 12:29:56 -0800241 * Wipe out the code cache content to force immediate crashes if
242 * stale JIT'ed code is invoked.
243 */
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800244 memset((char *) gDvmJit.codeCache + gDvmJit.templateSize,
245 0,
246 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
Ben Cheng60c24f42010-01-04 12:29:56 -0800247 cacheflush((intptr_t) gDvmJit.codeCache,
248 (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed, 0);
Ben Cheng60c24f42010-01-04 12:29:56 -0800249
250 /* Reset the current mark of used bytes to the end of template code */
251 gDvmJit.codeCacheByteUsed = gDvmJit.templateSize;
252 gDvmJit.numCompilations = 0;
253
254 /* Reset the work queue */
255 memset(gDvmJit.compilerWorkQueue, 0,
256 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
257 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
258 gDvmJit.compilerQueueLength = 0;
259
Ben Cheng6999d842010-01-26 16:46:15 -0800260 /* Reset the IC patch work queue */
261 dvmLockMutex(&gDvmJit.compilerICPatchLock);
262 gDvmJit.compilerICPatchIndex = 0;
263 dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
264
Ben Cheng60c24f42010-01-04 12:29:56 -0800265 /* All clear now */
266 gDvmJit.codeCacheFull = false;
267
Ben Cheng6999d842010-01-26 16:46:15 -0800268 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Cheng7a0bcd02010-01-22 16:45:45 -0800269
Ben Cheng6999d842010-01-26 16:46:15 -0800270 LOGD("JIT code cache reset in %lld ms (%d bytes %d/%d)",
271 (dvmGetRelativeTimeUsec() - startTime) / 1000,
272 byteUsed, ++gDvmJit.numCodeCacheReset,
273 gDvmJit.numCodeCacheResetDelayed);
274}
275
276/*
277 * Perform actions that are only safe when all threads are suspended. Currently
278 * we do:
279 * 1) Check if the code cache is full. If so reset it and restart populating it
280 * from scratch.
281 * 2) Patch predicted chaining cells by consuming recorded work orders.
282 */
283void dvmCompilerPerformSafePointChecks(void)
284{
285 if (gDvmJit.codeCacheFull) {
286 resetCodeCache();
287 }
288 dvmCompilerPatchInlineCache();
Ben Cheng60c24f42010-01-04 12:29:56 -0800289}
290
Bill Buzbee964a7b02010-01-28 12:54:19 -0800291bool compilerThreadStartup(void)
292{
293 JitEntry *pJitTable = NULL;
294 unsigned char *pJitProfTable = NULL;
295 unsigned int i;
296
297 if (!dvmCompilerArchInit())
298 goto fail;
299
300 /*
301 * Setup the code cache if we have not inherited a valid code cache
302 * from the zygote.
303 */
304 if (gDvmJit.codeCache == NULL) {
305 if (!dvmCompilerSetupCodeCache())
306 goto fail;
307 }
308
309 /* Allocate the initial arena block */
310 if (dvmCompilerHeapInit() == false) {
311 goto fail;
312 }
313
Bill Buzbee964a7b02010-01-28 12:54:19 -0800314 dvmLockMutex(&gDvmJit.compilerLock);
315
Ben Cheng1357e942010-02-10 17:21:39 -0800316#if defined(WITH_JIT_TUNING)
Bill Buzbee964a7b02010-01-28 12:54:19 -0800317 /* Track method-level compilation statistics */
318 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
Ben Cheng1357e942010-02-10 17:21:39 -0800319#endif
Bill Buzbee964a7b02010-01-28 12:54:19 -0800320
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}