Home | History | Annotate | Download | only in compiler
      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                               BasicBlock **immedPredBlockP)
    541 {
    542     MIR *insn = origBlock->firstMIRInsn;
    543     while (insn) {
    544         if (insn->offset == codeOffset) break;
    545         insn = insn->next;
    546     }
    547     if (insn == NULL) {
    548         LOGE("Break split failed");
    549         dvmAbort();
    550     }
    551     BasicBlock *bottomBlock = dvmCompilerNewBB(kDalvikByteCode,
    552                                                cUnit->numBlocks++);
    553     dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
    554 
    555     bottomBlock->startOffset = codeOffset;
    556     bottomBlock->firstMIRInsn = insn;
    557     bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
    558 
    559     /* Handle the taken path */
    560     bottomBlock->taken = origBlock->taken;
    561     if (bottomBlock->taken) {
    562         origBlock->taken = NULL;
    563         dvmCompilerClearBit(bottomBlock->taken->predecessors, origBlock->id);
    564         dvmCompilerSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
    565     }
    566 
    567     /* Handle the fallthrough path */
    568     bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
    569     bottomBlock->fallThrough = origBlock->fallThrough;
    570     origBlock->fallThrough = bottomBlock;
    571     origBlock->needFallThroughBranch = true;
    572     dvmCompilerSetBit(bottomBlock->predecessors, origBlock->id);
    573     if (bottomBlock->fallThrough) {
    574         dvmCompilerClearBit(bottomBlock->fallThrough->predecessors,
    575                             origBlock->id);
    576         dvmCompilerSetBit(bottomBlock->fallThrough->predecessors,
    577                           bottomBlock->id);
    578     }
    579 
    580     /* Handle the successor list */
    581     if (origBlock->successorBlockList.blockListType != kNotUsed) {
    582         bottomBlock->successorBlockList = origBlock->successorBlockList;
    583         origBlock->successorBlockList.blockListType = kNotUsed;
    584         GrowableListIterator iterator;
    585 
    586         dvmGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
    587                                     &iterator);
    588         while (true) {
    589             SuccessorBlockInfo *successorBlockInfo =
    590                 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
    591             if (successorBlockInfo == NULL) break;
    592             BasicBlock *bb = successorBlockInfo->block;
    593             dvmCompilerClearBit(bb->predecessors, origBlock->id);
    594             dvmCompilerSetBit(bb->predecessors, bottomBlock->id);
    595         }
    596     }
    597 
    598     origBlock->lastMIRInsn = insn->prev;
    599 
    600     insn->prev->next = NULL;
    601     insn->prev = NULL;
    602 
    603     /*
    604      * Update the immediate predecessor block pointer so that outgoing edges
    605      * can be applied to the proper block.
    606      */
    607     if (immedPredBlockP) {
    608         assert(*immedPredBlockP == origBlock);
    609         *immedPredBlockP = bottomBlock;
    610     }
    611     return bottomBlock;
    612 }
    613 
    614 /*
    615  * Given a code offset, find out the block that starts with it. If the offset
    616  * is in the middle of an existing block, split it into two. If immedPredBlockP
    617  * is non-null and is the block being split, update *immedPredBlockP to point
    618  * to the bottom block so that outgoing edges can be setup properly (by the
    619  * caller).
    620  */
    621 static BasicBlock *findBlock(CompilationUnit *cUnit,
    622                              unsigned int codeOffset,
    623                              bool split, bool create,
    624                              BasicBlock **immedPredBlockP)
    625 {
    626     GrowableList *blockList = &cUnit->blockList;
    627     BasicBlock *bb;
    628     unsigned int i;
    629 
    630     for (i = 0; i < blockList->numUsed; i++) {
    631         bb = (BasicBlock *) blockList->elemList[i];
    632         if (bb->blockType != kDalvikByteCode) continue;
    633         if (bb->startOffset == codeOffset) return bb;
    634         /* Check if a branch jumps into the middle of an existing block */
    635         if ((split == true) && (codeOffset > bb->startOffset) &&
    636             (bb->lastMIRInsn != NULL) &&
    637             (codeOffset <= bb->lastMIRInsn->offset)) {
    638             BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
    639                                            bb == *immedPredBlockP ?
    640                                                immedPredBlockP : NULL);
    641             return newBB;
    642         }
    643     }
    644     if (create) {
    645           bb = dvmCompilerNewBB(kDalvikByteCode, cUnit->numBlocks++);
    646           dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
    647           bb->startOffset = codeOffset;
    648           return bb;
    649     }
    650     return NULL;
    651 }
    652 
    653 /* Dump the CFG into a DOT graph */
    654 void dvmDumpCFG(CompilationUnit *cUnit, const char *dirPrefix)
    655 {
    656     const Method *method = cUnit->method;
    657     FILE *file;
    658     char *signature = dexProtoCopyMethodDescriptor(&method->prototype);
    659     char startOffset[80];
    660     sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
    661     char *fileName = (char *) dvmCompilerNew(
    662                                   strlen(dirPrefix) +
    663                                   strlen(method->clazz->descriptor) +
    664                                   strlen(method->name) +
    665                                   strlen(signature) +
    666                                   strlen(startOffset) +
    667                                   strlen(".dot") + 1, true);
    668     sprintf(fileName, "%s%s%s%s%s.dot", dirPrefix,
    669             method->clazz->descriptor, method->name, signature, startOffset);
    670     free(signature);
    671 
    672     /*
    673      * Convert the special characters into a filesystem- and shell-friendly
    674      * format.
    675      */
    676     int i;
    677     for (i = strlen(dirPrefix); fileName[i]; i++) {
    678         if (fileName[i] == '/') {
    679             fileName[i] = '_';
    680         } else if (fileName[i] == ';') {
    681             fileName[i] = '#';
    682         } else if (fileName[i] == '$') {
    683             fileName[i] = '+';
    684         } else if (fileName[i] == '(' || fileName[i] == ')') {
    685             fileName[i] = '@';
    686         } else if (fileName[i] == '<' || fileName[i] == '>') {
    687             fileName[i] = '=';
    688         }
    689     }
    690     file = fopen(fileName, "w");
    691     if (file == NULL) {
    692         return;
    693     }
    694     fprintf(file, "digraph G {\n");
    695 
    696     fprintf(file, "  rankdir=TB\n");
    697 
    698     int numReachableBlocks = cUnit->numReachableBlocks;
    699     int idx;
    700     const GrowableList *blockList = &cUnit->blockList;
    701 
    702     for (idx = 0; idx < numReachableBlocks; idx++) {
    703         int blockIdx = cUnit->dfsOrder.elemList[idx];
    704         BasicBlock *bb = (BasicBlock *) dvmGrowableListGetElement(blockList,
    705                                                                   blockIdx);
    706         if (bb == NULL) break;
    707         if (bb->blockType == kEntryBlock) {
    708             fprintf(file, "  entry [shape=Mdiamond];\n");
    709         } else if (bb->blockType == kExitBlock) {
    710             fprintf(file, "  exit [shape=Mdiamond];\n");
    711         } else if (bb->blockType == kDalvikByteCode) {
    712             fprintf(file, "  block%04x [shape=record,label = \"{ \\\n",
    713                     bb->startOffset);
    714             const MIR *mir;
    715             fprintf(file, "    {block id %d\\l}%s\\\n", bb->id,
    716                     bb->firstMIRInsn ? " | " : " ");
    717             for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
    718                 fprintf(file, "    {%04x %s\\l}%s\\\n", mir->offset,
    719                         mir->ssaRep ?
    720                             dvmCompilerFullDisassembler(cUnit, mir) :
    721                             dexGetOpcodeName(mir->dalvikInsn.opcode),
    722                         mir->next ? " | " : " ");
    723             }
    724             fprintf(file, "  }\"];\n\n");
    725         } else if (bb->blockType == kExceptionHandling) {
    726             char blockName[BLOCK_NAME_LEN];
    727 
    728             dvmGetBlockName(bb, blockName);
    729             fprintf(file, "  %s [shape=invhouse];\n", blockName);
    730         }
    731 
    732         char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
    733 
    734         if (bb->taken) {
    735             dvmGetBlockName(bb, blockName1);
    736             dvmGetBlockName(bb->taken, blockName2);
    737             fprintf(file, "  %s:s -> %s:n [style=dotted]\n",
    738                     blockName1, blockName2);
    739         }
    740         if (bb->fallThrough) {
    741             dvmGetBlockName(bb, blockName1);
    742             dvmGetBlockName(bb->fallThrough, blockName2);
    743             fprintf(file, "  %s:s -> %s:n\n", blockName1, blockName2);
    744         }
    745 
    746         if (bb->successorBlockList.blockListType != kNotUsed) {
    747             fprintf(file, "  succ%04x [shape=%s,label = \"{ \\\n",
    748                     bb->startOffset,
    749                     (bb->successorBlockList.blockListType == kCatch) ?
    750                         "Mrecord" : "record");
    751             GrowableListIterator iterator;
    752             dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
    753                                         &iterator);
    754             SuccessorBlockInfo *successorBlockInfo =
    755                 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
    756 
    757             int succId = 0;
    758             while (true) {
    759                 if (successorBlockInfo == NULL) break;
    760 
    761                 BasicBlock *destBlock = successorBlockInfo->block;
    762                 SuccessorBlockInfo *nextSuccessorBlockInfo =
    763                   (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
    764 
    765                 fprintf(file, "    {<f%d> %04x: %04x\\l}%s\\\n",
    766                         succId++,
    767                         successorBlockInfo->key,
    768                         destBlock->startOffset,
    769                         (nextSuccessorBlockInfo != NULL) ? " | " : " ");
    770 
    771                 successorBlockInfo = nextSuccessorBlockInfo;
    772             }
    773             fprintf(file, "  }\"];\n\n");
    774 
    775             dvmGetBlockName(bb, blockName1);
    776             fprintf(file, "  %s:s -> succ%04x:n [style=dashed]\n",
    777                     blockName1, bb->startOffset);
    778 
    779             if (bb->successorBlockList.blockListType == kPackedSwitch ||
    780                 bb->successorBlockList.blockListType == kSparseSwitch) {
    781 
    782                 dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
    783                                             &iterator);
    784 
    785                 succId = 0;
    786                 while (true) {
    787                     SuccessorBlockInfo *successorBlockInfo =
    788                         (SuccessorBlockInfo *)
    789                             dvmGrowableListIteratorNext(&iterator);
    790                     if (successorBlockInfo == NULL) break;
    791 
    792                     BasicBlock *destBlock = successorBlockInfo->block;
    793 
    794                     dvmGetBlockName(destBlock, blockName2);
    795                     fprintf(file, "  succ%04x:f%d:e -> %s:n\n",
    796                             bb->startOffset, succId++,
    797                             blockName2);
    798                 }
    799             }
    800         }
    801         fprintf(file, "\n");
    802 
    803         /*
    804          * If we need to debug the dominator tree, uncomment the following code
    805          */
    806 #if 1
    807         dvmGetBlockName(bb, blockName1);
    808         fprintf(file, "  cfg%s [label=\"%s\", shape=none];\n",
    809                 blockName1, blockName1);
    810         if (bb->iDom) {
    811             dvmGetBlockName(bb->iDom, blockName2);
    812             fprintf(file, "  cfg%s:s -> cfg%s:n\n\n",
    813                     blockName2, blockName1);
    814         }
    815 #endif
    816     }
    817     fprintf(file, "}\n");
    818     fclose(file);
    819 }
    820 
    821 /* Verify if all the successor is connected with all the claimed predecessors */
    822 static bool verifyPredInfo(CompilationUnit *cUnit, BasicBlock *bb)
    823 {
    824     BitVectorIterator bvIterator;
    825 
    826     dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
    827     while (true) {
    828         int blockIdx = dvmBitVectorIteratorNext(&bvIterator);
    829         if (blockIdx == -1) break;
    830         BasicBlock *predBB = (BasicBlock *)
    831             dvmGrowableListGetElement(&cUnit->blockList, blockIdx);
    832         bool found = false;
    833         if (predBB->taken == bb) {
    834             found = true;
    835         } else if (predBB->fallThrough == bb) {
    836             found = true;
    837         } else if (predBB->successorBlockList.blockListType != kNotUsed) {
    838             GrowableListIterator iterator;
    839             dvmGrowableListIteratorInit(&predBB->successorBlockList.blocks,
    840                                         &iterator);
    841             while (true) {
    842                 SuccessorBlockInfo *successorBlockInfo =
    843                     (SuccessorBlockInfo *)
    844                         dvmGrowableListIteratorNext(&iterator);
    845                 if (successorBlockInfo == NULL) break;
    846                 BasicBlock *succBB = successorBlockInfo->block;
    847                 if (succBB == bb) {
    848                     found = true;
    849                     break;
    850                 }
    851             }
    852         }
    853         if (found == false) {
    854             char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
    855             dvmGetBlockName(bb, blockName1);
    856             dvmGetBlockName(predBB, blockName2);
    857             dvmDumpCFG(cUnit, "/sdcard/cfg/");
    858             LOGE("Successor %s not found from %s",
    859                  blockName1, blockName2);
    860             dvmAbort();
    861         }
    862     }
    863     return true;
    864 }
    865 
    866 /* Identify code range in try blocks and set up the empty catch blocks */
    867 static void processTryCatchBlocks(CompilationUnit *cUnit)
    868 {
    869     const Method *meth = cUnit->method;
    870     const DexCode *pCode = dvmGetMethodCode(meth);
    871     int triesSize = pCode->triesSize;
    872     int i;
    873     int offset;
    874 
    875     if (triesSize == 0) {
    876         return;
    877     }
    878 
    879     const DexTry *pTries = dexGetTries(pCode);
    880     BitVector *tryBlockAddr = cUnit->tryBlockAddr;
    881 
    882     /* Mark all the insn offsets in Try blocks */
    883     for (i = 0; i < triesSize; i++) {
    884         const DexTry* pTry = &pTries[i];
    885         /* all in 16-bit units */
    886         int startOffset = pTry->startAddr;
    887         int endOffset = startOffset + pTry->insnCount;
    888 
    889         for (offset = startOffset; offset < endOffset; offset++) {
    890             dvmCompilerSetBit(tryBlockAddr, offset);
    891         }
    892     }
    893 
    894     /* Iterate over each of the handlers to enqueue the empty Catch blocks */
    895     offset = dexGetFirstHandlerOffset(pCode);
    896     int handlersSize = dexGetHandlersSize(pCode);
    897 
    898     for (i = 0; i < handlersSize; i++) {
    899         DexCatchIterator iterator;
    900         dexCatchIteratorInit(&iterator, pCode, offset);
    901 
    902         for (;;) {
    903             DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
    904 
    905             if (handler == NULL) {
    906                 break;
    907             }
    908 
    909             /*
    910              * Create dummy catch blocks first. Since these are created before
    911              * other blocks are processed, "split" is specified as false.
    912              */
    913             findBlock(cUnit, handler->address,
    914                       /* split */
    915                       false,
    916                       /* create */
    917                       true,
    918                       /* immedPredBlockP */
    919                       NULL);
    920         }
    921 
    922         offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
    923     }
    924 }
    925 
    926 /* Process instructions with the kInstrCanBranch flag */
    927 static void processCanBranch(CompilationUnit *cUnit, BasicBlock *curBlock,
    928                              MIR *insn, int curOffset, int width, int flags,
    929                              const u2* codePtr, const u2* codeEnd)
    930 {
    931     int target = curOffset;
    932     switch (insn->dalvikInsn.opcode) {
    933         case OP_GOTO:
    934         case OP_GOTO_16:
    935         case OP_GOTO_32:
    936             target += (int) insn->dalvikInsn.vA;
    937             break;
    938         case OP_IF_EQ:
    939         case OP_IF_NE:
    940         case OP_IF_LT:
    941         case OP_IF_GE:
    942         case OP_IF_GT:
    943         case OP_IF_LE:
    944             target += (int) insn->dalvikInsn.vC;
    945             break;
    946         case OP_IF_EQZ:
    947         case OP_IF_NEZ:
    948         case OP_IF_LTZ:
    949         case OP_IF_GEZ:
    950         case OP_IF_GTZ:
    951         case OP_IF_LEZ:
    952             target += (int) insn->dalvikInsn.vB;
    953             break;
    954         default:
    955             LOGE("Unexpected opcode(%d) with kInstrCanBranch set",
    956                  insn->dalvikInsn.opcode);
    957             dvmAbort();
    958     }
    959     BasicBlock *takenBlock = findBlock(cUnit, target,
    960                                        /* split */
    961                                        true,
    962                                        /* create */
    963                                        true,
    964                                        /* immedPredBlockP */
    965                                        &curBlock);
    966     curBlock->taken = takenBlock;
    967     dvmCompilerSetBit(takenBlock->predecessors, curBlock->id);
    968 
    969     /* Always terminate the current block for conditional branches */
    970     if (flags & kInstrCanContinue) {
    971         BasicBlock *fallthroughBlock = findBlock(cUnit,
    972                                                  curOffset +  width,
    973                                                  /*
    974                                                   * If the method is processed
    975                                                   * in sequential order from the
    976                                                   * beginning, we don't need to
    977                                                   * specify split for continue
    978                                                   * blocks. However, this
    979                                                   * routine can be called by
    980                                                   * compileLoop, which starts
    981                                                   * parsing the method from an
    982                                                   * arbitrary address in the
    983                                                   * method body.
    984                                                   */
    985                                                  true,
    986                                                  /* create */
    987                                                  true,
    988                                                  /* immedPredBlockP */
    989                                                  &curBlock);
    990         curBlock->fallThrough = fallthroughBlock;
    991         dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
    992     } else if (codePtr < codeEnd) {
    993         /* Create a fallthrough block for real instructions (incl. OP_NOP) */
    994         if (contentIsInsn(codePtr)) {
    995             findBlock(cUnit, curOffset + width,
    996                       /* split */
    997                       false,
    998                       /* create */
    999                       true,
   1000                       /* immedPredBlockP */
   1001                       NULL);
   1002         }
   1003     }
   1004 }
   1005 
   1006 /* Process instructions with the kInstrCanSwitch flag */
   1007 static void processCanSwitch(CompilationUnit *cUnit, BasicBlock *curBlock,
   1008                              MIR *insn, int curOffset, int width, int flags)
   1009 {
   1010     u2 *switchData= (u2 *) (cUnit->method->insns + curOffset +
   1011                             insn->dalvikInsn.vB);
   1012     int size;
   1013     int *keyTable;
   1014     int *targetTable;
   1015     int i;
   1016     int firstKey;
   1017 
   1018     /*
   1019      * Packed switch data format:
   1020      *  ushort ident = 0x0100   magic value
   1021      *  ushort size             number of entries in the table
   1022      *  int first_key           first (and lowest) switch case value
   1023      *  int targets[size]       branch targets, relative to switch opcode
   1024      *
   1025      * Total size is (4+size*2) 16-bit code units.
   1026      */
   1027     if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
   1028         assert(switchData[0] == kPackedSwitchSignature);
   1029         size = switchData[1];
   1030         firstKey = switchData[2] | (switchData[3] << 16);
   1031         targetTable = (int *) &switchData[4];
   1032         keyTable = NULL;        // Make the compiler happy
   1033     /*
   1034      * Sparse switch data format:
   1035      *  ushort ident = 0x0200   magic value
   1036      *  ushort size             number of entries in the table; > 0
   1037      *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
   1038      *  int targets[size]       branch targets, relative to switch opcode
   1039      *
   1040      * Total size is (2+size*4) 16-bit code units.
   1041      */
   1042     } else {
   1043         assert(switchData[0] == kSparseSwitchSignature);
   1044         size = switchData[1];
   1045         keyTable = (int *) &switchData[2];
   1046         targetTable = (int *) &switchData[2 + size*2];
   1047         firstKey = 0;   // To make the compiler happy
   1048     }
   1049 
   1050     if (curBlock->successorBlockList.blockListType != kNotUsed) {
   1051         LOGE("Successor block list already in use: %d",
   1052              curBlock->successorBlockList.blockListType);
   1053         dvmAbort();
   1054     }
   1055     curBlock->successorBlockList.blockListType =
   1056         (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
   1057         kPackedSwitch : kSparseSwitch;
   1058     dvmInitGrowableList(&curBlock->successorBlockList.blocks, size);
   1059 
   1060     for (i = 0; i < size; i++) {
   1061         BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
   1062                                           /* split */
   1063                                           true,
   1064                                           /* create */
   1065                                           true,
   1066                                           /* immedPredBlockP */
   1067                                           &curBlock);
   1068         SuccessorBlockInfo *successorBlockInfo =
   1069             (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
   1070                                                   false);
   1071         successorBlockInfo->block = caseBlock;
   1072         successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
   1073                                   firstKey + i : keyTable[i];
   1074         dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
   1075                               (intptr_t) successorBlockInfo);
   1076         dvmCompilerSetBit(caseBlock->predecessors, curBlock->id);
   1077     }
   1078 
   1079     /* Fall-through case */
   1080     BasicBlock *fallthroughBlock = findBlock(cUnit,
   1081                                              curOffset +  width,
   1082                                              /* split */
   1083                                              false,
   1084                                              /* create */
   1085                                              true,
   1086                                              /* immedPredBlockP */
   1087                                              NULL);
   1088     curBlock->fallThrough = fallthroughBlock;
   1089     dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
   1090 }
   1091 
   1092 /* Process instructions with the kInstrCanThrow flag */
   1093 static void processCanThrow(CompilationUnit *cUnit, BasicBlock *curBlock,
   1094                             MIR *insn, int curOffset, int width, int flags,
   1095                             BitVector *tryBlockAddr, const u2 *codePtr,
   1096                             const u2* codeEnd)
   1097 {
   1098     const Method *method = cUnit->method;
   1099     const DexCode *dexCode = dvmGetMethodCode(method);
   1100 
   1101     /* In try block */
   1102     if (dvmIsBitSet(tryBlockAddr, curOffset)) {
   1103         DexCatchIterator iterator;
   1104 
   1105         if (!dexFindCatchHandler(&iterator, dexCode, curOffset)) {
   1106             LOGE("Catch block not found in dexfile for insn %x in %s",
   1107                  curOffset, method->name);
   1108             dvmAbort();
   1109 
   1110         }
   1111         if (curBlock->successorBlockList.blockListType != kNotUsed) {
   1112             LOGE("Successor block list already in use: %d",
   1113                  curBlock->successorBlockList.blockListType);
   1114             dvmAbort();
   1115         }
   1116         curBlock->successorBlockList.blockListType = kCatch;
   1117         dvmInitGrowableList(&curBlock->successorBlockList.blocks, 2);
   1118 
   1119         for (;;) {
   1120             DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
   1121 
   1122             if (handler == NULL) {
   1123                 break;
   1124             }
   1125 
   1126             BasicBlock *catchBlock = findBlock(cUnit, handler->address,
   1127                                                /* split */
   1128                                                false,
   1129                                                /* create */
   1130                                                false,
   1131                                                /* immedPredBlockP */
   1132                                                NULL);
   1133 
   1134             SuccessorBlockInfo *successorBlockInfo =
   1135               (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
   1136                                                     false);
   1137             successorBlockInfo->block = catchBlock;
   1138             successorBlockInfo->key = handler->typeIdx;
   1139             dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
   1140                                   (intptr_t) successorBlockInfo);
   1141             dvmCompilerSetBit(catchBlock->predecessors, curBlock->id);
   1142         }
   1143     } else {
   1144         BasicBlock *ehBlock = dvmCompilerNewBB(kExceptionHandling,
   1145                                                cUnit->numBlocks++);
   1146         curBlock->taken = ehBlock;
   1147         dvmInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
   1148         ehBlock->startOffset = curOffset;
   1149         dvmCompilerSetBit(ehBlock->predecessors, curBlock->id);
   1150     }
   1151 
   1152     /*
   1153      * Force the current block to terminate.
   1154      *
   1155      * Data may be present before codeEnd, so we need to parse it to know
   1156      * whether it is code or data.
   1157      */
   1158     if (codePtr < codeEnd) {
   1159         /* Create a fallthrough block for real instructions (incl. OP_NOP) */
   1160         if (contentIsInsn(codePtr)) {
   1161             BasicBlock *fallthroughBlock = findBlock(cUnit,
   1162                                                      curOffset + width,
   1163                                                      /* split */
   1164                                                      false,
   1165                                                      /* create */
   1166                                                      true,
   1167                                                      /* immedPredBlockP */
   1168                                                      NULL);
   1169             /*
   1170              * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional
   1171              * branches.
   1172              */
   1173             if (insn->dalvikInsn.opcode != OP_THROW_VERIFICATION_ERROR &&
   1174                 insn->dalvikInsn.opcode != OP_THROW) {
   1175                 curBlock->fallThrough = fallthroughBlock;
   1176                 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
   1177             }
   1178         }
   1179     }
   1180 }
   1181 
   1182 /*
   1183  * Similar to dvmCompileTrace, but the entity processed here is the whole
   1184  * method.
   1185  *
   1186  * TODO: implementation will be revisited when the trace builder can provide
   1187  * whole-method traces.
   1188  */
   1189 bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
   1190 {
   1191     CompilationUnit cUnit;
   1192     const DexCode *dexCode = dvmGetMethodCode(method);
   1193     const u2 *codePtr = dexCode->insns;
   1194     const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
   1195     int numBlocks = 0;
   1196     unsigned int curOffset = 0;
   1197 
   1198     /* Method already compiled */
   1199     if (dvmJitGetMethodAddr(codePtr)) {
   1200         info->codeAddress = NULL;
   1201         return false;
   1202     }
   1203 
   1204     memset(&cUnit, 0, sizeof(cUnit));
   1205     cUnit.method = method;
   1206 
   1207     cUnit.jitMode = kJitMethod;
   1208 
   1209     /* Initialize the block list */
   1210     dvmInitGrowableList(&cUnit.blockList, 4);
   1211 
   1212     /*
   1213      * FIXME - PC reconstruction list won't be needed after the codegen routines
   1214      * are enhanced to true method mode.
   1215      */
   1216     /* Initialize the PC reconstruction list */
   1217     dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
   1218 
   1219     /* Allocate the bit-vector to track the beginning of basic blocks */
   1220     BitVector *tryBlockAddr = dvmCompilerAllocBitVector(dexCode->insnsSize,
   1221                                                         true /* expandable */);
   1222     cUnit.tryBlockAddr = tryBlockAddr;
   1223 
   1224     /* Create the default entry and exit blocks and enter them to the list */
   1225     BasicBlock *entryBlock = dvmCompilerNewBB(kEntryBlock, numBlocks++);
   1226     BasicBlock *exitBlock = dvmCompilerNewBB(kExitBlock, numBlocks++);
   1227 
   1228     cUnit.entryBlock = entryBlock;
   1229     cUnit.exitBlock = exitBlock;
   1230 
   1231     dvmInsertGrowableList(&cUnit.blockList, (intptr_t) entryBlock);
   1232     dvmInsertGrowableList(&cUnit.blockList, (intptr_t) exitBlock);
   1233 
   1234     /* Current block to record parsed instructions */
   1235     BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
   1236     curBlock->startOffset = 0;
   1237     dvmInsertGrowableList(&cUnit.blockList, (intptr_t) curBlock);
   1238     entryBlock->fallThrough = curBlock;
   1239     dvmCompilerSetBit(curBlock->predecessors, entryBlock->id);
   1240 
   1241     /*
   1242      * Store back the number of blocks since new blocks may be created of
   1243      * accessing cUnit.
   1244      */
   1245     cUnit.numBlocks = numBlocks;
   1246 
   1247     /* Identify code range in try blocks and set up the empty catch blocks */
   1248     processTryCatchBlocks(&cUnit);
   1249 
   1250     /* Parse all instructions and put them into containing basic blocks */
   1251     while (codePtr < codeEnd) {
   1252         MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true);
   1253         insn->offset = curOffset;
   1254         int width = parseInsn(codePtr, &insn->dalvikInsn, false);
   1255         insn->width = width;
   1256 
   1257         /* Terminate when the data section is seen */
   1258         if (width == 0)
   1259             break;
   1260 
   1261         dvmCompilerAppendMIR(curBlock, insn);
   1262 
   1263         codePtr += width;
   1264         int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
   1265 
   1266         if (flags & kInstrCanBranch) {
   1267             processCanBranch(&cUnit, curBlock, insn, curOffset, width, flags,
   1268                              codePtr, codeEnd);
   1269         } else if (flags & kInstrCanReturn) {
   1270             curBlock->fallThrough = exitBlock;
   1271             dvmCompilerSetBit(exitBlock->predecessors, curBlock->id);
   1272             /*
   1273              * Terminate the current block if there are instructions
   1274              * afterwards.
   1275              */
   1276             if (codePtr < codeEnd) {
   1277                 /*
   1278                  * Create a fallthrough block for real instructions
   1279                  * (incl. OP_NOP).
   1280                  */
   1281                 if (contentIsInsn(codePtr)) {
   1282                     findBlock(&cUnit, curOffset + width,
   1283                               /* split */
   1284                               false,
   1285                               /* create */
   1286                               true,
   1287                               /* immedPredBlockP */
   1288                               NULL);
   1289                 }
   1290             }
   1291         } else if (flags & kInstrCanThrow) {
   1292             processCanThrow(&cUnit, curBlock, insn, curOffset, width, flags,
   1293                             tryBlockAddr, codePtr, codeEnd);
   1294         } else if (flags & kInstrCanSwitch) {
   1295             processCanSwitch(&cUnit, curBlock, insn, curOffset, width, flags);
   1296         }
   1297         curOffset += width;
   1298         BasicBlock *nextBlock = findBlock(&cUnit, curOffset,
   1299                                           /* split */
   1300                                           false,
   1301                                           /* create */
   1302                                           false,
   1303                                           /* immedPredBlockP */
   1304                                           NULL);
   1305         if (nextBlock) {
   1306             /*
   1307              * The next instruction could be the target of a previously parsed
   1308              * forward branch so a block is already created. If the current
   1309              * instruction is not an unconditional branch, connect them through
   1310              * the fall-through link.
   1311              */
   1312             assert(curBlock->fallThrough == NULL ||
   1313                    curBlock->fallThrough == nextBlock ||
   1314                    curBlock->fallThrough == exitBlock);
   1315 
   1316             if ((curBlock->fallThrough == NULL) &&
   1317                 (flags & kInstrCanContinue)) {
   1318                 curBlock->fallThrough = nextBlock;
   1319                 dvmCompilerSetBit(nextBlock->predecessors, curBlock->id);
   1320             }
   1321             curBlock = nextBlock;
   1322         }
   1323     }
   1324 
   1325     if (cUnit.printMe) {
   1326         dvmCompilerDumpCompilationUnit(&cUnit);
   1327     }
   1328 
   1329     /* Adjust this value accordingly once inlining is performed */
   1330     cUnit.numDalvikRegisters = cUnit.method->registersSize;
   1331 
   1332     /* Verify if all blocks are connected as claimed */
   1333     /* FIXME - to be disabled in the future */
   1334     dvmCompilerDataFlowAnalysisDispatcher(&cUnit, verifyPredInfo,
   1335                                           kAllNodes,
   1336                                           false /* isIterative */);
   1337 
   1338 
   1339     /* Perform SSA transformation for the whole method */
   1340     dvmCompilerMethodSSATransformation(&cUnit);
   1341 
   1342     dvmCompilerInitializeRegAlloc(&cUnit);  // Needs to happen after SSA naming
   1343 
   1344     /* Allocate Registers using simple local allocation scheme */
   1345     dvmCompilerLocalRegAlloc(&cUnit);
   1346 
   1347     /* Convert MIR to LIR, etc. */
   1348     dvmCompilerMethodMIR2LIR(&cUnit);
   1349 
   1350     // Debugging only
   1351     //dvmDumpCFG(&cUnit, "/sdcard/cfg/");
   1352 
   1353     /* Method is not empty */
   1354     if (cUnit.firstLIRInsn) {
   1355         /* Convert LIR into machine code. Loop for recoverable retries */
   1356         do {
   1357             dvmCompilerAssembleLIR(&cUnit, info);
   1358             cUnit.assemblerRetries++;
   1359             if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
   1360                 LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
   1361                       cUnit.assemblerStatus);
   1362         } while (cUnit.assemblerStatus == kRetryAll);
   1363 
   1364         if (cUnit.printMe) {
   1365             dvmCompilerCodegenDump(&cUnit);
   1366         }
   1367 
   1368         if (info->codeAddress) {
   1369             dvmJitSetCodeAddr(dexCode->insns, info->codeAddress,
   1370                               info->instructionSet, true, 0);
   1371             /*
   1372              * Clear the codeAddress for the enclosing trace to reuse the info
   1373              */
   1374             info->codeAddress = NULL;
   1375         }
   1376     }
   1377 
   1378     return false;
   1379 }
   1380 
   1381 /* Extending the trace by crawling the code from curBlock */
   1382 static bool exhaustTrace(CompilationUnit *cUnit, BasicBlock *curBlock)
   1383 {
   1384     unsigned int curOffset = curBlock->startOffset;
   1385     const u2 *codePtr = cUnit->method->insns + curOffset;
   1386 
   1387     if (curBlock->visited == true) return false;
   1388 
   1389     curBlock->visited = true;
   1390 
   1391     if (curBlock->blockType == kEntryBlock ||
   1392         curBlock->blockType == kExitBlock) {
   1393         return false;
   1394     }
   1395 
   1396     /*
   1397      * Block has been parsed - check the taken/fallThrough in case it is a split
   1398      * block.
   1399      */
   1400     if (curBlock->firstMIRInsn != NULL) {
   1401           bool changed = false;
   1402           if (curBlock->taken)
   1403               changed |= exhaustTrace(cUnit, curBlock->taken);
   1404           if (curBlock->fallThrough)
   1405               changed |= exhaustTrace(cUnit, curBlock->fallThrough);
   1406           return changed;
   1407     }
   1408     while (true) {
   1409         MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true);
   1410         insn->offset = curOffset;
   1411         int width = parseInsn(codePtr, &insn->dalvikInsn, false);
   1412         insn->width = width;
   1413 
   1414         /* Terminate when the data section is seen */
   1415         if (width == 0)
   1416             break;
   1417 
   1418         dvmCompilerAppendMIR(curBlock, insn);
   1419 
   1420         codePtr += width;
   1421         int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
   1422 
   1423         /* Stop extending the trace after seeing these instructions */
   1424         if (flags & (kInstrCanReturn | kInstrCanSwitch | kInstrInvoke)) {
   1425             curBlock->fallThrough = cUnit->exitBlock;
   1426             dvmCompilerSetBit(cUnit->exitBlock->predecessors, curBlock->id);
   1427             break;
   1428         } else if (flags & kInstrCanBranch) {
   1429             processCanBranch(cUnit, curBlock, insn, curOffset, width, flags,
   1430                              codePtr, NULL);
   1431             if (curBlock->taken) {
   1432                 exhaustTrace(cUnit, curBlock->taken);
   1433             }
   1434             if (curBlock->fallThrough) {
   1435                 exhaustTrace(cUnit, curBlock->fallThrough);
   1436             }
   1437             break;
   1438         }
   1439         curOffset += width;
   1440         BasicBlock *nextBlock = findBlock(cUnit, curOffset,
   1441                                           /* split */
   1442                                           false,
   1443                                           /* create */
   1444                                           false,
   1445                                           /* immedPredBlockP */
   1446                                           NULL);
   1447         if (nextBlock) {
   1448             /*
   1449              * The next instruction could be the target of a previously parsed
   1450              * forward branch so a block is already created. If the current
   1451              * instruction is not an unconditional branch, connect them through
   1452              * the fall-through link.
   1453              */
   1454             assert(curBlock->fallThrough == NULL ||
   1455                    curBlock->fallThrough == nextBlock ||
   1456                    curBlock->fallThrough == cUnit->exitBlock);
   1457 
   1458             if ((curBlock->fallThrough == NULL) &&
   1459                 (flags & kInstrCanContinue)) {
   1460                 curBlock->needFallThroughBranch = true;
   1461                 curBlock->fallThrough = nextBlock;
   1462                 dvmCompilerSetBit(nextBlock->predecessors, curBlock->id);
   1463             }
   1464             /* Block has been visited - no more parsing needed */
   1465             if (nextBlock->visited == true) {
   1466                 return true;
   1467             }
   1468             curBlock = nextBlock;
   1469         }
   1470     }
   1471     return true;
   1472 }
   1473 
   1474 /* Compile a loop */
   1475 static bool compileLoop(CompilationUnit *cUnit, unsigned int startOffset,
   1476                         JitTraceDescription *desc, int numMaxInsts,
   1477                         JitTranslationInfo *info, jmp_buf *bailPtr,
   1478                         int optHints)
   1479 {
   1480     int numBlocks = 0;
   1481     unsigned int curOffset = startOffset;
   1482     bool changed;
   1483     BasicBlock *bb;
   1484 #if defined(WITH_JIT_TUNING)
   1485     CompilerMethodStats *methodStats;
   1486 #endif
   1487 
   1488     cUnit->jitMode = kJitLoop;
   1489 
   1490     /* Initialize the block list */
   1491     dvmInitGrowableList(&cUnit->blockList, 4);
   1492 
   1493     /* Initialize the PC reconstruction list */
   1494     dvmInitGrowableList(&cUnit->pcReconstructionList, 8);
   1495 
   1496     /* Create the default entry and exit blocks and enter them to the list */
   1497     BasicBlock *entryBlock = dvmCompilerNewBB(kEntryBlock, numBlocks++);
   1498     entryBlock->startOffset = curOffset;
   1499     BasicBlock *exitBlock = dvmCompilerNewBB(kExitBlock, numBlocks++);
   1500 
   1501     cUnit->entryBlock = entryBlock;
   1502     cUnit->exitBlock = exitBlock;
   1503 
   1504     dvmInsertGrowableList(&cUnit->blockList, (intptr_t) entryBlock);
   1505     dvmInsertGrowableList(&cUnit->blockList, (intptr_t) exitBlock);
   1506 
   1507     /* Current block to record parsed instructions */
   1508     BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
   1509     curBlock->startOffset = curOffset;
   1510 
   1511     dvmInsertGrowableList(&cUnit->blockList, (intptr_t) curBlock);
   1512     entryBlock->fallThrough = curBlock;
   1513     dvmCompilerSetBit(curBlock->predecessors, entryBlock->id);
   1514 
   1515     /*
   1516      * Store back the number of blocks since new blocks may be created of
   1517      * accessing cUnit.
   1518      */
   1519     cUnit->numBlocks = numBlocks;
   1520 
   1521     do {
   1522         dvmCompilerDataFlowAnalysisDispatcher(cUnit,
   1523                                               dvmCompilerClearVisitedFlag,
   1524                                               kAllNodes,
   1525                                               false /* isIterative */);
   1526         changed = exhaustTrace(cUnit, curBlock);
   1527     } while (changed);
   1528 
   1529     /* Backward chaining block */
   1530     bb = dvmCompilerNewBB(kChainingCellBackwardBranch, cUnit->numBlocks++);
   1531     dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
   1532     cUnit->backChainBlock = bb;
   1533 
   1534     /* A special block to host PC reconstruction code */
   1535     bb = dvmCompilerNewBB(kPCReconstruction, cUnit->numBlocks++);
   1536     dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
   1537 
   1538     /* And one final block that publishes the PC and raises the exception */
   1539     bb = dvmCompilerNewBB(kExceptionHandling, cUnit->numBlocks++);
   1540     dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
   1541     cUnit->puntBlock = bb;
   1542 
   1543     cUnit->numDalvikRegisters = cUnit->method->registersSize;
   1544 
   1545     /* Verify if all blocks are connected as claimed */
   1546     /* FIXME - to be disabled in the future */
   1547     dvmCompilerDataFlowAnalysisDispatcher(cUnit, verifyPredInfo,
   1548                                           kAllNodes,
   1549                                           false /* isIterative */);
   1550 
   1551 
   1552     /* Try to identify a loop */
   1553     if (!dvmCompilerBuildLoop(cUnit))
   1554         goto bail;
   1555 
   1556     dvmCompilerLoopOpt(cUnit);
   1557 
   1558     /*
   1559      * Change the backward branch to the backward chaining cell after dataflow
   1560      * analsys/optimizations are done.
   1561      */
   1562     dvmCompilerInsertBackwardChaining(cUnit);
   1563 
   1564     dvmCompilerInitializeRegAlloc(cUnit);
   1565 
   1566     /* Allocate Registers using simple local allocation scheme */
   1567     dvmCompilerLocalRegAlloc(cUnit);
   1568 
   1569     /* Convert MIR to LIR, etc. */
   1570     dvmCompilerMIR2LIR(cUnit);
   1571 
   1572     /* Loop contains never executed blocks / heavy instructions */
   1573     if (cUnit->quitLoopMode) {
   1574         if (cUnit->printMe || gDvmJit.receivedSIGUSR2) {
   1575             LOGD("Loop trace @ offset %04x aborted due to unresolved code info",
   1576                  cUnit->entryBlock->startOffset);
   1577         }
   1578         goto bail;
   1579     }
   1580 
   1581     /* Convert LIR into machine code. Loop for recoverable retries */
   1582     do {
   1583         dvmCompilerAssembleLIR(cUnit, info);
   1584         cUnit->assemblerRetries++;
   1585         if (cUnit->printMe && cUnit->assemblerStatus != kSuccess)
   1586             LOGD("Assembler abort #%d on %d", cUnit->assemblerRetries,
   1587                   cUnit->assemblerStatus);
   1588     } while (cUnit->assemblerStatus == kRetryAll);
   1589 
   1590     /* Loop is too big - bail out */
   1591     if (cUnit->assemblerStatus == kRetryHalve) {
   1592         goto bail;
   1593     }
   1594 
   1595     if (cUnit->printMe || gDvmJit.receivedSIGUSR2) {
   1596         LOGD("Loop trace @ offset %04x", cUnit->entryBlock->startOffset);
   1597         dvmCompilerCodegenDump(cUnit);
   1598     }
   1599 
   1600     /*
   1601      * If this trace uses class objects as constants,
   1602      * dvmJitInstallClassObjectPointers will switch the thread state
   1603      * to running and look up the class pointers using the descriptor/loader
   1604      * tuple stored in the callsite info structure. We need to make this window
   1605      * as short as possible since it is blocking GC.
   1606      */
   1607     if (cUnit->hasClassLiterals && info->codeAddress) {
   1608         dvmJitInstallClassObjectPointers(cUnit, (char *) info->codeAddress);
   1609     }
   1610 
   1611     /*
   1612      * Since callsiteinfo is allocated from the arena, delay the reset until
   1613      * class pointers are resolved.
   1614      */
   1615     dvmCompilerArenaReset();
   1616 
   1617     assert(cUnit->assemblerStatus == kSuccess);
   1618 #if defined(WITH_JIT_TUNING)
   1619     /* Locate the entry to store compilation statistics for this method */
   1620     methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
   1621     methodStats->nativeSize += cUnit->totalSize;
   1622 #endif
   1623     return info->codeAddress != NULL;
   1624 
   1625 bail:
   1626     /* Retry the original trace with JIT_OPT_NO_LOOP disabled */
   1627     dvmCompilerArenaReset();
   1628     return dvmCompileTrace(desc, numMaxInsts, info, bailPtr,
   1629                            optHints | JIT_OPT_NO_LOOP);
   1630 }
   1631 
   1632 /*
   1633  * Main entry point to start trace compilation. Basic blocks are constructed
   1634  * first and they will be passed to the codegen routines to convert Dalvik
   1635  * bytecode into machine code.
   1636  */
   1637 bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
   1638                      JitTranslationInfo *info, jmp_buf *bailPtr,
   1639                      int optHints)
   1640 {
   1641     const DexCode *dexCode = dvmGetMethodCode(desc->method);
   1642     const JitTraceRun* currRun = &desc->trace[0];
   1643     unsigned int curOffset = currRun->info.frag.startOffset;
   1644     unsigned int startOffset = curOffset;
   1645     unsigned int numInsts = currRun->info.frag.numInsts;
   1646     const u2 *codePtr = dexCode->insns + curOffset;
   1647     int traceSize = 0;  // # of half-words
   1648     const u2 *startCodePtr = codePtr;
   1649     BasicBlock *curBB, *entryCodeBB;
   1650     int numBlocks = 0;
   1651     static int compilationId;
   1652     CompilationUnit cUnit;
   1653     GrowableList *blockList;
   1654 #if defined(WITH_JIT_TUNING)
   1655     CompilerMethodStats *methodStats;
   1656 #endif
   1657 
   1658     /* If we've already compiled this trace, just return success */
   1659     if (dvmJitGetTraceAddr(startCodePtr) && !info->discardResult) {
   1660         /*
   1661          * Make sure the codeAddress is NULL so that it won't clobber the
   1662          * existing entry.
   1663          */
   1664         info->codeAddress = NULL;
   1665         return true;
   1666     }
   1667 
   1668     /* If the work order is stale, discard it */
   1669     if (info->cacheVersion != gDvmJit.cacheVersion) {
   1670         return false;
   1671     }
   1672 
   1673     compilationId++;
   1674     memset(&cUnit, 0, sizeof(CompilationUnit));
   1675 
   1676 #if defined(WITH_JIT_TUNING)
   1677     /* Locate the entry to store compilation statistics for this method */
   1678     methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
   1679 #endif
   1680 
   1681     /* Set the recover buffer pointer */
   1682     cUnit.bailPtr = bailPtr;
   1683 
   1684     /* Initialize the printMe flag */
   1685     cUnit.printMe = gDvmJit.printMe;
   1686 
   1687     /* Setup the method */
   1688     cUnit.method = desc->method;
   1689 
   1690     /* Store the trace descriptor and set the initial mode */
   1691     cUnit.traceDesc = desc;
   1692     cUnit.jitMode = kJitTrace;
   1693 
   1694     /* Initialize the PC reconstruction list */
   1695     dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
   1696 
   1697     /* Initialize the basic block list */
   1698     blockList = &cUnit.blockList;
   1699     dvmInitGrowableList(blockList, 8);
   1700 
   1701     /* Identify traces that we don't want to compile */
   1702     if (gDvmJit.methodTable) {
   1703         int len = strlen(desc->method->clazz->descriptor) +
   1704                   strlen(desc->method->name) + 1;
   1705         char *fullSignature = (char *)dvmCompilerNew(len, true);
   1706         strcpy(fullSignature, desc->method->clazz->descriptor);
   1707         strcat(fullSignature, desc->method->name);
   1708 
   1709         int hashValue = dvmComputeUtf8Hash(fullSignature);
   1710 
   1711         /*
   1712          * Doing three levels of screening to see whether we want to skip
   1713          * compiling this method
   1714          */
   1715 
   1716         /* First, check the full "class;method" signature */
   1717         bool methodFound =
   1718             dvmHashTableLookup(gDvmJit.methodTable, hashValue,
   1719                                fullSignature, (HashCompareFunc) strcmp,
   1720                                false) !=
   1721             NULL;
   1722 
   1723         /* Full signature not found - check the enclosing class */
   1724         if (methodFound == false) {
   1725             int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
   1726             methodFound =
   1727                 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
   1728                                (char *) desc->method->clazz->descriptor,
   1729                                (HashCompareFunc) strcmp, false) !=
   1730                 NULL;
   1731             /* Enclosing class not found - check the method name */
   1732             if (methodFound == false) {
   1733                 int hashValue = dvmComputeUtf8Hash(desc->method->name);
   1734                 methodFound =
   1735                     dvmHashTableLookup(gDvmJit.methodTable, hashValue,
   1736                                    (char *) desc->method->name,
   1737                                    (HashCompareFunc) strcmp, false) !=
   1738                     NULL;
   1739 
   1740                 /*
   1741                  * Debug by call-graph is enabled. Check if the debug list
   1742                  * covers any methods on the VM stack.
   1743                  */
   1744                 if (methodFound == false && gDvmJit.checkCallGraph == true) {
   1745                     methodFound =
   1746                         filterMethodByCallGraph(info->requestingThread,
   1747                                                 desc->method->name);
   1748                 }
   1749             }
   1750         }
   1751 
   1752         /*
   1753          * Under the following conditions, the trace will be *conservatively*
   1754          * compiled by only containing single-step instructions to and from the
   1755          * interpreter.
   1756          * 1) If includeSelectedMethod == false, the method matches the full or
   1757          *    partial signature stored in the hash table.
   1758          *
   1759          * 2) If includeSelectedMethod == true, the method does not match the
   1760          *    full and partial signature stored in the hash table.
   1761          */
   1762         if (gDvmJit.includeSelectedMethod != methodFound) {
   1763             cUnit.allSingleStep = true;
   1764         } else {
   1765             /* Compile the trace as normal */
   1766 
   1767             /* Print the method we cherry picked */
   1768             if (gDvmJit.includeSelectedMethod == true) {
   1769                 cUnit.printMe = true;
   1770             }
   1771         }
   1772     }
   1773 
   1774     /* Allocate the entry block */
   1775     curBB = dvmCompilerNewBB(kEntryBlock, numBlocks++);
   1776     dvmInsertGrowableList(blockList, (intptr_t) curBB);
   1777     curBB->startOffset = curOffset;
   1778 
   1779     entryCodeBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
   1780     dvmInsertGrowableList(blockList, (intptr_t) entryCodeBB);
   1781     entryCodeBB->startOffset = curOffset;
   1782     curBB->fallThrough = entryCodeBB;
   1783     curBB = entryCodeBB;
   1784 
   1785     if (cUnit.printMe) {
   1786         LOGD("--------\nCompiler: Building trace for %s, offset %#x",
   1787              desc->method->name, curOffset);
   1788     }
   1789 
   1790     /*
   1791      * Analyze the trace descriptor and include up to the maximal number
   1792      * of Dalvik instructions into the IR.
   1793      */
   1794     while (1) {
   1795         MIR *insn;
   1796         int width;
   1797         insn = (MIR *)dvmCompilerNew(sizeof(MIR), true);
   1798         insn->offset = curOffset;
   1799         width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
   1800 
   1801         /* The trace should never incude instruction data */
   1802         assert(width);
   1803         insn->width = width;
   1804         traceSize += width;
   1805         dvmCompilerAppendMIR(curBB, insn);
   1806         cUnit.numInsts++;
   1807 
   1808         int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
   1809 
   1810         if (flags & kInstrInvoke) {
   1811             const Method *calleeMethod = (const Method *)
   1812                 currRun[JIT_TRACE_CUR_METHOD].info.meta;
   1813             assert(numInsts == 1);
   1814             CallsiteInfo *callsiteInfo =
   1815                 (CallsiteInfo *)dvmCompilerNew(sizeof(CallsiteInfo), true);
   1816             callsiteInfo->classDescriptor = (const char *)
   1817                 currRun[JIT_TRACE_CLASS_DESC].info.meta;
   1818             callsiteInfo->classLoader = (Object *)
   1819                 currRun[JIT_TRACE_CLASS_LOADER].info.meta;
   1820             callsiteInfo->method = calleeMethod;
   1821             insn->meta.callsiteInfo = callsiteInfo;
   1822         }
   1823 
   1824         /* Instruction limit reached - terminate the trace here */
   1825         if (cUnit.numInsts >= numMaxInsts) {
   1826             break;
   1827         }
   1828         if (--numInsts == 0) {
   1829             if (currRun->info.frag.runEnd) {
   1830                 break;
   1831             } else {
   1832                 /* Advance to the next trace description (ie non-meta info) */
   1833                 do {
   1834                     currRun++;
   1835                 } while (!currRun->isCode);
   1836 
   1837                 /* Dummy end-of-run marker seen */
   1838                 if (currRun->info.frag.numInsts == 0) {
   1839                     break;
   1840                 }
   1841 
   1842                 curBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
   1843                 dvmInsertGrowableList(blockList, (intptr_t) curBB);
   1844                 curOffset = currRun->info.frag.startOffset;
   1845                 numInsts = currRun->info.frag.numInsts;
   1846                 curBB->startOffset = curOffset;
   1847                 codePtr = dexCode->insns + curOffset;
   1848             }
   1849         } else {
   1850             curOffset += width;
   1851             codePtr += width;
   1852         }
   1853     }
   1854 
   1855 #if defined(WITH_JIT_TUNING)
   1856     /* Convert # of half-word to bytes */
   1857     methodStats->compiledDalvikSize += traceSize * 2;
   1858 #endif
   1859 
   1860     /*
   1861      * Now scan basic blocks containing real code to connect the
   1862      * taken/fallthrough links. Also create chaining cells for code not included
   1863      * in the trace.
   1864      */
   1865     size_t blockId;
   1866     for (blockId = 0; blockId < blockList->numUsed; blockId++) {
   1867         curBB = (BasicBlock *) dvmGrowableListGetElement(blockList, blockId);
   1868         MIR *lastInsn = curBB->lastMIRInsn;
   1869         /* Skip empty blocks */
   1870         if (lastInsn == NULL) {
   1871             continue;
   1872         }
   1873         curOffset = lastInsn->offset;
   1874         unsigned int targetOffset = curOffset;
   1875         unsigned int fallThroughOffset = curOffset + lastInsn->width;
   1876         bool isInvoke = false;
   1877         const Method *callee = NULL;
   1878 
   1879         findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
   1880                           &targetOffset, &isInvoke, &callee);
   1881 
   1882         /* Link the taken and fallthrough blocks */
   1883         BasicBlock *searchBB;
   1884 
   1885         int flags = dexGetFlagsFromOpcode(lastInsn->dalvikInsn.opcode);
   1886 
   1887         if (flags & kInstrInvoke) {
   1888             cUnit.hasInvoke = true;
   1889         }
   1890 
   1891         /* Backward branch seen */
   1892         if (isInvoke == false &&
   1893             (flags & kInstrCanBranch) != 0 &&
   1894             targetOffset < curOffset &&
   1895             (optHints & JIT_OPT_NO_LOOP) == 0) {
   1896             dvmCompilerArenaReset();
   1897             return compileLoop(&cUnit, startOffset, desc, numMaxInsts,
   1898                                info, bailPtr, optHints);
   1899         }
   1900 
   1901         /* No backward branch in the trace - start searching the next BB */
   1902         size_t searchBlockId;
   1903         for (searchBlockId = blockId+1; searchBlockId < blockList->numUsed;
   1904              searchBlockId++) {
   1905             searchBB = (BasicBlock *) dvmGrowableListGetElement(blockList,
   1906                                                                 searchBlockId);
   1907             if (targetOffset == searchBB->startOffset) {
   1908                 curBB->taken = searchBB;
   1909                 dvmCompilerSetBit(searchBB->predecessors, curBB->id);
   1910             }
   1911             if (fallThroughOffset == searchBB->startOffset) {
   1912                 curBB->fallThrough = searchBB;
   1913                 dvmCompilerSetBit(searchBB->predecessors, curBB->id);
   1914 
   1915                 /*
   1916                  * Fallthrough block of an invoke instruction needs to be
   1917                  * aligned to 4-byte boundary (alignment instruction to be
   1918                  * inserted later.
   1919                  */
   1920                 if (flags & kInstrInvoke) {
   1921                     searchBB->isFallThroughFromInvoke = true;
   1922                 }
   1923             }
   1924         }
   1925 
   1926         /*
   1927          * Some blocks are ended by non-control-flow-change instructions,
   1928          * currently only due to trace length constraint. In this case we need
   1929          * to generate an explicit branch at the end of the block to jump to
   1930          * the chaining cell.
   1931          */
   1932         curBB->needFallThroughBranch =
   1933             ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
   1934                        kInstrInvoke)) == 0);
   1935         if (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ||
   1936             lastInsn->dalvikInsn.opcode == OP_SPARSE_SWITCH) {
   1937             int i;
   1938             const u2 *switchData = desc->method->insns + lastInsn->offset +
   1939                              lastInsn->dalvikInsn.vB;
   1940             int size = switchData[1];
   1941             int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
   1942 
   1943             /*
   1944              * Generate the landing pad for cases whose ranks are higher than
   1945              * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
   1946              * through the NoChain point.
   1947              */
   1948             if (maxChains != size) {
   1949                 cUnit.switchOverflowPad =
   1950                     desc->method->insns + lastInsn->offset;
   1951             }
   1952 
   1953             s4 *targets = (s4 *) (switchData + 2 +
   1954                     (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ?
   1955                      2 : size * 2));
   1956 
   1957             /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
   1958             for (i = 0; i < maxChains; i++) {
   1959                 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
   1960                                                          numBlocks++);
   1961                 dvmInsertGrowableList(blockList, (intptr_t) caseChain);
   1962                 caseChain->startOffset = lastInsn->offset + targets[i];
   1963             }
   1964 
   1965             /* One more chaining cell for the default case */
   1966             BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
   1967                                                      numBlocks++);
   1968             dvmInsertGrowableList(blockList, (intptr_t) caseChain);
   1969             caseChain->startOffset = lastInsn->offset + lastInsn->width;
   1970         /* Fallthrough block not included in the trace */
   1971         } else if (!isUnconditionalBranch(lastInsn) &&
   1972                    curBB->fallThrough == NULL) {
   1973             BasicBlock *fallThroughBB;
   1974             /*
   1975              * If the chaining cell is after an invoke or
   1976              * instruction that cannot change the control flow, request a hot
   1977              * chaining cell.
   1978              */
   1979             if (isInvoke || curBB->needFallThroughBranch) {
   1980                 fallThroughBB = dvmCompilerNewBB(kChainingCellHot, numBlocks++);
   1981             } else {
   1982                 fallThroughBB = dvmCompilerNewBB(kChainingCellNormal,
   1983                                                  numBlocks++);
   1984             }
   1985             dvmInsertGrowableList(blockList, (intptr_t) fallThroughBB);
   1986             fallThroughBB->startOffset = fallThroughOffset;
   1987             curBB->fallThrough = fallThroughBB;
   1988             dvmCompilerSetBit(fallThroughBB->predecessors, curBB->id);
   1989         }
   1990         /* Target block not included in the trace */
   1991         if (curBB->taken == NULL &&
   1992             (isGoto(lastInsn) || isInvoke ||
   1993             (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
   1994             BasicBlock *newBB = NULL;
   1995             if (isInvoke) {
   1996                 /* Monomorphic callee */
   1997                 if (callee) {
   1998                     /* JNI call doesn't need a chaining cell */
   1999                     if (!dvmIsNativeMethod(callee)) {
   2000                         newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton,
   2001                                                  numBlocks++);
   2002                         newBB->startOffset = 0;
   2003                         newBB->containingMethod = callee;
   2004                     }
   2005                 /* Will resolve at runtime */
   2006                 } else {
   2007                     newBB = dvmCompilerNewBB(kChainingCellInvokePredicted,
   2008                                              numBlocks++);
   2009                     newBB->startOffset = 0;
   2010                 }
   2011             /* For unconditional branches, request a hot chaining cell */
   2012             } else {
   2013 #if !defined(WITH_SELF_VERIFICATION)
   2014                 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
   2015                                                   kChainingCellHot :
   2016                                                   kChainingCellNormal,
   2017                                          numBlocks++);
   2018                 newBB->startOffset = targetOffset;
   2019 #else
   2020                 /* Handle branches that branch back into the block */
   2021                 if (targetOffset >= curBB->firstMIRInsn->offset &&
   2022                     targetOffset <= curBB->lastMIRInsn->offset) {
   2023                     newBB = dvmCompilerNewBB(kChainingCellBackwardBranch,
   2024                                              numBlocks++);
   2025                 } else {
   2026                     newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
   2027                                                       kChainingCellHot :
   2028                                                       kChainingCellNormal,
   2029                                              numBlocks++);
   2030                 }
   2031                 newBB->startOffset = targetOffset;
   2032 #endif
   2033             }
   2034             if (newBB) {
   2035                 curBB->taken = newBB;
   2036                 dvmCompilerSetBit(newBB->predecessors, curBB->id);
   2037                 dvmInsertGrowableList(blockList, (intptr_t) newBB);
   2038             }
   2039         }
   2040     }
   2041 
   2042     /* Now create a special block to host PC reconstruction code */
   2043     curBB = dvmCompilerNewBB(kPCReconstruction, numBlocks++);
   2044     dvmInsertGrowableList(blockList, (intptr_t) curBB);
   2045 
   2046     /* And one final block that publishes the PC and raise the exception */
   2047     curBB = dvmCompilerNewBB(kExceptionHandling, numBlocks++);
   2048     dvmInsertGrowableList(blockList, (intptr_t) curBB);
   2049     cUnit.puntBlock = curBB;
   2050 
   2051     if (cUnit.printMe) {
   2052         char* signature =
   2053             dexProtoCopyMethodDescriptor(&desc->method->prototype);
   2054         LOGD("TRACEINFO (%d): 0x%08x %s%s.%s %#x %d of %d, %d blocks",
   2055             compilationId,
   2056             (intptr_t) desc->method->insns,
   2057             desc->method->clazz->descriptor,
   2058             desc->method->name,
   2059             signature,
   2060             desc->trace[0].info.frag.startOffset,
   2061             traceSize,
   2062             dexCode->insnsSize,
   2063             numBlocks);
   2064         free(signature);
   2065     }
   2066 
   2067     cUnit.numBlocks = numBlocks;
   2068 
   2069     /* Set the instruction set to use (NOTE: later components may change it) */
   2070     cUnit.instructionSet = dvmCompilerInstructionSet();
   2071 
   2072     /* Inline transformation @ the MIR level */
   2073     if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
   2074         dvmCompilerInlineMIR(&cUnit, info);
   2075     }
   2076 
   2077     cUnit.numDalvikRegisters = cUnit.method->registersSize;
   2078 
   2079     /* Preparation for SSA conversion */
   2080     dvmInitializeSSAConversion(&cUnit);
   2081 
   2082     dvmCompilerNonLoopAnalysis(&cUnit);
   2083 
   2084     dvmCompilerInitializeRegAlloc(&cUnit);  // Needs to happen after SSA naming
   2085 
   2086     if (cUnit.printMe) {
   2087         dvmCompilerDumpCompilationUnit(&cUnit);
   2088     }
   2089 
   2090     /* Allocate Registers using simple local allocation scheme */
   2091     dvmCompilerLocalRegAlloc(&cUnit);
   2092 
   2093     /* Convert MIR to LIR, etc. */
   2094     dvmCompilerMIR2LIR(&cUnit);
   2095 
   2096     /* Convert LIR into machine code. Loop for recoverable retries */
   2097     do {
   2098         dvmCompilerAssembleLIR(&cUnit, info);
   2099         cUnit.assemblerRetries++;
   2100         if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
   2101             LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
   2102                   cUnit.assemblerStatus);
   2103     } while (cUnit.assemblerStatus == kRetryAll);
   2104 
   2105     if (cUnit.printMe) {
   2106         LOGD("Trace Dalvik PC: %p", startCodePtr);
   2107         dvmCompilerCodegenDump(&cUnit);
   2108         LOGD("End %s%s, %d Dalvik instructions",
   2109              desc->method->clazz->descriptor, desc->method->name,
   2110              cUnit.numInsts);
   2111     }
   2112 
   2113     if (cUnit.assemblerStatus == kRetryHalve) {
   2114         /* Reset the compiler resource pool before retry */
   2115         dvmCompilerArenaReset();
   2116 
   2117         /* Halve the instruction count and start from the top */
   2118         return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr,
   2119                                optHints);
   2120     }
   2121 
   2122     /*
   2123      * If this trace uses class objects as constants,
   2124      * dvmJitInstallClassObjectPointers will switch the thread state
   2125      * to running and look up the class pointers using the descriptor/loader
   2126      * tuple stored in the callsite info structure. We need to make this window
   2127      * as short as possible since it is blocking GC.
   2128      */
   2129     if (cUnit.hasClassLiterals && info->codeAddress) {
   2130         dvmJitInstallClassObjectPointers(&cUnit, (char *) info->codeAddress);
   2131     }
   2132 
   2133     /*
   2134      * Since callsiteinfo is allocated from the arena, delay the reset until
   2135      * class pointers are resolved.
   2136      */
   2137     dvmCompilerArenaReset();
   2138 
   2139     assert(cUnit.assemblerStatus == kSuccess);
   2140 #if defined(WITH_JIT_TUNING)
   2141     methodStats->nativeSize += cUnit.totalSize;
   2142 #endif
   2143 
   2144     return info->codeAddress != NULL;
   2145 }
   2146