summaryrefslogtreecommitdiffstats
path: root/vm/compiler/Frontend.cpp
diff options
context:
space:
mode:
authorBrian Carlstrom <bdc@google.com>2014-08-05 12:46:17 -0700
committerBrian Carlstrom <bdc@google.com>2014-08-05 12:51:13 -0700
commit870b4f2d70d67d6dbb7d0881d101c61bed8caad2 (patch)
tree7487dad3970556a040f88a49852a3dc9ed19bebd /vm/compiler/Frontend.cpp
parent76e15e367ae1189b6f641ba8d16ca92bd179dac0 (diff)
downloadandroid_dalvik-870b4f2d70d67d6dbb7d0881d101c61bed8caad2.tar.gz
android_dalvik-870b4f2d70d67d6dbb7d0881d101c61bed8caad2.tar.bz2
android_dalvik-870b4f2d70d67d6dbb7d0881d101c61bed8caad2.zip
Dalvik is dead, long live Dalvik!
croot cd dalvik repo start dalvik-is-dead-long-live-dalvik . repo sync -c . git rm -r README.txt git rm -r dexopt git rm -r tools/deadcode.py git rm -r tools/dex-preopt git rm -r tools/dexcheck git rm -r tools/gdbjithelper git rm -r unit-tests git rm -r vm git checkout HEAD vm/Common.h (needed by libdex) git checkout HEAD vm/DalvikVersion.h (needed by libdex) git checkout HEAD vm/Profile.h (needed by dmtracedump) git add Android.mk (after removing vm, dexopt, and unit-tests references) git commit -a -m 'Dalvik is dead, long live Dalvik!' Bug: 14298175 Change-Id: I9dd13053677629d13496d4238af4374452cda415
Diffstat (limited to 'vm/compiler/Frontend.cpp')
-rw-r--r--vm/compiler/Frontend.cpp2177
1 files changed, 0 insertions, 2177 deletions
diff --git a/vm/compiler/Frontend.cpp b/vm/compiler/Frontend.cpp
deleted file mode 100644
index 47c1898a0..000000000
--- a/vm/compiler/Frontend.cpp
+++ /dev/null
@@ -1,2177 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Dalvik.h"
-#include "libdex/DexOpcodes.h"
-#include "libdex/DexCatch.h"
-#include "interp/Jit.h"
-#include "CompilerInternals.h"
-#include "Dataflow.h"
-
-static inline bool contentIsInsn(const u2 *codePtr) {
- u2 instr = *codePtr;
- Opcode opcode = (Opcode)(instr & 0xff);
-
- /*
- * Since the low 8-bit in metadata may look like OP_NOP, we need to check
- * both the low and whole sub-word to determine whether it is code or data.
- */
- return (opcode != OP_NOP || instr == 0);
-}
-
-/*
- * Parse an instruction, return the length of the instruction
- */
-static inline int parseInsn(const u2 *codePtr, DecodedInstruction *decInsn,
- bool printMe)
-{
- // Don't parse instruction data
- if (!contentIsInsn(codePtr)) {
- return 0;
- }
-
- u2 instr = *codePtr;
- Opcode opcode = dexOpcodeFromCodeUnit(instr);
-
- dexDecodeInstruction(codePtr, decInsn);
- if (printMe) {
- char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn, NULL);
- ALOGD("%p: %#06x %s", codePtr, opcode, decodedString);
- }
- return dexGetWidthFromOpcode(opcode);
-}
-
-#define UNKNOWN_TARGET 0xffffffff
-
-/*
- * Identify block-ending instructions and collect supplemental information
- * regarding the following instructions.
- */
-static inline bool findBlockBoundary(const Method *caller, MIR *insn,
- unsigned int curOffset,
- unsigned int *target, bool *isInvoke,
- const Method **callee)
-{
- switch (insn->dalvikInsn.opcode) {
- /* Target is not compile-time constant */
- case OP_RETURN_VOID:
- case OP_RETURN:
- case OP_RETURN_WIDE:
- case OP_RETURN_OBJECT:
- case OP_THROW:
- *target = UNKNOWN_TARGET;
- break;
- case OP_INVOKE_VIRTUAL:
- case OP_INVOKE_VIRTUAL_RANGE:
- case OP_INVOKE_INTERFACE:
- case OP_INVOKE_INTERFACE_RANGE:
- case OP_INVOKE_VIRTUAL_QUICK:
- case OP_INVOKE_VIRTUAL_QUICK_RANGE:
- *isInvoke = true;
- break;
- case OP_INVOKE_SUPER:
- case OP_INVOKE_SUPER_RANGE: {
- int mIndex = caller->clazz->pDvmDex->
- pResMethods[insn->dalvikInsn.vB]->methodIndex;
- const Method *calleeMethod =
- caller->clazz->super->vtable[mIndex];
-
- if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
- *target = (unsigned int) calleeMethod->insns;
- }
- *isInvoke = true;
- *callee = calleeMethod;
- break;
- }
- case OP_INVOKE_STATIC:
- case OP_INVOKE_STATIC_RANGE: {
- const Method *calleeMethod =
- caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
-
- if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
- *target = (unsigned int) calleeMethod->insns;
- }
- *isInvoke = true;
- *callee = calleeMethod;
- break;
- }
- case OP_INVOKE_SUPER_QUICK:
- case OP_INVOKE_SUPER_QUICK_RANGE: {
- const Method *calleeMethod =
- caller->clazz->super->vtable[insn->dalvikInsn.vB];
-
- if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
- *target = (unsigned int) calleeMethod->insns;
- }
- *isInvoke = true;
- *callee = calleeMethod;
- break;
- }
- case OP_INVOKE_DIRECT:
- case OP_INVOKE_DIRECT_RANGE: {
- const Method *calleeMethod =
- caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
- if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
- *target = (unsigned int) calleeMethod->insns;
- }
- *isInvoke = true;
- *callee = calleeMethod;
- break;
- }
- case OP_GOTO:
- case OP_GOTO_16:
- case OP_GOTO_32:
- *target = curOffset + (int) insn->dalvikInsn.vA;
- break;
-
- case OP_IF_EQ:
- case OP_IF_NE:
- case OP_IF_LT:
- case OP_IF_GE:
- case OP_IF_GT:
- case OP_IF_LE:
- *target = curOffset + (int) insn->dalvikInsn.vC;
- break;
-
- case OP_IF_EQZ:
- case OP_IF_NEZ:
- case OP_IF_LTZ:
- case OP_IF_GEZ:
- case OP_IF_GTZ:
- case OP_IF_LEZ:
- *target = curOffset + (int) insn->dalvikInsn.vB;
- break;
-
- default:
- return false;
- }
- return true;
-}
-
-static inline bool isGoto(MIR *insn)
-{
- switch (insn->dalvikInsn.opcode) {
- case OP_GOTO:
- case OP_GOTO_16:
- case OP_GOTO_32:
- return true;
- default:
- return false;
- }
-}
-
-/*
- * Identify unconditional branch instructions
- */
-static inline bool isUnconditionalBranch(MIR *insn)
-{
- switch (insn->dalvikInsn.opcode) {
- case OP_RETURN_VOID:
- case OP_RETURN:
- case OP_RETURN_WIDE:
- case OP_RETURN_OBJECT:
- return true;
- default:
- return isGoto(insn);
- }
-}
-
-/*
- * dvmHashTableLookup() callback
- */
-static int compareMethod(const CompilerMethodStats *m1,
- const CompilerMethodStats *m2)
-{
- return (int) m1->method - (int) m2->method;
-}
-
-/*
- * Analyze the body of the method to collect high-level information regarding
- * inlining:
- * - is empty method?
- * - is getter/setter?
- * - can throw exception?
- *
- * Currently the inliner only handles getters and setters. When its capability
- * becomes more sophisticated more information will be retrieved here.
- */
-static int analyzeInlineTarget(DecodedInstruction *dalvikInsn, int attributes,
- int offset)
-{
- int flags = dexGetFlagsFromOpcode(dalvikInsn->opcode);
- int dalvikOpcode = dalvikInsn->opcode;
-
- if (flags & kInstrInvoke) {
- attributes &= ~METHOD_IS_LEAF;
- }
-
- if (!(flags & kInstrCanReturn)) {
- if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] &
- DF_IS_GETTER)) {
- attributes &= ~METHOD_IS_GETTER;
- }
- if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] &
- DF_IS_SETTER)) {
- attributes &= ~METHOD_IS_SETTER;
- }
- }
-
- /*
- * The expected instruction sequence is setter will never return value and
- * getter will also do. Clear the bits if the behavior is discovered
- * otherwise.
- */
- if (flags & kInstrCanReturn) {
- if (dalvikOpcode == OP_RETURN_VOID) {
- attributes &= ~METHOD_IS_GETTER;
- }
- else {
- attributes &= ~METHOD_IS_SETTER;
- }
- }
-
- if (flags & kInstrCanThrow) {
- attributes &= ~METHOD_IS_THROW_FREE;
- }
-
- if (offset == 0 && dalvikOpcode == OP_RETURN_VOID) {
- attributes |= METHOD_IS_EMPTY;
- }
-
- /*
- * Check if this opcode is selected for single stepping.
- * If so, don't inline the callee as there is no stack frame for the
- * interpreter to single-step through the instruction.
- */
- if (SINGLE_STEP_OP(dalvikOpcode)) {
- attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
- }
-
- return attributes;
-}
-
-/*
- * Analyze each method whose traces are ever compiled. Collect a variety of
- * statistics like the ratio of exercised vs overall code and code bloat
- * ratios. If isCallee is true, also analyze each instruction in more details
- * to see if it is suitable for inlining.
- */
-CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
- bool isCallee)
-{
- const DexCode *dexCode = dvmGetMethodCode(method);
- const u2 *codePtr = dexCode->insns;
- const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
- int insnSize = 0;
- int hashValue = dvmComputeUtf8Hash(method->name);
-
- CompilerMethodStats dummyMethodEntry; // For hash table lookup
- CompilerMethodStats *realMethodEntry; // For hash table storage
-
- /* For lookup only */
- dummyMethodEntry.method = method;
- realMethodEntry = (CompilerMethodStats *)
- dvmHashTableLookup(gDvmJit.methodStatsTable,
- hashValue,
- &dummyMethodEntry,
- (HashCompareFunc) compareMethod,
- false);
-
- /* This method has never been analyzed before - create an entry */
- if (realMethodEntry == NULL) {
- realMethodEntry =
- (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
- realMethodEntry->method = method;
-
- dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
- realMethodEntry,
- (HashCompareFunc) compareMethod,
- true);
- }
-
- /* This method is invoked as a callee and has been analyzed - just return */
- if ((isCallee == true) && (realMethodEntry->attributes & METHOD_IS_CALLEE))
- return realMethodEntry;
-
- /*
- * Similarly, return if this method has been compiled before as a hot
- * method already.
- */
- if ((isCallee == false) &&
- (realMethodEntry->attributes & METHOD_IS_HOT))
- return realMethodEntry;
-
- int attributes;
-
- /* Method hasn't been analyzed for the desired purpose yet */
- if (isCallee) {
- /* Aggressively set the attributes until proven otherwise */
- attributes = METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE |
- METHOD_IS_GETTER | METHOD_IS_SETTER;
- } else {
- attributes = METHOD_IS_HOT;
- }
-
- /* Count the number of instructions */
- while (codePtr < codeEnd) {
- DecodedInstruction dalvikInsn;
- int width = parseInsn(codePtr, &dalvikInsn, false);
-
- /* Terminate when the data section is seen */
- if (width == 0)
- break;
-
- if (isCallee) {
- attributes = analyzeInlineTarget(&dalvikInsn, attributes, insnSize);
- }
-
- insnSize += width;
- codePtr += width;
- }
-
- /*
- * Only handle simple getters/setters with one instruction followed by
- * return
- */
- if ((attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) &&
- (insnSize != 3)) {
- attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
- }
-
- realMethodEntry->dalvikSize = insnSize * 2;
- realMethodEntry->attributes |= attributes;
-
-#if 0
- /* Uncomment the following to explore various callee patterns */
- if (attributes & METHOD_IS_THROW_FREE) {
- ALOGE("%s%s is inlinable%s", method->clazz->descriptor, method->name,
- (attributes & METHOD_IS_EMPTY) ? " empty" : "");
- }
-
- if (attributes & METHOD_IS_LEAF) {
- ALOGE("%s%s is leaf %d%s", method->clazz->descriptor, method->name,
- insnSize, insnSize < 5 ? " (small)" : "");
- }
-
- if (attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) {
- ALOGE("%s%s is %s", method->clazz->descriptor, method->name,
- attributes & METHOD_IS_GETTER ? "getter": "setter");
- }
- if (attributes ==
- (METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE)) {
- ALOGE("%s%s is inlinable non setter/getter", method->clazz->descriptor,
- method->name);
- }
-#endif
-
- return realMethodEntry;
-}
-
-/*
- * Crawl the stack of the thread that requesed compilation to see if any of the
- * ancestors are on the blacklist.
- */
-static bool filterMethodByCallGraph(Thread *thread, const char *curMethodName)
-{
- /* Crawl the Dalvik stack frames and compare the method name*/
- StackSaveArea *ssaPtr = ((StackSaveArea *) thread->interpSave.curFrame) - 1;
- while (ssaPtr != ((StackSaveArea *) NULL) - 1) {
- const Method *method = ssaPtr->method;
- if (method) {
- int hashValue = dvmComputeUtf8Hash(method->name);
- bool found =
- dvmHashTableLookup(gDvmJit.methodTable, hashValue,
- (char *) method->name,
- (HashCompareFunc) strcmp, false) !=
- NULL;
- if (found) {
- ALOGD("Method %s (--> %s) found on the JIT %s list",
- method->name, curMethodName,
- gDvmJit.includeSelectedMethod ? "white" : "black");
- return true;
- }
-
- }
- ssaPtr = ((StackSaveArea *) ssaPtr->prevFrame) - 1;
- };
- return false;
-}
-
-/*
- * Since we are including instructions from possibly a cold method into the
- * current trace, we need to make sure that all the associated information
- * with the callee is properly initialized. If not, we punt on this inline
- * target.
- *
- * TODO: volatile instructions will be handled later.
- */
-bool dvmCompilerCanIncludeThisInstruction(const Method *method,
- const DecodedInstruction *insn)
-{
- switch (insn->opcode) {
- case OP_NEW_INSTANCE:
- case OP_CHECK_CAST: {
- ClassObject *classPtr = (ClassObject *)(void*)
- (method->clazz->pDvmDex->pResClasses[insn->vB]);
-
- /* Class hasn't been initialized yet */
- if (classPtr == NULL) {
- return false;
- }
- return true;
- }
- case OP_SGET:
- case OP_SGET_WIDE:
- case OP_SGET_OBJECT:
- case OP_SGET_BOOLEAN:
- case OP_SGET_BYTE:
- case OP_SGET_CHAR:
- case OP_SGET_SHORT:
- case OP_SPUT:
- case OP_SPUT_WIDE:
- case OP_SPUT_OBJECT:
- case OP_SPUT_BOOLEAN:
- case OP_SPUT_BYTE:
- case OP_SPUT_CHAR:
- case OP_SPUT_SHORT: {
- void *fieldPtr = (void*)
- (method->clazz->pDvmDex->pResFields[insn->vB]);
-
- if (fieldPtr == NULL) {
- return false;
- }
- return true;
- }
- case OP_INVOKE_SUPER:
- case OP_INVOKE_SUPER_RANGE: {
- int mIndex = method->clazz->pDvmDex->
- pResMethods[insn->vB]->methodIndex;
- const Method *calleeMethod = method->clazz->super->vtable[mIndex];
- if (calleeMethod == NULL) {
- return false;
- }
- return true;
- }
- case OP_INVOKE_SUPER_QUICK:
- case OP_INVOKE_SUPER_QUICK_RANGE: {
- const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
- if (calleeMethod == NULL) {
- return false;
- }
- return true;
- }
- case OP_INVOKE_STATIC:
- case OP_INVOKE_STATIC_RANGE:
- case OP_INVOKE_DIRECT:
- case OP_INVOKE_DIRECT_RANGE: {
- const Method *calleeMethod =
- method->clazz->pDvmDex->pResMethods[insn->vB];
- if (calleeMethod == NULL) {
- return false;
- }
- return true;
- }
- case OP_CONST_CLASS: {
- void *classPtr = (void*)
- (method->clazz->pDvmDex->pResClasses[insn->vB]);
-
- if (classPtr == NULL) {
- return false;
- }
- return true;
- }
- case OP_CONST_STRING_JUMBO:
- case OP_CONST_STRING: {
- void *strPtr = (void*)
- (method->clazz->pDvmDex->pResStrings[insn->vB]);
-
- if (strPtr == NULL) {
- return false;
- }
- return true;
- }
- default:
- return true;
- }
-}
-
-/* Split an existing block from the specified code offset into two */
-static BasicBlock *splitBlock(CompilationUnit *cUnit,
- unsigned int codeOffset,
- BasicBlock *origBlock,
- BasicBlock **immedPredBlockP)
-{
- MIR *insn = origBlock->firstMIRInsn;
- while (insn) {
- if (insn->offset == codeOffset) break;
- insn = insn->next;
- }
- if (insn == NULL) {
- ALOGE("Break split failed");
- dvmAbort();
- }
- BasicBlock *bottomBlock = dvmCompilerNewBB(kDalvikByteCode,
- cUnit->numBlocks++);
- dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
-
- bottomBlock->startOffset = codeOffset;
- bottomBlock->firstMIRInsn = insn;
- bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
-
- /* Handle the taken path */
- bottomBlock->taken = origBlock->taken;
- if (bottomBlock->taken) {
- origBlock->taken = NULL;
- dvmCompilerClearBit(bottomBlock->taken->predecessors, origBlock->id);
- dvmCompilerSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
- }
-
- /* Handle the fallthrough path */
- bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
- bottomBlock->fallThrough = origBlock->fallThrough;
- origBlock->fallThrough = bottomBlock;
- origBlock->needFallThroughBranch = true;
- dvmCompilerSetBit(bottomBlock->predecessors, origBlock->id);
- if (bottomBlock->fallThrough) {
- dvmCompilerClearBit(bottomBlock->fallThrough->predecessors,
- origBlock->id);
- dvmCompilerSetBit(bottomBlock->fallThrough->predecessors,
- bottomBlock->id);
- }
-
- /* Handle the successor list */
- if (origBlock->successorBlockList.blockListType != kNotUsed) {
- bottomBlock->successorBlockList = origBlock->successorBlockList;
- origBlock->successorBlockList.blockListType = kNotUsed;
- GrowableListIterator iterator;
-
- dvmGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
- &iterator);
- while (true) {
- SuccessorBlockInfo *successorBlockInfo =
- (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
- if (successorBlockInfo == NULL) break;
- BasicBlock *bb = successorBlockInfo->block;
- dvmCompilerClearBit(bb->predecessors, origBlock->id);
- dvmCompilerSetBit(bb->predecessors, bottomBlock->id);
- }
- }
-
- origBlock->lastMIRInsn = insn->prev;
-
- insn->prev->next = NULL;
- insn->prev = NULL;
-
- /*
- * Update the immediate predecessor block pointer so that outgoing edges
- * can be applied to the proper block.
- */
- if (immedPredBlockP) {
- assert(*immedPredBlockP == origBlock);
- *immedPredBlockP = bottomBlock;
- }
- return bottomBlock;
-}
-
-/*
- * Given a code offset, find out the block that starts with it. If the offset
- * is in the middle of an existing block, split it into two. If immedPredBlockP
- * is non-null and is the block being split, update *immedPredBlockP to point
- * to the bottom block so that outgoing edges can be setup properly (by the
- * caller).
- */
-static BasicBlock *findBlock(CompilationUnit *cUnit,
- unsigned int codeOffset,
- bool split, bool create,
- BasicBlock **immedPredBlockP)
-{
- GrowableList *blockList = &cUnit->blockList;
- BasicBlock *bb;
- unsigned int i;
-
- for (i = 0; i < blockList->numUsed; i++) {
- bb = (BasicBlock *) blockList->elemList[i];
- if (bb->blockType != kDalvikByteCode) continue;
- if (bb->startOffset == codeOffset) return bb;
- /* Check if a branch jumps into the middle of an existing block */
- if ((split == true) && (codeOffset > bb->startOffset) &&
- (bb->lastMIRInsn != NULL) &&
- (codeOffset <= bb->lastMIRInsn->offset)) {
- BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
- bb == *immedPredBlockP ?
- immedPredBlockP : NULL);
- return newBB;
- }
- }
- if (create) {
- bb = dvmCompilerNewBB(kDalvikByteCode, cUnit->numBlocks++);
- dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
- bb->startOffset = codeOffset;
- return bb;
- }
- return NULL;
-}
-
-/* Dump the CFG into a DOT graph */
-void dvmDumpCFG(CompilationUnit *cUnit, const char *dirPrefix)
-{
- const Method *method = cUnit->method;
- FILE *file;
- char *signature = dexProtoCopyMethodDescriptor(&method->prototype);
- char startOffset[80];
- sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
- char *fileName = (char *) dvmCompilerNew(
- strlen(dirPrefix) +
- strlen(method->clazz->descriptor) +
- strlen(method->name) +
- strlen(signature) +
- strlen(startOffset) +
- strlen(".dot") + 1, true);
- sprintf(fileName, "%s%s%s%s%s.dot", dirPrefix,
- method->clazz->descriptor, method->name, signature, startOffset);
- free(signature);
-
- /*
- * Convert the special characters into a filesystem- and shell-friendly
- * format.
- */
- int i;
- for (i = strlen(dirPrefix); fileName[i]; i++) {
- if (fileName[i] == '/') {
- fileName[i] = '_';
- } else if (fileName[i] == ';') {
- fileName[i] = '#';
- } else if (fileName[i] == '$') {
- fileName[i] = '+';
- } else if (fileName[i] == '(' || fileName[i] == ')') {
- fileName[i] = '@';
- } else if (fileName[i] == '<' || fileName[i] == '>') {
- fileName[i] = '=';
- }
- }
- file = fopen(fileName, "w");
- if (file == NULL) {
- return;
- }
- fprintf(file, "digraph G {\n");
-
- fprintf(file, " rankdir=TB\n");
-
- int numReachableBlocks = cUnit->numReachableBlocks;
- int idx;
- const GrowableList *blockList = &cUnit->blockList;
-
- for (idx = 0; idx < numReachableBlocks; idx++) {
- int blockIdx = cUnit->dfsOrder.elemList[idx];
- BasicBlock *bb = (BasicBlock *) dvmGrowableListGetElement(blockList,
- blockIdx);
- if (bb == NULL) break;
- if (bb->blockType == kEntryBlock) {
- fprintf(file, " entry [shape=Mdiamond];\n");
- } else if (bb->blockType == kExitBlock) {
- fprintf(file, " exit [shape=Mdiamond];\n");
- } else if (bb->blockType == kDalvikByteCode) {
- fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
- bb->startOffset);
- const MIR *mir;
- fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
- bb->firstMIRInsn ? " | " : " ");
- for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
- fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
- mir->ssaRep ?
- dvmCompilerFullDisassembler(cUnit, mir) :
- dexGetOpcodeName(mir->dalvikInsn.opcode),
- mir->next ? " | " : " ");
- }
- fprintf(file, " }\"];\n\n");
- } else if (bb->blockType == kExceptionHandling) {
- char blockName[BLOCK_NAME_LEN];
-
- dvmGetBlockName(bb, blockName);
- fprintf(file, " %s [shape=invhouse];\n", blockName);
- }
-
- char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
-
- if (bb->taken) {
- dvmGetBlockName(bb, blockName1);
- dvmGetBlockName(bb->taken, blockName2);
- fprintf(file, " %s:s -> %s:n [style=dotted]\n",
- blockName1, blockName2);
- }
- if (bb->fallThrough) {
- dvmGetBlockName(bb, blockName1);
- dvmGetBlockName(bb->fallThrough, blockName2);
- fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
- }
-
- if (bb->successorBlockList.blockListType != kNotUsed) {
- fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
- bb->startOffset,
- (bb->successorBlockList.blockListType == kCatch) ?
- "Mrecord" : "record");
- GrowableListIterator iterator;
- dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
- &iterator);
- SuccessorBlockInfo *successorBlockInfo =
- (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
-
- int succId = 0;
- while (true) {
- if (successorBlockInfo == NULL) break;
-
- BasicBlock *destBlock = successorBlockInfo->block;
- SuccessorBlockInfo *nextSuccessorBlockInfo =
- (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
-
- fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
- succId++,
- successorBlockInfo->key,
- destBlock->startOffset,
- (nextSuccessorBlockInfo != NULL) ? " | " : " ");
-
- successorBlockInfo = nextSuccessorBlockInfo;
- }
- fprintf(file, " }\"];\n\n");
-
- dvmGetBlockName(bb, blockName1);
- fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
- blockName1, bb->startOffset);
-
- if (bb->successorBlockList.blockListType == kPackedSwitch ||
- bb->successorBlockList.blockListType == kSparseSwitch) {
-
- dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
- &iterator);
-
- succId = 0;
- while (true) {
- SuccessorBlockInfo *successorBlockInfo =
- (SuccessorBlockInfo *)
- dvmGrowableListIteratorNext(&iterator);
- if (successorBlockInfo == NULL) break;
-
- BasicBlock *destBlock = successorBlockInfo->block;
-
- dvmGetBlockName(destBlock, blockName2);
- fprintf(file, " succ%04x:f%d:e -> %s:n\n",
- bb->startOffset, succId++,
- blockName2);
- }
- }
- }
- fprintf(file, "\n");
-
- /*
- * If we need to debug the dominator tree, uncomment the following code
- */
-#if 1
- dvmGetBlockName(bb, blockName1);
- fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
- blockName1, blockName1);
- if (bb->iDom) {
- dvmGetBlockName(bb->iDom, blockName2);
- fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
- blockName2, blockName1);
- }
-#endif
- }
- fprintf(file, "}\n");
- fclose(file);
-}
-
-/* Verify if all the successor is connected with all the claimed predecessors */
-static bool verifyPredInfo(CompilationUnit *cUnit, BasicBlock *bb)
-{
- BitVectorIterator bvIterator;
-
- dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
- while (true) {
- int blockIdx = dvmBitVectorIteratorNext(&bvIterator);
- if (blockIdx == -1) break;
- BasicBlock *predBB = (BasicBlock *)
- dvmGrowableListGetElement(&cUnit->blockList, blockIdx);
- bool found = false;
- if (predBB->taken == bb) {
- found = true;
- } else if (predBB->fallThrough == bb) {
- found = true;
- } else if (predBB->successorBlockList.blockListType != kNotUsed) {
- GrowableListIterator iterator;
- dvmGrowableListIteratorInit(&predBB->successorBlockList.blocks,
- &iterator);
- while (true) {
- SuccessorBlockInfo *successorBlockInfo =
- (SuccessorBlockInfo *)
- dvmGrowableListIteratorNext(&iterator);
- if (successorBlockInfo == NULL) break;
- BasicBlock *succBB = successorBlockInfo->block;
- if (succBB == bb) {
- found = true;
- break;
- }
- }
- }
- if (found == false) {
- char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
- dvmGetBlockName(bb, blockName1);
- dvmGetBlockName(predBB, blockName2);
- dvmDumpCFG(cUnit, "/sdcard/cfg/");
- ALOGE("Successor %s not found from %s",
- blockName1, blockName2);
- dvmAbort();
- }
- }
- return true;
-}
-
-/* Identify code range in try blocks and set up the empty catch blocks */
-static void processTryCatchBlocks(CompilationUnit *cUnit)
-{
- const Method *meth = cUnit->method;
- const DexCode *pCode = dvmGetMethodCode(meth);
- int triesSize = pCode->triesSize;
- int i;
- int offset;
-
- if (triesSize == 0) {
- return;
- }
-
- const DexTry *pTries = dexGetTries(pCode);
- BitVector *tryBlockAddr = cUnit->tryBlockAddr;
-
- /* Mark all the insn offsets in Try blocks */
- for (i = 0; i < triesSize; i++) {
- const DexTry* pTry = &pTries[i];
- /* all in 16-bit units */
- int startOffset = pTry->startAddr;
- int endOffset = startOffset + pTry->insnCount;
-
- for (offset = startOffset; offset < endOffset; offset++) {
- dvmCompilerSetBit(tryBlockAddr, offset);
- }
- }
-
- /* Iterate over each of the handlers to enqueue the empty Catch blocks */
- offset = dexGetFirstHandlerOffset(pCode);
- int handlersSize = dexGetHandlersSize(pCode);
-
- for (i = 0; i < handlersSize; i++) {
- DexCatchIterator iterator;
- dexCatchIteratorInit(&iterator, pCode, offset);
-
- for (;;) {
- DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
-
- if (handler == NULL) {
- break;
- }
-
- /*
- * Create dummy catch blocks first. Since these are created before
- * other blocks are processed, "split" is specified as false.
- */
- findBlock(cUnit, handler->address,
- /* split */
- false,
- /* create */
- true,
- /* immedPredBlockP */
- NULL);
- }
-
- offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
- }
-}
-
-/* Process instructions with the kInstrCanBranch flag */
-static void processCanBranch(CompilationUnit *cUnit, BasicBlock *curBlock,
- MIR *insn, int curOffset, int width, int flags,
- const u2* codePtr, const u2* codeEnd)
-{
- int target = curOffset;
- switch (insn->dalvikInsn.opcode) {
- case OP_GOTO:
- case OP_GOTO_16:
- case OP_GOTO_32:
- target += (int) insn->dalvikInsn.vA;
- break;
- case OP_IF_EQ:
- case OP_IF_NE:
- case OP_IF_LT:
- case OP_IF_GE:
- case OP_IF_GT:
- case OP_IF_LE:
- target += (int) insn->dalvikInsn.vC;
- break;
- case OP_IF_EQZ:
- case OP_IF_NEZ:
- case OP_IF_LTZ:
- case OP_IF_GEZ:
- case OP_IF_GTZ:
- case OP_IF_LEZ:
- target += (int) insn->dalvikInsn.vB;
- break;
- default:
- ALOGE("Unexpected opcode(%d) with kInstrCanBranch set",
- insn->dalvikInsn.opcode);
- dvmAbort();
- }
- BasicBlock *takenBlock = findBlock(cUnit, target,
- /* split */
- true,
- /* create */
- true,
- /* immedPredBlockP */
- &curBlock);
- curBlock->taken = takenBlock;
- dvmCompilerSetBit(takenBlock->predecessors, curBlock->id);
-
- /* Always terminate the current block for conditional branches */
- if (flags & kInstrCanContinue) {
- BasicBlock *fallthroughBlock = findBlock(cUnit,
- curOffset + width,
- /*
- * If the method is processed
- * in sequential order from the
- * beginning, we don't need to
- * specify split for continue
- * blocks. However, this
- * routine can be called by
- * compileLoop, which starts
- * parsing the method from an
- * arbitrary address in the
- * method body.
- */
- true,
- /* create */
- true,
- /* immedPredBlockP */
- &curBlock);
- curBlock->fallThrough = fallthroughBlock;
- dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
- } else if (codePtr < codeEnd) {
- /* Create a fallthrough block for real instructions (incl. OP_NOP) */
- if (contentIsInsn(codePtr)) {
- findBlock(cUnit, curOffset + width,
- /* split */
- false,
- /* create */
- true,
- /* immedPredBlockP */
- NULL);
- }
- }
-}
-
-/* Process instructions with the kInstrCanSwitch flag */
-static void processCanSwitch(CompilationUnit *cUnit, BasicBlock *curBlock,
- MIR *insn, int curOffset, int width, int flags)
-{
- u2 *switchData= (u2 *) (cUnit->method->insns + curOffset +
- insn->dalvikInsn.vB);
- int size;
- int *keyTable;
- int *targetTable;
- int i;
- int firstKey;
-
- /*
- * Packed switch data format:
- * ushort ident = 0x0100 magic value
- * ushort size number of entries in the table
- * int first_key first (and lowest) switch case value
- * int targets[size] branch targets, relative to switch opcode
- *
- * Total size is (4+size*2) 16-bit code units.
- */
- if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
- assert(switchData[0] == kPackedSwitchSignature);
- size = switchData[1];
- firstKey = switchData[2] | (switchData[3] << 16);
- targetTable = (int *) &switchData[4];
- keyTable = NULL; // Make the compiler happy
- /*
- * Sparse switch data format:
- * ushort ident = 0x0200 magic value
- * ushort size number of entries in the table; > 0
- * int keys[size] keys, sorted low-to-high; 32-bit aligned
- * int targets[size] branch targets, relative to switch opcode
- *
- * Total size is (2+size*4) 16-bit code units.
- */
- } else {
- assert(switchData[0] == kSparseSwitchSignature);
- size = switchData[1];
- keyTable = (int *) &switchData[2];
- targetTable = (int *) &switchData[2 + size*2];
- firstKey = 0; // To make the compiler happy
- }
-
- if (curBlock->successorBlockList.blockListType != kNotUsed) {
- ALOGE("Successor block list already in use: %d",
- curBlock->successorBlockList.blockListType);
- dvmAbort();
- }
- curBlock->successorBlockList.blockListType =
- (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
- kPackedSwitch : kSparseSwitch;
- dvmInitGrowableList(&curBlock->successorBlockList.blocks, size);
-
- for (i = 0; i < size; i++) {
- BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
- /* split */
- true,
- /* create */
- true,
- /* immedPredBlockP */
- &curBlock);
- SuccessorBlockInfo *successorBlockInfo =
- (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
- false);
- successorBlockInfo->block = caseBlock;
- successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
- firstKey + i : keyTable[i];
- dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
- (intptr_t) successorBlockInfo);
- dvmCompilerSetBit(caseBlock->predecessors, curBlock->id);
- }
-
- /* Fall-through case */
- BasicBlock *fallthroughBlock = findBlock(cUnit,
- curOffset + width,
- /* split */
- false,
- /* create */
- true,
- /* immedPredBlockP */
- NULL);
- curBlock->fallThrough = fallthroughBlock;
- dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
-}
-
-/* Process instructions with the kInstrCanThrow flag */
-static void processCanThrow(CompilationUnit *cUnit, BasicBlock *curBlock,
- MIR *insn, int curOffset, int width, int flags,
- BitVector *tryBlockAddr, const u2 *codePtr,
- const u2* codeEnd)
-{
- const Method *method = cUnit->method;
- const DexCode *dexCode = dvmGetMethodCode(method);
-
- /* In try block */
- if (dvmIsBitSet(tryBlockAddr, curOffset)) {
- DexCatchIterator iterator;
-
- if (!dexFindCatchHandler(&iterator, dexCode, curOffset)) {
- ALOGE("Catch block not found in dexfile for insn %x in %s",
- curOffset, method->name);
- dvmAbort();
-
- }
- if (curBlock->successorBlockList.blockListType != kNotUsed) {
- ALOGE("Successor block list already in use: %d",
- curBlock->successorBlockList.blockListType);
- dvmAbort();
- }
- curBlock->successorBlockList.blockListType = kCatch;
- dvmInitGrowableList(&curBlock->successorBlockList.blocks, 2);
-
- for (;;) {
- DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
-
- if (handler == NULL) {
- break;
- }
-
- BasicBlock *catchBlock = findBlock(cUnit, handler->address,
- /* split */
- false,
- /* create */
- false,
- /* immedPredBlockP */
- NULL);
-
- SuccessorBlockInfo *successorBlockInfo =
- (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
- false);
- successorBlockInfo->block = catchBlock;
- successorBlockInfo->key = handler->typeIdx;
- dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
- (intptr_t) successorBlockInfo);
- dvmCompilerSetBit(catchBlock->predecessors, curBlock->id);
- }
- } else {
- BasicBlock *ehBlock = dvmCompilerNewBB(kExceptionHandling,
- cUnit->numBlocks++);
- curBlock->taken = ehBlock;
- dvmInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
- ehBlock->startOffset = curOffset;
- dvmCompilerSetBit(ehBlock->predecessors, curBlock->id);
- }
-
- /*
- * Force the current block to terminate.
- *
- * Data may be present before codeEnd, so we need to parse it to know
- * whether it is code or data.
- */
- if (codePtr < codeEnd) {
- /* Create a fallthrough block for real instructions (incl. OP_NOP) */
- if (contentIsInsn(codePtr)) {
- BasicBlock *fallthroughBlock = findBlock(cUnit,
- curOffset + width,
- /* split */
- false,
- /* create */
- true,
- /* immedPredBlockP */
- NULL);
- /*
- * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional
- * branches.
- */
- if (insn->dalvikInsn.opcode != OP_THROW_VERIFICATION_ERROR &&
- insn->dalvikInsn.opcode != OP_THROW) {
- curBlock->fallThrough = fallthroughBlock;
- dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
- }
- }
- }
-}
-
-/*
- * Similar to dvmCompileTrace, but the entity processed here is the whole
- * method.
- *
- * TODO: implementation will be revisited when the trace builder can provide
- * whole-method traces.
- */
-bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
-{
- CompilationUnit cUnit;
- const DexCode *dexCode = dvmGetMethodCode(method);
- const u2 *codePtr = dexCode->insns;
- const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
- int numBlocks = 0;
- unsigned int curOffset = 0;
-
- /* Method already compiled */
- if (dvmJitGetMethodAddr(codePtr)) {
- info->codeAddress = NULL;
- return false;
- }
-
- memset(&cUnit, 0, sizeof(cUnit));
- cUnit.method = method;
-
- cUnit.jitMode = kJitMethod;
-
- /* Initialize the block list */
- dvmInitGrowableList(&cUnit.blockList, 4);
-
- /*
- * FIXME - PC reconstruction list won't be needed after the codegen routines
- * are enhanced to true method mode.
- */
- /* Initialize the PC reconstruction list */
- dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
-
- /* Allocate the bit-vector to track the beginning of basic blocks */
- BitVector *tryBlockAddr = dvmCompilerAllocBitVector(dexCode->insnsSize,
- true /* expandable */);
- cUnit.tryBlockAddr = tryBlockAddr;
-
- /* Create the default entry and exit blocks and enter them to the list */
- BasicBlock *entryBlock = dvmCompilerNewBB(kEntryBlock, numBlocks++);
- BasicBlock *exitBlock = dvmCompilerNewBB(kExitBlock, numBlocks++);
-
- cUnit.entryBlock = entryBlock;
- cUnit.exitBlock = exitBlock;
-
- dvmInsertGrowableList(&cUnit.blockList, (intptr_t) entryBlock);
- dvmInsertGrowableList(&cUnit.blockList, (intptr_t) exitBlock);
-
- /* Current block to record parsed instructions */
- BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
- curBlock->startOffset = 0;
- dvmInsertGrowableList(&cUnit.blockList, (intptr_t) curBlock);
- entryBlock->fallThrough = curBlock;
- dvmCompilerSetBit(curBlock->predecessors, entryBlock->id);
-
- /*
- * Store back the number of blocks since new blocks may be created of
- * accessing cUnit.
- */
- cUnit.numBlocks = numBlocks;
-
- /* Identify code range in try blocks and set up the empty catch blocks */
- processTryCatchBlocks(&cUnit);
-
- /* Parse all instructions and put them into containing basic blocks */
- while (codePtr < codeEnd) {
- MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true);
- insn->offset = curOffset;
- int width = parseInsn(codePtr, &insn->dalvikInsn, false);
- insn->width = width;
-
- /* Terminate when the data section is seen */
- if (width == 0)
- break;
-
- dvmCompilerAppendMIR(curBlock, insn);
-
- codePtr += width;
- int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
-
- if (flags & kInstrCanBranch) {
- processCanBranch(&cUnit, curBlock, insn, curOffset, width, flags,
- codePtr, codeEnd);
- } else if (flags & kInstrCanReturn) {
- curBlock->fallThrough = exitBlock;
- dvmCompilerSetBit(exitBlock->predecessors, curBlock->id);
- /*
- * Terminate the current block if there are instructions
- * afterwards.
- */
- if (codePtr < codeEnd) {
- /*
- * Create a fallthrough block for real instructions
- * (incl. OP_NOP).
- */
- if (contentIsInsn(codePtr)) {
- findBlock(&cUnit, curOffset + width,
- /* split */
- false,
- /* create */
- true,
- /* immedPredBlockP */
- NULL);
- }
- }
- } else if (flags & kInstrCanThrow) {
- processCanThrow(&cUnit, curBlock, insn, curOffset, width, flags,
- tryBlockAddr, codePtr, codeEnd);
- } else if (flags & kInstrCanSwitch) {
- processCanSwitch(&cUnit, curBlock, insn, curOffset, width, flags);
- }
- curOffset += width;
- BasicBlock *nextBlock = findBlock(&cUnit, curOffset,
- /* split */
- false,
- /* create */
- false,
- /* immedPredBlockP */
- NULL);
- if (nextBlock) {
- /*
- * The next instruction could be the target of a previously parsed
- * forward branch so a block is already created. If the current
- * instruction is not an unconditional branch, connect them through
- * the fall-through link.
- */
- assert(curBlock->fallThrough == NULL ||
- curBlock->fallThrough == nextBlock ||
- curBlock->fallThrough == exitBlock);
-
- if ((curBlock->fallThrough == NULL) &&
- (flags & kInstrCanContinue)) {
- curBlock->fallThrough = nextBlock;
- dvmCompilerSetBit(nextBlock->predecessors, curBlock->id);
- }
- curBlock = nextBlock;
- }
- }
-
- if (cUnit.printMe) {
- dvmCompilerDumpCompilationUnit(&cUnit);
- }
-
- /* Adjust this value accordingly once inlining is performed */
- cUnit.numDalvikRegisters = cUnit.method->registersSize;
-
- /* Verify if all blocks are connected as claimed */
- /* FIXME - to be disabled in the future */
- dvmCompilerDataFlowAnalysisDispatcher(&cUnit, verifyPredInfo,
- kAllNodes,
- false /* isIterative */);
-
-
- /* Perform SSA transformation for the whole method */
- dvmCompilerMethodSSATransformation(&cUnit);
-
-#ifndef ARCH_IA32
- dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
-
- /* Allocate Registers using simple local allocation scheme */
- dvmCompilerLocalRegAlloc(&cUnit);
-#endif
-
- /* Convert MIR to LIR, etc. */
- dvmCompilerMethodMIR2LIR(&cUnit);
-
- // Debugging only
- //dvmDumpCFG(&cUnit, "/sdcard/cfg/");
-
- /* Method is not empty */
- if (cUnit.firstLIRInsn) {
- /* Convert LIR into machine code. Loop for recoverable retries */
- do {
- dvmCompilerAssembleLIR(&cUnit, info);
- cUnit.assemblerRetries++;
- if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
- ALOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
- cUnit.assemblerStatus);
- } while (cUnit.assemblerStatus == kRetryAll);
-
- if (cUnit.printMe) {
- dvmCompilerCodegenDump(&cUnit);
- }
-
- if (info->codeAddress) {
- dvmJitSetCodeAddr(dexCode->insns, info->codeAddress,
- info->instructionSet, true, 0);
- /*
- * Clear the codeAddress for the enclosing trace to reuse the info
- */
- info->codeAddress = NULL;
- }
- }
-
- return false;
-}
-
-/* Extending the trace by crawling the code from curBlock */
-static bool exhaustTrace(CompilationUnit *cUnit, BasicBlock *curBlock)
-{
- unsigned int curOffset = curBlock->startOffset;
- const u2 *codePtr = cUnit->method->insns + curOffset;
-
- if (curBlock->visited == true) return false;
-
- curBlock->visited = true;
-
- if (curBlock->blockType == kEntryBlock ||
- curBlock->blockType == kExitBlock) {
- return false;
- }
-
- /*
- * Block has been parsed - check the taken/fallThrough in case it is a split
- * block.
- */
- if (curBlock->firstMIRInsn != NULL) {
- bool changed = false;
- if (curBlock->taken)
- changed |= exhaustTrace(cUnit, curBlock->taken);
- if (curBlock->fallThrough)
- changed |= exhaustTrace(cUnit, curBlock->fallThrough);
- return changed;
- }
- while (true) {
- MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true);
- insn->offset = curOffset;
- int width = parseInsn(codePtr, &insn->dalvikInsn, false);
- insn->width = width;
-
- /* Terminate when the data section is seen */
- if (width == 0)
- break;
-
- dvmCompilerAppendMIR(curBlock, insn);
-
- codePtr += width;
- int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
-
- /* Stop extending the trace after seeing these instructions */
- if (flags & (kInstrCanReturn | kInstrCanSwitch | kInstrInvoke)) {
- curBlock->fallThrough = cUnit->exitBlock;
- dvmCompilerSetBit(cUnit->exitBlock->predecessors, curBlock->id);
- break;
- } else if (flags & kInstrCanBranch) {
- processCanBranch(cUnit, curBlock, insn, curOffset, width, flags,
- codePtr, NULL);
- if (curBlock->taken) {
- exhaustTrace(cUnit, curBlock->taken);
- }
- if (curBlock->fallThrough) {
- exhaustTrace(cUnit, curBlock->fallThrough);
- }
- break;
- }
- curOffset += width;
- BasicBlock *nextBlock = findBlock(cUnit, curOffset,
- /* split */
- false,
- /* create */
- false,
- /* immedPredBlockP */
- NULL);
- if (nextBlock) {
- /*
- * The next instruction could be the target of a previously parsed
- * forward branch so a block is already created. If the current
- * instruction is not an unconditional branch, connect them through
- * the fall-through link.
- */
- assert(curBlock->fallThrough == NULL ||
- curBlock->fallThrough == nextBlock ||
- curBlock->fallThrough == cUnit->exitBlock);
-
- if ((curBlock->fallThrough == NULL) &&
- (flags & kInstrCanContinue)) {
- curBlock->needFallThroughBranch = true;
- curBlock->fallThrough = nextBlock;
- dvmCompilerSetBit(nextBlock->predecessors, curBlock->id);
- }
- /* Block has been visited - no more parsing needed */
- if (nextBlock->visited == true) {
- return true;
- }
- curBlock = nextBlock;
- }
- }
- return true;
-}
-
-/* Compile a loop */
-static bool compileLoop(CompilationUnit *cUnit, unsigned int startOffset,
- JitTraceDescription *desc, int numMaxInsts,
- JitTranslationInfo *info, jmp_buf *bailPtr,
- int optHints)
-{
- int numBlocks = 0;
- unsigned int curOffset = startOffset;
- bool changed;
- BasicBlock *bb;
-#if defined(WITH_JIT_TUNING)
- CompilerMethodStats *methodStats;
-#endif
-
- cUnit->jitMode = kJitLoop;
-
- /* Initialize the block list */
- dvmInitGrowableList(&cUnit->blockList, 4);
-
- /* Initialize the PC reconstruction list */
- dvmInitGrowableList(&cUnit->pcReconstructionList, 8);
-
- /* Create the default entry and exit blocks and enter them to the list */
- BasicBlock *entryBlock = dvmCompilerNewBB(kEntryBlock, numBlocks++);
- entryBlock->startOffset = curOffset;
- BasicBlock *exitBlock = dvmCompilerNewBB(kExitBlock, numBlocks++);
-
- cUnit->entryBlock = entryBlock;
- cUnit->exitBlock = exitBlock;
-
- dvmInsertGrowableList(&cUnit->blockList, (intptr_t) entryBlock);
- dvmInsertGrowableList(&cUnit->blockList, (intptr_t) exitBlock);
-
- /* Current block to record parsed instructions */
- BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
- curBlock->startOffset = curOffset;
-
- dvmInsertGrowableList(&cUnit->blockList, (intptr_t) curBlock);
- entryBlock->fallThrough = curBlock;
- dvmCompilerSetBit(curBlock->predecessors, entryBlock->id);
-
- /*
- * Store back the number of blocks since new blocks may be created of
- * accessing cUnit.
- */
- cUnit->numBlocks = numBlocks;
-
- do {
- dvmCompilerDataFlowAnalysisDispatcher(cUnit,
- dvmCompilerClearVisitedFlag,
- kAllNodes,
- false /* isIterative */);
- changed = exhaustTrace(cUnit, curBlock);
- } while (changed);
-
- /* Backward chaining block */
- bb = dvmCompilerNewBB(kChainingCellBackwardBranch, cUnit->numBlocks++);
- dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
- cUnit->backChainBlock = bb;
-
- /* A special block to host PC reconstruction code */
- bb = dvmCompilerNewBB(kPCReconstruction, cUnit->numBlocks++);
- dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
-
- /* And one final block that publishes the PC and raises the exception */
- bb = dvmCompilerNewBB(kExceptionHandling, cUnit->numBlocks++);
- dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
- cUnit->puntBlock = bb;
-
- cUnit->numDalvikRegisters = cUnit->method->registersSize;
-
- /* Verify if all blocks are connected as claimed */
- /* FIXME - to be disabled in the future */
- dvmCompilerDataFlowAnalysisDispatcher(cUnit, verifyPredInfo,
- kAllNodes,
- false /* isIterative */);
-
-
- /* Try to identify a loop */
- if (!dvmCompilerBuildLoop(cUnit))
- goto bail;
-
- dvmCompilerLoopOpt(cUnit);
-
- /*
- * Change the backward branch to the backward chaining cell after dataflow
- * analsys/optimizations are done.
- */
- dvmCompilerInsertBackwardChaining(cUnit);
-
-#if defined(ARCH_IA32)
- /* Convert MIR to LIR, etc. */
- dvmCompilerMIR2LIR(cUnit, info);
-#else
- dvmCompilerInitializeRegAlloc(cUnit);
-
- /* Allocate Registers using simple local allocation scheme */
- dvmCompilerLocalRegAlloc(cUnit);
-
- /* Convert MIR to LIR, etc. */
- dvmCompilerMIR2LIR(cUnit);
-#endif
-
- /* Loop contains never executed blocks / heavy instructions */
- if (cUnit->quitLoopMode) {
- if (cUnit->printMe || gDvmJit.receivedSIGUSR2) {
- ALOGD("Loop trace @ offset %04x aborted due to unresolved code info",
- cUnit->entryBlock->startOffset);
- }
- goto bail;
- }
-
- /* Convert LIR into machine code. Loop for recoverable retries */
- do {
- dvmCompilerAssembleLIR(cUnit, info);
- cUnit->assemblerRetries++;
- if (cUnit->printMe && cUnit->assemblerStatus != kSuccess)
- ALOGD("Assembler abort #%d on %d", cUnit->assemblerRetries,
- cUnit->assemblerStatus);
- } while (cUnit->assemblerStatus == kRetryAll);
-
- /* Loop is too big - bail out */
- if (cUnit->assemblerStatus == kRetryHalve) {
- goto bail;
- }
-
- if (cUnit->printMe || gDvmJit.receivedSIGUSR2) {
- ALOGD("Loop trace @ offset %04x", cUnit->entryBlock->startOffset);
- dvmCompilerCodegenDump(cUnit);
- }
-
- /*
- * If this trace uses class objects as constants,
- * dvmJitInstallClassObjectPointers will switch the thread state
- * to running and look up the class pointers using the descriptor/loader
- * tuple stored in the callsite info structure. We need to make this window
- * as short as possible since it is blocking GC.
- */
- if (cUnit->hasClassLiterals && info->codeAddress) {
- dvmJitInstallClassObjectPointers(cUnit, (char *) info->codeAddress);
- }
-
- /*
- * Since callsiteinfo is allocated from the arena, delay the reset until
- * class pointers are resolved.
- */
- dvmCompilerArenaReset();
-
- assert(cUnit->assemblerStatus == kSuccess);
-#if defined(WITH_JIT_TUNING)
- /* Locate the entry to store compilation statistics for this method */
- methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
- methodStats->nativeSize += cUnit->totalSize;
-#endif
- return info->codeAddress != NULL;
-
-bail:
- /* Retry the original trace with JIT_OPT_NO_LOOP disabled */
- dvmCompilerArenaReset();
- return dvmCompileTrace(desc, numMaxInsts, info, bailPtr,
- optHints | JIT_OPT_NO_LOOP);
-}
-
-static bool searchClassTablePrefix(const Method* method) {
- if (gDvmJit.classTable == NULL) {
- return false;
- }
- HashIter iter;
- HashTable* pTab = gDvmJit.classTable;
- for (dvmHashIterBegin(pTab, &iter); !dvmHashIterDone(&iter);
- dvmHashIterNext(&iter))
- {
- const char* str = (const char*) dvmHashIterData(&iter);
- if (strncmp(method->clazz->descriptor, str, strlen(str)) == 0) {
- return true;
- }
- }
- return false;
-}
-
-/*
- * Main entry point to start trace compilation. Basic blocks are constructed
- * first and they will be passed to the codegen routines to convert Dalvik
- * bytecode into machine code.
- */
-bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
- JitTranslationInfo *info, jmp_buf *bailPtr,
- int optHints)
-{
- const DexCode *dexCode = dvmGetMethodCode(desc->method);
- const JitTraceRun* currRun = &desc->trace[0];
- unsigned int curOffset = currRun->info.frag.startOffset;
- unsigned int startOffset = curOffset;
- unsigned int numInsts = currRun->info.frag.numInsts;
- const u2 *codePtr = dexCode->insns + curOffset;
- int traceSize = 0; // # of half-words
- const u2 *startCodePtr = codePtr;
- BasicBlock *curBB, *entryCodeBB;
- int numBlocks = 0;
- static int compilationId;
- CompilationUnit cUnit;
- GrowableList *blockList;
-#if defined(WITH_JIT_TUNING)
- CompilerMethodStats *methodStats;
-#endif
-
- /* If we've already compiled this trace, just return success */
- if (dvmJitGetTraceAddr(startCodePtr) && !info->discardResult) {
- /*
- * Make sure the codeAddress is NULL so that it won't clobber the
- * existing entry.
- */
- info->codeAddress = NULL;
- return true;
- }
-
- /* If the work order is stale, discard it */
- if (info->cacheVersion != gDvmJit.cacheVersion) {
- return false;
- }
-
- compilationId++;
- memset(&cUnit, 0, sizeof(CompilationUnit));
-
-#if defined(WITH_JIT_TUNING)
- /* Locate the entry to store compilation statistics for this method */
- methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
-#endif
-
- /* Set the recover buffer pointer */
- cUnit.bailPtr = bailPtr;
-
- /* Initialize the printMe flag */
- cUnit.printMe = gDvmJit.printMe;
-
- /* Setup the method */
- cUnit.method = desc->method;
-
- /* Store the trace descriptor and set the initial mode */
- cUnit.traceDesc = desc;
- cUnit.jitMode = kJitTrace;
-
- /* Initialize the PC reconstruction list */
- dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
-
- /* Initialize the basic block list */
- blockList = &cUnit.blockList;
- dvmInitGrowableList(blockList, 8);
-
- /* Identify traces that we don't want to compile */
- if (gDvmJit.classTable) {
- bool classFound = searchClassTablePrefix(desc->method);
- if (gDvmJit.classTable && gDvmJit.includeSelectedMethod != classFound) {
- return false;
- }
- }
- if (gDvmJit.methodTable) {
- int len = strlen(desc->method->clazz->descriptor) +
- strlen(desc->method->name) + 1;
- char *fullSignature = (char *)dvmCompilerNew(len, true);
- strcpy(fullSignature, desc->method->clazz->descriptor);
- strcat(fullSignature, desc->method->name);
-
- int hashValue = dvmComputeUtf8Hash(fullSignature);
-
- /*
- * Doing three levels of screening to see whether we want to skip
- * compiling this method
- */
-
- /* First, check the full "class;method" signature */
- bool methodFound =
- dvmHashTableLookup(gDvmJit.methodTable, hashValue,
- fullSignature, (HashCompareFunc) strcmp,
- false) !=
- NULL;
-
- /* Full signature not found - check the enclosing class */
- if (methodFound == false) {
- int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
- methodFound =
- dvmHashTableLookup(gDvmJit.methodTable, hashValue,
- (char *) desc->method->clazz->descriptor,
- (HashCompareFunc) strcmp, false) !=
- NULL;
- /* Enclosing class not found - check the method name */
- if (methodFound == false) {
- int hashValue = dvmComputeUtf8Hash(desc->method->name);
- methodFound =
- dvmHashTableLookup(gDvmJit.methodTable, hashValue,
- (char *) desc->method->name,
- (HashCompareFunc) strcmp, false) !=
- NULL;
-
- /*
- * Debug by call-graph is enabled. Check if the debug list
- * covers any methods on the VM stack.
- */
- if (methodFound == false && gDvmJit.checkCallGraph == true) {
- methodFound =
- filterMethodByCallGraph(info->requestingThread,
- desc->method->name);
- }
- }
- }
-
- /*
- * Under the following conditions, the trace will be *conservatively*
- * compiled by only containing single-step instructions to and from the
- * interpreter.
- * 1) If includeSelectedMethod == false, the method matches the full or
- * partial signature stored in the hash table.
- *
- * 2) If includeSelectedMethod == true, the method does not match the
- * full and partial signature stored in the hash table.
- */
- if (gDvmJit.methodTable && gDvmJit.includeSelectedMethod != methodFound) {
-#ifdef ARCH_IA32
- return false;
-#else
- cUnit.allSingleStep = true;
-#endif
- } else {
- /* Compile the trace as normal */
-
- /* Print the method we cherry picked */
- if (gDvmJit.includeSelectedMethod == true) {
- cUnit.printMe = true;
- }
- }
- }
-
- // Each pair is a range, check whether curOffset falls into a range.
- bool includeOffset = (gDvmJit.num_entries_pcTable < 2);
- for (int pcOff = 0; pcOff < gDvmJit.num_entries_pcTable; ) {
- if (pcOff+1 >= gDvmJit.num_entries_pcTable) {
- break;
- }
- if (curOffset >= gDvmJit.pcTable[pcOff] && curOffset <= gDvmJit.pcTable[pcOff+1]) {
- includeOffset = true;
- break;
- }
- pcOff += 2;
- }
- if (!includeOffset) {
- return false;
- }
-
- /* Allocate the entry block */
- curBB = dvmCompilerNewBB(kEntryBlock, numBlocks++);
- dvmInsertGrowableList(blockList, (intptr_t) curBB);
- curBB->startOffset = curOffset;
-
- entryCodeBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
- dvmInsertGrowableList(blockList, (intptr_t) entryCodeBB);
- entryCodeBB->startOffset = curOffset;
- curBB->fallThrough = entryCodeBB;
- curBB = entryCodeBB;
-
- if (cUnit.printMe) {
- ALOGD("--------\nCompiler: Building trace for %s, offset %#x",
- desc->method->name, curOffset);
- }
-
- /*
- * Analyze the trace descriptor and include up to the maximal number
- * of Dalvik instructions into the IR.
- */
- while (1) {
- MIR *insn;
- int width;
- insn = (MIR *)dvmCompilerNew(sizeof(MIR), true);
- insn->offset = curOffset;
- width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
-
- /* The trace should never incude instruction data */
- assert(width);
- insn->width = width;
- traceSize += width;
- dvmCompilerAppendMIR(curBB, insn);
- cUnit.numInsts++;
-
- int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
-
- if (flags & kInstrInvoke) {
- const Method *calleeMethod = (const Method *)
- currRun[JIT_TRACE_CUR_METHOD].info.meta;
- assert(numInsts == 1);
- CallsiteInfo *callsiteInfo =
- (CallsiteInfo *)dvmCompilerNew(sizeof(CallsiteInfo), true);
- callsiteInfo->classDescriptor = (const char *)
- currRun[JIT_TRACE_CLASS_DESC].info.meta;
- callsiteInfo->classLoader = (Object *)
- currRun[JIT_TRACE_CLASS_LOADER].info.meta;
- callsiteInfo->method = calleeMethod;
- insn->meta.callsiteInfo = callsiteInfo;
- }
-
- /* Instruction limit reached - terminate the trace here */
- if (cUnit.numInsts >= numMaxInsts) {
- break;
- }
- if (--numInsts == 0) {
- if (currRun->info.frag.runEnd) {
- break;
- } else {
- /* Advance to the next trace description (ie non-meta info) */
- do {
- currRun++;
- } while (!currRun->isCode);
-
- /* Dummy end-of-run marker seen */
- if (currRun->info.frag.numInsts == 0) {
- break;
- }
-
- curBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
- dvmInsertGrowableList(blockList, (intptr_t) curBB);
- curOffset = currRun->info.frag.startOffset;
- numInsts = currRun->info.frag.numInsts;
- curBB->startOffset = curOffset;
- codePtr = dexCode->insns + curOffset;
- }
- } else {
- curOffset += width;
- codePtr += width;
- }
- }
-
-#if defined(WITH_JIT_TUNING)
- /* Convert # of half-word to bytes */
- methodStats->compiledDalvikSize += traceSize * 2;
-#endif
-
- /*
- * Now scan basic blocks containing real code to connect the
- * taken/fallthrough links. Also create chaining cells for code not included
- * in the trace.
- */
- size_t blockId;
- for (blockId = 0; blockId < blockList->numUsed; blockId++) {
- curBB = (BasicBlock *) dvmGrowableListGetElement(blockList, blockId);
- MIR *lastInsn = curBB->lastMIRInsn;
- /* Skip empty blocks */
- if (lastInsn == NULL) {
- continue;
- }
- curOffset = lastInsn->offset;
- unsigned int targetOffset = curOffset;
- unsigned int fallThroughOffset = curOffset + lastInsn->width;
- bool isInvoke = false;
- const Method *callee = NULL;
-
- findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
- &targetOffset, &isInvoke, &callee);
-
- /* Link the taken and fallthrough blocks */
- BasicBlock *searchBB;
-
- int flags = dexGetFlagsFromOpcode(lastInsn->dalvikInsn.opcode);
-
- if (flags & kInstrInvoke) {
- cUnit.hasInvoke = true;
- }
-
- /* Backward branch seen */
- if (isInvoke == false &&
- (flags & kInstrCanBranch) != 0 &&
- targetOffset < curOffset &&
- (optHints & JIT_OPT_NO_LOOP) == 0) {
- dvmCompilerArenaReset();
- return compileLoop(&cUnit, startOffset, desc, numMaxInsts,
- info, bailPtr, optHints);
- }
-
- /* No backward branch in the trace - start searching the next BB */
- size_t searchBlockId;
- for (searchBlockId = blockId+1; searchBlockId < blockList->numUsed;
- searchBlockId++) {
- searchBB = (BasicBlock *) dvmGrowableListGetElement(blockList,
- searchBlockId);
- if (targetOffset == searchBB->startOffset) {
- curBB->taken = searchBB;
- dvmCompilerSetBit(searchBB->predecessors, curBB->id);
- }
- if (fallThroughOffset == searchBB->startOffset) {
- curBB->fallThrough = searchBB;
- dvmCompilerSetBit(searchBB->predecessors, curBB->id);
-
- /*
- * Fallthrough block of an invoke instruction needs to be
- * aligned to 4-byte boundary (alignment instruction to be
- * inserted later.
- */
- if (flags & kInstrInvoke) {
- searchBB->isFallThroughFromInvoke = true;
- }
- }
- }
-
- /*
- * Some blocks are ended by non-control-flow-change instructions,
- * currently only due to trace length constraint. In this case we need
- * to generate an explicit branch at the end of the block to jump to
- * the chaining cell.
- */
- curBB->needFallThroughBranch =
- ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
- kInstrInvoke)) == 0);
- if (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ||
- lastInsn->dalvikInsn.opcode == OP_SPARSE_SWITCH) {
- int i;
- const u2 *switchData = desc->method->insns + lastInsn->offset +
- lastInsn->dalvikInsn.vB;
- int size = switchData[1];
- int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
-
- /*
- * Generate the landing pad for cases whose ranks are higher than
- * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
- * through the NoChain point.
- */
- if (maxChains != size) {
- cUnit.switchOverflowPad =
- desc->method->insns + lastInsn->offset;
- }
-
- s4 *targets = (s4 *) (switchData + 2 +
- (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ?
- 2 : size * 2));
-
- /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
- for (i = 0; i < maxChains; i++) {
- BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
- numBlocks++);
- dvmInsertGrowableList(blockList, (intptr_t) caseChain);
- caseChain->startOffset = lastInsn->offset + targets[i];
- }
-
- /* One more chaining cell for the default case */
- BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
- numBlocks++);
- dvmInsertGrowableList(blockList, (intptr_t) caseChain);
- caseChain->startOffset = lastInsn->offset + lastInsn->width;
- /* Fallthrough block not included in the trace */
- } else if (!isUnconditionalBranch(lastInsn) &&
- curBB->fallThrough == NULL) {
- BasicBlock *fallThroughBB;
- /*
- * If the chaining cell is after an invoke or
- * instruction that cannot change the control flow, request a hot
- * chaining cell.
- */
- if (isInvoke || curBB->needFallThroughBranch) {
- fallThroughBB = dvmCompilerNewBB(kChainingCellHot, numBlocks++);
- } else {
- fallThroughBB = dvmCompilerNewBB(kChainingCellNormal,
- numBlocks++);
- }
- dvmInsertGrowableList(blockList, (intptr_t) fallThroughBB);
- fallThroughBB->startOffset = fallThroughOffset;
- curBB->fallThrough = fallThroughBB;
- dvmCompilerSetBit(fallThroughBB->predecessors, curBB->id);
- }
- /* Target block not included in the trace */
- if (curBB->taken == NULL &&
- (isGoto(lastInsn) || isInvoke ||
- (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
- BasicBlock *newBB = NULL;
- if (isInvoke) {
- /* Monomorphic callee */
- if (callee) {
- /* JNI call doesn't need a chaining cell */
- if (!dvmIsNativeMethod(callee)) {
- newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton,
- numBlocks++);
- newBB->startOffset = 0;
- newBB->containingMethod = callee;
- }
- /* Will resolve at runtime */
- } else {
- newBB = dvmCompilerNewBB(kChainingCellInvokePredicted,
- numBlocks++);
- newBB->startOffset = 0;
- }
- /* For unconditional branches, request a hot chaining cell */
- } else {
-#if !defined(WITH_SELF_VERIFICATION)
- newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
- kChainingCellHot :
- kChainingCellNormal,
- numBlocks++);
- newBB->startOffset = targetOffset;
-#else
- /* Handle branches that branch back into the block */
- if (targetOffset >= curBB->firstMIRInsn->offset &&
- targetOffset <= curBB->lastMIRInsn->offset) {
- newBB = dvmCompilerNewBB(kChainingCellBackwardBranch,
- numBlocks++);
- } else {
- newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
- kChainingCellHot :
- kChainingCellNormal,
- numBlocks++);
- }
- newBB->startOffset = targetOffset;
-#endif
- }
- if (newBB) {
- curBB->taken = newBB;
- dvmCompilerSetBit(newBB->predecessors, curBB->id);
- dvmInsertGrowableList(blockList, (intptr_t) newBB);
- }
- }
- }
-
- /* Now create a special block to host PC reconstruction code */
- curBB = dvmCompilerNewBB(kPCReconstruction, numBlocks++);
- dvmInsertGrowableList(blockList, (intptr_t) curBB);
-
- /* And one final block that publishes the PC and raise the exception */
- curBB = dvmCompilerNewBB(kExceptionHandling, numBlocks++);
- dvmInsertGrowableList(blockList, (intptr_t) curBB);
- cUnit.puntBlock = curBB;
-
- if (cUnit.printMe) {
- char* signature =
- dexProtoCopyMethodDescriptor(&desc->method->prototype);
- ALOGD("TRACEINFO (%d): 0x%08x %s%s.%s %#x %d of %d, %d blocks",
- compilationId,
- (intptr_t) desc->method->insns,
- desc->method->clazz->descriptor,
- desc->method->name,
- signature,
- desc->trace[0].info.frag.startOffset,
- traceSize,
- dexCode->insnsSize,
- numBlocks);
- free(signature);
- }
-
- cUnit.numBlocks = numBlocks;
-
- /* Set the instruction set to use (NOTE: later components may change it) */
- cUnit.instructionSet = dvmCompilerInstructionSet();
-
- /* Inline transformation @ the MIR level */
- if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
- dvmCompilerInlineMIR(&cUnit, info);
- }
-
- cUnit.numDalvikRegisters = cUnit.method->registersSize;
-
- /* Preparation for SSA conversion */
- dvmInitializeSSAConversion(&cUnit);
-
- dvmCompilerNonLoopAnalysis(&cUnit);
-
-#ifndef ARCH_IA32
- dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
-#endif
-
- if (cUnit.printMe) {
- dvmCompilerDumpCompilationUnit(&cUnit);
- }
-
-#ifndef ARCH_IA32
- /* Allocate Registers using simple local allocation scheme */
- dvmCompilerLocalRegAlloc(&cUnit);
-
- /* Convert MIR to LIR, etc. */
- dvmCompilerMIR2LIR(&cUnit);
-#else /* ARCH_IA32 */
- /* Convert MIR to LIR, etc. */
- dvmCompilerMIR2LIR(&cUnit, info);
-#endif
-
- /* Convert LIR into machine code. Loop for recoverable retries */
- do {
- dvmCompilerAssembleLIR(&cUnit, info);
- cUnit.assemblerRetries++;
- if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
- ALOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
- cUnit.assemblerStatus);
- } while (cUnit.assemblerStatus == kRetryAll);
-
- if (cUnit.printMe) {
- ALOGD("Trace Dalvik PC: %p", startCodePtr);
- dvmCompilerCodegenDump(&cUnit);
- ALOGD("End %s%s, %d Dalvik instructions",
- desc->method->clazz->descriptor, desc->method->name,
- cUnit.numInsts);
- }
-
- if (cUnit.assemblerStatus == kRetryHalve) {
- /* Reset the compiler resource pool before retry */
- dvmCompilerArenaReset();
-
- /* Halve the instruction count and start from the top */
- return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr,
- optHints);
- }
-
- /*
- * If this trace uses class objects as constants,
- * dvmJitInstallClassObjectPointers will switch the thread state
- * to running and look up the class pointers using the descriptor/loader
- * tuple stored in the callsite info structure. We need to make this window
- * as short as possible since it is blocking GC.
- */
- if (cUnit.hasClassLiterals && info->codeAddress) {
- dvmJitInstallClassObjectPointers(&cUnit, (char *) info->codeAddress);
- }
-
- /*
- * Since callsiteinfo is allocated from the arena, delay the reset until
- * class pointers are resolved.
- */
- dvmCompilerArenaReset();
-
- assert(cUnit.assemblerStatus == kSuccess);
-#if defined(WITH_JIT_TUNING)
- methodStats->nativeSize += cUnit.totalSize;
-#endif
-
- return info->codeAddress != NULL;
-}