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