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 "Dalvik.h" 18 #include "libdex/DexOpcodes.h" 19 #include "libdex/DexCatch.h" 20 #include "interp/Jit.h" 21 #include "CompilerInternals.h" 22 #include "Dataflow.h" 23 24 static inline bool contentIsInsn(const u2 *codePtr) { 25 u2 instr = *codePtr; 26 Opcode opcode = (Opcode)(instr & 0xff); 27 28 /* 29 * Since the low 8-bit in metadata may look like OP_NOP, we need to check 30 * both the low and whole sub-word to determine whether it is code or data. 31 */ 32 return (opcode != OP_NOP || instr == 0); 33 } 34 35 /* 36 * Parse an instruction, return the length of the instruction 37 */ 38 static inline int parseInsn(const u2 *codePtr, DecodedInstruction *decInsn, 39 bool printMe) 40 { 41 // Don't parse instruction data 42 if (!contentIsInsn(codePtr)) { 43 return 0; 44 } 45 46 u2 instr = *codePtr; 47 Opcode opcode = dexOpcodeFromCodeUnit(instr); 48 49 dexDecodeInstruction(codePtr, decInsn); 50 if (printMe) { 51 char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn, NULL); 52 ALOGD("%p: %#06x %s", codePtr, opcode, decodedString); 53 } 54 return dexGetWidthFromOpcode(opcode); 55 } 56 57 #define UNKNOWN_TARGET 0xffffffff 58 59 /* 60 * Identify block-ending instructions and collect supplemental information 61 * regarding the following instructions. 62 */ 63 static inline bool findBlockBoundary(const Method *caller, MIR *insn, 64 unsigned int curOffset, 65 unsigned int *target, bool *isInvoke, 66 const Method **callee) 67 { 68 switch (insn->dalvikInsn.opcode) { 69 /* Target is not compile-time constant */ 70 case OP_RETURN_VOID: 71 case OP_RETURN: 72 case OP_RETURN_WIDE: 73 case OP_RETURN_OBJECT: 74 case OP_THROW: 75 *target = UNKNOWN_TARGET; 76 break; 77 case OP_INVOKE_VIRTUAL: 78 case OP_INVOKE_VIRTUAL_RANGE: 79 case OP_INVOKE_INTERFACE: 80 case OP_INVOKE_INTERFACE_RANGE: 81 case OP_INVOKE_VIRTUAL_QUICK: 82 case OP_INVOKE_VIRTUAL_QUICK_RANGE: 83 *isInvoke = true; 84 break; 85 case OP_INVOKE_SUPER: 86 case OP_INVOKE_SUPER_RANGE: { 87 int mIndex = caller->clazz->pDvmDex-> 88 pResMethods[insn->dalvikInsn.vB]->methodIndex; 89 const Method *calleeMethod = 90 caller->clazz->super->vtable[mIndex]; 91 92 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) { 93 *target = (unsigned int) calleeMethod->insns; 94 } 95 *isInvoke = true; 96 *callee = calleeMethod; 97 break; 98 } 99 case OP_INVOKE_STATIC: 100 case OP_INVOKE_STATIC_RANGE: { 101 const Method *calleeMethod = 102 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB]; 103 104 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) { 105 *target = (unsigned int) calleeMethod->insns; 106 } 107 *isInvoke = true; 108 *callee = calleeMethod; 109 break; 110 } 111 case OP_INVOKE_SUPER_QUICK: 112 case OP_INVOKE_SUPER_QUICK_RANGE: { 113 const Method *calleeMethod = 114 caller->clazz->super->vtable[insn->dalvikInsn.vB]; 115 116 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) { 117 *target = (unsigned int) calleeMethod->insns; 118 } 119 *isInvoke = true; 120 *callee = calleeMethod; 121 break; 122 } 123 case OP_INVOKE_DIRECT: 124 case OP_INVOKE_DIRECT_RANGE: { 125 const Method *calleeMethod = 126 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB]; 127 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) { 128 *target = (unsigned int) calleeMethod->insns; 129 } 130 *isInvoke = true; 131 *callee = calleeMethod; 132 break; 133 } 134 case OP_GOTO: 135 case OP_GOTO_16: 136 case OP_GOTO_32: 137 *target = curOffset + (int) insn->dalvikInsn.vA; 138 break; 139 140 case OP_IF_EQ: 141 case OP_IF_NE: 142 case OP_IF_LT: 143 case OP_IF_GE: 144 case OP_IF_GT: 145 case OP_IF_LE: 146 *target = curOffset + (int) insn->dalvikInsn.vC; 147 break; 148 149 case OP_IF_EQZ: 150 case OP_IF_NEZ: 151 case OP_IF_LTZ: 152 case OP_IF_GEZ: 153 case OP_IF_GTZ: 154 case OP_IF_LEZ: 155 *target = curOffset + (int) insn->dalvikInsn.vB; 156 break; 157 158 default: 159 return false; 160 } 161 return true; 162 } 163 164 static inline bool isGoto(MIR *insn) 165 { 166 switch (insn->dalvikInsn.opcode) { 167 case OP_GOTO: 168 case OP_GOTO_16: 169 case OP_GOTO_32: 170 return true; 171 default: 172 return false; 173 } 174 } 175 176 /* 177 * Identify unconditional branch instructions 178 */ 179 static inline bool isUnconditionalBranch(MIR *insn) 180 { 181 switch (insn->dalvikInsn.opcode) { 182 case OP_RETURN_VOID: 183 case OP_RETURN: 184 case OP_RETURN_WIDE: 185 case OP_RETURN_OBJECT: 186 return true; 187 default: 188 return isGoto(insn); 189 } 190 } 191 192 /* 193 * dvmHashTableLookup() callback 194 */ 195 static int compareMethod(const CompilerMethodStats *m1, 196 const CompilerMethodStats *m2) 197 { 198 return (int) m1->method - (int) m2->method; 199 } 200 201 /* 202 * Analyze the body of the method to collect high-level information regarding 203 * inlining: 204 * - is empty method? 205 * - is getter/setter? 206 * - can throw exception? 207 * 208 * Currently the inliner only handles getters and setters. When its capability 209 * becomes more sophisticated more information will be retrieved here. 210 */ 211 static int analyzeInlineTarget(DecodedInstruction *dalvikInsn, int attributes, 212 int offset) 213 { 214 int flags = dexGetFlagsFromOpcode(dalvikInsn->opcode); 215 int dalvikOpcode = dalvikInsn->opcode; 216 217 if (flags & kInstrInvoke) { 218 attributes &= ~METHOD_IS_LEAF; 219 } 220 221 if (!(flags & kInstrCanReturn)) { 222 if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] & 223 DF_IS_GETTER)) { 224 attributes &= ~METHOD_IS_GETTER; 225 } 226 if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] & 227 DF_IS_SETTER)) { 228 attributes &= ~METHOD_IS_SETTER; 229 } 230 } 231 232 /* 233 * The expected instruction sequence is setter will never return value and 234 * getter will also do. Clear the bits if the behavior is discovered 235 * otherwise. 236 */ 237 if (flags & kInstrCanReturn) { 238 if (dalvikOpcode == OP_RETURN_VOID) { 239 attributes &= ~METHOD_IS_GETTER; 240 } 241 else { 242 attributes &= ~METHOD_IS_SETTER; 243 } 244 } 245 246 if (flags & kInstrCanThrow) { 247 attributes &= ~METHOD_IS_THROW_FREE; 248 } 249 250 if (offset == 0 && dalvikOpcode == OP_RETURN_VOID) { 251 attributes |= METHOD_IS_EMPTY; 252 } 253 254 /* 255 * Check if this opcode is selected for single stepping. 256 * If so, don't inline the callee as there is no stack frame for the 257 * interpreter to single-step through the instruction. 258 */ 259 if (SINGLE_STEP_OP(dalvikOpcode)) { 260 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER); 261 } 262 263 return attributes; 264 } 265 266 /* 267 * Analyze each method whose traces are ever compiled. Collect a variety of 268 * statistics like the ratio of exercised vs overall code and code bloat 269 * ratios. If isCallee is true, also analyze each instruction in more details 270 * to see if it is suitable for inlining. 271 */ 272 CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method, 273 bool isCallee) 274 { 275 const DexCode *dexCode = dvmGetMethodCode(method); 276 const u2 *codePtr = dexCode->insns; 277 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize; 278 int insnSize = 0; 279 int hashValue = dvmComputeUtf8Hash(method->name); 280 281 CompilerMethodStats dummyMethodEntry; // For hash table lookup 282 CompilerMethodStats *realMethodEntry; // For hash table storage 283 284 /* For lookup only */ 285 dummyMethodEntry.method = method; 286 realMethodEntry = (CompilerMethodStats *) 287 dvmHashTableLookup(gDvmJit.methodStatsTable, 288 hashValue, 289 &dummyMethodEntry, 290 (HashCompareFunc) compareMethod, 291 false); 292 293 /* This method has never been analyzed before - create an entry */ 294 if (realMethodEntry == NULL) { 295 realMethodEntry = 296 (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats)); 297 realMethodEntry->method = method; 298 299 dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue, 300 realMethodEntry, 301 (HashCompareFunc) compareMethod, 302 true); 303 } 304 305 /* This method is invoked as a callee and has been analyzed - just return */ 306 if ((isCallee == true) && (realMethodEntry->attributes & METHOD_IS_CALLEE)) 307 return realMethodEntry; 308 309 /* 310 * Similarly, return if this method has been compiled before as a hot 311 * method already. 312 */ 313 if ((isCallee == false) && 314 (realMethodEntry->attributes & METHOD_IS_HOT)) 315 return realMethodEntry; 316 317 int attributes; 318 319 /* Method hasn't been analyzed for the desired purpose yet */ 320 if (isCallee) { 321 /* Aggressively set the attributes until proven otherwise */ 322 attributes = METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE | 323 METHOD_IS_GETTER | METHOD_IS_SETTER; 324 } else { 325 attributes = METHOD_IS_HOT; 326 } 327 328 /* Count the number of instructions */ 329 while (codePtr < codeEnd) { 330 DecodedInstruction dalvikInsn; 331 int width = parseInsn(codePtr, &dalvikInsn, false); 332 333 /* Terminate when the data section is seen */ 334 if (width == 0) 335 break; 336 337 if (isCallee) { 338 attributes = analyzeInlineTarget(&dalvikInsn, attributes, insnSize); 339 } 340 341 insnSize += width; 342 codePtr += width; 343 } 344 345 /* 346 * Only handle simple getters/setters with one instruction followed by 347 * return 348 */ 349 if ((attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) && 350 (insnSize != 3)) { 351 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER); 352 } 353 354 realMethodEntry->dalvikSize = insnSize * 2; 355 realMethodEntry->attributes |= attributes; 356 357 #if 0 358 /* Uncomment the following to explore various callee patterns */ 359 if (attributes & METHOD_IS_THROW_FREE) { 360 ALOGE("%s%s is inlinable%s", method->clazz->descriptor, method->name, 361 (attributes & METHOD_IS_EMPTY) ? " empty" : ""); 362 } 363 364 if (attributes & METHOD_IS_LEAF) { 365 ALOGE("%s%s is leaf %d%s", method->clazz->descriptor, method->name, 366 insnSize, insnSize < 5 ? " (small)" : ""); 367 } 368 369 if (attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) { 370 ALOGE("%s%s is %s", method->clazz->descriptor, method->name, 371 attributes & METHOD_IS_GETTER ? "getter": "setter"); 372 } 373 if (attributes == 374 (METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE)) { 375 ALOGE("%s%s is inlinable non setter/getter", method->clazz->descriptor, 376 method->name); 377 } 378 #endif 379 380 return realMethodEntry; 381 } 382 383 /* 384 * Crawl the stack of the thread that requesed compilation to see if any of the 385 * ancestors are on the blacklist. 386 */ 387 static bool filterMethodByCallGraph(Thread *thread, const char *curMethodName) 388 { 389 /* Crawl the Dalvik stack frames and compare the method name*/ 390 StackSaveArea *ssaPtr = ((StackSaveArea *) thread->interpSave.curFrame) - 1; 391 while (ssaPtr != ((StackSaveArea *) NULL) - 1) { 392 const Method *method = ssaPtr->method; 393 if (method) { 394 int hashValue = dvmComputeUtf8Hash(method->name); 395 bool found = 396 dvmHashTableLookup(gDvmJit.methodTable, hashValue, 397 (char *) method->name, 398 (HashCompareFunc) strcmp, false) != 399 NULL; 400 if (found) { 401 ALOGD("Method %s (--> %s) found on the JIT %s list", 402 method->name, curMethodName, 403 gDvmJit.includeSelectedMethod ? "white" : "black"); 404 return true; 405 } 406 407 } 408 ssaPtr = ((StackSaveArea *) ssaPtr->prevFrame) - 1; 409 }; 410 return false; 411 } 412 413 /* 414 * Since we are including instructions from possibly a cold method into the 415 * current trace, we need to make sure that all the associated information 416 * with the callee is properly initialized. If not, we punt on this inline 417 * target. 418 * 419 * TODO: volatile instructions will be handled later. 420 */ 421 bool dvmCompilerCanIncludeThisInstruction(const Method *method, 422 const DecodedInstruction *insn) 423 { 424 switch (insn->opcode) { 425 case OP_NEW_INSTANCE: 426 case OP_CHECK_CAST: { 427 ClassObject *classPtr = (ClassObject *)(void*) 428 (method->clazz->pDvmDex->pResClasses[insn->vB]); 429 430 /* Class hasn't been initialized yet */ 431 if (classPtr == NULL) { 432 return false; 433 } 434 return true; 435 } 436 case OP_SGET: 437 case OP_SGET_WIDE: 438 case OP_SGET_OBJECT: 439 case OP_SGET_BOOLEAN: 440 case OP_SGET_BYTE: 441 case OP_SGET_CHAR: 442 case OP_SGET_SHORT: 443 case OP_SPUT: 444 case OP_SPUT_WIDE: 445 case OP_SPUT_OBJECT: 446 case OP_SPUT_BOOLEAN: 447 case OP_SPUT_BYTE: 448 case OP_SPUT_CHAR: 449 case OP_SPUT_SHORT: { 450 void *fieldPtr = (void*) 451 (method->clazz->pDvmDex->pResFields[insn->vB]); 452 453 if (fieldPtr == NULL) { 454 return false; 455 } 456 return true; 457 } 458 case OP_INVOKE_SUPER: 459 case OP_INVOKE_SUPER_RANGE: { 460 int mIndex = method->clazz->pDvmDex-> 461 pResMethods[insn->vB]->methodIndex; 462 const Method *calleeMethod = method->clazz->super->vtable[mIndex]; 463 if (calleeMethod == NULL) { 464 return false; 465 } 466 return true; 467 } 468 case OP_INVOKE_SUPER_QUICK: 469 case OP_INVOKE_SUPER_QUICK_RANGE: { 470 const Method *calleeMethod = method->clazz->super->vtable[insn->vB]; 471 if (calleeMethod == NULL) { 472 return false; 473 } 474 return true; 475 } 476 case OP_INVOKE_STATIC: 477 case OP_INVOKE_STATIC_RANGE: 478 case OP_INVOKE_DIRECT: 479 case OP_INVOKE_DIRECT_RANGE: { 480 const Method *calleeMethod = 481 method->clazz->pDvmDex->pResMethods[insn->vB]; 482 if (calleeMethod == NULL) { 483 return false; 484 } 485 return true; 486 } 487 case OP_CONST_CLASS: { 488 void *classPtr = (void*) 489 (method->clazz->pDvmDex->pResClasses[insn->vB]); 490 491 if (classPtr == NULL) { 492 return false; 493 } 494 return true; 495 } 496 case OP_CONST_STRING_JUMBO: 497 case OP_CONST_STRING: { 498 void *strPtr = (void*) 499 (method->clazz->pDvmDex->pResStrings[insn->vB]); 500 501 if (strPtr == NULL) { 502 return false; 503 } 504 return true; 505 } 506 default: 507 return true; 508 } 509 } 510 511 /* Split an existing block from the specified code offset into two */ 512 static BasicBlock *splitBlock(CompilationUnit *cUnit, 513 unsigned int codeOffset, 514 BasicBlock *origBlock, 515 BasicBlock **immedPredBlockP) 516 { 517 MIR *insn = origBlock->firstMIRInsn; 518 while (insn) { 519 if (insn->offset == codeOffset) break; 520 insn = insn->next; 521 } 522 if (insn == NULL) { 523 ALOGE("Break split failed"); 524 dvmAbort(); 525 } 526 BasicBlock *bottomBlock = dvmCompilerNewBB(kDalvikByteCode, 527 cUnit->numBlocks++); 528 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock); 529 530 bottomBlock->startOffset = codeOffset; 531 bottomBlock->firstMIRInsn = insn; 532 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn; 533 534 /* Handle the taken path */ 535 bottomBlock->taken = origBlock->taken; 536 if (bottomBlock->taken) { 537 origBlock->taken = NULL; 538 dvmCompilerClearBit(bottomBlock->taken->predecessors, origBlock->id); 539 dvmCompilerSetBit(bottomBlock->taken->predecessors, bottomBlock->id); 540 } 541 542 /* Handle the fallthrough path */ 543 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch; 544 bottomBlock->fallThrough = origBlock->fallThrough; 545 origBlock->fallThrough = bottomBlock; 546 origBlock->needFallThroughBranch = true; 547 dvmCompilerSetBit(bottomBlock->predecessors, origBlock->id); 548 if (bottomBlock->fallThrough) { 549 dvmCompilerClearBit(bottomBlock->fallThrough->predecessors, 550 origBlock->id); 551 dvmCompilerSetBit(bottomBlock->fallThrough->predecessors, 552 bottomBlock->id); 553 } 554 555 /* Handle the successor list */ 556 if (origBlock->successorBlockList.blockListType != kNotUsed) { 557 bottomBlock->successorBlockList = origBlock->successorBlockList; 558 origBlock->successorBlockList.blockListType = kNotUsed; 559 GrowableListIterator iterator; 560 561 dvmGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks, 562 &iterator); 563 while (true) { 564 SuccessorBlockInfo *successorBlockInfo = 565 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator); 566 if (successorBlockInfo == NULL) break; 567 BasicBlock *bb = successorBlockInfo->block; 568 dvmCompilerClearBit(bb->predecessors, origBlock->id); 569 dvmCompilerSetBit(bb->predecessors, bottomBlock->id); 570 } 571 } 572 573 origBlock->lastMIRInsn = insn->prev; 574 575 insn->prev->next = NULL; 576 insn->prev = NULL; 577 578 /* 579 * Update the immediate predecessor block pointer so that outgoing edges 580 * can be applied to the proper block. 581 */ 582 if (immedPredBlockP) { 583 assert(*immedPredBlockP == origBlock); 584 *immedPredBlockP = bottomBlock; 585 } 586 return bottomBlock; 587 } 588 589 /* 590 * Given a code offset, find out the block that starts with it. If the offset 591 * is in the middle of an existing block, split it into two. If immedPredBlockP 592 * is non-null and is the block being split, update *immedPredBlockP to point 593 * to the bottom block so that outgoing edges can be setup properly (by the 594 * caller). 595 */ 596 static BasicBlock *findBlock(CompilationUnit *cUnit, 597 unsigned int codeOffset, 598 bool split, bool create, 599 BasicBlock **immedPredBlockP) 600 { 601 GrowableList *blockList = &cUnit->blockList; 602 BasicBlock *bb; 603 unsigned int i; 604 605 for (i = 0; i < blockList->numUsed; i++) { 606 bb = (BasicBlock *) blockList->elemList[i]; 607 if (bb->blockType != kDalvikByteCode) continue; 608 if (bb->startOffset == codeOffset) return bb; 609 /* Check if a branch jumps into the middle of an existing block */ 610 if ((split == true) && (codeOffset > bb->startOffset) && 611 (bb->lastMIRInsn != NULL) && 612 (codeOffset <= bb->lastMIRInsn->offset)) { 613 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb, 614 bb == *immedPredBlockP ? 615 immedPredBlockP : NULL); 616 return newBB; 617 } 618 } 619 if (create) { 620 bb = dvmCompilerNewBB(kDalvikByteCode, cUnit->numBlocks++); 621 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb); 622 bb->startOffset = codeOffset; 623 return bb; 624 } 625 return NULL; 626 } 627 628 /* Dump the CFG into a DOT graph */ 629 void dvmDumpCFG(CompilationUnit *cUnit, const char *dirPrefix) 630 { 631 const Method *method = cUnit->method; 632 FILE *file; 633 char *signature = dexProtoCopyMethodDescriptor(&method->prototype); 634 char startOffset[80]; 635 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset); 636 char *fileName = (char *) dvmCompilerNew( 637 strlen(dirPrefix) + 638 strlen(method->clazz->descriptor) + 639 strlen(method->name) + 640 strlen(signature) + 641 strlen(startOffset) + 642 strlen(".dot") + 1, true); 643 sprintf(fileName, "%s%s%s%s%s.dot", dirPrefix, 644 method->clazz->descriptor, method->name, signature, startOffset); 645 free(signature); 646 647 /* 648 * Convert the special characters into a filesystem- and shell-friendly 649 * format. 650 */ 651 int i; 652 for (i = strlen(dirPrefix); fileName[i]; i++) { 653 if (fileName[i] == '/') { 654 fileName[i] = '_'; 655 } else if (fileName[i] == ';') { 656 fileName[i] = '#'; 657 } else if (fileName[i] == '$') { 658 fileName[i] = '+'; 659 } else if (fileName[i] == '(' || fileName[i] == ')') { 660 fileName[i] = '@'; 661 } else if (fileName[i] == '<' || fileName[i] == '>') { 662 fileName[i] = '='; 663 } 664 } 665 file = fopen(fileName, "w"); 666 if (file == NULL) { 667 return; 668 } 669 fprintf(file, "digraph G {\n"); 670 671 fprintf(file, " rankdir=TB\n"); 672 673 int numReachableBlocks = cUnit->numReachableBlocks; 674 int idx; 675 const GrowableList *blockList = &cUnit->blockList; 676 677 for (idx = 0; idx < numReachableBlocks; idx++) { 678 int blockIdx = cUnit->dfsOrder.elemList[idx]; 679 BasicBlock *bb = (BasicBlock *) dvmGrowableListGetElement(blockList, 680 blockIdx); 681 if (bb == NULL) break; 682 if (bb->blockType == kEntryBlock) { 683 fprintf(file, " entry [shape=Mdiamond];\n"); 684 } else if (bb->blockType == kExitBlock) { 685 fprintf(file, " exit [shape=Mdiamond];\n"); 686 } else if (bb->blockType == kDalvikByteCode) { 687 fprintf(file, " block%04x [shape=record,label = \"{ \\\n", 688 bb->startOffset); 689 const MIR *mir; 690 fprintf(file, " {block id %d\\l}%s\\\n", bb->id, 691 bb->firstMIRInsn ? " | " : " "); 692 for (mir = bb->firstMIRInsn; mir; mir = mir->next) { 693 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset, 694 mir->ssaRep ? 695 dvmCompilerFullDisassembler(cUnit, mir) : 696 dexGetOpcodeName(mir->dalvikInsn.opcode), 697 mir->next ? " | " : " "); 698 } 699 fprintf(file, " }\"];\n\n"); 700 } else if (bb->blockType == kExceptionHandling) { 701 char blockName[BLOCK_NAME_LEN]; 702 703 dvmGetBlockName(bb, blockName); 704 fprintf(file, " %s [shape=invhouse];\n", blockName); 705 } 706 707 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN]; 708 709 if (bb->taken) { 710 dvmGetBlockName(bb, blockName1); 711 dvmGetBlockName(bb->taken, blockName2); 712 fprintf(file, " %s:s -> %s:n [style=dotted]\n", 713 blockName1, blockName2); 714 } 715 if (bb->fallThrough) { 716 dvmGetBlockName(bb, blockName1); 717 dvmGetBlockName(bb->fallThrough, blockName2); 718 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2); 719 } 720 721 if (bb->successorBlockList.blockListType != kNotUsed) { 722 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n", 723 bb->startOffset, 724 (bb->successorBlockList.blockListType == kCatch) ? 725 "Mrecord" : "record"); 726 GrowableListIterator iterator; 727 dvmGrowableListIteratorInit(&bb->successorBlockList.blocks, 728 &iterator); 729 SuccessorBlockInfo *successorBlockInfo = 730 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator); 731 732 int succId = 0; 733 while (true) { 734 if (successorBlockInfo == NULL) break; 735 736 BasicBlock *destBlock = successorBlockInfo->block; 737 SuccessorBlockInfo *nextSuccessorBlockInfo = 738 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator); 739 740 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n", 741 succId++, 742 successorBlockInfo->key, 743 destBlock->startOffset, 744 (nextSuccessorBlockInfo != NULL) ? " | " : " "); 745 746 successorBlockInfo = nextSuccessorBlockInfo; 747 } 748 fprintf(file, " }\"];\n\n"); 749 750 dvmGetBlockName(bb, blockName1); 751 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n", 752 blockName1, bb->startOffset); 753 754 if (bb->successorBlockList.blockListType == kPackedSwitch || 755 bb->successorBlockList.blockListType == kSparseSwitch) { 756 757 dvmGrowableListIteratorInit(&bb->successorBlockList.blocks, 758 &iterator); 759 760 succId = 0; 761 while (true) { 762 SuccessorBlockInfo *successorBlockInfo = 763 (SuccessorBlockInfo *) 764 dvmGrowableListIteratorNext(&iterator); 765 if (successorBlockInfo == NULL) break; 766 767 BasicBlock *destBlock = successorBlockInfo->block; 768 769 dvmGetBlockName(destBlock, blockName2); 770 fprintf(file, " succ%04x:f%d:e -> %s:n\n", 771 bb->startOffset, succId++, 772 blockName2); 773 } 774 } 775 } 776 fprintf(file, "\n"); 777 778 /* 779 * If we need to debug the dominator tree, uncomment the following code 780 */ 781 #if 1 782 dvmGetBlockName(bb, blockName1); 783 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n", 784 blockName1, blockName1); 785 if (bb->iDom) { 786 dvmGetBlockName(bb->iDom, blockName2); 787 fprintf(file, " cfg%s:s -> cfg%s:n\n\n", 788 blockName2, blockName1); 789 } 790 #endif 791 } 792 fprintf(file, "}\n"); 793 fclose(file); 794 } 795 796 /* Verify if all the successor is connected with all the claimed predecessors */ 797 static bool verifyPredInfo(CompilationUnit *cUnit, BasicBlock *bb) 798 { 799 BitVectorIterator bvIterator; 800 801 dvmBitVectorIteratorInit(bb->predecessors, &bvIterator); 802 while (true) { 803 int blockIdx = dvmBitVectorIteratorNext(&bvIterator); 804 if (blockIdx == -1) break; 805 BasicBlock *predBB = (BasicBlock *) 806 dvmGrowableListGetElement(&cUnit->blockList, blockIdx); 807 bool found = false; 808 if (predBB->taken == bb) { 809 found = true; 810 } else if (predBB->fallThrough == bb) { 811 found = true; 812 } else if (predBB->successorBlockList.blockListType != kNotUsed) { 813 GrowableListIterator iterator; 814 dvmGrowableListIteratorInit(&predBB->successorBlockList.blocks, 815 &iterator); 816 while (true) { 817 SuccessorBlockInfo *successorBlockInfo = 818 (SuccessorBlockInfo *) 819 dvmGrowableListIteratorNext(&iterator); 820 if (successorBlockInfo == NULL) break; 821 BasicBlock *succBB = successorBlockInfo->block; 822 if (succBB == bb) { 823 found = true; 824 break; 825 } 826 } 827 } 828 if (found == false) { 829 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN]; 830 dvmGetBlockName(bb, blockName1); 831 dvmGetBlockName(predBB, blockName2); 832 dvmDumpCFG(cUnit, "/sdcard/cfg/"); 833 ALOGE("Successor %s not found from %s", 834 blockName1, blockName2); 835 dvmAbort(); 836 } 837 } 838 return true; 839 } 840 841 /* Identify code range in try blocks and set up the empty catch blocks */ 842 static void processTryCatchBlocks(CompilationUnit *cUnit) 843 { 844 const Method *meth = cUnit->method; 845 const DexCode *pCode = dvmGetMethodCode(meth); 846 int triesSize = pCode->triesSize; 847 int i; 848 int offset; 849 850 if (triesSize == 0) { 851 return; 852 } 853 854 const DexTry *pTries = dexGetTries(pCode); 855 BitVector *tryBlockAddr = cUnit->tryBlockAddr; 856 857 /* Mark all the insn offsets in Try blocks */ 858 for (i = 0; i < triesSize; i++) { 859 const DexTry* pTry = &pTries[i]; 860 /* all in 16-bit units */ 861 int startOffset = pTry->startAddr; 862 int endOffset = startOffset + pTry->insnCount; 863 864 for (offset = startOffset; offset < endOffset; offset++) { 865 dvmCompilerSetBit(tryBlockAddr, offset); 866 } 867 } 868 869 /* Iterate over each of the handlers to enqueue the empty Catch blocks */ 870 offset = dexGetFirstHandlerOffset(pCode); 871 int handlersSize = dexGetHandlersSize(pCode); 872 873 for (i = 0; i < handlersSize; i++) { 874 DexCatchIterator iterator; 875 dexCatchIteratorInit(&iterator, pCode, offset); 876 877 for (;;) { 878 DexCatchHandler* handler = dexCatchIteratorNext(&iterator); 879 880 if (handler == NULL) { 881 break; 882 } 883 884 /* 885 * Create dummy catch blocks first. Since these are created before 886 * other blocks are processed, "split" is specified as false. 887 */ 888 findBlock(cUnit, handler->address, 889 /* split */ 890 false, 891 /* create */ 892 true, 893 /* immedPredBlockP */ 894 NULL); 895 } 896 897 offset = dexCatchIteratorGetEndOffset(&iterator, pCode); 898 } 899 } 900 901 /* Process instructions with the kInstrCanBranch flag */ 902 static void processCanBranch(CompilationUnit *cUnit, BasicBlock *curBlock, 903 MIR *insn, int curOffset, int width, int flags, 904 const u2* codePtr, const u2* codeEnd) 905 { 906 int target = curOffset; 907 switch (insn->dalvikInsn.opcode) { 908 case OP_GOTO: 909 case OP_GOTO_16: 910 case OP_GOTO_32: 911 target += (int) insn->dalvikInsn.vA; 912 break; 913 case OP_IF_EQ: 914 case OP_IF_NE: 915 case OP_IF_LT: 916 case OP_IF_GE: 917 case OP_IF_GT: 918 case OP_IF_LE: 919 target += (int) insn->dalvikInsn.vC; 920 break; 921 case OP_IF_EQZ: 922 case OP_IF_NEZ: 923 case OP_IF_LTZ: 924 case OP_IF_GEZ: 925 case OP_IF_GTZ: 926 case OP_IF_LEZ: 927 target += (int) insn->dalvikInsn.vB; 928 break; 929 default: 930 ALOGE("Unexpected opcode(%d) with kInstrCanBranch set", 931 insn->dalvikInsn.opcode); 932 dvmAbort(); 933 } 934 BasicBlock *takenBlock = findBlock(cUnit, target, 935 /* split */ 936 true, 937 /* create */ 938 true, 939 /* immedPredBlockP */ 940 &curBlock); 941 curBlock->taken = takenBlock; 942 dvmCompilerSetBit(takenBlock->predecessors, curBlock->id); 943 944 /* Always terminate the current block for conditional branches */ 945 if (flags & kInstrCanContinue) { 946 BasicBlock *fallthroughBlock = findBlock(cUnit, 947 curOffset + width, 948 /* 949 * If the method is processed 950 * in sequential order from the 951 * beginning, we don't need to 952 * specify split for continue 953 * blocks. However, this 954 * routine can be called by 955 * compileLoop, which starts 956 * parsing the method from an 957 * arbitrary address in the 958 * method body. 959 */ 960 true, 961 /* create */ 962 true, 963 /* immedPredBlockP */ 964 &curBlock); 965 curBlock->fallThrough = fallthroughBlock; 966 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id); 967 } else if (codePtr < codeEnd) { 968 /* Create a fallthrough block for real instructions (incl. OP_NOP) */ 969 if (contentIsInsn(codePtr)) { 970 findBlock(cUnit, curOffset + width, 971 /* split */ 972 false, 973 /* create */ 974 true, 975 /* immedPredBlockP */ 976 NULL); 977 } 978 } 979 } 980 981 /* Process instructions with the kInstrCanSwitch flag */ 982 static void processCanSwitch(CompilationUnit *cUnit, BasicBlock *curBlock, 983 MIR *insn, int curOffset, int width, int flags) 984 { 985 u2 *switchData= (u2 *) (cUnit->method->insns + curOffset + 986 insn->dalvikInsn.vB); 987 int size; 988 int *keyTable; 989 int *targetTable; 990 int i; 991 int firstKey; 992 993 /* 994 * Packed switch data format: 995 * ushort ident = 0x0100 magic value 996 * ushort size number of entries in the table 997 * int first_key first (and lowest) switch case value 998 * int targets[size] branch targets, relative to switch opcode 999 * 1000 * Total size is (4+size*2) 16-bit code units. 1001 */ 1002 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) { 1003 assert(switchData[0] == kPackedSwitchSignature); 1004 size = switchData[1]; 1005 firstKey = switchData[2] | (switchData[3] << 16); 1006 targetTable = (int *) &switchData[4]; 1007 keyTable = NULL; // Make the compiler happy 1008 /* 1009 * Sparse switch data format: 1010 * ushort ident = 0x0200 magic value 1011 * ushort size number of entries in the table; > 0 1012 * int keys[size] keys, sorted low-to-high; 32-bit aligned 1013 * int targets[size] branch targets, relative to switch opcode 1014 * 1015 * Total size is (2+size*4) 16-bit code units. 1016 */ 1017 } else { 1018 assert(switchData[0] == kSparseSwitchSignature); 1019 size = switchData[1]; 1020 keyTable = (int *) &switchData[2]; 1021 targetTable = (int *) &switchData[2 + size*2]; 1022 firstKey = 0; // To make the compiler happy 1023 } 1024 1025 if (curBlock->successorBlockList.blockListType != kNotUsed) { 1026 ALOGE("Successor block list already in use: %d", 1027 curBlock->successorBlockList.blockListType); 1028 dvmAbort(); 1029 } 1030 curBlock->successorBlockList.blockListType = 1031 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ? 1032 kPackedSwitch : kSparseSwitch; 1033 dvmInitGrowableList(&curBlock->successorBlockList.blocks, size); 1034 1035 for (i = 0; i < size; i++) { 1036 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i], 1037 /* split */ 1038 true, 1039 /* create */ 1040 true, 1041 /* immedPredBlockP */ 1042 &curBlock); 1043 SuccessorBlockInfo *successorBlockInfo = 1044 (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo), 1045 false); 1046 successorBlockInfo->block = caseBlock; 1047 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)? 1048 firstKey + i : keyTable[i]; 1049 dvmInsertGrowableList(&curBlock->successorBlockList.blocks, 1050 (intptr_t) successorBlockInfo); 1051 dvmCompilerSetBit(caseBlock->predecessors, curBlock->id); 1052 } 1053 1054 /* Fall-through case */ 1055 BasicBlock *fallthroughBlock = findBlock(cUnit, 1056 curOffset + width, 1057 /* split */ 1058 false, 1059 /* create */ 1060 true, 1061 /* immedPredBlockP */ 1062 NULL); 1063 curBlock->fallThrough = fallthroughBlock; 1064 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id); 1065 } 1066 1067 /* Process instructions with the kInstrCanThrow flag */ 1068 static void processCanThrow(CompilationUnit *cUnit, BasicBlock *curBlock, 1069 MIR *insn, int curOffset, int width, int flags, 1070 BitVector *tryBlockAddr, const u2 *codePtr, 1071 const u2* codeEnd) 1072 { 1073 const Method *method = cUnit->method; 1074 const DexCode *dexCode = dvmGetMethodCode(method); 1075 1076 /* In try block */ 1077 if (dvmIsBitSet(tryBlockAddr, curOffset)) { 1078 DexCatchIterator iterator; 1079 1080 if (!dexFindCatchHandler(&iterator, dexCode, curOffset)) { 1081 ALOGE("Catch block not found in dexfile for insn %x in %s", 1082 curOffset, method->name); 1083 dvmAbort(); 1084 1085 } 1086 if (curBlock->successorBlockList.blockListType != kNotUsed) { 1087 ALOGE("Successor block list already in use: %d", 1088 curBlock->successorBlockList.blockListType); 1089 dvmAbort(); 1090 } 1091 curBlock->successorBlockList.blockListType = kCatch; 1092 dvmInitGrowableList(&curBlock->successorBlockList.blocks, 2); 1093 1094 for (;;) { 1095 DexCatchHandler* handler = dexCatchIteratorNext(&iterator); 1096 1097 if (handler == NULL) { 1098 break; 1099 } 1100 1101 BasicBlock *catchBlock = findBlock(cUnit, handler->address, 1102 /* split */ 1103 false, 1104 /* create */ 1105 false, 1106 /* immedPredBlockP */ 1107 NULL); 1108 1109 SuccessorBlockInfo *successorBlockInfo = 1110 (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo), 1111 false); 1112 successorBlockInfo->block = catchBlock; 1113 successorBlockInfo->key = handler->typeIdx; 1114 dvmInsertGrowableList(&curBlock->successorBlockList.blocks, 1115 (intptr_t) successorBlockInfo); 1116 dvmCompilerSetBit(catchBlock->predecessors, curBlock->id); 1117 } 1118 } else { 1119 BasicBlock *ehBlock = dvmCompilerNewBB(kExceptionHandling, 1120 cUnit->numBlocks++); 1121 curBlock->taken = ehBlock; 1122 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock); 1123 ehBlock->startOffset = curOffset; 1124 dvmCompilerSetBit(ehBlock->predecessors, curBlock->id); 1125 } 1126 1127 /* 1128 * Force the current block to terminate. 1129 * 1130 * Data may be present before codeEnd, so we need to parse it to know 1131 * whether it is code or data. 1132 */ 1133 if (codePtr < codeEnd) { 1134 /* Create a fallthrough block for real instructions (incl. OP_NOP) */ 1135 if (contentIsInsn(codePtr)) { 1136 BasicBlock *fallthroughBlock = findBlock(cUnit, 1137 curOffset + width, 1138 /* split */ 1139 false, 1140 /* create */ 1141 true, 1142 /* immedPredBlockP */ 1143 NULL); 1144 /* 1145 * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional 1146 * branches. 1147 */ 1148 if (insn->dalvikInsn.opcode != OP_THROW_VERIFICATION_ERROR && 1149 insn->dalvikInsn.opcode != OP_THROW) { 1150 curBlock->fallThrough = fallthroughBlock; 1151 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id); 1152 } 1153 } 1154 } 1155 } 1156 1157 /* 1158 * Similar to dvmCompileTrace, but the entity processed here is the whole 1159 * method. 1160 * 1161 * TODO: implementation will be revisited when the trace builder can provide 1162 * whole-method traces. 1163 */ 1164 bool dvmCompileMethod(const Method *method, JitTranslationInfo *info) 1165 { 1166 CompilationUnit cUnit; 1167 const DexCode *dexCode = dvmGetMethodCode(method); 1168 const u2 *codePtr = dexCode->insns; 1169 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize; 1170 int numBlocks = 0; 1171 unsigned int curOffset = 0; 1172 1173 /* Method already compiled */ 1174 if (dvmJitGetMethodAddr(codePtr)) { 1175 info->codeAddress = NULL; 1176 return false; 1177 } 1178 1179 memset(&cUnit, 0, sizeof(cUnit)); 1180 cUnit.method = method; 1181 1182 cUnit.jitMode = kJitMethod; 1183 1184 /* Initialize the block list */ 1185 dvmInitGrowableList(&cUnit.blockList, 4); 1186 1187 /* 1188 * FIXME - PC reconstruction list won't be needed after the codegen routines 1189 * are enhanced to true method mode. 1190 */ 1191 /* Initialize the PC reconstruction list */ 1192 dvmInitGrowableList(&cUnit.pcReconstructionList, 8); 1193 1194 /* Allocate the bit-vector to track the beginning of basic blocks */ 1195 BitVector *tryBlockAddr = dvmCompilerAllocBitVector(dexCode->insnsSize, 1196 true /* expandable */); 1197 cUnit.tryBlockAddr = tryBlockAddr; 1198 1199 /* Create the default entry and exit blocks and enter them to the list */ 1200 BasicBlock *entryBlock = dvmCompilerNewBB(kEntryBlock, numBlocks++); 1201 BasicBlock *exitBlock = dvmCompilerNewBB(kExitBlock, numBlocks++); 1202 1203 cUnit.entryBlock = entryBlock; 1204 cUnit.exitBlock = exitBlock; 1205 1206 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) entryBlock); 1207 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) exitBlock); 1208 1209 /* Current block to record parsed instructions */ 1210 BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++); 1211 curBlock->startOffset = 0; 1212 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) curBlock); 1213 entryBlock->fallThrough = curBlock; 1214 dvmCompilerSetBit(curBlock->predecessors, entryBlock->id); 1215 1216 /* 1217 * Store back the number of blocks since new blocks may be created of 1218 * accessing cUnit. 1219 */ 1220 cUnit.numBlocks = numBlocks; 1221 1222 /* Identify code range in try blocks and set up the empty catch blocks */ 1223 processTryCatchBlocks(&cUnit); 1224 1225 /* Parse all instructions and put them into containing basic blocks */ 1226 while (codePtr < codeEnd) { 1227 MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true); 1228 insn->offset = curOffset; 1229 int width = parseInsn(codePtr, &insn->dalvikInsn, false); 1230 insn->width = width; 1231 1232 /* Terminate when the data section is seen */ 1233 if (width == 0) 1234 break; 1235 1236 dvmCompilerAppendMIR(curBlock, insn); 1237 1238 codePtr += width; 1239 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode); 1240 1241 if (flags & kInstrCanBranch) { 1242 processCanBranch(&cUnit, curBlock, insn, curOffset, width, flags, 1243 codePtr, codeEnd); 1244 } else if (flags & kInstrCanReturn) { 1245 curBlock->fallThrough = exitBlock; 1246 dvmCompilerSetBit(exitBlock->predecessors, curBlock->id); 1247 /* 1248 * Terminate the current block if there are instructions 1249 * afterwards. 1250 */ 1251 if (codePtr < codeEnd) { 1252 /* 1253 * Create a fallthrough block for real instructions 1254 * (incl. OP_NOP). 1255 */ 1256 if (contentIsInsn(codePtr)) { 1257 findBlock(&cUnit, curOffset + width, 1258 /* split */ 1259 false, 1260 /* create */ 1261 true, 1262 /* immedPredBlockP */ 1263 NULL); 1264 } 1265 } 1266 } else if (flags & kInstrCanThrow) { 1267 processCanThrow(&cUnit, curBlock, insn, curOffset, width, flags, 1268 tryBlockAddr, codePtr, codeEnd); 1269 } else if (flags & kInstrCanSwitch) { 1270 processCanSwitch(&cUnit, curBlock, insn, curOffset, width, flags); 1271 } 1272 curOffset += width; 1273 BasicBlock *nextBlock = findBlock(&cUnit, curOffset, 1274 /* split */ 1275 false, 1276 /* create */ 1277 false, 1278 /* immedPredBlockP */ 1279 NULL); 1280 if (nextBlock) { 1281 /* 1282 * The next instruction could be the target of a previously parsed 1283 * forward branch so a block is already created. If the current 1284 * instruction is not an unconditional branch, connect them through 1285 * the fall-through link. 1286 */ 1287 assert(curBlock->fallThrough == NULL || 1288 curBlock->fallThrough == nextBlock || 1289 curBlock->fallThrough == exitBlock); 1290 1291 if ((curBlock->fallThrough == NULL) && 1292 (flags & kInstrCanContinue)) { 1293 curBlock->fallThrough = nextBlock; 1294 dvmCompilerSetBit(nextBlock->predecessors, curBlock->id); 1295 } 1296 curBlock = nextBlock; 1297 } 1298 } 1299 1300 if (cUnit.printMe) { 1301 dvmCompilerDumpCompilationUnit(&cUnit); 1302 } 1303 1304 /* Adjust this value accordingly once inlining is performed */ 1305 cUnit.numDalvikRegisters = cUnit.method->registersSize; 1306 1307 /* Verify if all blocks are connected as claimed */ 1308 /* FIXME - to be disabled in the future */ 1309 dvmCompilerDataFlowAnalysisDispatcher(&cUnit, verifyPredInfo, 1310 kAllNodes, 1311 false /* isIterative */); 1312 1313 1314 /* Perform SSA transformation for the whole method */ 1315 dvmCompilerMethodSSATransformation(&cUnit); 1316 1317 #ifndef ARCH_IA32 1318 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming 1319 1320 /* Allocate Registers using simple local allocation scheme */ 1321 dvmCompilerLocalRegAlloc(&cUnit); 1322 #endif 1323 1324 /* Convert MIR to LIR, etc. */ 1325 dvmCompilerMethodMIR2LIR(&cUnit); 1326 1327 // Debugging only 1328 //dvmDumpCFG(&cUnit, "/sdcard/cfg/"); 1329 1330 /* Method is not empty */ 1331 if (cUnit.firstLIRInsn) { 1332 /* Convert LIR into machine code. Loop for recoverable retries */ 1333 do { 1334 dvmCompilerAssembleLIR(&cUnit, info); 1335 cUnit.assemblerRetries++; 1336 if (cUnit.printMe && cUnit.assemblerStatus != kSuccess) 1337 ALOGD("Assembler abort #%d on %d",cUnit.assemblerRetries, 1338 cUnit.assemblerStatus); 1339 } while (cUnit.assemblerStatus == kRetryAll); 1340 1341 if (cUnit.printMe) { 1342 dvmCompilerCodegenDump(&cUnit); 1343 } 1344 1345 if (info->codeAddress) { 1346 dvmJitSetCodeAddr(dexCode->insns, info->codeAddress, 1347 info->instructionSet, true, 0); 1348 /* 1349 * Clear the codeAddress for the enclosing trace to reuse the info 1350 */ 1351 info->codeAddress = NULL; 1352 } 1353 } 1354 1355 return false; 1356 } 1357 1358 /* Extending the trace by crawling the code from curBlock */ 1359 static bool exhaustTrace(CompilationUnit *cUnit, BasicBlock *curBlock) 1360 { 1361 unsigned int curOffset = curBlock->startOffset; 1362 const u2 *codePtr = cUnit->method->insns + curOffset; 1363 1364 if (curBlock->visited == true) return false; 1365 1366 curBlock->visited = true; 1367 1368 if (curBlock->blockType == kEntryBlock || 1369 curBlock->blockType == kExitBlock) { 1370 return false; 1371 } 1372 1373 /* 1374 * Block has been parsed - check the taken/fallThrough in case it is a split 1375 * block. 1376 */ 1377 if (curBlock->firstMIRInsn != NULL) { 1378 bool changed = false; 1379 if (curBlock->taken) 1380 changed |= exhaustTrace(cUnit, curBlock->taken); 1381 if (curBlock->fallThrough) 1382 changed |= exhaustTrace(cUnit, curBlock->fallThrough); 1383 return changed; 1384 } 1385 while (true) { 1386 MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true); 1387 insn->offset = curOffset; 1388 int width = parseInsn(codePtr, &insn->dalvikInsn, false); 1389 insn->width = width; 1390 1391 /* Terminate when the data section is seen */ 1392 if (width == 0) 1393 break; 1394 1395 dvmCompilerAppendMIR(curBlock, insn); 1396 1397 codePtr += width; 1398 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode); 1399 1400 /* Stop extending the trace after seeing these instructions */ 1401 if (flags & (kInstrCanReturn | kInstrCanSwitch | kInstrInvoke)) { 1402 curBlock->fallThrough = cUnit->exitBlock; 1403 dvmCompilerSetBit(cUnit->exitBlock->predecessors, curBlock->id); 1404 break; 1405 } else if (flags & kInstrCanBranch) { 1406 processCanBranch(cUnit, curBlock, insn, curOffset, width, flags, 1407 codePtr, NULL); 1408 if (curBlock->taken) { 1409 exhaustTrace(cUnit, curBlock->taken); 1410 } 1411 if (curBlock->fallThrough) { 1412 exhaustTrace(cUnit, curBlock->fallThrough); 1413 } 1414 break; 1415 } 1416 curOffset += width; 1417 BasicBlock *nextBlock = findBlock(cUnit, curOffset, 1418 /* split */ 1419 false, 1420 /* create */ 1421 false, 1422 /* immedPredBlockP */ 1423 NULL); 1424 if (nextBlock) { 1425 /* 1426 * The next instruction could be the target of a previously parsed 1427 * forward branch so a block is already created. If the current 1428 * instruction is not an unconditional branch, connect them through 1429 * the fall-through link. 1430 */ 1431 assert(curBlock->fallThrough == NULL || 1432 curBlock->fallThrough == nextBlock || 1433 curBlock->fallThrough == cUnit->exitBlock); 1434 1435 if ((curBlock->fallThrough == NULL) && 1436 (flags & kInstrCanContinue)) { 1437 curBlock->needFallThroughBranch = true; 1438 curBlock->fallThrough = nextBlock; 1439 dvmCompilerSetBit(nextBlock->predecessors, curBlock->id); 1440 } 1441 /* Block has been visited - no more parsing needed */ 1442 if (nextBlock->visited == true) { 1443 return true; 1444 } 1445 curBlock = nextBlock; 1446 } 1447 } 1448 return true; 1449 } 1450 1451 /* Compile a loop */ 1452 static bool compileLoop(CompilationUnit *cUnit, unsigned int startOffset, 1453 JitTraceDescription *desc, int numMaxInsts, 1454 JitTranslationInfo *info, jmp_buf *bailPtr, 1455 int optHints) 1456 { 1457 int numBlocks = 0; 1458 unsigned int curOffset = startOffset; 1459 bool changed; 1460 BasicBlock *bb; 1461 #if defined(WITH_JIT_TUNING) 1462 CompilerMethodStats *methodStats; 1463 #endif 1464 1465 cUnit->jitMode = kJitLoop; 1466 1467 /* Initialize the block list */ 1468 dvmInitGrowableList(&cUnit->blockList, 4); 1469 1470 /* Initialize the PC reconstruction list */ 1471 dvmInitGrowableList(&cUnit->pcReconstructionList, 8); 1472 1473 /* Create the default entry and exit blocks and enter them to the list */ 1474 BasicBlock *entryBlock = dvmCompilerNewBB(kEntryBlock, numBlocks++); 1475 entryBlock->startOffset = curOffset; 1476 BasicBlock *exitBlock = dvmCompilerNewBB(kExitBlock, numBlocks++); 1477 1478 cUnit->entryBlock = entryBlock; 1479 cUnit->exitBlock = exitBlock; 1480 1481 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) entryBlock); 1482 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) exitBlock); 1483 1484 /* Current block to record parsed instructions */ 1485 BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++); 1486 curBlock->startOffset = curOffset; 1487 1488 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) curBlock); 1489 entryBlock->fallThrough = curBlock; 1490 dvmCompilerSetBit(curBlock->predecessors, entryBlock->id); 1491 1492 /* 1493 * Store back the number of blocks since new blocks may be created of 1494 * accessing cUnit. 1495 */ 1496 cUnit->numBlocks = numBlocks; 1497 1498 do { 1499 dvmCompilerDataFlowAnalysisDispatcher(cUnit, 1500 dvmCompilerClearVisitedFlag, 1501 kAllNodes, 1502 false /* isIterative */); 1503 changed = exhaustTrace(cUnit, curBlock); 1504 } while (changed); 1505 1506 /* Backward chaining block */ 1507 bb = dvmCompilerNewBB(kChainingCellBackwardBranch, cUnit->numBlocks++); 1508 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb); 1509 cUnit->backChainBlock = bb; 1510 1511 /* A special block to host PC reconstruction code */ 1512 bb = dvmCompilerNewBB(kPCReconstruction, cUnit->numBlocks++); 1513 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb); 1514 1515 /* And one final block that publishes the PC and raises the exception */ 1516 bb = dvmCompilerNewBB(kExceptionHandling, cUnit->numBlocks++); 1517 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb); 1518 cUnit->puntBlock = bb; 1519 1520 cUnit->numDalvikRegisters = cUnit->method->registersSize; 1521 1522 /* Verify if all blocks are connected as claimed */ 1523 /* FIXME - to be disabled in the future */ 1524 dvmCompilerDataFlowAnalysisDispatcher(cUnit, verifyPredInfo, 1525 kAllNodes, 1526 false /* isIterative */); 1527 1528 1529 /* Try to identify a loop */ 1530 if (!dvmCompilerBuildLoop(cUnit)) 1531 goto bail; 1532 1533 dvmCompilerLoopOpt(cUnit); 1534 1535 /* 1536 * Change the backward branch to the backward chaining cell after dataflow 1537 * analsys/optimizations are done. 1538 */ 1539 dvmCompilerInsertBackwardChaining(cUnit); 1540 1541 #if defined(ARCH_IA32) 1542 /* Convert MIR to LIR, etc. */ 1543 dvmCompilerMIR2LIR(cUnit, info); 1544 #else 1545 dvmCompilerInitializeRegAlloc(cUnit); 1546 1547 /* Allocate Registers using simple local allocation scheme */ 1548 dvmCompilerLocalRegAlloc(cUnit); 1549 1550 /* Convert MIR to LIR, etc. */ 1551 dvmCompilerMIR2LIR(cUnit); 1552 #endif 1553 1554 /* Loop contains never executed blocks / heavy instructions */ 1555 if (cUnit->quitLoopMode) { 1556 if (cUnit->printMe || gDvmJit.receivedSIGUSR2) { 1557 ALOGD("Loop trace @ offset %04x aborted due to unresolved code info", 1558 cUnit->entryBlock->startOffset); 1559 } 1560 goto bail; 1561 } 1562 1563 /* Convert LIR into machine code. Loop for recoverable retries */ 1564 do { 1565 dvmCompilerAssembleLIR(cUnit, info); 1566 cUnit->assemblerRetries++; 1567 if (cUnit->printMe && cUnit->assemblerStatus != kSuccess) 1568 ALOGD("Assembler abort #%d on %d", cUnit->assemblerRetries, 1569 cUnit->assemblerStatus); 1570 } while (cUnit->assemblerStatus == kRetryAll); 1571 1572 /* Loop is too big - bail out */ 1573 if (cUnit->assemblerStatus == kRetryHalve) { 1574 goto bail; 1575 } 1576 1577 if (cUnit->printMe || gDvmJit.receivedSIGUSR2) { 1578 ALOGD("Loop trace @ offset %04x", cUnit->entryBlock->startOffset); 1579 dvmCompilerCodegenDump(cUnit); 1580 } 1581 1582 /* 1583 * If this trace uses class objects as constants, 1584 * dvmJitInstallClassObjectPointers will switch the thread state 1585 * to running and look up the class pointers using the descriptor/loader 1586 * tuple stored in the callsite info structure. We need to make this window 1587 * as short as possible since it is blocking GC. 1588 */ 1589 if (cUnit->hasClassLiterals && info->codeAddress) { 1590 dvmJitInstallClassObjectPointers(cUnit, (char *) info->codeAddress); 1591 } 1592 1593 /* 1594 * Since callsiteinfo is allocated from the arena, delay the reset until 1595 * class pointers are resolved. 1596 */ 1597 dvmCompilerArenaReset(); 1598 1599 assert(cUnit->assemblerStatus == kSuccess); 1600 #if defined(WITH_JIT_TUNING) 1601 /* Locate the entry to store compilation statistics for this method */ 1602 methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false); 1603 methodStats->nativeSize += cUnit->totalSize; 1604 #endif 1605 return info->codeAddress != NULL; 1606 1607 bail: 1608 /* Retry the original trace with JIT_OPT_NO_LOOP disabled */ 1609 dvmCompilerArenaReset(); 1610 return dvmCompileTrace(desc, numMaxInsts, info, bailPtr, 1611 optHints | JIT_OPT_NO_LOOP); 1612 } 1613 1614 static bool searchClassTablePrefix(const Method* method) { 1615 if (gDvmJit.classTable == NULL) { 1616 return false; 1617 } 1618 HashIter iter; 1619 HashTable* pTab = gDvmJit.classTable; 1620 for (dvmHashIterBegin(pTab, &iter); !dvmHashIterDone(&iter); 1621 dvmHashIterNext(&iter)) 1622 { 1623 const char* str = (const char*) dvmHashIterData(&iter); 1624 if (strncmp(method->clazz->descriptor, str, strlen(str)) == 0) { 1625 return true; 1626 } 1627 } 1628 return false; 1629 } 1630 1631 /* 1632 * Main entry point to start trace compilation. Basic blocks are constructed 1633 * first and they will be passed to the codegen routines to convert Dalvik 1634 * bytecode into machine code. 1635 */ 1636 bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, 1637 JitTranslationInfo *info, jmp_buf *bailPtr, 1638 int optHints) 1639 { 1640 const DexCode *dexCode = dvmGetMethodCode(desc->method); 1641 const JitTraceRun* currRun = &desc->trace[0]; 1642 unsigned int curOffset = currRun->info.frag.startOffset; 1643 unsigned int startOffset = curOffset; 1644 unsigned int numInsts = currRun->info.frag.numInsts; 1645 const u2 *codePtr = dexCode->insns + curOffset; 1646 int traceSize = 0; // # of half-words 1647 const u2 *startCodePtr = codePtr; 1648 BasicBlock *curBB, *entryCodeBB; 1649 int numBlocks = 0; 1650 static int compilationId; 1651 CompilationUnit cUnit; 1652 GrowableList *blockList; 1653 #if defined(WITH_JIT_TUNING) 1654 CompilerMethodStats *methodStats; 1655 #endif 1656 1657 /* If we've already compiled this trace, just return success */ 1658 if (dvmJitGetTraceAddr(startCodePtr) && !info->discardResult) { 1659 /* 1660 * Make sure the codeAddress is NULL so that it won't clobber the 1661 * existing entry. 1662 */ 1663 info->codeAddress = NULL; 1664 return true; 1665 } 1666 1667 /* If the work order is stale, discard it */ 1668 if (info->cacheVersion != gDvmJit.cacheVersion) { 1669 return false; 1670 } 1671 1672 compilationId++; 1673 memset(&cUnit, 0, sizeof(CompilationUnit)); 1674 1675 #if defined(WITH_JIT_TUNING) 1676 /* Locate the entry to store compilation statistics for this method */ 1677 methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false); 1678 #endif 1679 1680 /* Set the recover buffer pointer */ 1681 cUnit.bailPtr = bailPtr; 1682 1683 /* Initialize the printMe flag */ 1684 cUnit.printMe = gDvmJit.printMe; 1685 1686 /* Setup the method */ 1687 cUnit.method = desc->method; 1688 1689 /* Store the trace descriptor and set the initial mode */ 1690 cUnit.traceDesc = desc; 1691 cUnit.jitMode = kJitTrace; 1692 1693 /* Initialize the PC reconstruction list */ 1694 dvmInitGrowableList(&cUnit.pcReconstructionList, 8); 1695 1696 /* Initialize the basic block list */ 1697 blockList = &cUnit.blockList; 1698 dvmInitGrowableList(blockList, 8); 1699 1700 /* Identify traces that we don't want to compile */ 1701 if (gDvmJit.classTable) { 1702 bool classFound = searchClassTablePrefix(desc->method); 1703 if (gDvmJit.classTable && gDvmJit.includeSelectedMethod != classFound) { 1704 return false; 1705 } 1706 } 1707 if (gDvmJit.methodTable) { 1708 int len = strlen(desc->method->clazz->descriptor) + 1709 strlen(desc->method->name) + 1; 1710 char *fullSignature = (char *)dvmCompilerNew(len, true); 1711 strcpy(fullSignature, desc->method->clazz->descriptor); 1712 strcat(fullSignature, desc->method->name); 1713 1714 int hashValue = dvmComputeUtf8Hash(fullSignature); 1715 1716 /* 1717 * Doing three levels of screening to see whether we want to skip 1718 * compiling this method 1719 */ 1720 1721 /* First, check the full "class;method" signature */ 1722 bool methodFound = 1723 dvmHashTableLookup(gDvmJit.methodTable, hashValue, 1724 fullSignature, (HashCompareFunc) strcmp, 1725 false) != 1726 NULL; 1727 1728 /* Full signature not found - check the enclosing class */ 1729 if (methodFound == false) { 1730 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor); 1731 methodFound = 1732 dvmHashTableLookup(gDvmJit.methodTable, hashValue, 1733 (char *) desc->method->clazz->descriptor, 1734 (HashCompareFunc) strcmp, false) != 1735 NULL; 1736 /* Enclosing class not found - check the method name */ 1737 if (methodFound == false) { 1738 int hashValue = dvmComputeUtf8Hash(desc->method->name); 1739 methodFound = 1740 dvmHashTableLookup(gDvmJit.methodTable, hashValue, 1741 (char *) desc->method->name, 1742 (HashCompareFunc) strcmp, false) != 1743 NULL; 1744 1745 /* 1746 * Debug by call-graph is enabled. Check if the debug list 1747 * covers any methods on the VM stack. 1748 */ 1749 if (methodFound == false && gDvmJit.checkCallGraph == true) { 1750 methodFound = 1751 filterMethodByCallGraph(info->requestingThread, 1752 desc->method->name); 1753 } 1754 } 1755 } 1756 1757 /* 1758 * Under the following conditions, the trace will be *conservatively* 1759 * compiled by only containing single-step instructions to and from the 1760 * interpreter. 1761 * 1) If includeSelectedMethod == false, the method matches the full or 1762 * partial signature stored in the hash table. 1763 * 1764 * 2) If includeSelectedMethod == true, the method does not match the 1765 * full and partial signature stored in the hash table. 1766 */ 1767 if (gDvmJit.methodTable && gDvmJit.includeSelectedMethod != methodFound) { 1768 #ifdef ARCH_IA32 1769 return false; 1770 #else 1771 cUnit.allSingleStep = true; 1772 #endif 1773 } else { 1774 /* Compile the trace as normal */ 1775 1776 /* Print the method we cherry picked */ 1777 if (gDvmJit.includeSelectedMethod == true) { 1778 cUnit.printMe = true; 1779 } 1780 } 1781 } 1782 1783 // Each pair is a range, check whether curOffset falls into a range. 1784 bool includeOffset = (gDvmJit.num_entries_pcTable < 2); 1785 for (int pcOff = 0; pcOff < gDvmJit.num_entries_pcTable; ) { 1786 if (pcOff+1 >= gDvmJit.num_entries_pcTable) { 1787 break; 1788 } 1789 if (curOffset >= gDvmJit.pcTable[pcOff] && curOffset <= gDvmJit.pcTable[pcOff+1]) { 1790 includeOffset = true; 1791 break; 1792 } 1793 pcOff += 2; 1794 } 1795 if (!includeOffset) { 1796 return false; 1797 } 1798 1799 /* Allocate the entry block */ 1800 curBB = dvmCompilerNewBB(kEntryBlock, numBlocks++); 1801 dvmInsertGrowableList(blockList, (intptr_t) curBB); 1802 curBB->startOffset = curOffset; 1803 1804 entryCodeBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++); 1805 dvmInsertGrowableList(blockList, (intptr_t) entryCodeBB); 1806 entryCodeBB->startOffset = curOffset; 1807 curBB->fallThrough = entryCodeBB; 1808 curBB = entryCodeBB; 1809 1810 if (cUnit.printMe) { 1811 ALOGD("--------\nCompiler: Building trace for %s, offset %#x", 1812 desc->method->name, curOffset); 1813 } 1814 1815 /* 1816 * Analyze the trace descriptor and include up to the maximal number 1817 * of Dalvik instructions into the IR. 1818 */ 1819 while (1) { 1820 MIR *insn; 1821 int width; 1822 insn = (MIR *)dvmCompilerNew(sizeof(MIR), true); 1823 insn->offset = curOffset; 1824 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe); 1825 1826 /* The trace should never incude instruction data */ 1827 assert(width); 1828 insn->width = width; 1829 traceSize += width; 1830 dvmCompilerAppendMIR(curBB, insn); 1831 cUnit.numInsts++; 1832 1833 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode); 1834 1835 if (flags & kInstrInvoke) { 1836 const Method *calleeMethod = (const Method *) 1837 currRun[JIT_TRACE_CUR_METHOD].info.meta; 1838 assert(numInsts == 1); 1839 CallsiteInfo *callsiteInfo = 1840 (CallsiteInfo *)dvmCompilerNew(sizeof(CallsiteInfo), true); 1841 callsiteInfo->classDescriptor = (const char *) 1842 currRun[JIT_TRACE_CLASS_DESC].info.meta; 1843 callsiteInfo->classLoader = (Object *) 1844 currRun[JIT_TRACE_CLASS_LOADER].info.meta; 1845 callsiteInfo->method = calleeMethod; 1846 insn->meta.callsiteInfo = callsiteInfo; 1847 } 1848 1849 /* Instruction limit reached - terminate the trace here */ 1850 if (cUnit.numInsts >= numMaxInsts) { 1851 break; 1852 } 1853 if (--numInsts == 0) { 1854 if (currRun->info.frag.runEnd) { 1855 break; 1856 } else { 1857 /* Advance to the next trace description (ie non-meta info) */ 1858 do { 1859 currRun++; 1860 } while (!currRun->isCode); 1861 1862 /* Dummy end-of-run marker seen */ 1863 if (currRun->info.frag.numInsts == 0) { 1864 break; 1865 } 1866 1867 curBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++); 1868 dvmInsertGrowableList(blockList, (intptr_t) curBB); 1869 curOffset = currRun->info.frag.startOffset; 1870 numInsts = currRun->info.frag.numInsts; 1871 curBB->startOffset = curOffset; 1872 codePtr = dexCode->insns + curOffset; 1873 } 1874 } else { 1875 curOffset += width; 1876 codePtr += width; 1877 } 1878 } 1879 1880 #if defined(WITH_JIT_TUNING) 1881 /* Convert # of half-word to bytes */ 1882 methodStats->compiledDalvikSize += traceSize * 2; 1883 #endif 1884 1885 /* 1886 * Now scan basic blocks containing real code to connect the 1887 * taken/fallthrough links. Also create chaining cells for code not included 1888 * in the trace. 1889 */ 1890 size_t blockId; 1891 for (blockId = 0; blockId < blockList->numUsed; blockId++) { 1892 curBB = (BasicBlock *) dvmGrowableListGetElement(blockList, blockId); 1893 MIR *lastInsn = curBB->lastMIRInsn; 1894 /* Skip empty blocks */ 1895 if (lastInsn == NULL) { 1896 continue; 1897 } 1898 curOffset = lastInsn->offset; 1899 unsigned int targetOffset = curOffset; 1900 unsigned int fallThroughOffset = curOffset + lastInsn->width; 1901 bool isInvoke = false; 1902 const Method *callee = NULL; 1903 1904 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset, 1905 &targetOffset, &isInvoke, &callee); 1906 1907 /* Link the taken and fallthrough blocks */ 1908 BasicBlock *searchBB; 1909 1910 int flags = dexGetFlagsFromOpcode(lastInsn->dalvikInsn.opcode); 1911 1912 if (flags & kInstrInvoke) { 1913 cUnit.hasInvoke = true; 1914 } 1915 1916 /* Backward branch seen */ 1917 if (isInvoke == false && 1918 (flags & kInstrCanBranch) != 0 && 1919 targetOffset < curOffset && 1920 (optHints & JIT_OPT_NO_LOOP) == 0) { 1921 dvmCompilerArenaReset(); 1922 return compileLoop(&cUnit, startOffset, desc, numMaxInsts, 1923 info, bailPtr, optHints); 1924 } 1925 1926 /* No backward branch in the trace - start searching the next BB */ 1927 size_t searchBlockId; 1928 for (searchBlockId = blockId+1; searchBlockId < blockList->numUsed; 1929 searchBlockId++) { 1930 searchBB = (BasicBlock *) dvmGrowableListGetElement(blockList, 1931 searchBlockId); 1932 if (targetOffset == searchBB->startOffset) { 1933 curBB->taken = searchBB; 1934 dvmCompilerSetBit(searchBB->predecessors, curBB->id); 1935 } 1936 if (fallThroughOffset == searchBB->startOffset) { 1937 curBB->fallThrough = searchBB; 1938 dvmCompilerSetBit(searchBB->predecessors, curBB->id); 1939 1940 /* 1941 * Fallthrough block of an invoke instruction needs to be 1942 * aligned to 4-byte boundary (alignment instruction to be 1943 * inserted later. 1944 */ 1945 if (flags & kInstrInvoke) { 1946 searchBB->isFallThroughFromInvoke = true; 1947 } 1948 } 1949 } 1950 1951 /* 1952 * Some blocks are ended by non-control-flow-change instructions, 1953 * currently only due to trace length constraint. In this case we need 1954 * to generate an explicit branch at the end of the block to jump to 1955 * the chaining cell. 1956 */ 1957 curBB->needFallThroughBranch = 1958 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn | 1959 kInstrInvoke)) == 0); 1960 if (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH || 1961 lastInsn->dalvikInsn.opcode == OP_SPARSE_SWITCH) { 1962 int i; 1963 const u2 *switchData = desc->method->insns + lastInsn->offset + 1964 lastInsn->dalvikInsn.vB; 1965 int size = switchData[1]; 1966 int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES); 1967 1968 /* 1969 * Generate the landing pad for cases whose ranks are higher than 1970 * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter 1971 * through the NoChain point. 1972 */ 1973 if (maxChains != size) { 1974 cUnit.switchOverflowPad = 1975 desc->method->insns + lastInsn->offset; 1976 } 1977 1978 s4 *targets = (s4 *) (switchData + 2 + 1979 (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ? 1980 2 : size * 2)); 1981 1982 /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */ 1983 for (i = 0; i < maxChains; i++) { 1984 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal, 1985 numBlocks++); 1986 dvmInsertGrowableList(blockList, (intptr_t) caseChain); 1987 caseChain->startOffset = lastInsn->offset + targets[i]; 1988 } 1989 1990 /* One more chaining cell for the default case */ 1991 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal, 1992 numBlocks++); 1993 dvmInsertGrowableList(blockList, (intptr_t) caseChain); 1994 caseChain->startOffset = lastInsn->offset + lastInsn->width; 1995 /* Fallthrough block not included in the trace */ 1996 } else if (!isUnconditionalBranch(lastInsn) && 1997 curBB->fallThrough == NULL) { 1998 BasicBlock *fallThroughBB; 1999 /* 2000 * If the chaining cell is after an invoke or 2001 * instruction that cannot change the control flow, request a hot 2002 * chaining cell. 2003 */ 2004 if (isInvoke || curBB->needFallThroughBranch) { 2005 fallThroughBB = dvmCompilerNewBB(kChainingCellHot, numBlocks++); 2006 } else { 2007 fallThroughBB = dvmCompilerNewBB(kChainingCellNormal, 2008 numBlocks++); 2009 } 2010 dvmInsertGrowableList(blockList, (intptr_t) fallThroughBB); 2011 fallThroughBB->startOffset = fallThroughOffset; 2012 curBB->fallThrough = fallThroughBB; 2013 dvmCompilerSetBit(fallThroughBB->predecessors, curBB->id); 2014 } 2015 /* Target block not included in the trace */ 2016 if (curBB->taken == NULL && 2017 (isGoto(lastInsn) || isInvoke || 2018 (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) { 2019 BasicBlock *newBB = NULL; 2020 if (isInvoke) { 2021 /* Monomorphic callee */ 2022 if (callee) { 2023 /* JNI call doesn't need a chaining cell */ 2024 if (!dvmIsNativeMethod(callee)) { 2025 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton, 2026 numBlocks++); 2027 newBB->startOffset = 0; 2028 newBB->containingMethod = callee; 2029 } 2030 /* Will resolve at runtime */ 2031 } else { 2032 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted, 2033 numBlocks++); 2034 newBB->startOffset = 0; 2035 } 2036 /* For unconditional branches, request a hot chaining cell */ 2037 } else { 2038 #if !defined(WITH_SELF_VERIFICATION) 2039 newBB = dvmCompilerNewBB(dexIsGoto(flags) ? 2040 kChainingCellHot : 2041 kChainingCellNormal, 2042 numBlocks++); 2043 newBB->startOffset = targetOffset; 2044 #else 2045 /* Handle branches that branch back into the block */ 2046 if (targetOffset >= curBB->firstMIRInsn->offset && 2047 targetOffset <= curBB->lastMIRInsn->offset) { 2048 newBB = dvmCompilerNewBB(kChainingCellBackwardBranch, 2049 numBlocks++); 2050 } else { 2051 newBB = dvmCompilerNewBB(dexIsGoto(flags) ? 2052 kChainingCellHot : 2053 kChainingCellNormal, 2054 numBlocks++); 2055 } 2056 newBB->startOffset = targetOffset; 2057 #endif 2058 } 2059 if (newBB) { 2060 curBB->taken = newBB; 2061 dvmCompilerSetBit(newBB->predecessors, curBB->id); 2062 dvmInsertGrowableList(blockList, (intptr_t) newBB); 2063 } 2064 } 2065 } 2066 2067 /* Now create a special block to host PC reconstruction code */ 2068 curBB = dvmCompilerNewBB(kPCReconstruction, numBlocks++); 2069 dvmInsertGrowableList(blockList, (intptr_t) curBB); 2070 2071 /* And one final block that publishes the PC and raise the exception */ 2072 curBB = dvmCompilerNewBB(kExceptionHandling, numBlocks++); 2073 dvmInsertGrowableList(blockList, (intptr_t) curBB); 2074 cUnit.puntBlock = curBB; 2075 2076 if (cUnit.printMe) { 2077 char* signature = 2078 dexProtoCopyMethodDescriptor(&desc->method->prototype); 2079 ALOGD("TRACEINFO (%d): 0x%08x %s%s.%s %#x %d of %d, %d blocks", 2080 compilationId, 2081 (intptr_t) desc->method->insns, 2082 desc->method->clazz->descriptor, 2083 desc->method->name, 2084 signature, 2085 desc->trace[0].info.frag.startOffset, 2086 traceSize, 2087 dexCode->insnsSize, 2088 numBlocks); 2089 free(signature); 2090 } 2091 2092 cUnit.numBlocks = numBlocks; 2093 2094 /* Set the instruction set to use (NOTE: later components may change it) */ 2095 cUnit.instructionSet = dvmCompilerInstructionSet(); 2096 2097 /* Inline transformation @ the MIR level */ 2098 if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) { 2099 dvmCompilerInlineMIR(&cUnit, info); 2100 } 2101 2102 cUnit.numDalvikRegisters = cUnit.method->registersSize; 2103 2104 /* Preparation for SSA conversion */ 2105 dvmInitializeSSAConversion(&cUnit); 2106 2107 dvmCompilerNonLoopAnalysis(&cUnit); 2108 2109 #ifndef ARCH_IA32 2110 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming 2111 #endif 2112 2113 if (cUnit.printMe) { 2114 dvmCompilerDumpCompilationUnit(&cUnit); 2115 } 2116 2117 #ifndef ARCH_IA32 2118 /* Allocate Registers using simple local allocation scheme */ 2119 dvmCompilerLocalRegAlloc(&cUnit); 2120 2121 /* Convert MIR to LIR, etc. */ 2122 dvmCompilerMIR2LIR(&cUnit); 2123 #else /* ARCH_IA32 */ 2124 /* Convert MIR to LIR, etc. */ 2125 dvmCompilerMIR2LIR(&cUnit, info); 2126 #endif 2127 2128 /* Convert LIR into machine code. Loop for recoverable retries */ 2129 do { 2130 dvmCompilerAssembleLIR(&cUnit, info); 2131 cUnit.assemblerRetries++; 2132 if (cUnit.printMe && cUnit.assemblerStatus != kSuccess) 2133 ALOGD("Assembler abort #%d on %d",cUnit.assemblerRetries, 2134 cUnit.assemblerStatus); 2135 } while (cUnit.assemblerStatus == kRetryAll); 2136 2137 if (cUnit.printMe) { 2138 ALOGD("Trace Dalvik PC: %p", startCodePtr); 2139 dvmCompilerCodegenDump(&cUnit); 2140 ALOGD("End %s%s, %d Dalvik instructions", 2141 desc->method->clazz->descriptor, desc->method->name, 2142 cUnit.numInsts); 2143 } 2144 2145 if (cUnit.assemblerStatus == kRetryHalve) { 2146 /* Reset the compiler resource pool before retry */ 2147 dvmCompilerArenaReset(); 2148 2149 /* Halve the instruction count and start from the top */ 2150 return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr, 2151 optHints); 2152 } 2153 2154 /* 2155 * If this trace uses class objects as constants, 2156 * dvmJitInstallClassObjectPointers will switch the thread state 2157 * to running and look up the class pointers using the descriptor/loader 2158 * tuple stored in the callsite info structure. We need to make this window 2159 * as short as possible since it is blocking GC. 2160 */ 2161 if (cUnit.hasClassLiterals && info->codeAddress) { 2162 dvmJitInstallClassObjectPointers(&cUnit, (char *) info->codeAddress); 2163 } 2164 2165 /* 2166 * Since callsiteinfo is allocated from the arena, delay the reset until 2167 * class pointers are resolved. 2168 */ 2169 dvmCompilerArenaReset(); 2170 2171 assert(cUnit.assemblerStatus == kSuccess); 2172 #if defined(WITH_JIT_TUNING) 2173 methodStats->nativeSize += cUnit.totalSize; 2174 #endif 2175 2176 return info->codeAddress != NULL; 2177 } 2178