2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "libdex/DexOpcodes.h"
19 #include "libdex/DexCatch.h"
20 #include "interp/Jit.h"
21 #include "CompilerInternals.h"
24 static inline bool contentIsInsn(const u2 *codePtr) {
26 Opcode opcode = instr & 0xff;
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.
32 return (opcode != OP_NOP || instr == 0);
36 * Parse an instruction, return the length of the instruction
38 static inline int parseInsn(const u2 *codePtr, DecodedInstruction *decInsn,
41 // Don't parse instruction data
42 if (!contentIsInsn(codePtr)) {
47 Opcode opcode = dexOpcodeFromCodeUnit(instr);
49 dexDecodeInstruction(codePtr, decInsn);
51 char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn, NULL);
52 LOGD("%p: %#06x %s\n", codePtr, opcode, decodedString);
54 return dexGetWidthFromOpcode(opcode);
57 #define UNKNOWN_TARGET 0xffffffff
60 * Identify block-ending instructions and collect supplemental information
61 * regarding the following instructions.
63 static inline bool findBlockBoundary(const Method *caller, MIR *insn,
64 unsigned int curOffset,
65 unsigned int *target, bool *isInvoke,
66 const Method **callee)
68 switch (insn->dalvikInsn.opcode) {
69 /* Target is not compile-time constant */
73 case OP_RETURN_OBJECT:
75 *target = UNKNOWN_TARGET;
77 case OP_INVOKE_VIRTUAL:
78 case OP_INVOKE_VIRTUAL_RANGE:
79 case OP_INVOKE_INTERFACE:
80 case OP_INVOKE_INTERFACE_RANGE:
81 case OP_INVOKE_VIRTUAL_QUICK:
82 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
86 case OP_INVOKE_SUPER_RANGE: {
87 int mIndex = caller->clazz->pDvmDex->
88 pResMethods[insn->dalvikInsn.vB]->methodIndex;
89 const Method *calleeMethod =
90 caller->clazz->super->vtable[mIndex];
92 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
93 *target = (unsigned int) calleeMethod->insns;
96 *callee = calleeMethod;
99 case OP_INVOKE_STATIC:
100 case OP_INVOKE_STATIC_RANGE: {
101 const Method *calleeMethod =
102 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
104 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
105 *target = (unsigned int) calleeMethod->insns;
108 *callee = calleeMethod;
111 case OP_INVOKE_SUPER_QUICK:
112 case OP_INVOKE_SUPER_QUICK_RANGE: {
113 const Method *calleeMethod =
114 caller->clazz->super->vtable[insn->dalvikInsn.vB];
116 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
117 *target = (unsigned int) calleeMethod->insns;
120 *callee = calleeMethod;
123 case OP_INVOKE_DIRECT:
124 case OP_INVOKE_DIRECT_RANGE: {
125 const Method *calleeMethod =
126 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
127 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
128 *target = (unsigned int) calleeMethod->insns;
131 *callee = calleeMethod;
137 *target = curOffset + (int) insn->dalvikInsn.vA;
146 *target = curOffset + (int) insn->dalvikInsn.vC;
155 *target = curOffset + (int) insn->dalvikInsn.vB;
164 static inline bool isGoto(MIR *insn)
166 switch (insn->dalvikInsn.opcode) {
177 * Identify unconditional branch instructions
179 static inline bool isUnconditionalBranch(MIR *insn)
181 switch (insn->dalvikInsn.opcode) {
185 case OP_RETURN_OBJECT:
193 * dvmHashTableLookup() callback
195 static int compareMethod(const CompilerMethodStats *m1,
196 const CompilerMethodStats *m2)
198 return (int) m1->method - (int) m2->method;
202 * Analyze the body of the method to collect high-level information regarding
205 * - is getter/setter?
206 * - can throw exception?
208 * Currently the inliner only handles getters and setters. When its capability
209 * becomes more sophisticated more information will be retrieved here.
211 static int analyzeInlineTarget(DecodedInstruction *dalvikInsn, int attributes,
214 int flags = dexGetFlagsFromOpcode(dalvikInsn->opcode);
215 int dalvikOpcode = dalvikInsn->opcode;
217 if (flags & kInstrInvoke) {
218 attributes &= ~METHOD_IS_LEAF;
221 if (!(flags & kInstrCanReturn)) {
222 if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] &
224 attributes &= ~METHOD_IS_GETTER;
226 if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] &
228 attributes &= ~METHOD_IS_SETTER;
233 * The expected instruction sequence is setter will never return value and
234 * getter will also do. Clear the bits if the behavior is discovered
237 if (flags & kInstrCanReturn) {
238 if (dalvikOpcode == OP_RETURN_VOID) {
239 attributes &= ~METHOD_IS_GETTER;
242 attributes &= ~METHOD_IS_SETTER;
246 if (flags & kInstrCanThrow) {
247 attributes &= ~METHOD_IS_THROW_FREE;
250 if (offset == 0 && dalvikOpcode == OP_RETURN_VOID) {
251 attributes |= METHOD_IS_EMPTY;
255 * Check if this opcode is selected for single stepping.
256 * If so, don't inline the callee as there is no stack frame for the
257 * interpreter to single-step through the instruction.
259 if (SINGLE_STEP_OP(dalvikOpcode)) {
260 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
267 * Analyze each method whose traces are ever compiled. Collect a variety of
268 * statistics like the ratio of exercised vs overall code and code bloat
269 * ratios. If isCallee is true, also analyze each instruction in more details
270 * to see if it is suitable for inlining.
272 CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
275 const DexCode *dexCode = dvmGetMethodCode(method);
276 const u2 *codePtr = dexCode->insns;
277 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
279 int hashValue = dvmComputeUtf8Hash(method->name);
281 CompilerMethodStats dummyMethodEntry; // For hash table lookup
282 CompilerMethodStats *realMethodEntry; // For hash table storage
284 /* For lookup only */
285 dummyMethodEntry.method = method;
287 (CompilerMethodStats *) dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
289 (HashCompareFunc) compareMethod,
292 /* This method has never been analyzed before - create an entry */
293 if (realMethodEntry == NULL) {
295 (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
296 realMethodEntry->method = method;
298 dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
300 (HashCompareFunc) compareMethod,
304 /* This method is invoked as a callee and has been analyzed - just return */
305 if ((isCallee == true) && (realMethodEntry->attributes & METHOD_IS_CALLEE))
306 return realMethodEntry;
309 * Similarly, return if this method has been compiled before as a hot
312 if ((isCallee == false) &&
313 (realMethodEntry->attributes & METHOD_IS_HOT))
314 return realMethodEntry;
318 /* Method hasn't been analyzed for the desired purpose yet */
320 /* Aggressively set the attributes until proven otherwise */
321 attributes = METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE |
322 METHOD_IS_GETTER | METHOD_IS_SETTER;
324 attributes = METHOD_IS_HOT;
327 /* Count the number of instructions */
328 while (codePtr < codeEnd) {
329 DecodedInstruction dalvikInsn;
330 int width = parseInsn(codePtr, &dalvikInsn, false);
332 /* Terminate when the data section is seen */
337 attributes = analyzeInlineTarget(&dalvikInsn, attributes, insnSize);
345 * Only handle simple getters/setters with one instruction followed by
348 if ((attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) &&
350 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
353 realMethodEntry->dalvikSize = insnSize * 2;
354 realMethodEntry->attributes |= attributes;
357 /* Uncomment the following to explore various callee patterns */
358 if (attributes & METHOD_IS_THROW_FREE) {
359 LOGE("%s%s is inlinable%s", method->clazz->descriptor, method->name,
360 (attributes & METHOD_IS_EMPTY) ? " empty" : "");
363 if (attributes & METHOD_IS_LEAF) {
364 LOGE("%s%s is leaf %d%s", method->clazz->descriptor, method->name,
365 insnSize, insnSize < 5 ? " (small)" : "");
368 if (attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) {
369 LOGE("%s%s is %s", method->clazz->descriptor, method->name,
370 attributes & METHOD_IS_GETTER ? "getter": "setter");
373 (METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE)) {
374 LOGE("%s%s is inlinable non setter/getter", method->clazz->descriptor,
379 return realMethodEntry;
383 * Crawl the stack of the thread that requesed compilation to see if any of the
384 * ancestors are on the blacklist.
386 static bool filterMethodByCallGraph(Thread *thread, const char *curMethodName)
388 /* Crawl the Dalvik stack frames and compare the method name*/
389 StackSaveArea *ssaPtr = ((StackSaveArea *) thread->curFrame) - 1;
390 while (ssaPtr != ((StackSaveArea *) NULL) - 1) {
391 const Method *method = ssaPtr->method;
393 int hashValue = dvmComputeUtf8Hash(method->name);
395 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
396 (char *) method->name,
397 (HashCompareFunc) strcmp, false) !=
400 LOGD("Method %s (--> %s) found on the JIT %s list",
401 method->name, curMethodName,
402 gDvmJit.includeSelectedMethod ? "white" : "black");
407 ssaPtr = ((StackSaveArea *) ssaPtr->prevFrame) - 1;
413 * Main entry point to start trace compilation. Basic blocks are constructed
414 * first and they will be passed to the codegen routines to convert Dalvik
415 * bytecode into machine code.
417 bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
418 JitTranslationInfo *info, jmp_buf *bailPtr,
421 const DexCode *dexCode = dvmGetMethodCode(desc->method);
422 const JitTraceRun* currRun = &desc->trace[0];
423 unsigned int curOffset = currRun->frag.startOffset;
424 unsigned int numInsts = currRun->frag.numInsts;
425 const u2 *codePtr = dexCode->insns + curOffset;
426 int traceSize = 0; // # of half-words
427 const u2 *startCodePtr = codePtr;
428 BasicBlock *curBB, *entryCodeBB;
430 static int compilationId;
431 CompilationUnit cUnit;
432 GrowableList *blockList;
433 #if defined(WITH_JIT_TUNING)
434 CompilerMethodStats *methodStats;
437 /* If we've already compiled this trace, just return success */
438 if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
440 * Make sure the codeAddress is NULL so that it won't clobber the
443 info->codeAddress = NULL;
448 memset(&cUnit, 0, sizeof(CompilationUnit));
450 #if defined(WITH_JIT_TUNING)
451 /* Locate the entry to store compilation statistics for this method */
452 methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
455 /* Set the recover buffer pointer */
456 cUnit.bailPtr = bailPtr;
458 /* Initialize the printMe flag */
459 cUnit.printMe = gDvmJit.printMe;
461 /* Initialize the profile flag */
462 cUnit.executionCount = gDvmJit.profile;
464 /* Setup the method */
465 cUnit.method = desc->method;
467 /* Initialize the PC reconstruction list */
468 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
470 /* Initialize the basic block list */
471 blockList = &cUnit.blockList;
472 dvmInitGrowableList(blockList, 8);
474 /* Identify traces that we don't want to compile */
475 if (gDvmJit.methodTable) {
476 int len = strlen(desc->method->clazz->descriptor) +
477 strlen(desc->method->name) + 1;
478 char *fullSignature = (char *)dvmCompilerNew(len, true);
479 strcpy(fullSignature, desc->method->clazz->descriptor);
480 strcat(fullSignature, desc->method->name);
482 int hashValue = dvmComputeUtf8Hash(fullSignature);
485 * Doing three levels of screening to see whether we want to skip
486 * compiling this method
489 /* First, check the full "class;method" signature */
491 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
492 fullSignature, (HashCompareFunc) strcmp,
496 /* Full signature not found - check the enclosing class */
497 if (methodFound == false) {
498 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
500 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
501 (char *) desc->method->clazz->descriptor,
502 (HashCompareFunc) strcmp, false) !=
504 /* Enclosing class not found - check the method name */
505 if (methodFound == false) {
506 int hashValue = dvmComputeUtf8Hash(desc->method->name);
508 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
509 (char *) desc->method->name,
510 (HashCompareFunc) strcmp, false) !=
514 * Debug by call-graph is enabled. Check if the debug list
515 * covers any methods on the VM stack.
517 if (methodFound == false && gDvmJit.checkCallGraph == true) {
519 filterMethodByCallGraph(info->requestingThread,
526 * Under the following conditions, the trace will be *conservatively*
527 * compiled by only containing single-step instructions to and from the
529 * 1) If includeSelectedMethod == false, the method matches the full or
530 * partial signature stored in the hash table.
532 * 2) If includeSelectedMethod == true, the method does not match the
533 * full and partial signature stored in the hash table.
535 if (gDvmJit.includeSelectedMethod != methodFound) {
536 cUnit.allSingleStep = true;
538 /* Compile the trace as normal */
540 /* Print the method we cherry picked */
541 if (gDvmJit.includeSelectedMethod == true) {
542 cUnit.printMe = true;
547 /* Allocate the entry block */
548 curBB = dvmCompilerNewBB(kTraceEntryBlock, numBlocks++);
549 dvmInsertGrowableList(blockList, (intptr_t) curBB);
550 curBB->startOffset = curOffset;
552 entryCodeBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
553 dvmInsertGrowableList(blockList, (intptr_t) entryCodeBB);
554 entryCodeBB->startOffset = curOffset;
555 curBB->fallThrough = entryCodeBB;
559 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
560 desc->method->name, curOffset);
564 * Analyze the trace descriptor and include up to the maximal number
565 * of Dalvik instructions into the IR.
570 insn = (MIR *)dvmCompilerNew(sizeof(MIR), true);
571 insn->offset = curOffset;
572 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
574 /* The trace should never incude instruction data */
578 dvmCompilerAppendMIR(curBB, insn);
581 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
583 if (flags & kInstrInvoke) {
584 assert(numInsts == 1);
585 CallsiteInfo *callsiteInfo =
586 (CallsiteInfo *)dvmCompilerNew(sizeof(CallsiteInfo), true);
587 callsiteInfo->clazz = (ClassObject *)currRun[1].meta;
588 callsiteInfo->method = (Method *)currRun[2].meta;
589 insn->meta.callsiteInfo = callsiteInfo;
592 /* Instruction limit reached - terminate the trace here */
593 if (cUnit.numInsts >= numMaxInsts) {
596 if (--numInsts == 0) {
597 if (currRun->frag.runEnd) {
600 /* Advance to the next trace description (ie non-meta info) */
603 } while (!currRun->frag.isCode);
605 /* Dummy end-of-run marker seen */
606 if (currRun->frag.numInsts == 0) {
610 curBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
611 dvmInsertGrowableList(blockList, (intptr_t) curBB);
612 curOffset = currRun->frag.startOffset;
613 numInsts = currRun->frag.numInsts;
614 curBB->startOffset = curOffset;
615 codePtr = dexCode->insns + curOffset;
623 #if defined(WITH_JIT_TUNING)
624 /* Convert # of half-word to bytes */
625 methodStats->compiledDalvikSize += traceSize * 2;
629 * Now scan basic blocks containing real code to connect the
630 * taken/fallthrough links. Also create chaining cells for code not included
634 for (blockId = 0; blockId < blockList->numUsed; blockId++) {
635 curBB = (BasicBlock *) dvmGrowableListGetElement(blockList, blockId);
636 MIR *lastInsn = curBB->lastMIRInsn;
637 /* Skip empty blocks */
638 if (lastInsn == NULL) {
641 curOffset = lastInsn->offset;
642 unsigned int targetOffset = curOffset;
643 unsigned int fallThroughOffset = curOffset + lastInsn->width;
644 bool isInvoke = false;
645 const Method *callee = NULL;
647 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
648 &targetOffset, &isInvoke, &callee);
650 /* Link the taken and fallthrough blocks */
651 BasicBlock *searchBB;
653 int flags = dexGetFlagsFromOpcode(lastInsn->dalvikInsn.opcode);
655 if (flags & kInstrInvoke) {
656 cUnit.hasInvoke = true;
659 /* No backward branch in the trace - start searching the next BB */
660 size_t searchBlockId;
661 for (searchBlockId = blockId+1; searchBlockId < blockList->numUsed;
663 searchBB = (BasicBlock *) dvmGrowableListGetElement(blockList,
665 if (targetOffset == searchBB->startOffset) {
666 curBB->taken = searchBB;
668 if (fallThroughOffset == searchBB->startOffset) {
669 curBB->fallThrough = searchBB;
672 * Fallthrough block of an invoke instruction needs to be
673 * aligned to 4-byte boundary (alignment instruction to be
676 if (flags & kInstrInvoke) {
677 searchBB->isFallThroughFromInvoke = true;
683 * Some blocks are ended by non-control-flow-change instructions,
684 * currently only due to trace length constraint. In this case we need
685 * to generate an explicit branch at the end of the block to jump to
688 curBB->needFallThroughBranch =
689 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
690 kInstrInvoke)) == 0);
692 /* Only form a loop if JIT_OPT_NO_LOOP is not set */
693 if (curBB->taken == NULL &&
694 curBB->fallThrough == NULL &&
695 flags == (kInstrCanBranch | kInstrCanContinue) &&
696 fallThroughOffset == entryCodeBB->startOffset &&
697 JIT_OPT_NO_LOOP != (optHints & JIT_OPT_NO_LOOP)) {
698 BasicBlock *loopBranch = curBB;
700 BasicBlock *exitChainingCell;
703 LOGD("Natural loop detected!");
705 exitBB = dvmCompilerNewBB(kTraceExitBlock, numBlocks++);
706 dvmInsertGrowableList(blockList, (intptr_t) exitBB);
707 exitBB->startOffset = targetOffset;
708 exitBB->needFallThroughBranch = true;
710 loopBranch->taken = exitBB;
711 #if defined(WITH_SELF_VERIFICATION)
712 BasicBlock *backwardCell =
713 dvmCompilerNewBB(kChainingCellBackwardBranch, numBlocks++);
714 dvmInsertGrowableList(blockList, (intptr_t) backwardCell);
715 backwardCell->startOffset = entryCodeBB->startOffset;
716 loopBranch->fallThrough = backwardCell;
717 #elif defined(WITH_JIT_TUNING)
718 if (gDvmJit.profile) {
719 BasicBlock *backwardCell =
720 dvmCompilerNewBB(kChainingCellBackwardBranch, numBlocks++);
721 dvmInsertGrowableList(blockList, (intptr_t) backwardCell);
722 backwardCell->startOffset = entryCodeBB->startOffset;
723 loopBranch->fallThrough = backwardCell;
725 loopBranch->fallThrough = entryCodeBB;
728 loopBranch->fallThrough = entryCodeBB;
731 /* Create the chaining cell as the fallthrough of the exit block */
732 exitChainingCell = dvmCompilerNewBB(kChainingCellNormal,
734 dvmInsertGrowableList(blockList, (intptr_t) exitChainingCell);
735 exitChainingCell->startOffset = targetOffset;
737 exitBB->fallThrough = exitChainingCell;
739 cUnit.hasLoop = true;
742 if (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ||
743 lastInsn->dalvikInsn.opcode == OP_SPARSE_SWITCH) {
745 const u2 *switchData = desc->method->insns + lastInsn->offset +
746 lastInsn->dalvikInsn.vB;
747 int size = switchData[1];
748 int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
751 * Generate the landing pad for cases whose ranks are higher than
752 * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
753 * through the NoChain point.
755 if (maxChains != size) {
756 cUnit.switchOverflowPad =
757 desc->method->insns + lastInsn->offset;
760 s4 *targets = (s4 *) (switchData + 2 +
761 (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ?
764 /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
765 for (i = 0; i < maxChains; i++) {
766 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
768 dvmInsertGrowableList(blockList, (intptr_t) caseChain);
769 caseChain->startOffset = lastInsn->offset + targets[i];
772 /* One more chaining cell for the default case */
773 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
775 dvmInsertGrowableList(blockList, (intptr_t) caseChain);
776 caseChain->startOffset = lastInsn->offset + lastInsn->width;
777 /* Fallthrough block not included in the trace */
778 } else if (!isUnconditionalBranch(lastInsn) &&
779 curBB->fallThrough == NULL) {
780 BasicBlock *fallThroughBB;
782 * If the chaining cell is after an invoke or
783 * instruction that cannot change the control flow, request a hot
786 if (isInvoke || curBB->needFallThroughBranch) {
787 fallThroughBB = dvmCompilerNewBB(kChainingCellHot, numBlocks++);
789 fallThroughBB = dvmCompilerNewBB(kChainingCellNormal,
792 dvmInsertGrowableList(blockList, (intptr_t) fallThroughBB);
793 fallThroughBB->startOffset = fallThroughOffset;
794 curBB->fallThrough = fallThroughBB;
796 /* Target block not included in the trace */
797 if (curBB->taken == NULL &&
798 (isGoto(lastInsn) || isInvoke ||
799 (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
802 /* Monomorphic callee */
804 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton,
806 newBB->startOffset = 0;
807 newBB->containingMethod = callee;
808 /* Will resolve at runtime */
810 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted,
812 newBB->startOffset = 0;
814 /* For unconditional branches, request a hot chaining cell */
816 #if !defined(WITH_SELF_VERIFICATION)
817 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
821 newBB->startOffset = targetOffset;
823 /* Handle branches that branch back into the block */
824 if (targetOffset >= curBB->firstMIRInsn->offset &&
825 targetOffset <= curBB->lastMIRInsn->offset) {
826 newBB = dvmCompilerNewBB(kChainingCellBackwardBranch,
829 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
834 newBB->startOffset = targetOffset;
837 curBB->taken = newBB;
838 dvmInsertGrowableList(blockList, (intptr_t) newBB);
842 /* Now create a special block to host PC reconstruction code */
843 curBB = dvmCompilerNewBB(kPCReconstruction, numBlocks++);
844 dvmInsertGrowableList(blockList, (intptr_t) curBB);
846 /* And one final block that publishes the PC and raise the exception */
847 curBB = dvmCompilerNewBB(kExceptionHandling, numBlocks++);
848 dvmInsertGrowableList(blockList, (intptr_t) curBB);
852 dexProtoCopyMethodDescriptor(&desc->method->prototype);
853 LOGD("TRACEINFO (%d): 0x%08x %s%s.%s 0x%x %d of %d, %d blocks",
855 (intptr_t) desc->method->insns,
856 desc->method->clazz->descriptor,
859 desc->trace[0].frag.startOffset,
866 cUnit.traceDesc = desc;
867 cUnit.numBlocks = numBlocks;
869 /* Set the instruction set to use (NOTE: later components may change it) */
870 cUnit.instructionSet = dvmCompilerInstructionSet();
872 /* Inline transformation @ the MIR level */
873 if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
874 dvmCompilerInlineMIR(&cUnit);
877 cUnit.numDalvikRegisters = cUnit.method->registersSize;
879 /* Preparation for SSA conversion */
880 dvmInitializeSSAConversion(&cUnit);
884 * Loop is not optimizable (for example lack of a single induction
885 * variable), punt and recompile the trace with loop optimization
888 bool loopOpt = dvmCompilerLoopOpt(&cUnit);
889 if (loopOpt == false) {
891 LOGD("Loop is not optimizable - retry codegen");
893 /* Reset the compiler resource pool */
894 dvmCompilerArenaReset();
895 return dvmCompileTrace(desc, cUnit.numInsts, info, bailPtr,
896 optHints | JIT_OPT_NO_LOOP);
900 dvmCompilerNonLoopAnalysis(&cUnit);
903 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
906 dvmCompilerDumpCompilationUnit(&cUnit);
909 /* Allocate Registers */
910 dvmCompilerRegAlloc(&cUnit);
912 /* Convert MIR to LIR, etc. */
913 dvmCompilerMIR2LIR(&cUnit);
915 /* Convert LIR into machine code. Loop for recoverable retries */
917 dvmCompilerAssembleLIR(&cUnit, info);
918 cUnit.assemblerRetries++;
919 if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
920 LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
921 cUnit.assemblerStatus);
922 } while (cUnit.assemblerStatus == kRetryAll);
925 dvmCompilerCodegenDump(&cUnit);
926 LOGD("End %s%s, %d Dalvik instructions",
927 desc->method->clazz->descriptor, desc->method->name,
931 /* Reset the compiler resource pool */
932 dvmCompilerArenaReset();
934 if (cUnit.assemblerStatus == kRetryHalve) {
935 /* Halve the instruction count and start from the top */
936 return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr,
940 assert(cUnit.assemblerStatus == kSuccess);
941 #if defined(WITH_JIT_TUNING)
942 methodStats->nativeSize += cUnit.totalSize;
945 /* FIXME - to exercise the method parser, uncomment the following code */
947 bool dvmCompileMethod(const Method *method);
948 if (desc->trace[0].frag.startOffset == 0) {
949 dvmCompileMethod(desc->method);
953 return info->codeAddress != NULL;
957 * Since we are including instructions from possibly a cold method into the
958 * current trace, we need to make sure that all the associated information
959 * with the callee is properly initialized. If not, we punt on this inline
962 * TODO: volatile instructions will be handled later.
964 bool dvmCompilerCanIncludeThisInstruction(const Method *method,
965 const DecodedInstruction *insn)
967 switch (insn->opcode) {
968 case OP_NEW_INSTANCE:
969 case OP_CHECK_CAST: {
970 ClassObject *classPtr = (ClassObject *)(void*)
971 (method->clazz->pDvmDex->pResClasses[insn->vB]);
973 /* Class hasn't been initialized yet */
974 if (classPtr == NULL) {
980 case OP_SGET_BOOLEAN:
987 case OP_SPUT_BOOLEAN:
993 void *fieldPtr = (void*)
994 (method->clazz->pDvmDex->pResFields[insn->vB]);
996 if (fieldPtr == NULL) {
1001 case OP_INVOKE_SUPER:
1002 case OP_INVOKE_SUPER_RANGE: {
1003 int mIndex = method->clazz->pDvmDex->
1004 pResMethods[insn->vB]->methodIndex;
1005 const Method *calleeMethod = method->clazz->super->vtable[mIndex];
1006 if (calleeMethod == NULL) {
1011 case OP_INVOKE_SUPER_QUICK:
1012 case OP_INVOKE_SUPER_QUICK_RANGE: {
1013 const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
1014 if (calleeMethod == NULL) {
1019 case OP_INVOKE_STATIC:
1020 case OP_INVOKE_STATIC_RANGE:
1021 case OP_INVOKE_DIRECT:
1022 case OP_INVOKE_DIRECT_RANGE: {
1023 const Method *calleeMethod =
1024 method->clazz->pDvmDex->pResMethods[insn->vB];
1025 if (calleeMethod == NULL) {
1030 case OP_CONST_CLASS: {
1031 void *classPtr = (void*)
1032 (method->clazz->pDvmDex->pResClasses[insn->vB]);
1034 if (classPtr == NULL) {
1039 case OP_CONST_STRING_JUMBO:
1040 case OP_CONST_STRING: {
1041 void *strPtr = (void*)
1042 (method->clazz->pDvmDex->pResStrings[insn->vB]);
1044 if (strPtr == NULL) {
1054 /* Split an existing block from the specified code offset into two */
1055 static BasicBlock *splitBlock(CompilationUnit *cUnit,
1056 unsigned int codeOffset,
1057 BasicBlock *origBlock)
1059 MIR *insn = origBlock->firstMIRInsn;
1061 if (insn->offset == codeOffset) break;
1065 LOGE("Break split failed");
1068 BasicBlock *bottomBlock = dvmCompilerNewBB(kDalvikByteCode,
1069 cUnit->numBlocks++);
1070 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
1072 bottomBlock->startOffset = codeOffset;
1073 bottomBlock->firstMIRInsn = insn;
1074 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
1076 /* Only the top half of split blocks is tagged as BA_CATCH_BLOCK */
1077 bottomBlock->blockAttributes = origBlock->blockAttributes & ~BA_CATCH_BLOCK;
1079 /* Handle the taken path */
1080 bottomBlock->taken = origBlock->taken;
1081 if (bottomBlock->taken) {
1082 origBlock->taken = NULL;
1083 dvmCompilerClearBit(bottomBlock->taken->predecessors, origBlock->id);
1084 dvmCompilerSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
1087 /* Handle the fallthrough path */
1088 bottomBlock->fallThrough = origBlock->fallThrough;
1089 origBlock->fallThrough = bottomBlock;
1090 dvmCompilerSetBit(bottomBlock->predecessors, origBlock->id);
1091 if (bottomBlock->fallThrough) {
1092 dvmCompilerClearBit(bottomBlock->fallThrough->predecessors,
1094 dvmCompilerSetBit(bottomBlock->fallThrough->predecessors,
1098 /* Handle the successor list */
1099 if (origBlock->successorBlockList.blockListType != kNotUsed) {
1100 bottomBlock->successorBlockList = origBlock->successorBlockList;
1101 origBlock->successorBlockList.blockListType = kNotUsed;
1102 GrowableListIterator iterator;
1104 dvmGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
1108 (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
1109 if (bb == NULL) break;
1110 dvmCompilerClearBit(bb->predecessors, origBlock->id);
1111 dvmCompilerSetBit(bb->predecessors, bottomBlock->id);
1115 origBlock->lastMIRInsn = insn->prev;
1116 /* Only the bottom half of split blocks is tagged as BA_ENDS_WITH_THROW */
1117 origBlock->blockAttributes &= ~BA_ENDS_WITH_THROW;
1119 insn->prev->next = NULL;
1125 * Given a code offset, find out the block that starts with it. If the offset
1126 * is in the middle of an existing block, split it into two.
1128 static BasicBlock *findBlock(CompilationUnit *cUnit,
1129 unsigned int codeOffset,
1130 bool split, bool create)
1132 GrowableList *blockList = &cUnit->blockList;
1136 for (i = 0; i < blockList->numUsed; i++) {
1137 bb = (BasicBlock *) blockList->elemList[i];
1138 if (bb->blockType != kDalvikByteCode) continue;
1139 if (bb->startOffset == codeOffset) return bb;
1140 /* Check if a branch jumps into the middle of an existing block */
1141 if ((split == true) && (codeOffset > bb->startOffset) &&
1142 (bb->lastMIRInsn != NULL) &&
1143 (codeOffset <= bb->lastMIRInsn->offset)) {
1144 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb);
1149 bb = dvmCompilerNewBB(kDalvikByteCode, cUnit->numBlocks++);
1150 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
1151 bb->startOffset = codeOffset;
1157 /* Dump the CFG into a DOT graph */
1158 void dumpCFG(CompilationUnit *cUnit, const char *dirPrefix)
1160 const Method *method = cUnit->method;
1162 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
1163 char *fileName = (char *) dvmCompilerNew(
1165 strlen(method->clazz->descriptor) +
1166 strlen(method->name) +
1168 strlen(".dot") + 1, true);
1169 sprintf(fileName, "%s%s%s%s.dot", dirPrefix,
1170 method->clazz->descriptor, method->name, signature);
1174 * Convert the special characters into a filesystem- and shell-friendly
1178 for (i = strlen(dirPrefix); fileName[i]; i++) {
1179 if (fileName[i] == '/') {
1181 } else if (fileName[i] == ';') {
1183 } else if (fileName[i] == '$') {
1185 } else if (fileName[i] == '(' || fileName[i] == ')') {
1187 } else if (fileName[i] == '<' || fileName[i] == '>') {
1191 file = fopen(fileName, "w");
1195 fprintf(file, "digraph G {\n");
1197 fprintf(file, " rankdir=TB\n");
1199 int numReachableBlocks = cUnit->numReachableBlocks;
1201 const GrowableList *blockList = &cUnit->blockList;
1203 for (idx = 0; idx < numReachableBlocks; idx++) {
1204 int blockIdx = cUnit->dfsOrder.elemList[idx];
1205 BasicBlock *bb = (BasicBlock *) dvmGrowableListGetElement(blockList,
1207 if (bb == NULL) break;
1208 if (bb->blockType == kMethodEntryBlock) {
1209 fprintf(file, " entry [shape=Mdiamond];\n");
1210 } else if (bb->blockType == kMethodExitBlock) {
1211 fprintf(file, " exit [shape=Mdiamond];\n");
1212 } else if (bb->blockType == kDalvikByteCode) {
1213 fprintf(file, " block%04x [shape=%s,label = \"{ \\\n",
1215 bb->blockAttributes & BA_CATCH_BLOCK ?
1216 "Mrecord" : "record");
1217 if (bb->blockAttributes & BA_CATCH_BLOCK) {
1218 if (bb->exceptionTypeIdx == kDexNoIndex) {
1219 fprintf(file, " {any\\l} |\\\n");
1221 fprintf(file, " {throwable type:%x\\l} |\\\n",
1222 bb->exceptionTypeIdx);
1226 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1227 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
1228 dvmCompilerFullDisassembler(cUnit, mir),
1229 mir->next ? " | " : " ");
1231 fprintf(file, " }\"];\n\n");
1232 } else if (bb->blockType == kExceptionHandling) {
1233 char blockName[BLOCK_NAME_LEN];
1235 dvmGetBlockName(bb, blockName);
1236 fprintf(file, " %s [shape=invhouse];\n", blockName);
1239 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
1242 dvmGetBlockName(bb, blockName1);
1243 dvmGetBlockName(bb->taken, blockName2);
1244 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
1245 blockName1, blockName2);
1247 if (bb->fallThrough) {
1248 dvmGetBlockName(bb, blockName1);
1249 dvmGetBlockName(bb->fallThrough, blockName2);
1250 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
1253 if (bb->successorBlockList.blockListType != kNotUsed) {
1254 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
1256 (bb->successorBlockList.blockListType == kCatch) ?
1257 "Mrecord" : "record");
1258 GrowableListIterator iterator;
1259 dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
1262 BasicBlock *destBlock =
1263 (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
1267 if (destBlock == NULL) break;
1268 BasicBlock *nextBlock =
1269 (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
1270 fprintf(file, " {<f%d> %04x\\l}%s\\\n",
1272 destBlock->startOffset,
1273 (nextBlock != NULL) ? " | " : " ");
1274 destBlock = nextBlock;
1276 fprintf(file, " }\"];\n\n");
1278 dvmGetBlockName(bb, blockName1);
1279 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
1280 blockName1, bb->startOffset);
1282 if (bb->successorBlockList.blockListType == kPackedSwitch ||
1283 bb->successorBlockList.blockListType == kSparseSwitch) {
1285 dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
1290 BasicBlock *destBlock =
1291 (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
1292 if (destBlock == NULL) break;
1294 dvmGetBlockName(destBlock, blockName2);
1295 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
1296 bb->startOffset, succId++,
1301 fprintf(file, "\n");
1304 * If we need to debug the dominator tree, uncomment the following code
1307 dvmGetBlockName(bb, blockName1);
1308 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
1309 blockName1, blockName1);
1311 dvmGetBlockName(bb->iDom, blockName2);
1312 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
1313 blockName2, blockName1);
1317 fprintf(file, "}\n");
1321 /* Verify if all the successor is connected with all the claimed predecessors */
1322 static bool verifyPredInfo(CompilationUnit *cUnit, BasicBlock *bb)
1324 BitVectorIterator bvIterator;
1326 dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
1328 int blockIdx = dvmBitVectorIteratorNext(&bvIterator);
1329 if (blockIdx == -1) break;
1330 BasicBlock *predBB = (BasicBlock *)
1331 dvmGrowableListGetElement(&cUnit->blockList, blockIdx);
1333 if (predBB->taken == bb) {
1335 } else if (predBB->fallThrough == bb) {
1337 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
1338 GrowableListIterator iterator;
1339 dvmGrowableListIteratorInit(&predBB->successorBlockList.blocks,
1342 BasicBlock *succBB =
1343 (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
1344 if (succBB == NULL) break;
1351 if (found == false) {
1352 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
1353 dvmGetBlockName(bb, blockName1);
1354 dvmGetBlockName(predBB, blockName2);
1355 dumpCFG(cUnit, "/data/tombstones/");
1356 LOGE("Successor %s not found from %s",
1357 blockName1, blockName2);
1364 /* Identify code range in try blocks and set up the empty catch blocks */
1365 static void processTryCatchBlocks(CompilationUnit *cUnit)
1367 const Method *meth = cUnit->method;
1368 const DexCode *pCode = dvmGetMethodCode(meth);
1369 int triesSize = pCode->triesSize;
1373 if (triesSize == 0) {
1377 const DexTry *pTries = dexGetTries(pCode);
1378 BitVector *tryBlockAddr = cUnit->tryBlockAddr;
1380 /* Mark all the insn offsets in Try blocks */
1381 for (i = 0; i < triesSize; i++) {
1382 const DexTry* pTry = &pTries[i];
1383 /* all in 16-bit units */
1384 int startOffset = pTry->startAddr;
1385 int endOffset = startOffset + pTry->insnCount;
1387 for (offset = startOffset; offset < endOffset; offset++) {
1388 dvmCompilerSetBit(tryBlockAddr, offset);
1392 /* Iterate over each of the handlers to enqueue the empty Catch blocks */
1393 offset = dexGetFirstHandlerOffset(pCode);
1394 int handlersSize = dexGetHandlersSize(pCode);
1396 for (i = 0; i < handlersSize; i++) {
1397 DexCatchIterator iterator;
1398 dexCatchIteratorInit(&iterator, pCode, offset);
1401 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
1403 if (handler == NULL) {
1407 BasicBlock *catchBlock = findBlock(cUnit, handler->address,
1412 catchBlock->blockAttributes |= BA_CATCH_BLOCK;
1413 catchBlock->exceptionTypeIdx = handler->typeIdx;
1416 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
1420 /* Process instructions with the kInstrCanBranch flag */
1421 static void processCanBranch(CompilationUnit *cUnit, BasicBlock *curBlock,
1422 MIR *insn, int curOffset, int width, int flags,
1423 const u2* codePtr, const u2* codeEnd)
1425 int target = curOffset;
1426 switch (insn->dalvikInsn.opcode) {
1430 target += (int) insn->dalvikInsn.vA;
1438 target += (int) insn->dalvikInsn.vC;
1446 target += (int) insn->dalvikInsn.vB;
1449 LOGE("Unexpected opcode(%d) with kInstrCanBranch set",
1450 insn->dalvikInsn.opcode);
1453 BasicBlock *takenBlock = findBlock(cUnit, target,
1458 curBlock->taken = takenBlock;
1459 dvmCompilerSetBit(takenBlock->predecessors, curBlock->id);
1461 /* Always terminate the current block for conditional branches */
1462 if (flags & kInstrCanContinue) {
1463 BasicBlock *fallthroughBlock = findBlock(cUnit,
1469 curBlock->fallThrough = fallthroughBlock;
1470 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1471 } else if (codePtr < codeEnd) {
1472 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
1473 if (contentIsInsn(codePtr)) {
1474 findBlock(cUnit, curOffset + width,
1483 /* Process instructions with the kInstrCanSwitch flag */
1484 static void processCanSwitch(CompilationUnit *cUnit, BasicBlock *curBlock,
1485 MIR *insn, int curOffset, int width, int flags)
1487 u2 *switchData= (u2 *) (cUnit->method->insns + curOffset +
1488 insn->dalvikInsn.vB);
1494 * Packed switch data format:
1495 * ushort ident = 0x0100 magic value
1496 * ushort size number of entries in the table
1497 * int first_key first (and lowest) switch case value
1498 * int targets[size] branch targets, relative to switch opcode
1500 * Total size is (4+size*2) 16-bit code units.
1502 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
1503 assert(switchData[0] == kPackedSwitchSignature);
1504 size = switchData[1];
1505 targetTable = (int *) &switchData[4];
1507 * Sparse switch data format:
1508 * ushort ident = 0x0200 magic value
1509 * ushort size number of entries in the table; > 0
1510 * int keys[size] keys, sorted low-to-high; 32-bit aligned
1511 * int targets[size] branch targets, relative to switch opcode
1513 * Total size is (2+size*4) 16-bit code units.
1516 assert(switchData[0] == kSparseSwitchSignature);
1517 size = switchData[1];
1518 targetTable = (int *) &switchData[2 + size*2];
1521 if (curBlock->successorBlockList.blockListType != kNotUsed) {
1522 LOGE("Successor block list already in use: %d",
1523 curBlock->successorBlockList.blockListType);
1526 curBlock->successorBlockList.blockListType =
1527 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
1528 kPackedSwitch : kSparseSwitch;
1529 dvmInitGrowableList(&curBlock->successorBlockList.blocks, size);
1531 for (i = 0; i < size; i++) {
1532 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
1537 dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
1538 (intptr_t) caseBlock);
1539 dvmCompilerSetBit(caseBlock->predecessors, curBlock->id);
1542 /* Fall-through case */
1543 BasicBlock *fallthroughBlock = findBlock(cUnit,
1549 curBlock->fallThrough = fallthroughBlock;
1550 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1553 /* Process instructions with the kInstrCanThrow flag */
1554 static void processCanThrow(CompilationUnit *cUnit, BasicBlock *curBlock,
1555 MIR *insn, int curOffset, int width, int flags,
1556 BitVector *tryBlockAddr, const u2 *codePtr,
1559 const Method *method = cUnit->method;
1560 const DexCode *dexCode = dvmGetMethodCode(method);
1562 curBlock->blockAttributes |= BA_ENDS_WITH_THROW;
1564 if (dvmIsBitSet(tryBlockAddr, curOffset)) {
1565 DexCatchIterator iterator;
1567 if (!dexFindCatchHandler(&iterator, dexCode, curOffset)) {
1568 LOGE("Catch block not found in dexfile for insn %x in %s",
1569 curOffset, method->name);
1573 if (curBlock->successorBlockList.blockListType != kNotUsed) {
1574 LOGE("Successor block list already in use: %d",
1575 curBlock->successorBlockList.blockListType);
1578 curBlock->successorBlockList.blockListType = kCatch;
1579 dvmInitGrowableList(&curBlock->successorBlockList.blocks, 2);
1582 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
1584 if (handler == NULL) {
1588 BasicBlock *catchBlock = findBlock(cUnit, handler->address,
1594 assert(catchBlock->blockAttributes & BA_CATCH_BLOCK);
1595 dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
1596 (intptr_t) catchBlock);
1597 dvmCompilerSetBit(catchBlock->predecessors, curBlock->id);
1600 BasicBlock *ehBlock = dvmCompilerNewBB(kExceptionHandling,
1601 cUnit->numBlocks++);
1602 curBlock->taken = ehBlock;
1603 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
1604 ehBlock->startOffset = curOffset;
1605 dvmCompilerSetBit(ehBlock->predecessors, curBlock->id);
1609 * Force the current block to terminate.
1611 * Data may be present before codeEnd, so we need to parse it to know
1612 * whether it is code or data.
1614 if (codePtr < codeEnd) {
1615 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
1616 if (contentIsInsn(codePtr)) {
1617 BasicBlock *fallthroughBlock = findBlock(cUnit,
1624 * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional
1627 if (insn->dalvikInsn.opcode != OP_THROW_VERIFICATION_ERROR &&
1628 insn->dalvikInsn.opcode != OP_THROW) {
1629 curBlock->fallThrough = fallthroughBlock;
1630 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1637 * Similar to dvmCompileTrace, but the entity processed here is the whole
1640 * TODO: implementation will be revisited when the trace builder can provide
1641 * whole-method traces.
1643 bool dvmCompileMethod(const Method *method)
1645 CompilationUnit cUnit;
1646 const DexCode *dexCode = dvmGetMethodCode(method);
1647 const u2 *codePtr = dexCode->insns;
1648 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
1650 unsigned int curOffset = 0;
1652 memset(&cUnit, 0, sizeof(cUnit));
1653 cUnit.method = method;
1655 /* Initialize the block list */
1656 dvmInitGrowableList(&cUnit.blockList, 4);
1658 /* Allocate the bit-vector to track the beginning of basic blocks */
1659 BitVector *tryBlockAddr = dvmCompilerAllocBitVector(dexCode->insnsSize,
1660 true /* expandable */);
1661 cUnit.tryBlockAddr = tryBlockAddr;
1663 /* Create the default entry and exit blocks and enter them to the list */
1664 BasicBlock *entryBlock = dvmCompilerNewBB(kMethodEntryBlock, numBlocks++);
1665 BasicBlock *exitBlock = dvmCompilerNewBB(kMethodExitBlock, numBlocks++);
1667 cUnit.entryBlock = entryBlock;
1668 cUnit.exitBlock = exitBlock;
1670 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) entryBlock);
1671 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) exitBlock);
1673 /* Current block to record parsed instructions */
1674 BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
1675 curBlock->startOffset = 0;
1676 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) curBlock);
1677 entryBlock->fallThrough = curBlock;
1678 dvmCompilerSetBit(curBlock->predecessors, entryBlock->id);
1681 * Store back the number of blocks since new blocks may be created of
1684 cUnit.numBlocks = numBlocks;
1686 /* Identify code range in try blocks and set up the empty catch blocks */
1687 processTryCatchBlocks(&cUnit);
1689 /* Parse all instructions and put them into containing basic blocks */
1690 while (codePtr < codeEnd) {
1691 MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true);
1692 insn->offset = curOffset;
1693 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
1694 insn->width = width;
1696 /* Terminate when the data section is seen */
1700 dvmCompilerAppendMIR(curBlock, insn);
1703 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
1705 if (flags & kInstrCanBranch) {
1706 processCanBranch(&cUnit, curBlock, insn, curOffset, width, flags,
1708 } else if (flags & kInstrCanReturn) {
1709 curBlock->fallThrough = exitBlock;
1710 dvmCompilerSetBit(exitBlock->predecessors, curBlock->id);
1712 * Terminate the current block if there are instructions
1715 if (codePtr < codeEnd) {
1717 * Create a fallthrough block for real instructions
1720 if (contentIsInsn(codePtr)) {
1721 findBlock(&cUnit, curOffset + width,
1728 } else if (flags & kInstrCanThrow) {
1729 processCanThrow(&cUnit, curBlock, insn, curOffset, width, flags,
1730 tryBlockAddr, codePtr, codeEnd);
1731 } else if (flags & kInstrCanSwitch) {
1732 processCanSwitch(&cUnit, curBlock, insn, curOffset, width, flags);
1735 BasicBlock *nextBlock = findBlock(&cUnit, curOffset,
1742 * The next instruction could be the target of a previously parsed
1743 * forward branch so a block is already created. If the current
1744 * instruction is not an unconditional branch, connect them through
1745 * the fall-through link.
1747 assert(curBlock->fallThrough == NULL ||
1748 curBlock->fallThrough == nextBlock ||
1749 curBlock->fallThrough == exitBlock);
1751 if ((curBlock->fallThrough == NULL) &&
1752 !dexIsGoto(flags) &&
1753 !(flags & kInstrCanReturn)) {
1754 curBlock->fallThrough = nextBlock;
1755 dvmCompilerSetBit(nextBlock->predecessors, curBlock->id);
1757 curBlock = nextBlock;
1761 /* Adjust this value accordingly once inlining is performed */
1762 cUnit.numDalvikRegisters = cUnit.method->registersSize;
1764 /* Verify if all blocks are connected as claimed */
1765 /* FIXME - to be disabled in the future */
1766 dvmCompilerDataFlowAnalysisDispatcher(&cUnit, verifyPredInfo,
1768 false /* isIterative */);
1771 /* Perform SSA transformation for the whole method */
1772 dvmCompilerMethodSSATransformation(&cUnit);
1774 if (cUnit.printMe) dumpCFG(&cUnit, "/data/tombstones/");
1776 /* Reset the compiler resource pool */
1777 dvmCompilerArenaReset();