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