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