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