Compiler.cpp revision 60fc806b679a3655c228b4093058c59941a49cfe
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->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", 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 dvmDisableSubMode(thread, kSubModeJitTraceBuild); 286 } 287 dvmUnlockThreadList(); 288 289 if (inJit) { 290 LOGD("JIT code cache reset delayed (%d bytes %d/%d)", 291 gDvmJit.codeCacheByteUsed, gDvmJit.numCodeCacheReset, 292 ++gDvmJit.numCodeCacheResetDelayed); 293 return; 294 } 295 296 /* Lock the mutex to clean up the work queue */ 297 dvmLockMutex(&gDvmJit.compilerLock); 298 299 /* Update the translation cache version */ 300 gDvmJit.cacheVersion++; 301 302 /* Drain the work queue to free the work orders */ 303 while (workQueueLength()) { 304 CompilerWorkOrder work = workDequeue(); 305 free(work.info); 306 } 307 308 /* Reset the JitEntry table contents to the initial unpopulated state */ 309 dvmJitResetTable(); 310 311 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed); 312 /* 313 * Wipe out the code cache content to force immediate crashes if 314 * stale JIT'ed code is invoked. 315 */ 316 memset((char *) gDvmJit.codeCache + gDvmJit.templateSize, 317 0, 318 gDvmJit.codeCacheByteUsed - gDvmJit.templateSize); 319 dvmCompilerCacheFlush((intptr_t) gDvmJit.codeCache, 320 (intptr_t) gDvmJit.codeCache + 321 gDvmJit.codeCacheByteUsed, 0); 322 323 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed); 324 325 /* Reset the current mark of used bytes to the end of template code */ 326 gDvmJit.codeCacheByteUsed = gDvmJit.templateSize; 327 gDvmJit.numCompilations = 0; 328 329 /* Reset the work queue */ 330 memset(gDvmJit.compilerWorkQueue, 0, 331 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE); 332 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0; 333 gDvmJit.compilerQueueLength = 0; 334 335 /* Reset the IC patch work queue */ 336 dvmLockMutex(&gDvmJit.compilerICPatchLock); 337 gDvmJit.compilerICPatchIndex = 0; 338 dvmUnlockMutex(&gDvmJit.compilerICPatchLock); 339 340 /* 341 * Reset the inflight compilation address (can only be done in safe points 342 * or by the compiler thread when its thread state is RUNNING). 343 */ 344 gDvmJit.inflightBaseAddr = NULL; 345 346 /* All clear now */ 347 gDvmJit.codeCacheFull = false; 348 349 dvmUnlockMutex(&gDvmJit.compilerLock); 350 351 LOGD("JIT code cache reset in %lld ms (%d bytes %d/%d)", 352 (dvmGetRelativeTimeUsec() - startTime) / 1000, 353 byteUsed, ++gDvmJit.numCodeCacheReset, 354 gDvmJit.numCodeCacheResetDelayed); 355} 356 357/* 358 * Perform actions that are only safe when all threads are suspended. Currently 359 * we do: 360 * 1) Check if the code cache is full. If so reset it and restart populating it 361 * from scratch. 362 * 2) Patch predicted chaining cells by consuming recorded work orders. 363 */ 364void dvmCompilerPerformSafePointChecks(void) 365{ 366 if (gDvmJit.codeCacheFull) { 367 resetCodeCache(); 368 } 369 dvmCompilerPatchInlineCache(); 370} 371 372static bool compilerThreadStartup(void) 373{ 374 JitEntry *pJitTable = NULL; 375 unsigned char *pJitProfTable = NULL; 376 JitTraceProfCounters *pJitTraceProfCounters = NULL; 377 unsigned int i; 378 379 if (!dvmCompilerArchInit()) 380 goto fail; 381 382 /* 383 * Setup the code cache if we have not inherited a valid code cache 384 * from the zygote. 385 */ 386 if (gDvmJit.codeCache == NULL) { 387 if (!dvmCompilerSetupCodeCache()) 388 goto fail; 389 } 390 391 /* Allocate the initial arena block */ 392 if (dvmCompilerHeapInit() == false) { 393 goto fail; 394 } 395 396 /* Cache the thread pointer */ 397 gDvmJit.compilerThread = dvmThreadSelf(); 398 399 dvmLockMutex(&gDvmJit.compilerLock); 400 401 /* Track method-level compilation statistics */ 402 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL); 403 404#if defined(WITH_JIT_TUNING) 405 gDvm.verboseShutdown = true; 406#endif 407 408 dvmUnlockMutex(&gDvmJit.compilerLock); 409 410 /* Set up the JitTable */ 411 412 /* Power of 2? */ 413 assert(gDvmJit.jitTableSize && 414 !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1))); 415 416 dvmInitMutex(&gDvmJit.tableLock); 417 dvmLockMutex(&gDvmJit.tableLock); 418 pJitTable = (JitEntry*) 419 calloc(gDvmJit.jitTableSize, sizeof(*pJitTable)); 420 if (!pJitTable) { 421 LOGE("jit table allocation failed"); 422 dvmUnlockMutex(&gDvmJit.tableLock); 423 goto fail; 424 } 425 /* 426 * NOTE: the profile table must only be allocated once, globally. 427 * Profiling is turned on and off by nulling out gDvm.pJitProfTable 428 * and then restoring its original value. However, this action 429 * is not synchronized for speed so threads may continue to hold 430 * and update the profile table after profiling has been turned 431 * off by null'ng the global pointer. Be aware. 432 */ 433 pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE); 434 if (!pJitProfTable) { 435 LOGE("jit prof table allocation failed"); 436 dvmUnlockMutex(&gDvmJit.tableLock); 437 goto fail; 438 } 439 memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE); 440 for (i=0; i < gDvmJit.jitTableSize; i++) { 441 pJitTable[i].u.info.chain = gDvmJit.jitTableSize; 442 } 443 /* Is chain field wide enough for termination pattern? */ 444 assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize); 445 446 /* Allocate the trace profiling structure */ 447 pJitTraceProfCounters = (JitTraceProfCounters*) 448 calloc(1, sizeof(*pJitTraceProfCounters)); 449 if (!pJitTraceProfCounters) { 450 LOGE("jit trace prof counters allocation failed"); 451 dvmUnlockMutex(&gDvmJit.tableLock); 452 goto fail; 453 } 454 455 gDvmJit.pJitEntryTable = pJitTable; 456 gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1; 457 gDvmJit.jitTableEntriesUsed = 0; 458 gDvmJit.compilerHighWater = 459 COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4); 460 /* 461 * If the VM is launched with wait-on-the-debugger, we will need to hide 462 * the profile table here 463 */ 464 gDvmJit.pProfTable = dvmDebuggerOrProfilerActive() ? NULL : pJitProfTable; 465 gDvmJit.pProfTableCopy = pJitProfTable; 466 gDvmJit.pJitTraceProfCounters = pJitTraceProfCounters; 467 dvmJitUpdateThreadStateAll(); 468 dvmUnlockMutex(&gDvmJit.tableLock); 469 470 /* Signal running threads to refresh their cached pJitTable pointers */ 471 dvmSuspendAllThreads(SUSPEND_FOR_REFRESH); 472 dvmResumeAllThreads(SUSPEND_FOR_REFRESH); 473 474 /* Enable signature breakpoints by customizing the following code */ 475#if defined(SIGNATURE_BREAKPOINT) 476 /* 477 * Suppose one sees the following native crash in the bugreport: 478 * I/DEBUG ( 1638): Build fingerprint: 'unknown' 479 * I/DEBUG ( 1638): pid: 2468, tid: 2507 >>> com.google.android.gallery3d 480 * I/DEBUG ( 1638): signal 11 (SIGSEGV), fault addr 00001400 481 * I/DEBUG ( 1638): r0 44ea7190 r1 44e4f7b8 r2 44ebc710 r3 00000000 482 * I/DEBUG ( 1638): r4 00000a00 r5 41862dec r6 4710dc10 r7 00000280 483 * I/DEBUG ( 1638): r8 ad010f40 r9 46a37a12 10 001116b0 fp 42a78208 484 * I/DEBUG ( 1638): ip 00000090 sp 4710dbc8 lr ad060e67 pc 46b90682 485 * cpsr 00000030 486 * I/DEBUG ( 1638): #00 pc 46b90682 /dev/ashmem/dalvik-jit-code-cache 487 * I/DEBUG ( 1638): #01 pc 00060e62 /system/lib/libdvm.so 488 * 489 * I/DEBUG ( 1638): code around pc: 490 * I/DEBUG ( 1638): 46b90660 6888d01c 34091dcc d2174287 4a186b68 491 * I/DEBUG ( 1638): 46b90670 d0052800 68006809 28004790 6b68d00e 492 * I/DEBUG ( 1638): 46b90680 512000bc 37016eaf 6ea866af 6f696028 493 * I/DEBUG ( 1638): 46b90690 682a6069 429a686b e003da08 6df1480b 494 * I/DEBUG ( 1638): 46b906a0 1c2d4788 47806d70 46a378fa 47806d70 495 * 496 * Clearly it is a JIT bug. To find out which translation contains the 497 * offending code, the content of the memory dump around the faulting PC 498 * can be pasted into the gDvmJit.signatureBreakpoint[] array and next time 499 * when a similar compilation is being created, the JIT compiler replay the 500 * trace in the verbose mode and one can investigate the instruction 501 * sequence in details. 502 * 503 * The length of the signature may need additional experiments to determine. 504 * The rule of thumb is don't include PC-relative instructions in the 505 * signature since it may be affected by the alignment of the compiled code. 506 * However, a signature that's too short might increase the chance of false 507 * positive matches. Using gdbjithelper to disassembly the memory content 508 * first might be a good companion approach. 509 * 510 * For example, if the next 4 words starting from 46b90680 is pasted into 511 * the data structure: 512 */ 513 514 gDvmJit.signatureBreakpointSize = 4; 515 gDvmJit.signatureBreakpoint = 516 malloc(sizeof(u4) * gDvmJit.signatureBreakpointSize); 517 gDvmJit.signatureBreakpoint[0] = 0x512000bc; 518 gDvmJit.signatureBreakpoint[1] = 0x37016eaf; 519 gDvmJit.signatureBreakpoint[2] = 0x6ea866af; 520 gDvmJit.signatureBreakpoint[3] = 0x6f696028; 521 522 /* 523 * The following log will be printed when a match is found in subsequent 524 * testings: 525 * 526 * D/dalvikvm( 2468): Signature match starting from offset 0x34 (4 words) 527 * D/dalvikvm( 2468): -------- 528 * D/dalvikvm( 2468): Compiler: Building trace for computeVisibleItems, 529 * offset 0x1f7 530 * D/dalvikvm( 2468): 0x46a37a12: 0x0090 add-int v42, v5, v26 531 * D/dalvikvm( 2468): 0x46a37a16: 0x004d aput-object v13, v14, v42 532 * D/dalvikvm( 2468): 0x46a37a1a: 0x0028 goto, (#0), (#0) 533 * D/dalvikvm( 2468): 0x46a3794e: 0x00d8 add-int/lit8 v26, v26, (#1) 534 * D/dalvikvm( 2468): 0x46a37952: 0x0028 goto, (#0), (#0) 535 * D/dalvikvm( 2468): 0x46a378ee: 0x0002 move/from16 v0, v26, (#0) 536 * D/dalvikvm( 2468): 0x46a378f2: 0x0002 move/from16 v1, v29, (#0) 537 * D/dalvikvm( 2468): 0x46a378f6: 0x0035 if-ge v0, v1, (#10) 538 * D/dalvikvm( 2468): TRACEINFO (554): 0x46a37624 539 * Lcom/cooliris/media/GridLayer;computeVisibleItems 0x1f7 14 of 934, 8 540 * blocks 541 * : 542 * : 543 * D/dalvikvm( 2468): 0x20 (0020): ldr r0, [r5, #52] 544 * D/dalvikvm( 2468): 0x22 (0022): ldr r2, [pc, #96] 545 * D/dalvikvm( 2468): 0x24 (0024): cmp r0, #0 546 * D/dalvikvm( 2468): 0x26 (0026): beq 0x00000034 547 * D/dalvikvm( 2468): 0x28 (0028): ldr r1, [r1, #0] 548 * D/dalvikvm( 2468): 0x2a (002a): ldr r0, [r0, #0] 549 * D/dalvikvm( 2468): 0x2c (002c): blx r2 550 * D/dalvikvm( 2468): 0x2e (002e): cmp r0, #0 551 * D/dalvikvm( 2468): 0x30 (0030): beq 0x00000050 552 * D/dalvikvm( 2468): 0x32 (0032): ldr r0, [r5, #52] 553 * D/dalvikvm( 2468): 0x34 (0034): lsls r4, r7, #2 554 * D/dalvikvm( 2468): 0x36 (0036): str r0, [r4, r4] 555 * D/dalvikvm( 2468): -------- dalvik offset: 0x01fb @ goto, (#0), (#0) 556 * D/dalvikvm( 2468): L0x0195: 557 * D/dalvikvm( 2468): -------- dalvik offset: 0x0195 @ add-int/lit8 v26, 558 * v26, (#1) 559 * D/dalvikvm( 2468): 0x38 (0038): ldr r7, [r5, #104] 560 * D/dalvikvm( 2468): 0x3a (003a): adds r7, r7, #1 561 * D/dalvikvm( 2468): 0x3c (003c): str r7, [r5, #104] 562 * D/dalvikvm( 2468): -------- dalvik offset: 0x0197 @ goto, (#0), (#0) 563 * D/dalvikvm( 2468): L0x0165: 564 * D/dalvikvm( 2468): -------- dalvik offset: 0x0165 @ move/from16 v0, v26, 565 * (#0) 566 * D/dalvikvm( 2468): 0x3e (003e): ldr r0, [r5, #104] 567 * D/dalvikvm( 2468): 0x40 (0040): str r0, [r5, #0] 568 * 569 * The "str r0, [r4, r4]" is indeed the culprit of the native crash. 570 */ 571#endif 572 573 return true; 574 575fail: 576 return false; 577 578} 579 580static void *compilerThreadStart(void *arg) 581{ 582 dvmChangeStatus(NULL, THREAD_VMWAIT); 583 584 /* 585 * If we're not running stand-alone, wait a little before 586 * recieving translation requests on the assumption that process start 587 * up code isn't worth compiling. We'll resume when the framework 588 * signals us that the first screen draw has happened, or the timer 589 * below expires (to catch daemons). 590 * 591 * There is a theoretical race between the callback to 592 * VMRuntime.startJitCompiation and when the compiler thread reaches this 593 * point. In case the callback happens earlier, in order not to permanently 594 * hold the system_server (which is not using the timed wait) in 595 * interpreter-only mode we bypass the delay here. 596 */ 597 if (gDvmJit.runningInAndroidFramework && 598 !gDvmJit.alreadyEnabledViaFramework) { 599 /* 600 * If the current VM instance is the system server (detected by having 601 * 0 in gDvm.systemServerPid), we will use the indefinite wait on the 602 * conditional variable to determine whether to start the JIT or not. 603 * If the system server detects that the whole system is booted in 604 * safe mode, the conditional variable will never be signaled and the 605 * system server will remain in the interpreter-only mode. All 606 * subsequent apps will be started with the --enable-safemode flag 607 * explicitly appended. 608 */ 609 if (gDvm.systemServerPid == 0) { 610 dvmLockMutex(&gDvmJit.compilerLock); 611 pthread_cond_wait(&gDvmJit.compilerQueueActivity, 612 &gDvmJit.compilerLock); 613 dvmUnlockMutex(&gDvmJit.compilerLock); 614 LOGD("JIT started for system_server"); 615 } else { 616 dvmLockMutex(&gDvmJit.compilerLock); 617 /* 618 * TUNING: experiment with the delay & perhaps make it 619 * target-specific 620 */ 621 dvmRelativeCondWait(&gDvmJit.compilerQueueActivity, 622 &gDvmJit.compilerLock, 3000, 0); 623 dvmUnlockMutex(&gDvmJit.compilerLock); 624 } 625 if (gDvmJit.haltCompilerThread) { 626 return NULL; 627 } 628 } 629 630 compilerThreadStartup(); 631 632 dvmLockMutex(&gDvmJit.compilerLock); 633 /* 634 * Since the compiler thread will not touch any objects on the heap once 635 * being created, we just fake its state as VMWAIT so that it can be a 636 * bit late when there is suspend request pending. 637 */ 638 while (!gDvmJit.haltCompilerThread) { 639 if (workQueueLength() == 0) { 640 int cc; 641 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty); 642 assert(cc == 0); 643 pthread_cond_wait(&gDvmJit.compilerQueueActivity, 644 &gDvmJit.compilerLock); 645 continue; 646 } else { 647 do { 648 CompilerWorkOrder work = workDequeue(); 649 dvmUnlockMutex(&gDvmJit.compilerLock); 650#if defined(WITH_JIT_TUNING) 651 u8 startTime = dvmGetRelativeTimeUsec(); 652#endif 653 /* 654 * Check whether there is a suspend request on me. This 655 * is necessary to allow a clean shutdown. 656 * 657 * However, in the blocking stress testing mode, let the 658 * compiler thread continue doing compilations to unblock 659 * other requesting threads. This may occasionally cause 660 * shutdown from proceeding cleanly in the standalone invocation 661 * of the vm but this should be acceptable. 662 */ 663 if (!gDvmJit.blockingMode) 664 dvmCheckSuspendPending(dvmThreadSelf()); 665 /* Is JitTable filling up? */ 666 if (gDvmJit.jitTableEntriesUsed > 667 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) { 668 bool resizeFail = 669 dvmJitResizeJitTable(gDvmJit.jitTableSize * 2); 670 /* 671 * If the jit table is full, consider it's time to reset 672 * the code cache too. 673 */ 674 gDvmJit.codeCacheFull |= resizeFail; 675 } 676 if (gDvmJit.haltCompilerThread) { 677 LOGD("Compiler shutdown in progress - discarding request"); 678 } else if (!gDvmJit.codeCacheFull) { 679 jmp_buf jmpBuf; 680 work.bailPtr = &jmpBuf; 681 bool aborted = setjmp(jmpBuf); 682 if (!aborted) { 683 bool codeCompiled = dvmCompilerDoWork(&work); 684 /* 685 * Make sure we are still operating with the 686 * same translation cache version. See 687 * Issue 4271784 for details. 688 */ 689 dvmLockMutex(&gDvmJit.compilerLock); 690 if ((work.result.cacheVersion == 691 gDvmJit.cacheVersion) && 692 codeCompiled && 693 !work.result.discardResult && 694 work.result.codeAddress) { 695 dvmJitSetCodeAddr(work.pc, work.result.codeAddress, 696 work.result.instructionSet, 697 false, /* not method entry */ 698 work.result.profileCodeSize); 699 } 700 dvmUnlockMutex(&gDvmJit.compilerLock); 701 } 702 dvmCompilerArenaReset(); 703 } 704 free(work.info); 705#if defined(WITH_JIT_TUNING) 706 gDvmJit.jitTime += dvmGetRelativeTimeUsec() - startTime; 707#endif 708 dvmLockMutex(&gDvmJit.compilerLock); 709 } while (workQueueLength() != 0); 710 } 711 } 712 pthread_cond_signal(&gDvmJit.compilerQueueEmpty); 713 dvmUnlockMutex(&gDvmJit.compilerLock); 714 715 /* 716 * As part of detaching the thread we need to call into Java code to update 717 * the ThreadGroup, and we should not be in VMWAIT state while executing 718 * interpreted code. 719 */ 720 dvmChangeStatus(NULL, THREAD_RUNNING); 721 722 if (gDvm.verboseShutdown) 723 LOGD("Compiler thread shutting down"); 724 return NULL; 725} 726 727bool dvmCompilerStartup(void) 728{ 729 730 dvmInitMutex(&gDvmJit.compilerLock); 731 dvmInitMutex(&gDvmJit.compilerICPatchLock); 732 dvmInitMutex(&gDvmJit.codeCacheProtectionLock); 733 dvmLockMutex(&gDvmJit.compilerLock); 734 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL); 735 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL); 736 737 /* Reset the work queue */ 738 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0; 739 gDvmJit.compilerQueueLength = 0; 740 dvmUnlockMutex(&gDvmJit.compilerLock); 741 742 /* 743 * Defer rest of initialization until we're sure JIT'ng makes sense. Launch 744 * the compiler thread, which will do the real initialization if and 745 * when it is signalled to do so. 746 */ 747 return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler", 748 compilerThreadStart, NULL); 749} 750 751void dvmCompilerShutdown(void) 752{ 753 void *threadReturn; 754 755 /* Disable new translation requests */ 756 gDvmJit.pProfTable = NULL; 757 gDvmJit.pProfTableCopy = NULL; 758 dvmJitUpdateThreadStateAll(); 759 760 if (gDvm.verboseShutdown || 761 gDvmJit.profileMode == kTraceProfilingContinuous) { 762 dvmCompilerDumpStats(); 763 while (gDvmJit.compilerQueueLength) 764 sleep(5); 765 } 766 767 if (gDvmJit.compilerHandle) { 768 769 gDvmJit.haltCompilerThread = true; 770 771 dvmLockMutex(&gDvmJit.compilerLock); 772 pthread_cond_signal(&gDvmJit.compilerQueueActivity); 773 dvmUnlockMutex(&gDvmJit.compilerLock); 774 775 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0) 776 LOGW("Compiler thread join failed"); 777 else if (gDvm.verboseShutdown) 778 LOGD("Compiler thread has shut down"); 779 } 780 781 /* Break loops within the translation cache */ 782 dvmJitUnchainAll(); 783 784 /* 785 * NOTE: our current implementatation doesn't allow for the compiler 786 * thread to be restarted after it exits here. We aren't freeing 787 * the JitTable or the ProfTable because threads which still may be 788 * running or in the process of shutting down may hold references to 789 * them. 790 */ 791} 792 793void dvmCompilerUpdateGlobalState() 794{ 795 bool jitActive; 796 bool jitActivate; 797 bool needUnchain = false; 798 799 /* 800 * The tableLock might not be initialized yet by the compiler thread if 801 * debugger is attached from the very beginning of the VM launch. If 802 * pProfTableCopy is NULL, the lock is not initialized yet and we don't 803 * need to refresh anything either. 804 */ 805 if (gDvmJit.pProfTableCopy == NULL) { 806 return; 807 } 808 809 /* 810 * On the first enabling of method tracing, switch the compiler 811 * into a mode that includes trace support for invokes and returns. 812 * If there are any existing translations, flush them. NOTE: we 813 * can't blindly flush the translation cache because this code 814 * may be executed before the compiler thread has finished 815 * initialization. 816 */ 817 if ((gDvm.activeProfilers != 0) && 818 !gDvmJit.methodTraceSupport) { 819 bool resetRequired; 820 /* 821 * compilerLock will prevent new compilations from being 822 * installed while we are working. 823 */ 824 dvmLockMutex(&gDvmJit.compilerLock); 825 gDvmJit.cacheVersion++; // invalidate compilations in flight 826 gDvmJit.methodTraceSupport = true; 827 resetRequired = (gDvmJit.numCompilations != 0); 828 dvmUnlockMutex(&gDvmJit.compilerLock); 829 if (resetRequired) { 830 dvmSuspendAllThreads(SUSPEND_FOR_CC_RESET); 831 resetCodeCache(); 832 dvmResumeAllThreads(SUSPEND_FOR_CC_RESET); 833 } 834 } 835 836 dvmLockMutex(&gDvmJit.tableLock); 837 jitActive = gDvmJit.pProfTable != NULL; 838 jitActivate = !dvmDebuggerOrProfilerActive(); 839 840 if (jitActivate && !jitActive) { 841 gDvmJit.pProfTable = gDvmJit.pProfTableCopy; 842 } else if (!jitActivate && jitActive) { 843 gDvmJit.pProfTable = NULL; 844 needUnchain = true; 845 } 846 dvmUnlockMutex(&gDvmJit.tableLock); 847 if (needUnchain) 848 dvmJitUnchainAll(); 849 // Make sure all threads have current values 850 dvmJitUpdateThreadStateAll(); 851} 852