1 /* 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 #include <cutils/ashmem.h> 20 21 #include "Dalvik.h" 22 #include "interp/Jit.h" 23 #include "CompilerInternals.h" 24 25 static inline bool workQueueLength(void) 26 { 27 return gDvmJit.compilerQueueLength; 28 } 29 30 static CompilerWorkOrder workDequeue(void) 31 { 32 assert(gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex].kind 33 != kWorkOrderInvalid); 34 CompilerWorkOrder work = 35 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex]; 36 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex++].kind = 37 kWorkOrderInvalid; 38 if (gDvmJit.compilerWorkDequeueIndex == COMPILER_WORK_QUEUE_SIZE) { 39 gDvmJit.compilerWorkDequeueIndex = 0; 40 } 41 gDvmJit.compilerQueueLength--; 42 if (gDvmJit.compilerQueueLength == 0) { 43 dvmSignalCond(&gDvmJit.compilerQueueEmpty); 44 } 45 46 /* Remember the high water mark of the queue length */ 47 if (gDvmJit.compilerQueueLength > gDvmJit.compilerMaxQueued) 48 gDvmJit.compilerMaxQueued = gDvmJit.compilerQueueLength; 49 50 return work; 51 } 52 53 /* 54 * Attempt to enqueue a work order, returning true if successful. 55 * This routine will not block, but simply return if it couldn't 56 * aquire the lock or if the queue is full. 57 * 58 * NOTE: Make sure that the caller frees the info pointer if the return value 59 * is false. 60 */ 61 bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info) 62 { 63 int cc; 64 int i; 65 int numWork; 66 bool result = true; 67 68 if (dvmTryLockMutex(&gDvmJit.compilerLock)) { 69 return false; // Couldn't acquire the lock 70 } 71 72 /* 73 * Return if queue or code cache is full. 74 */ 75 if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE || 76 gDvmJit.codeCacheFull == true) { 77 result = false; 78 goto unlockAndExit; 79 } 80 81 for (numWork = gDvmJit.compilerQueueLength, 82 i = gDvmJit.compilerWorkDequeueIndex; 83 numWork > 0; 84 numWork--) { 85 /* Already enqueued */ 86 if (gDvmJit.compilerWorkQueue[i++].pc == pc) 87 goto unlockAndExit; 88 /* Wrap around */ 89 if (i == COMPILER_WORK_QUEUE_SIZE) 90 i = 0; 91 } 92 93 CompilerWorkOrder *newOrder = 94 &gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex]; 95 newOrder->pc = pc; 96 newOrder->kind = kind; 97 newOrder->info = info; 98 newOrder->result.methodCompilationAborted = NULL; 99 newOrder->result.codeAddress = NULL; 100 newOrder->result.discardResult = 101 (kind == kWorkOrderTraceDebug) ? true : false; 102 newOrder->result.requestingThread = dvmThreadSelf(); 103 104 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 111 unlockAndExit: 112 dvmUnlockMutex(&gDvmJit.compilerLock); 113 return result; 114 } 115 116 /* Block until the queue length is 0, or there is a pending suspend request */ 117 void dvmCompilerDrainQueue(void) 118 { 119 Thread *self = dvmThreadSelf(); 120 121 dvmLockMutex(&gDvmJit.compilerLock); 122 while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread && 123 self->suspendCount == 0) { 124 /* 125 * Use timed wait here - more than one mutator threads may be blocked 126 * but the compiler thread will only signal once when the queue is 127 * emptied. Furthermore, the compiler thread may have been shutdown 128 * so the blocked thread may never get the wakeup signal. 129 */ 130 dvmRelativeCondWait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock, 1000, 0); 131 } 132 dvmUnlockMutex(&gDvmJit.compilerLock); 133 } 134 135 bool dvmCompilerSetupCodeCache(void) 136 { 137 extern void dvmCompilerTemplateStart(void); 138 extern void dmvCompilerTemplateEnd(void); 139 int fd; 140 141 /* Allocate the code cache */ 142 fd = ashmem_create_region("dalvik-jit-code-cache", gDvmJit.codeCacheSize); 143 if (fd < 0) { 144 LOGE("Could not create %u-byte ashmem region for the JIT code cache", 145 gDvmJit.codeCacheSize); 146 return false; 147 } 148 gDvmJit.codeCache = mmap(NULL, gDvmJit.codeCacheSize, 149 PROT_READ | PROT_WRITE | PROT_EXEC, 150 MAP_PRIVATE , fd, 0); 151 close(fd); 152 if (gDvmJit.codeCache == MAP_FAILED) { 153 LOGE("Failed to mmap the JIT code cache: %s\n", strerror(errno)); 154 return false; 155 } 156 157 gDvmJit.pageSizeMask = getpagesize() - 1; 158 159 /* This can be found through "dalvik-jit-code-cache" in /proc/<pid>/maps */ 160 // LOGD("Code cache starts at %p", gDvmJit.codeCache); 161 162 /* Copy the template code into the beginning of the code cache */ 163 int templateSize = (intptr_t) dmvCompilerTemplateEnd - 164 (intptr_t) dvmCompilerTemplateStart; 165 memcpy((void *) gDvmJit.codeCache, 166 (void *) dvmCompilerTemplateStart, 167 templateSize); 168 169 /* 170 * Work around a CPU bug by keeping the 32-bit ARM handler code in its own 171 * page. 172 */ 173 if (dvmCompilerInstructionSet() == DALVIK_JIT_THUMB2) { 174 templateSize = (templateSize + 4095) & ~4095; 175 } 176 177 gDvmJit.templateSize = templateSize; 178 gDvmJit.codeCacheByteUsed = templateSize; 179 180 /* Only flush the part in the code cache that is being used now */ 181 cacheflush((intptr_t) gDvmJit.codeCache, 182 (intptr_t) gDvmJit.codeCache + templateSize, 0); 183 184 int result = mprotect(gDvmJit.codeCache, gDvmJit.codeCacheSize, 185 PROTECT_CODE_CACHE_ATTRS); 186 187 if (result == -1) { 188 LOGE("Failed to remove the write permission for the code cache"); 189 dvmAbort(); 190 } 191 192 return true; 193 } 194 195 static void crawlDalvikStack(Thread *thread, bool print) 196 { 197 void *fp = thread->curFrame; 198 StackSaveArea* saveArea = NULL; 199 int stackLevel = 0; 200 201 if (print) { 202 LOGD("Crawling tid %d (%s / %p %s)", thread->systemTid, 203 dvmGetThreadStatusStr(thread->status), 204 thread->inJitCodeCache, 205 thread->inJitCodeCache ? "jit" : "interp"); 206 } 207 /* Crawl the Dalvik stack frames to clear the returnAddr field */ 208 while (fp != NULL) { 209 saveArea = SAVEAREA_FROM_FP(fp); 210 211 if (print) { 212 if (dvmIsBreakFrame(fp)) { 213 LOGD(" #%d: break frame (%p)", 214 stackLevel, saveArea->returnAddr); 215 } 216 else { 217 LOGD(" #%d: %s.%s%s (%p)", 218 stackLevel, 219 saveArea->method->clazz->descriptor, 220 saveArea->method->name, 221 dvmIsNativeMethod(saveArea->method) ? 222 " (native)" : "", 223 saveArea->returnAddr); 224 } 225 } 226 stackLevel++; 227 saveArea->returnAddr = NULL; 228 assert(fp != saveArea->prevFrame); 229 fp = saveArea->prevFrame; 230 } 231 /* Make sure the stack is fully unwound to the bottom */ 232 assert(saveArea == NULL || 233 (u1 *) (saveArea+1) == thread->interpStackStart); 234 } 235 236 static void resetCodeCache(void) 237 { 238 Thread* thread; 239 u8 startTime = dvmGetRelativeTimeUsec(); 240 int inJit = 0; 241 int byteUsed = gDvmJit.codeCacheByteUsed; 242 243 /* If any thread is found stuck in the JIT state, don't reset the cache */ 244 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { 245 /* 246 * Crawl the stack to wipe out the returnAddr field so that 247 * 1) the soon-to-be-deleted code in the JIT cache won't be used 248 * 2) or the thread stuck in the JIT land will soon return 249 * to the interpreter land 250 */ 251 crawlDalvikStack(thread, false); 252 if (thread->inJitCodeCache) { 253 inJit++; 254 } 255 } 256 257 if (inJit) { 258 LOGD("JIT code cache reset delayed (%d bytes %d/%d)", 259 gDvmJit.codeCacheByteUsed, gDvmJit.numCodeCacheReset, 260 ++gDvmJit.numCodeCacheResetDelayed); 261 return; 262 } 263 264 /* Lock the mutex to clean up the work queue */ 265 dvmLockMutex(&gDvmJit.compilerLock); 266 267 /* Drain the work queue to free the work orders */ 268 while (workQueueLength()) { 269 CompilerWorkOrder work = workDequeue(); 270 free(work.info); 271 } 272 273 /* Reset the JitEntry table contents to the initial unpopulated state */ 274 dvmJitResetTable(); 275 276 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed); 277 /* 278 * Wipe out the code cache content to force immediate crashes if 279 * stale JIT'ed code is invoked. 280 */ 281 memset((char *) gDvmJit.codeCache + gDvmJit.templateSize, 282 0, 283 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize); 284 cacheflush((intptr_t) gDvmJit.codeCache, 285 (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed, 0); 286 287 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed); 288 289 /* Reset the current mark of used bytes to the end of template code */ 290 gDvmJit.codeCacheByteUsed = gDvmJit.templateSize; 291 gDvmJit.numCompilations = 0; 292 293 /* Reset the work queue */ 294 memset(gDvmJit.compilerWorkQueue, 0, 295 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE); 296 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0; 297 gDvmJit.compilerQueueLength = 0; 298 299 /* Reset the IC patch work queue */ 300 dvmLockMutex(&gDvmJit.compilerICPatchLock); 301 gDvmJit.compilerICPatchIndex = 0; 302 dvmUnlockMutex(&gDvmJit.compilerICPatchLock); 303 304 /* All clear now */ 305 gDvmJit.codeCacheFull = false; 306 307 dvmUnlockMutex(&gDvmJit.compilerLock); 308 309 LOGD("JIT code cache reset in %lld ms (%d bytes %d/%d)", 310 (dvmGetRelativeTimeUsec() - startTime) / 1000, 311 byteUsed, ++gDvmJit.numCodeCacheReset, 312 gDvmJit.numCodeCacheResetDelayed); 313 } 314 315 /* 316 * Perform actions that are only safe when all threads are suspended. Currently 317 * we do: 318 * 1) Check if the code cache is full. If so reset it and restart populating it 319 * from scratch. 320 * 2) Patch predicted chaining cells by consuming recorded work orders. 321 */ 322 void dvmCompilerPerformSafePointChecks(void) 323 { 324 if (gDvmJit.codeCacheFull) { 325 resetCodeCache(); 326 } 327 dvmCompilerPatchInlineCache(); 328 } 329 330 bool compilerThreadStartup(void) 331 { 332 JitEntry *pJitTable = NULL; 333 unsigned char *pJitProfTable = NULL; 334 unsigned int i; 335 336 if (!dvmCompilerArchInit()) 337 goto fail; 338 339 /* 340 * Setup the code cache if we have not inherited a valid code cache 341 * from the zygote. 342 */ 343 if (gDvmJit.codeCache == NULL) { 344 if (!dvmCompilerSetupCodeCache()) 345 goto fail; 346 } 347 348 /* Allocate the initial arena block */ 349 if (dvmCompilerHeapInit() == false) { 350 goto fail; 351 } 352 353 dvmLockMutex(&gDvmJit.compilerLock); 354 355 /* Track method-level compilation statistics */ 356 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL); 357 358 #if defined(WITH_JIT_TUNING) 359 gDvm.verboseShutdown = true; 360 #endif 361 362 dvmUnlockMutex(&gDvmJit.compilerLock); 363 364 /* Set up the JitTable */ 365 366 /* Power of 2? */ 367 assert(gDvmJit.jitTableSize && 368 !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1))); 369 370 dvmInitMutex(&gDvmJit.tableLock); 371 dvmLockMutex(&gDvmJit.tableLock); 372 pJitTable = (JitEntry*) 373 calloc(gDvmJit.jitTableSize, sizeof(*pJitTable)); 374 if (!pJitTable) { 375 LOGE("jit table allocation failed\n"); 376 dvmUnlockMutex(&gDvmJit.tableLock); 377 goto fail; 378 } 379 /* 380 * NOTE: the profile table must only be allocated once, globally. 381 * Profiling is turned on and off by nulling out gDvm.pJitProfTable 382 * and then restoring its original value. However, this action 383 * is not syncronized for speed so threads may continue to hold 384 * and update the profile table after profiling has been turned 385 * off by null'ng the global pointer. Be aware. 386 */ 387 pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE); 388 if (!pJitProfTable) { 389 LOGE("jit prof table allocation failed\n"); 390 dvmUnlockMutex(&gDvmJit.tableLock); 391 goto fail; 392 } 393 memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE); 394 for (i=0; i < gDvmJit.jitTableSize; i++) { 395 pJitTable[i].u.info.chain = gDvmJit.jitTableSize; 396 } 397 /* Is chain field wide enough for termination pattern? */ 398 assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize); 399 400 gDvmJit.pJitEntryTable = pJitTable; 401 gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1; 402 gDvmJit.jitTableEntriesUsed = 0; 403 gDvmJit.compilerHighWater = 404 COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4); 405 /* 406 * If the VM is launched with wait-on-the-debugger, we will need to hide 407 * the profile table here 408 */ 409 gDvmJit.pProfTable = dvmDebuggerOrProfilerActive() ? NULL : pJitProfTable; 410 gDvmJit.pProfTableCopy = pJitProfTable; 411 dvmUnlockMutex(&gDvmJit.tableLock); 412 413 /* Signal running threads to refresh their cached pJitTable pointers */ 414 dvmSuspendAllThreads(SUSPEND_FOR_REFRESH); 415 dvmResumeAllThreads(SUSPEND_FOR_REFRESH); 416 417 /* Enable signature breakpoints by customizing the following code */ 418 #if defined(SIGNATURE_BREAKPOINT) 419 /* 420 * Suppose one sees the following native crash in the bugreport: 421 * I/DEBUG ( 1638): Build fingerprint: 'unknown' 422 * I/DEBUG ( 1638): pid: 2468, tid: 2507 >>> com.google.android.gallery3d 423 * I/DEBUG ( 1638): signal 11 (SIGSEGV), fault addr 00001400 424 * I/DEBUG ( 1638): r0 44ea7190 r1 44e4f7b8 r2 44ebc710 r3 00000000 425 * I/DEBUG ( 1638): r4 00000a00 r5 41862dec r6 4710dc10 r7 00000280 426 * I/DEBUG ( 1638): r8 ad010f40 r9 46a37a12 10 001116b0 fp 42a78208 427 * I/DEBUG ( 1638): ip 00000090 sp 4710dbc8 lr ad060e67 pc 46b90682 428 * cpsr 00000030 429 * I/DEBUG ( 1638): #00 pc 46b90682 /dev/ashmem/dalvik-jit-code-cache 430 * I/DEBUG ( 1638): #01 pc 00060e62 /system/lib/libdvm.so 431 * 432 * I/DEBUG ( 1638): code around pc: 433 * I/DEBUG ( 1638): 46b90660 6888d01c 34091dcc d2174287 4a186b68 434 * I/DEBUG ( 1638): 46b90670 d0052800 68006809 28004790 6b68d00e 435 * I/DEBUG ( 1638): 46b90680 512000bc 37016eaf 6ea866af 6f696028 436 * I/DEBUG ( 1638): 46b90690 682a6069 429a686b e003da08 6df1480b 437 * I/DEBUG ( 1638): 46b906a0 1c2d4788 47806d70 46a378fa 47806d70 438 * 439 * Clearly it is a JIT bug. To find out which translation contains the 440 * offending code, the content of the memory dump around the faulting PC 441 * can be pasted into the gDvmJit.signatureBreakpoint[] array and next time 442 * when a similar compilation is being created, the JIT compiler replay the 443 * trace in the verbose mode and one can investigate the instruction 444 * sequence in details. 445 * 446 * The length of the signature may need additional experiments to determine. 447 * The rule of thumb is don't include PC-relative instructions in the 448 * signature since it may be affected by the alignment of the compiled code. 449 * However, a signature that's too short might increase the chance of false 450 * positive matches. Using gdbjithelper to disassembly the memory content 451 * first might be a good companion approach. 452 * 453 * For example, if the next 4 words starting from 46b90680 is pasted into 454 * the data structure: 455 */ 456 457 gDvmJit.signatureBreakpointSize = 4; 458 gDvmJit.signatureBreakpoint = 459 malloc(sizeof(u4) * gDvmJit.signatureBreakpointSize); 460 gDvmJit.signatureBreakpoint[0] = 0x512000bc; 461 gDvmJit.signatureBreakpoint[1] = 0x37016eaf; 462 gDvmJit.signatureBreakpoint[2] = 0x6ea866af; 463 gDvmJit.signatureBreakpoint[3] = 0x6f696028; 464 465 /* 466 * The following log will be printed when a match is found in subsequent 467 * testings: 468 * 469 * D/dalvikvm( 2468): Signature match starting from offset 0x34 (4 words) 470 * D/dalvikvm( 2468): -------- 471 * D/dalvikvm( 2468): Compiler: Building trace for computeVisibleItems, 472 * offset 0x1f7 473 * D/dalvikvm( 2468): 0x46a37a12: 0x0090 add-int v42, v5, v26 474 * D/dalvikvm( 2468): 0x46a37a16: 0x004d aput-object v13, v14, v42 475 * D/dalvikvm( 2468): 0x46a37a1a: 0x0028 goto, (#0), (#0) 476 * D/dalvikvm( 2468): 0x46a3794e: 0x00d8 add-int/lit8 v26, v26, (#1) 477 * D/dalvikvm( 2468): 0x46a37952: 0x0028 goto, (#0), (#0) 478 * D/dalvikvm( 2468): 0x46a378ee: 0x0002 move/from16 v0, v26, (#0) 479 * D/dalvikvm( 2468): 0x46a378f2: 0x0002 move/from16 v1, v29, (#0) 480 * D/dalvikvm( 2468): 0x46a378f6: 0x0035 if-ge v0, v1, (#10) 481 * D/dalvikvm( 2468): TRACEINFO (554): 0x46a37624 482 * Lcom/cooliris/media/GridLayer;computeVisibleItems 0x1f7 14 of 934, 8 483 * blocks 484 * : 485 * : 486 * D/dalvikvm( 2468): 0x20 (0020): ldr r0, [r5, #52] 487 * D/dalvikvm( 2468): 0x22 (0022): ldr r2, [pc, #96] 488 * D/dalvikvm( 2468): 0x24 (0024): cmp r0, #0 489 * D/dalvikvm( 2468): 0x26 (0026): beq 0x00000034 490 * D/dalvikvm( 2468): 0x28 (0028): ldr r1, [r1, #0] 491 * D/dalvikvm( 2468): 0x2a (002a): ldr r0, [r0, #0] 492 * D/dalvikvm( 2468): 0x2c (002c): blx r2 493 * D/dalvikvm( 2468): 0x2e (002e): cmp r0, #0 494 * D/dalvikvm( 2468): 0x30 (0030): beq 0x00000050 495 * D/dalvikvm( 2468): 0x32 (0032): ldr r0, [r5, #52] 496 * D/dalvikvm( 2468): 0x34 (0034): lsls r4, r7, #2 497 * D/dalvikvm( 2468): 0x36 (0036): str r0, [r4, r4] 498 * D/dalvikvm( 2468): -------- dalvik offset: 0x01fb @ goto, (#0), (#0) 499 * D/dalvikvm( 2468): L0x0195: 500 * D/dalvikvm( 2468): -------- dalvik offset: 0x0195 @ add-int/lit8 v26, 501 * v26, (#1) 502 * D/dalvikvm( 2468): 0x38 (0038): ldr r7, [r5, #104] 503 * D/dalvikvm( 2468): 0x3a (003a): adds r7, r7, #1 504 * D/dalvikvm( 2468): 0x3c (003c): str r7, [r5, #104] 505 * D/dalvikvm( 2468): -------- dalvik offset: 0x0197 @ goto, (#0), (#0) 506 * D/dalvikvm( 2468): L0x0165: 507 * D/dalvikvm( 2468): -------- dalvik offset: 0x0165 @ move/from16 v0, v26, 508 * (#0) 509 * D/dalvikvm( 2468): 0x3e (003e): ldr r0, [r5, #104] 510 * D/dalvikvm( 2468): 0x40 (0040): str r0, [r5, #0] 511 * 512 * The "str r0, [r4, r4]" is indeed the culprit of the native crash. 513 */ 514 #endif 515 516 return true; 517 518 fail: 519 return false; 520 521 } 522 523 static void *compilerThreadStart(void *arg) 524 { 525 dvmChangeStatus(NULL, THREAD_VMWAIT); 526 527 /* 528 * If we're not running stand-alone, wait a little before 529 * recieving translation requests on the assumption that process start 530 * up code isn't worth compiling. We'll resume when the framework 531 * signals us that the first screen draw has happened, or the timer 532 * below expires (to catch daemons). 533 * 534 * There is a theoretical race between the callback to 535 * VMRuntime.startJitCompiation and when the compiler thread reaches this 536 * point. In case the callback happens earlier, in order not to permanently 537 * hold the system_server (which is not using the timed wait) in 538 * interpreter-only mode we bypass the delay here. 539 */ 540 if (gDvmJit.runningInAndroidFramework && 541 !gDvmJit.alreadyEnabledViaFramework) { 542 /* 543 * If the current VM instance is the system server (detected by having 544 * 0 in gDvm.systemServerPid), we will use the indefinite wait on the 545 * conditional variable to determine whether to start the JIT or not. 546 * If the system server detects that the whole system is booted in 547 * safe mode, the conditional variable will never be signaled and the 548 * system server will remain in the interpreter-only mode. All 549 * subsequent apps will be started with the --enable-safemode flag 550 * explicitly appended. 551 */ 552 if (gDvm.systemServerPid == 0) { 553 dvmLockMutex(&gDvmJit.compilerLock); 554 pthread_cond_wait(&gDvmJit.compilerQueueActivity, 555 &gDvmJit.compilerLock); 556 dvmUnlockMutex(&gDvmJit.compilerLock); 557 LOGD("JIT started for system_server"); 558 } else { 559 dvmLockMutex(&gDvmJit.compilerLock); 560 /* 561 * TUNING: experiment with the delay & perhaps make it 562 * target-specific 563 */ 564 dvmRelativeCondWait(&gDvmJit.compilerQueueActivity, 565 &gDvmJit.compilerLock, 3000, 0); 566 dvmUnlockMutex(&gDvmJit.compilerLock); 567 } 568 if (gDvmJit.haltCompilerThread) { 569 return NULL; 570 } 571 } 572 573 compilerThreadStartup(); 574 575 dvmLockMutex(&gDvmJit.compilerLock); 576 /* 577 * Since the compiler thread will not touch any objects on the heap once 578 * being created, we just fake its state as VMWAIT so that it can be a 579 * bit late when there is suspend request pending. 580 */ 581 while (!gDvmJit.haltCompilerThread) { 582 if (workQueueLength() == 0) { 583 int cc; 584 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty); 585 assert(cc == 0); 586 pthread_cond_wait(&gDvmJit.compilerQueueActivity, 587 &gDvmJit.compilerLock); 588 continue; 589 } else { 590 do { 591 CompilerWorkOrder work = workDequeue(); 592 dvmUnlockMutex(&gDvmJit.compilerLock); 593 #if defined(WITH_JIT_TUNING) 594 u8 startTime = dvmGetRelativeTimeUsec(); 595 #endif 596 /* 597 * Check whether there is a suspend request on me. This 598 * is necessary to allow a clean shutdown. 599 * 600 * However, in the blocking stress testing mode, let the 601 * compiler thread continue doing compilations to unblock 602 * other requesting threads. This may occasionally cause 603 * shutdown from proceeding cleanly in the standalone invocation 604 * of the vm but this should be acceptable. 605 */ 606 if (!gDvmJit.blockingMode) 607 dvmCheckSuspendPending(dvmThreadSelf()); 608 /* Is JitTable filling up? */ 609 if (gDvmJit.jitTableEntriesUsed > 610 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) { 611 bool resizeFail = 612 dvmJitResizeJitTable(gDvmJit.jitTableSize * 2); 613 /* 614 * If the jit table is full, consider it's time to reset 615 * the code cache too. 616 */ 617 gDvmJit.codeCacheFull |= resizeFail; 618 } 619 if (gDvmJit.haltCompilerThread) { 620 LOGD("Compiler shutdown in progress - discarding request"); 621 } else if (!gDvmJit.codeCacheFull) { 622 bool compileOK = false; 623 jmp_buf jmpBuf; 624 work.bailPtr = &jmpBuf; 625 bool aborted = setjmp(jmpBuf); 626 if (!aborted) { 627 compileOK = dvmCompilerDoWork(&work); 628 } 629 if (aborted || !compileOK) { 630 dvmCompilerArenaReset(); 631 } else if (!work.result.discardResult && 632 work.result.codeAddress) { 633 /* Make sure that proper code addr is installed */ 634 assert(work.result.codeAddress != NULL); 635 dvmJitSetCodeAddr(work.pc, work.result.codeAddress, 636 work.result.instructionSet); 637 } 638 } 639 free(work.info); 640 #if defined(WITH_JIT_TUNING) 641 gDvmJit.jitTime += dvmGetRelativeTimeUsec() - startTime; 642 #endif 643 dvmLockMutex(&gDvmJit.compilerLock); 644 } while (workQueueLength() != 0); 645 } 646 } 647 pthread_cond_signal(&gDvmJit.compilerQueueEmpty); 648 dvmUnlockMutex(&gDvmJit.compilerLock); 649 650 /* 651 * As part of detaching the thread we need to call into Java code to update 652 * the ThreadGroup, and we should not be in VMWAIT state while executing 653 * interpreted code. 654 */ 655 dvmChangeStatus(NULL, THREAD_RUNNING); 656 657 if (gDvm.verboseShutdown) 658 LOGD("Compiler thread shutting down\n"); 659 return NULL; 660 } 661 662 bool dvmCompilerStartup(void) 663 { 664 665 dvmInitMutex(&gDvmJit.compilerLock); 666 dvmInitMutex(&gDvmJit.compilerICPatchLock); 667 dvmInitMutex(&gDvmJit.codeCacheProtectionLock); 668 dvmLockMutex(&gDvmJit.compilerLock); 669 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL); 670 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL); 671 672 /* Reset the work queue */ 673 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0; 674 gDvmJit.compilerQueueLength = 0; 675 dvmUnlockMutex(&gDvmJit.compilerLock); 676 677 /* 678 * Defer rest of initialization until we're sure JIT'ng makes sense. Launch 679 * the compiler thread, which will do the real initialization if and 680 * when it is signalled to do so. 681 */ 682 return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler", 683 compilerThreadStart, NULL); 684 } 685 686 void dvmCompilerShutdown(void) 687 { 688 void *threadReturn; 689 690 /* Disable new translation requests */ 691 gDvmJit.pProfTable = NULL; 692 gDvmJit.pProfTableCopy = NULL; 693 694 if (gDvm.verboseShutdown) { 695 dvmCompilerDumpStats(); 696 while (gDvmJit.compilerQueueLength) 697 sleep(5); 698 } 699 700 if (gDvmJit.compilerHandle) { 701 702 gDvmJit.haltCompilerThread = true; 703 704 dvmLockMutex(&gDvmJit.compilerLock); 705 pthread_cond_signal(&gDvmJit.compilerQueueActivity); 706 dvmUnlockMutex(&gDvmJit.compilerLock); 707 708 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0) 709 LOGW("Compiler thread join failed\n"); 710 else if (gDvm.verboseShutdown) 711 LOGD("Compiler thread has shut down\n"); 712 } 713 714 /* Break loops within the translation cache */ 715 dvmJitUnchainAll(); 716 717 /* 718 * NOTE: our current implementatation doesn't allow for the compiler 719 * thread to be restarted after it exits here. We aren't freeing 720 * the JitTable or the ProfTable because threads which still may be 721 * running or in the process of shutting down may hold references to 722 * them. 723 */ 724 } 725 726 void dvmCompilerStateRefresh() 727 { 728 bool jitActive; 729 bool jitActivate; 730 bool needUnchain = false; 731 732 /* 733 * The tableLock might not be initialized yet by the compiler thread if 734 * debugger is attached from the very beginning of the VM launch. If 735 * pProfTableCopy is NULL, the lock is not initialized yet and we don't 736 * need to refresh anything either. 737 */ 738 if (gDvmJit.pProfTableCopy == NULL) { 739 return; 740 } 741 742 dvmLockMutex(&gDvmJit.tableLock); 743 jitActive = gDvmJit.pProfTable != NULL; 744 jitActivate = !(gDvm.debuggerActive || (gDvm.activeProfilers > 0)); 745 746 if (jitActivate && !jitActive) { 747 gDvmJit.pProfTable = gDvmJit.pProfTableCopy; 748 } else if (!jitActivate && jitActive) { 749 gDvmJit.pProfTable = NULL; 750 needUnchain = true; 751 } 752 dvmUnlockMutex(&gDvmJit.tableLock); 753 if (needUnchain) 754 dvmJitUnchainAll(); 755 } 756