diff options
-rw-r--r-- | vm/BitVector.c | 87 | ||||
-rw-r--r-- | vm/BitVector.h | 29 | ||||
-rw-r--r-- | vm/Dvm.mk | 1 | ||||
-rw-r--r-- | vm/Misc.h | 1 | ||||
-rw-r--r-- | vm/compiler/Compiler.h | 37 | ||||
-rw-r--r-- | vm/compiler/CompilerIR.h | 50 | ||||
-rw-r--r-- | vm/compiler/CompilerUtility.h | 24 | ||||
-rw-r--r-- | vm/compiler/Dataflow.c | 352 | ||||
-rw-r--r-- | vm/compiler/Frontend.c | 1059 | ||||
-rw-r--r-- | vm/compiler/InlineTransformation.c | 8 | ||||
-rw-r--r-- | vm/compiler/IntermediateRep.c | 5 | ||||
-rw-r--r-- | vm/compiler/Loop.c | 59 | ||||
-rw-r--r-- | vm/compiler/MethodSSATransformation.c | 559 | ||||
-rw-r--r-- | vm/compiler/Ralloc.c | 40 | ||||
-rw-r--r-- | vm/compiler/Utility.c | 116 | ||||
-rw-r--r-- | vm/compiler/codegen/arm/CodegenCommon.c | 3 | ||||
-rw-r--r-- | vm/compiler/codegen/arm/CodegenDriver.c | 90 | ||||
-rw-r--r-- | vm/mterp/out/InterpC-allstubs.c | 6 | ||||
-rw-r--r-- | vm/mterp/out/InterpC-x86-atom.c | 6 | ||||
-rw-r--r-- | vm/mterp/out/InterpC-x86.c | 6 |
20 files changed, 2062 insertions, 476 deletions
diff --git a/vm/BitVector.c b/vm/BitVector.c index 68f19b086..04c3d3ff8 100644 --- a/vm/BitVector.c +++ b/vm/BitVector.c @@ -143,6 +143,24 @@ void dvmClearAllBits(BitVector* pBits) } /* + * Mark specified number of bits as "set". Cannot set all bits like ClearAll + * since there might be unused bits - setting those to one will confuse the + * iterator. + */ +void dvmSetInitialBits(BitVector* pBits, int numBits) +{ + int i; + assert(((numBits + 31) >> 5) <= pBits->storageSize); + for (i = 0; i < (numBits >> 5); i++) { + pBits->storage[i] = -1; + } + int remNumBits = numBits & 0x1f; + if (remNumBits) { + pBits->storage[i] = (1 << remNumBits) - 1; + } +} + +/* * Determine whether or not the specified bit is set. */ bool dvmIsBitSet(const BitVector* pBits, int num) @@ -194,8 +212,7 @@ bool dvmCopyBitVector(BitVector *dest, const BitVector *src) } /* - * Intersect two bit vectores and merge the result on top of the pre-existing - * value in the dest vector. + * Intersect two bit vectors and store the result to the dest vector. */ bool dvmIntersectBitVectors(BitVector *dest, const BitVector *src1, const BitVector *src2) @@ -208,7 +225,71 @@ bool dvmIntersectBitVectors(BitVector *dest, const BitVector *src1, int i; for (i = 0; i < dest->storageSize; i++) { - dest->storage[i] |= src1->storage[i] & src2->storage[i]; + dest->storage[i] = src1->storage[i] & src2->storage[i]; } return true; } + +/* + * Unify two bit vectors and store the result to the dest vector. + */ +bool dvmUnifyBitVectors(BitVector *dest, const BitVector *src1, + const BitVector *src2) +{ + if (dest->storageSize != src1->storageSize || + dest->storageSize != src2->storageSize || + dest->expandable != src1->expandable || + dest->expandable != src2->expandable) + return false; + + int i; + for (i = 0; i < dest->storageSize; i++) { + dest->storage[i] = src1->storage[i] | src2->storage[i]; + } + return true; +} + +/* + * Compare two bit vectors and return true if difference is seen. + */ +bool dvmCompareBitVectors(const BitVector *src1, const BitVector *src2) +{ + if (src1->storageSize != src2->storageSize || + src1->expandable != src2->expandable) + return true; + + int i; + for (i = 0; i < src1->storageSize; i++) { + if (src1->storage[i] != src2->storage[i]) return true; + } + return false; +} + +/* Initialize the iterator structure */ +void dvmBitVectorIteratorInit(BitVector* pBits, BitVectorIterator* iterator) +{ + iterator->pBits = pBits; + iterator->bitSize = pBits->storageSize * sizeof(u4) * 8; + iterator->idx = 0; +} + +/* Return the next position set to 1. -1 means end-of-element reached */ +int dvmBitVectorIteratorNext(BitVectorIterator* iterator) +{ + const BitVector* pBits = iterator->pBits; + u4 bitIndex = iterator->idx; + + assert(iterator->bitSize == pBits->storageSize * sizeof(u4) * 8); + if (bitIndex >= iterator->bitSize) return -1; + + for (; bitIndex < iterator->bitSize; bitIndex++) { + int wordIndex = bitIndex >> 5; + int mask = 1 << (bitIndex & 0x1f); + if (pBits->storage[wordIndex] & mask) { + iterator->idx = bitIndex+1; + return bitIndex; + } + } + /* No more set bits */ + return -1; +} diff --git a/vm/BitVector.h b/vm/BitVector.h index 94abe7b85..3c926b14e 100644 --- a/vm/BitVector.h +++ b/vm/BitVector.h @@ -32,6 +32,13 @@ typedef struct BitVector { u4* storage; } BitVector; +/* Handy iterator to walk through the bit positions set to 1 */ +typedef struct BitVectorIterator { + BitVector *pBits; + u4 idx; + u4 bitSize; +} BitVectorIterator; + /* allocate a bit vector with enough space to hold "startBits" bits */ BitVector* dvmAllocBitVector(int startBits, bool expandable); void dvmFreeBitVector(BitVector* pBits); @@ -44,12 +51,15 @@ void dvmFreeBitVector(BitVector* pBits); * dvmSetBit sets the specified bit, expanding the vector if necessary * (and possible). * + * dvmSetInitialBits sets all bits in [0..numBits-1]. Won't expand the vector. + * * dvmIsBitSet returns "true" if the bit is set. */ int dvmAllocBit(BitVector* pBits); bool dvmSetBit(BitVector* pBits, int num); void dvmClearBit(BitVector* pBits, int num); void dvmClearAllBits(BitVector* pBits); +void dvmSetInitialBits(BitVector* pBits, int numBits); bool dvmIsBitSet(const BitVector* pBits, int num); /* count the number of bits that have been set */ @@ -59,11 +69,26 @@ int dvmCountSetBits(const BitVector* pBits); bool dvmCopyBitVector(BitVector *dest, const BitVector *src); /* - * Intersect two bit vectores and merge the result on top of the pre-existing - * value in the dest vector. + * Intersect two bit vectors and store the result to the dest vector. */ bool dvmIntersectBitVectors(BitVector *dest, const BitVector *src1, const BitVector *src2); +/* + * Unify two bit vectors and store the result to the dest vector. + */ +bool dvmUnifyBitVectors(BitVector *dest, const BitVector *src1, + const BitVector *src2); + +/* + * Compare two bit vectors and return true if difference is seen. + */ +bool dvmCompareBitVectors(const BitVector *src1, const BitVector *src2); + +/* Initialize the iterator structure */ +void dvmBitVectorIteratorInit(BitVector* pBits, BitVectorIterator* iterator); + +/* Return the next position set to 1. -1 means end-of-vector reached */ +int dvmBitVectorIteratorNext(BitVectorIterator* iterator); #endif /*_DALVIK_BITVECTOR*/ @@ -224,6 +224,7 @@ ifeq ($(WITH_JIT),true) compiler/InlineTransformation.c \ compiler/IntermediateRep.c \ compiler/Dataflow.c \ + compiler/MethodSSATransformation.c \ compiler/Loop.c \ compiler/Ralloc.c \ interp/Jit.c @@ -128,7 +128,6 @@ void dvmPrintDebugMessage(const DebugOutputTarget* target, const char* format, #endif ; - /* * Return a newly-allocated string in which all occurrences of '.' have * been changed to '/'. If we find a '/' in the original string, NULL diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h index 6dd9cbd58..0a43df3c9 100644 --- a/vm/compiler/Compiler.h +++ b/vm/compiler/Compiler.h @@ -236,6 +236,15 @@ typedef enum JitOptimizationHints { #define JIT_OPT_NO_LOOP (1 << kJitOptNoLoop) +/* Customized node traversal orders for different needs */ +typedef enum DataFlowAnalysisMode { + kAllNodes = 0, // All nodes + kReachableNodes, // All reachable nodes + kPreOrderDFSTraversal, // Depth-First-Search / Pre-Order + kPostOrderDFSTraversal, // Depth-First-Search / Post-Order + kPostOrderDOMTraversal, // Dominator tree / Post-Order +} DataFlowAnalysisMode; + typedef struct CompilerMethodStats { const Method *method; // Used as hash entry signature int dalvikSize; // # of bytes for dalvik bytecodes @@ -262,8 +271,7 @@ CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method, bool isCallee); bool dvmCompilerCanIncludeThisInstruction(const Method *method, const DecodedInstruction *insn); -bool dvmCompileMethod(struct CompilationUnit *cUnit, const Method *method, - JitTranslationInfo *info); +bool dvmCompileMethod(const Method *method); bool dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts, JitTranslationInfo *info, jmp_buf *bailPtr, int optHints); void dvmCompilerDumpStats(void); @@ -273,22 +281,31 @@ void dvmCompilerSortAndPrintTraceProfiles(void); void dvmCompilerPerformSafePointChecks(void); void dvmCompilerInlineMIR(struct CompilationUnit *cUnit); void dvmInitializeSSAConversion(struct CompilationUnit *cUnit); -int dvmConvertSSARegToDalvik(struct CompilationUnit *cUnit, int ssaReg); +int dvmConvertSSARegToDalvik(const struct CompilationUnit *cUnit, int ssaReg); bool dvmCompilerLoopOpt(struct CompilationUnit *cUnit); void dvmCompilerNonLoopAnalysis(struct CompilationUnit *cUnit); -void dvmCompilerFindLiveIn(struct CompilationUnit *cUnit, - struct BasicBlock *bb); -void dvmCompilerDoSSAConversion(struct CompilationUnit *cUnit, +bool dvmCompilerFindLocalLiveIn(struct CompilationUnit *cUnit, + struct BasicBlock *bb); +bool dvmCompilerDoSSAConversion(struct CompilationUnit *cUnit, struct BasicBlock *bb); -void dvmCompilerDoConstantPropagation(struct CompilationUnit *cUnit, +bool dvmCompilerDoConstantPropagation(struct CompilationUnit *cUnit, struct BasicBlock *bb); -void dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit, +bool dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit, struct BasicBlock *bb); -char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn, char *note); +/* Clear the visited flag for each BB */ +bool dvmCompilerClearVisitedFlag(struct CompilationUnit *cUnit, + struct BasicBlock *bb); +char *dvmCompilerGetDalvikDisassembly(const DecodedInstruction *insn, + char *note); +char *dvmCompilerFullDisassembler(const struct CompilationUnit *cUnit, + const struct MIR *mir); char *dvmCompilerGetSSAString(struct CompilationUnit *cUnit, struct SSARepresentation *ssaRep); void dvmCompilerDataFlowAnalysisDispatcher(struct CompilationUnit *cUnit, - void (*func)(struct CompilationUnit *, struct BasicBlock *)); + bool (*func)(struct CompilationUnit *, struct BasicBlock *), + DataFlowAnalysisMode dfaMode, + bool isIterative); +void dvmCompilerMethodSSATransformation(struct CompilationUnit *cUnit); void dvmCompilerStateRefresh(void); JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc, const struct JitEntry *desc); diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h index 712ca4ce8..95a75b828 100644 --- a/vm/compiler/CompilerIR.h +++ b/vm/compiler/CompilerIR.h @@ -61,6 +61,7 @@ typedef enum BBType { kMethodExitBlock, kPCReconstruction, kExceptionHandling, + kCatchEntry, } BBType; typedef struct ChainCellCounts { @@ -133,20 +134,47 @@ typedef struct MIR { struct BasicBlockDataFlow; +/* FIXME - debugging prupose only */ +typedef enum BlockAttributes { + kEndsWithThrow = 0, + kCatchBlock, +} BlockAttributes; + +/* For successorBlockList */ +typedef enum BlockListType { + kNotUsed = 0, + kCatch, + kPackedSwitch, + kSparseSwitch, +} BlockListType; + +#define BA_ENDS_WITH_THROW (1 << kEndsWithThrow) +#define BA_CATCH_BLOCK (1 << kCatchBlock) + typedef struct BasicBlock { int id; - int visited; + bool visited; unsigned int startOffset; const Method *containingMethod; // For blocks from the callee BBType blockType; bool needFallThroughBranch; // For blocks ended due to length limit bool isFallThroughFromInvoke; // True means the block needs alignment + u4 blockAttributes; // FIXME - debugging purpose only + u4 exceptionTypeIdx; // FIXME - will be put elsewhere MIR *firstMIRInsn; MIR *lastMIRInsn; struct BasicBlock *fallThrough; struct BasicBlock *taken; - struct BasicBlock *next; // Serial link for book keeping purposes + struct BasicBlock *iDom; // Immediate dominator struct BasicBlockDataFlow *dataFlowInfo; + BitVector *predecessors; + BitVector *dominators; + BitVector *iDominated; // Set nodes being immediately dominated + BitVector *domFrontier; // Dominance frontier + struct { // For one-to-many successors like + BlockListType blockListType; // switch and exception handling + GrowableList blocks; + } successorBlockList; } BasicBlock; struct LoopAnalysis; @@ -161,7 +189,7 @@ typedef enum AssemblerStatus { typedef struct CompilationUnit { int numInsts; int numBlocks; - BasicBlock **blockList; + GrowableList blockList; const Method *method; const JitTraceDescription *traceDesc; LIR *firstLIRInsn; @@ -213,6 +241,20 @@ typedef struct CompilationUnit { * MAX_CHAINED_SWITCH_CASES cases. */ const u2 *switchOverflowPad; + + /* New fields only for method-based compilation */ + int numReachableBlocks; + int numDalvikRegisters; // method->registersSize + inlined + BasicBlock *entryBlock; + BasicBlock *exitBlock; + GrowableList dfsOrder; + GrowableList domPostOrderTraversal; + BitVector *tryBlockAddr; + BitVector **defBlockMatrix; // numDalvikRegister x numBlocks + BitVector *tempBlockV; + BitVector *tempDalvikRegisterV; + BitVector *tempSSARegisterV; // numSSARegs + bool printSSANames; } CompilationUnit; #if defined(WITH_SELF_VERIFICATION) @@ -221,7 +263,7 @@ typedef struct CompilationUnit { #define HEAP_ACCESS_SHADOW(_state) #endif -BasicBlock *dvmCompilerNewBB(BBType blockType); +BasicBlock *dvmCompilerNewBB(BBType blockType, int blockId); void dvmCompilerAppendMIR(BasicBlock *bb, MIR *mir); diff --git a/vm/compiler/CompilerUtility.h b/vm/compiler/CompilerUtility.h index 551edb8ab..d3f2d6aef 100644 --- a/vm/compiler/CompilerUtility.h +++ b/vm/compiler/CompilerUtility.h @@ -39,19 +39,39 @@ void dvmCompilerArenaReset(void); typedef struct GrowableList { size_t numAllocated; size_t numUsed; - void **elemList; + intptr_t *elemList; } GrowableList; +typedef struct GrowableListIterator { + GrowableList *list; + size_t idx; + size_t size; +} GrowableListIterator; + #define GET_ELEM_N(LIST, TYPE, N) (((TYPE*) LIST->elemList)[N]) +#define BLOCK_NAME_LEN 80 + +/* Forward declarations */ struct LIR; +struct BasicBlock; void dvmInitGrowableList(GrowableList *gList, size_t initLength); -void dvmInsertGrowableList(GrowableList *gList, void *elem); +void dvmInsertGrowableList(GrowableList *gList, intptr_t elem); +void dvmGrowableListIteratorInit(GrowableList *gList, + GrowableListIterator *iterator); +intptr_t dvmGrowableListIteratorNext(GrowableListIterator *iterator); +intptr_t dvmGrowableListGetElement(const GrowableList *gList, size_t idx); + BitVector* dvmCompilerAllocBitVector(int startBits, bool expandable); bool dvmCompilerSetBit(BitVector* pBits, int num); +bool dvmCompilerClearBit(BitVector* pBits, int num); +void dvmCompilerMarkAllBits(BitVector *pBits, bool set); void dvmDebugBitVector(char *msg, const BitVector *bv, int length); void dvmDumpLIRInsn(struct LIR *lir, unsigned char *baseAddr); void dvmDumpResourceMask(struct LIR *lir, u8 mask, const char *prefix); +void dvmDumpBlockBitVector(const GrowableList *blocks, char *msg, + const BitVector *bv, int length); +void dvmGetBlockName(struct BasicBlock *bb, char *name); #endif /* _DALVIK_COMPILER_UTILITY */ diff --git a/vm/compiler/Dataflow.c b/vm/compiler/Dataflow.c index da1bf24f1..411f456e7 100644 --- a/vm/compiler/Dataflow.c +++ b/vm/compiler/Dataflow.c @@ -809,7 +809,7 @@ int dvmCompilerDataFlowAttributes[kMirOpLast] = { }; /* Return the Dalvik register/subscript pair of a given SSA register */ -int dvmConvertSSARegToDalvik(CompilationUnit *cUnit, int ssaReg) +int dvmConvertSSARegToDalvik(const CompilationUnit *cUnit, int ssaReg) { return GET_ELEM_N(cUnit->ssaToDalvikMap, int, ssaReg); } @@ -819,21 +819,58 @@ int dvmConvertSSARegToDalvik(CompilationUnit *cUnit, int ssaReg) * and subscript pair. Each SSA register can be used to index the * ssaToDalvikMap list to get the subscript[31..16]/dalvik_reg[15..0] mapping. */ -char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn, +char *dvmCompilerGetDalvikDisassembly(const DecodedInstruction *insn, char *note) { char buffer[256]; int opcode = insn->opcode; int dfAttributes = dvmCompilerDataFlowAttributes[opcode]; + int flags = dexGetFlagsFromOpcode(insn->opcode); char *ret; buffer[0] = 0; - strcpy(buffer, dexGetOpcodeName(opcode)); + if (opcode >= kMirOpFirst) { + if (opcode == kMirOpPhi) { + strcpy(buffer, "PHI"); + } + else { + sprintf(buffer, "Opcode 0x%x", opcode); + } + } else { + strcpy(buffer, dexGetOpcodeName(opcode)); + } if (note) strcat(buffer, note); - if (dfAttributes & DF_FORMAT_35C) { + /* For branches, decode the instructions to print out the branch targets */ + if (flags & kInstrCanBranch) { + InstructionFormat dalvikFormat = dexGetFormatFromOpcode(insn->opcode); + int offset = 0; + switch (dalvikFormat) { + case kFmt21t: + snprintf(buffer + strlen(buffer), 256, " v%d,", insn->vA); + offset = (int) insn->vB; + break; + case kFmt22t: + snprintf(buffer + strlen(buffer), 256, " v%d, v%d,", + insn->vA, insn->vB); + offset = (int) insn->vC; + break; + case kFmt10t: + case kFmt20t: + case kFmt30t: + offset = (int) insn->vA; + break; + default: + LOGE("Unexpected branch format: %d", dalvikFormat); + dvmAbort(); + break; + } + snprintf(buffer + strlen(buffer), 256, " (%c%x)", + offset > 0 ? '+' : '-', + offset > 0 ? offset : -offset); + } else if (dfAttributes & DF_FORMAT_35C) { unsigned int i; for (i = 0; i < insn->vA; i++) { if (i != 0) strcat(buffer, ","); @@ -851,13 +888,13 @@ char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn, if (dfAttributes & DF_B_IS_REG) { snprintf(buffer + strlen(buffer), 256, ", v%d", insn->vB); } - else { + else if (opcode < kMirOpFirst) { snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn->vB); } if (dfAttributes & DF_C_IS_REG) { snprintf(buffer + strlen(buffer), 256, ", v%d", insn->vC); } - else { + else if (opcode < kMirOpFirst) { snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn->vC); } } @@ -867,6 +904,141 @@ char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn, return ret; } +char *getSSAName(const CompilationUnit *cUnit, int ssaReg, char *name) +{ + int ssa2DalvikValue = dvmConvertSSARegToDalvik(cUnit, ssaReg); + + sprintf(name, "v%d_%d", + DECODE_REG(ssa2DalvikValue), DECODE_SUB(ssa2DalvikValue)); + return name; +} + +/* + * Dalvik instruction disassembler with optional SSA printing. + */ +char *dvmCompilerFullDisassembler(const CompilationUnit *cUnit, + const MIR *mir) +{ + char buffer[256]; + char operand0[256], operand1[256]; + const DecodedInstruction *insn = &mir->dalvikInsn; + int opcode = insn->opcode; + int dfAttributes = dvmCompilerDataFlowAttributes[opcode]; + int flags = dexGetFlagsFromOpcode(insn->opcode); + char *ret; + int length; + + buffer[0] = 0; + if (opcode >= kMirOpFirst) { + if (opcode == kMirOpPhi) { + snprintf(buffer, 256, "PHI %s = (%s", + getSSAName(cUnit, mir->ssaRep->defs[0], operand0), + getSSAName(cUnit, mir->ssaRep->uses[0], operand1)); + int i; + for (i = 1; i < mir->ssaRep->numUses; i++) { + snprintf(buffer + strlen(buffer), 256, ", %s", + getSSAName(cUnit, mir->ssaRep->uses[i], operand0)); + } + snprintf(buffer + strlen(buffer), 256, ")"); + } + else { + sprintf(buffer, "Opcode 0x%x", opcode); + } + goto done; + } else { + strcpy(buffer, dexGetOpcodeName(opcode)); + } + + /* For branches, decode the instructions to print out the branch targets */ + if (flags & kInstrCanBranch) { + InstructionFormat dalvikFormat = dexGetFormatFromOpcode(insn->opcode); + int delta = 0; + switch (dalvikFormat) { + case kFmt21t: + snprintf(buffer + strlen(buffer), 256, " %s, ", + getSSAName(cUnit, mir->ssaRep->uses[0], operand0)); + delta = (int) insn->vB; + break; + case kFmt22t: + snprintf(buffer + strlen(buffer), 256, " %s, %s, ", + getSSAName(cUnit, mir->ssaRep->uses[0], operand0), + getSSAName(cUnit, mir->ssaRep->uses[1], operand1)); + delta = (int) insn->vC; + break; + case kFmt10t: + case kFmt20t: + case kFmt30t: + delta = (int) insn->vA; + break; + default: + LOGE("Unexpected branch format: %d", dalvikFormat); + dvmAbort(); + break; + } + snprintf(buffer + strlen(buffer), 256, " %04x", + mir->offset + delta); + } else if (dfAttributes & (DF_FORMAT_35C | DF_FORMAT_3RC)) { + unsigned int i; + for (i = 0; i < insn->vA; i++) { + if (i != 0) strcat(buffer, ","); + snprintf(buffer + strlen(buffer), 256, " %s", + getSSAName(cUnit, mir->ssaRep->uses[i], operand0)); + } + } else { + int udIdx; + if (mir->ssaRep->numDefs) { + + for (udIdx = 0; udIdx < mir->ssaRep->numDefs; udIdx++) { + snprintf(buffer + strlen(buffer), 256, " %s", + getSSAName(cUnit, mir->ssaRep->defs[udIdx], operand0)); + } + strcat(buffer, ","); + } + if (mir->ssaRep->numUses) { + /* No leading ',' for the first use */ + snprintf(buffer + strlen(buffer), 256, " %s", + getSSAName(cUnit, mir->ssaRep->uses[0], operand0)); + for (udIdx = 1; udIdx < mir->ssaRep->numUses; udIdx++) { + snprintf(buffer + strlen(buffer), 256, ", %s", + getSSAName(cUnit, mir->ssaRep->uses[udIdx], operand0)); + } + } + if (opcode < kMirOpFirst) { + InstructionFormat dalvikFormat = dexGetFormatFromOpcode(opcode); + switch (dalvikFormat) { + case kFmt11n: // op vA, #+B + case kFmt21s: // op vAA, #+BBBB + case kFmt21h: // op vAA, #+BBBB00000[00000000] + case kFmt31i: // op vAA, #+BBBBBBBB + case kFmt51l: // op vAA, #+BBBBBBBBBBBBBBBB + snprintf(buffer + strlen(buffer), 256, " #%#x", insn->vB); + break; + case kFmt21c: // op vAA, thing@BBBB + case kFmt31c: // op vAA, thing@BBBBBBBB + snprintf(buffer + strlen(buffer), 256, " @%#x", insn->vB); + break; + case kFmt22b: // op vAA, vBB, #+CC + case kFmt22s: // op vA, vB, #+CCCC + snprintf(buffer + strlen(buffer), 256, " #%#x", insn->vC); + break; + case kFmt22c: // op vA, vB, thing@CCCC + case kFmt22cs: // [opt] op vA, vB, field offset CCCC + snprintf(buffer + strlen(buffer), 256, " @%#x", insn->vC); + break; + /* No need for special printing */ + default: + break; + } + } + } + +done: + length = strlen(buffer) + 1; + ret = (char *) dvmCompilerNew(length, false); + memcpy(ret, buffer, length); + return ret; +} + /* * Utility function to convert encoded SSA register value into Dalvik register * and subscript pair. Each SSA register can be used to index the @@ -920,7 +1092,7 @@ static inline void handleLiveInUse(BitVector *useV, BitVector *defV, } /* Mark a reg as being defined */ -static inline void handleLiveInDef(BitVector *defV, int dalvikRegId) +static inline void handleDef(BitVector *defV, int dalvikRegId) { dvmCompilerSetBit(defV, dalvikRegId); } @@ -929,22 +1101,19 @@ static inline void handleLiveInDef(BitVector *defV, int dalvikRegId) * Find out live-in variables for natural loops. Variables that are live-in in * the main loop body are considered to be defined in the entry block. */ -void dvmCompilerFindLiveIn(CompilationUnit *cUnit, BasicBlock *bb) +bool dvmCompilerFindLocalLiveIn(CompilationUnit *cUnit, BasicBlock *bb) { MIR *mir; BitVector *useV, *defV, *liveInV; - if (bb->blockType != kDalvikByteCode && - bb->blockType != kTraceEntryBlock) { - return; - } + if (bb->dataFlowInfo == NULL) return false; useV = bb->dataFlowInfo->useV = - dvmCompilerAllocBitVector(cUnit->method->registersSize, false); + dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false); defV = bb->dataFlowInfo->defV = - dvmCompilerAllocBitVector(cUnit->method->registersSize, false); + dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false); liveInV = bb->dataFlowInfo->liveInV = - dvmCompilerAllocBitVector(cUnit->method->registersSize, false); + dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false); for (mir = bb->firstMIRInsn; mir; mir = mir->next) { int dfAttributes = @@ -972,12 +1141,13 @@ void dvmCompilerFindLiveIn(CompilationUnit *cUnit, BasicBlock *bb) } } if (dfAttributes & DF_HAS_DEFS) { - handleLiveInDef(defV, dInsn->vA); + handleDef(defV, dInsn->vA); if (dfAttributes & DF_DA_WIDE) { - handleLiveInDef(defV, dInsn->vA+1); + handleDef(defV, dInsn->vA+1); } } } + return true; } /* Find out the latest SSA register for a given Dalvik register */ @@ -1002,7 +1172,7 @@ static void handleSSADef(CompilationUnit *cUnit, int *defs, int dalvikReg, cUnit->dalvikToSSAMap[dalvikReg] = newD2SMapping; int newS2DMapping = ENCODE_REG_SUB(dalvikReg, dalvikSub); - dvmInsertGrowableList(cUnit->ssaToDalvikMap, (void *) newS2DMapping); + dvmInsertGrowableList(cUnit->ssaToDalvikMap, newS2DMapping); defs[regIndex] = ssaReg; } @@ -1038,13 +1208,11 @@ static void dataFlowSSAFormat3RC(CompilationUnit *cUnit, MIR *mir) } /* Entry function to convert a block into SSA representation */ -void dvmCompilerDoSSAConversion(CompilationUnit *cUnit, BasicBlock *bb) +bool dvmCompilerDoSSAConversion(CompilationUnit *cUnit, BasicBlock *bb) { MIR *mir; - if (bb->blockType != kDalvikByteCode && bb->blockType != kTraceEntryBlock) { - return; - } + if (bb->dataFlowInfo == NULL) return false; for (mir = bb->firstMIRInsn; mir; mir = mir->next) { mir->ssaRep = (struct SSARepresentation *) @@ -1150,13 +1318,18 @@ void dvmCompilerDoSSAConversion(CompilationUnit *cUnit, BasicBlock *bb) } } + /* + * Take a snapshot of Dalvik->SSA mapping at the end of each block. The + * input to PHI nodes can be derived from the snapshot of all predecessor + * blocks. + */ bb->dataFlowInfo->dalvikToSSAMap = (int *)dvmCompilerNew(sizeof(int) * cUnit->method->registersSize, false); - /* Take a snapshot of Dalvik->SSA mapping at the end of each block */ memcpy(bb->dataFlowInfo->dalvikToSSAMap, cUnit->dalvikToSSAMap, sizeof(int) * cUnit->method->registersSize); + return true; } /* Setup a constant value for opcodes thare have the DF_SETS_CONST attribute */ @@ -1166,7 +1339,7 @@ static void setConstant(CompilationUnit *cUnit, int ssaReg, int value) cUnit->constantValues[ssaReg] = value; } -void dvmCompilerDoConstantPropagation(CompilationUnit *cUnit, BasicBlock *bb) +bool dvmCompilerDoConstantPropagation(CompilationUnit *cUnit, BasicBlock *bb) { MIR *mir; BitVector *isConstantV = cUnit->isConstantV; @@ -1236,9 +1409,10 @@ void dvmCompilerDoConstantPropagation(CompilationUnit *cUnit, BasicBlock *bb) } } /* TODO: implement code to handle arithmetic operations */ + return true; } -void dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit, +bool dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit, struct BasicBlock *bb) { BitVector *isIndVarV = cUnit->loopAnalysis->isIndVarV; @@ -1248,13 +1422,13 @@ void dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit, if (bb->blockType != kDalvikByteCode && bb->blockType != kTraceEntryBlock) { - return; + return false; } /* If the bb doesn't have a phi it cannot contain an induction variable */ if (bb->firstMIRInsn == NULL || bb->firstMIRInsn->dalvikInsn.opcode != kMirOpPhi) { - return; + return false; } /* Find basic induction variable first */ @@ -1314,7 +1488,7 @@ void dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit, ivInfo->m = 1; // always 1 to basic iv ivInfo->c = 0; // N/A to basic iv ivInfo->inc = deltaValue; - dvmInsertGrowableList(ivList, (void *) ivInfo); + dvmInsertGrowableList(ivList, (intptr_t) ivInfo); cUnit->loopAnalysis->numBasicIV++; break; } @@ -1396,10 +1570,11 @@ void dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit, ivInfo->m = ivInfoOld->m; ivInfo->c = c + ivInfoOld->c; ivInfo->inc = ivInfoOld->inc; - dvmInsertGrowableList(ivList, (void *) ivInfo); + dvmInsertGrowableList(ivList, (intptr_t) ivInfo); } } } + return true; } /* Setup the basic data structures for SSA conversion */ @@ -1424,8 +1599,7 @@ void dvmInitializeSSAConversion(CompilationUnit *cUnit) * into "(0 << 16) | i" */ for (i = 0; i < numDalvikReg; i++) { - dvmInsertGrowableList(cUnit->ssaToDalvikMap, - (void *) ENCODE_REG_SUB(i, 0)); + dvmInsertGrowableList(cUnit->ssaToDalvikMap, ENCODE_REG_SUB(i, 0)); } /* @@ -1442,10 +1616,17 @@ void dvmInitializeSSAConversion(CompilationUnit *cUnit) /* * Allocate the BasicBlockDataFlow structure for the entry and code blocks */ - for (i = 0; i < cUnit->numBlocks; i++) { - BasicBlock *bb = cUnit->blockList[i]; + GrowableListIterator iterator; + + dvmGrowableListIteratorInit(&cUnit->blockList, &iterator); + + while (true) { + BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + if (bb == NULL) break; if (bb->blockType == kDalvikByteCode || - bb->blockType == kTraceEntryBlock) { + bb->blockType == kTraceEntryBlock || + bb->blockType == kMethodEntryBlock || + bb->blockType == kMethodExitBlock) { bb->dataFlowInfo = (BasicBlockDataFlow *) dvmCompilerNew(sizeof(BasicBlockDataFlow), true); @@ -1453,18 +1634,109 @@ void dvmInitializeSSAConversion(CompilationUnit *cUnit) } } +/* Clear the visited flag for each BB */ +bool dvmCompilerClearVisitedFlag(struct CompilationUnit *cUnit, + struct BasicBlock *bb) +{ + bb->visited = false; + return true; +} + void dvmCompilerDataFlowAnalysisDispatcher(CompilationUnit *cUnit, - void (*func)(CompilationUnit *, BasicBlock *)) + bool (*func)(CompilationUnit *, BasicBlock *), + DataFlowAnalysisMode dfaMode, + bool isIterative) { - int i; - for (i = 0; i < cUnit->numBlocks; i++) { - BasicBlock *bb = cUnit->blockList[i]; - (*func)(cUnit, bb); + bool change = true; + + while (change) { + change = false; + + /* Scan all blocks and perform the operations specified in func */ + if (dfaMode == kAllNodes) { + GrowableListIterator iterator; + dvmGrowableListIteratorInit(&cUnit->blockList, &iterator); + while (true) { + BasicBlock *bb = + (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + if (bb == NULL) break; + change |= (*func)(cUnit, bb); + } + } + /* + * Scan all reachable blocks and perform the operations specified in + * func. + */ + else if (dfaMode == kReachableNodes) { + 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); + change |= (*func)(cUnit, bb); + } + } + /* + * Scan all reachable blocks by the pre-order in the depth-first-search + * CFG and perform the operations specified in func. + */ + else if (dfaMode == kPreOrderDFSTraversal) { + int numReachableBlocks = cUnit->numReachableBlocks; + int idx; + const GrowableList *blockList = &cUnit->blockList; + + for (idx = 0; idx < numReachableBlocks; idx++) { + int dfsIdx = cUnit->dfsOrder.elemList[idx]; + BasicBlock *bb = + (BasicBlock *) dvmGrowableListGetElement(blockList, dfsIdx); + change |= (*func)(cUnit, bb); + } + } + /* + * Scan all reachable blocks by the post-order in the depth-first-search + * CFG and perform the operations specified in func. + */ + else if (dfaMode == kPostOrderDFSTraversal) { + int numReachableBlocks = cUnit->numReachableBlocks; + int idx; + const GrowableList *blockList = &cUnit->blockList; + + for (idx = numReachableBlocks - 1; idx >= 0; idx--) { + int dfsIdx = cUnit->dfsOrder.elemList[idx]; + BasicBlock *bb = + (BasicBlock *) dvmGrowableListGetElement(blockList, dfsIdx); + change |= (*func)(cUnit, bb); + } + } + /* + * Scan all reachable blocks by the post-order in the dominator tree + * and perform the operations specified in func. + */ + else if (dfaMode == kPostOrderDOMTraversal) { + int numReachableBlocks = cUnit->numReachableBlocks; + int idx; + const GrowableList *blockList = &cUnit->blockList; + + for (idx = 0; idx < numReachableBlocks; idx++) { + int domIdx = cUnit->domPostOrderTraversal.elemList[idx]; + BasicBlock *bb = + (BasicBlock *) dvmGrowableListGetElement(blockList, domIdx); + change |= (*func)(cUnit, bb); + } + } + /* If isIterative is false, exit the loop after the first iteration */ + change &= isIterative; } } /* Main entry point to do SSA conversion for non-loop traces */ void dvmCompilerNonLoopAnalysis(CompilationUnit *cUnit) { - dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion); + dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion, + kAllNodes, + false /* isIterative */); } diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c index 76783ae92..ab0421559 100644 --- a/vm/compiler/Frontend.c +++ b/vm/compiler/Frontend.c @@ -16,36 +16,42 @@ #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 = 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) { - u2 instr = *codePtr; - Opcode opcode = dexOpcodeFromCodeUnit(instr); - int insnWidth; - // Don't parse instruction data - if (opcode == OP_NOP && instr != 0) { + if (!contentIsInsn(codePtr)) { return 0; - } else { - insnWidth = dexGetWidthFromOpcode(opcode); - if (insnWidth < 0) { - insnWidth = -insnWidth; - } } + u2 instr = *codePtr; + Opcode opcode = dexOpcodeFromCodeUnit(instr); + dexDecodeInstruction(codePtr, decInsn); if (printMe) { char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn, NULL); LOGD("%p: %#06x %s\n", codePtr, opcode, decodedString); } - return insnWidth; + return dexGetWidthFromOpcode(opcode); } #define UNKNOWN_TARGET 0xffffffff @@ -419,10 +425,11 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, const u2 *codePtr = dexCode->insns + curOffset; int traceSize = 0; // # of half-words const u2 *startCodePtr = codePtr; - BasicBlock *startBB, *curBB, *lastBB; + BasicBlock *curBB, *entryCodeBB; int numBlocks = 0; static int compilationId; CompilationUnit cUnit; + GrowableList *blockList; #if defined(WITH_JIT_TUNING) CompilerMethodStats *methodStats; #endif @@ -460,6 +467,10 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, /* 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.methodTable) { int len = strlen(desc->method->clazz->descriptor) + @@ -534,18 +545,15 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, } /* Allocate the entry block */ - lastBB = startBB = curBB = dvmCompilerNewBB(kTraceEntryBlock); - curBB->startOffset = curOffset; - curBB->id = numBlocks++; - - curBB = dvmCompilerNewBB(kDalvikByteCode); + curBB = dvmCompilerNewBB(kTraceEntryBlock, numBlocks++); + dvmInsertGrowableList(blockList, (intptr_t) curBB); curBB->startOffset = curOffset; - curBB->id = numBlocks++; - /* Make the first real dalvik block the fallthrough of the entry block */ - startBB->fallThrough = curBB; - lastBB->next = curBB; - lastBB = curBB; + entryCodeBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++); + dvmInsertGrowableList(blockList, (intptr_t) entryCodeBB); + entryCodeBB->startOffset = curOffset; + curBB->fallThrough = entryCodeBB; + curBB = entryCodeBB; if (cUnit.printMe) { LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n", @@ -599,10 +607,8 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, break; } - curBB = dvmCompilerNewBB(kDalvikByteCode); - lastBB->next = curBB; - lastBB = curBB; - curBB->id = numBlocks++; + curBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++); + dvmInsertGrowableList(blockList, (intptr_t) curBB); curOffset = currRun->frag.startOffset; numInsts = currRun->frag.numInsts; curBB->startOffset = curOffset; @@ -624,7 +630,9 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, * taken/fallthrough links. Also create chaining cells for code not included * in the trace. */ - for (curBB = startBB; curBB; curBB = curBB->next) { + 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) { @@ -649,7 +657,11 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, } /* No backward branch in the trace - start searching the next BB */ - for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) { + size_t searchBlockId; + for (searchBlockId = blockId+1; searchBlockId < blockList->numUsed; + searchBlockId++) { + searchBB = (BasicBlock *) dvmGrowableListGetElement(blockList, + searchBlockId); if (targetOffset == searchBB->startOffset) { curBB->taken = searchBB; } @@ -681,7 +693,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, if (curBB->taken == NULL && curBB->fallThrough == NULL && flags == (kInstrCanBranch | kInstrCanContinue) && - fallThroughOffset == startBB->startOffset && + fallThroughOffset == entryCodeBB->startOffset && JIT_OPT_NO_LOOP != (optHints & JIT_OPT_NO_LOOP)) { BasicBlock *loopBranch = curBB; BasicBlock *exitBB; @@ -690,48 +702,37 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, if (cUnit.printMe) { LOGD("Natural loop detected!"); } - exitBB = dvmCompilerNewBB(kTraceExitBlock); - lastBB->next = exitBB; - lastBB = exitBB; - + exitBB = dvmCompilerNewBB(kTraceExitBlock, numBlocks++); + dvmInsertGrowableList(blockList, (intptr_t) exitBB); exitBB->startOffset = targetOffset; - exitBB->id = numBlocks++; exitBB->needFallThroughBranch = true; loopBranch->taken = exitBB; #if defined(WITH_SELF_VERIFICATION) BasicBlock *backwardCell = - dvmCompilerNewBB(kChainingCellBackwardBranch); - lastBB->next = backwardCell; - lastBB = backwardCell; - - backwardCell->startOffset = startBB->startOffset; - backwardCell->id = numBlocks++; + dvmCompilerNewBB(kChainingCellBackwardBranch, numBlocks++); + dvmInsertGrowableList(blockList, (intptr_t) backwardCell); + backwardCell->startOffset = entryCodeBB->startOffset; loopBranch->fallThrough = backwardCell; #elif defined(WITH_JIT_TUNING) if (gDvmJit.profile) { BasicBlock *backwardCell = - dvmCompilerNewBB(kChainingCellBackwardBranch); - lastBB->next = backwardCell; - lastBB = backwardCell; - - backwardCell->startOffset = startBB->startOffset; - backwardCell->id = numBlocks++; + dvmCompilerNewBB(kChainingCellBackwardBranch, numBlocks++); + dvmInsertGrowableList(blockList, (intptr_t) backwardCell); + backwardCell->startOffset = entryCodeBB->startOffset; loopBranch->fallThrough = backwardCell; } else { - loopBranch->fallThrough = startBB->next; + loopBranch->fallThrough = entryCodeBB; } #else - loopBranch->fallThrough = startBB->next; + loopBranch->fallThrough = entryCodeBB; #endif /* Create the chaining cell as the fallthrough of the exit block */ - exitChainingCell = dvmCompilerNewBB(kChainingCellNormal); - lastBB->next = exitChainingCell; - lastBB = exitChainingCell; - + exitChainingCell = dvmCompilerNewBB(kChainingCellNormal, + numBlocks++); + dvmInsertGrowableList(blockList, (intptr_t) exitChainingCell); exitChainingCell->startOffset = targetOffset; - exitChainingCell->id = numBlocks++; exitBB->fallThrough = exitChainingCell; @@ -762,38 +763,35 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */ for (i = 0; i < maxChains; i++) { - BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal); - lastBB->next = caseChain; - lastBB = caseChain; - + BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal, + numBlocks++); + dvmInsertGrowableList(blockList, (intptr_t) caseChain); caseChain->startOffset = lastInsn->offset + targets[i]; - caseChain->id = numBlocks++; } /* One more chaining cell for the default case */ - BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal); - lastBB->next = caseChain; - lastBB = caseChain; - + BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal, + numBlocks++); + dvmInsertGrowableList(blockList, (intptr_t) caseChain); caseChain->startOffset = lastInsn->offset + lastInsn->width; - caseChain->id = numBlocks++; /* 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) { - lastBB->next = dvmCompilerNewBB(kChainingCellHot); + fallThroughBB = dvmCompilerNewBB(kChainingCellHot, numBlocks++); } else { - lastBB->next = dvmCompilerNewBB(kChainingCellNormal); + fallThroughBB = dvmCompilerNewBB(kChainingCellNormal, + numBlocks++); } - lastBB = lastBB->next; - lastBB->id = numBlocks++; - lastBB->startOffset = fallThroughOffset; - curBB->fallThrough = lastBB; + dvmInsertGrowableList(blockList, (intptr_t) fallThroughBB); + fallThroughBB->startOffset = fallThroughOffset; + curBB->fallThrough = fallThroughBB; } /* Target block not included in the trace */ if (curBB->taken == NULL && @@ -803,12 +801,14 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, if (isInvoke) { /* Monomorphic callee */ if (callee) { - newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton); + newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton, + numBlocks++); newBB->startOffset = 0; newBB->containingMethod = callee; /* Will resolve at runtime */ } else { - newBB = dvmCompilerNewBB(kChainingCellInvokePredicted); + newBB = dvmCompilerNewBB(kChainingCellInvokePredicted, + numBlocks++); newBB->startOffset = 0; } /* For unconditional branches, request a hot chaining cell */ @@ -816,40 +816,40 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, #if !defined(WITH_SELF_VERIFICATION) newBB = dvmCompilerNewBB(dexIsGoto(flags) ? kChainingCellHot : - kChainingCellNormal); + 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); + newBB = dvmCompilerNewBB(kChainingCellBackwardBranch, + numBlocks++); } else { newBB = dvmCompilerNewBB(dexIsGoto(flags) ? kChainingCellHot : - kChainingCellNormal); + kChainingCellNormal, + numBlocks++); } newBB->startOffset = targetOffset; #endif } - newBB->id = numBlocks++; curBB->taken = newBB; - lastBB->next = newBB; - lastBB = newBB; + dvmInsertGrowableList(blockList, (intptr_t) newBB); } } /* Now create a special block to host PC reconstruction code */ - lastBB->next = dvmCompilerNewBB(kPCReconstruction); - lastBB = lastBB->next; - lastBB->id = numBlocks++; + curBB = dvmCompilerNewBB(kPCReconstruction, numBlocks++); + dvmInsertGrowableList(blockList, (intptr_t) curBB); /* And one final block that publishes the PC and raise the exception */ - lastBB->next = dvmCompilerNewBB(kExceptionHandling); - lastBB = lastBB->next; - lastBB->id = numBlocks++; + curBB = dvmCompilerNewBB(kExceptionHandling, numBlocks++); + dvmInsertGrowableList(blockList, (intptr_t) curBB); if (cUnit.printMe) { - char* signature = dexProtoCopyMethodDescriptor(&desc->method->prototype); + char* signature = + dexProtoCopyMethodDescriptor(&desc->method->prototype); LOGD("TRACEINFO (%d): 0x%08x %s%s.%s 0x%x %d of %d, %d blocks", compilationId, (intptr_t) desc->method->insns, @@ -863,21 +863,8 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, free(signature); } - BasicBlock **blockList; - cUnit.traceDesc = desc; cUnit.numBlocks = numBlocks; - blockList = cUnit.blockList = - (BasicBlock **)dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true); - - int i; - - for (i = 0, curBB = startBB; i < numBlocks; i++) { - blockList[i] = curBB; - curBB = curBB->next; - } - /* Make sure all blocks are added to the cUnit */ - assert(curBB == NULL); /* Set the instruction set to use (NOTE: later components may change it) */ cUnit.instructionSet = dvmCompilerInstructionSet(); @@ -887,6 +874,8 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, dvmCompilerInlineMIR(&cUnit); } + cUnit.numDalvikRegisters = cUnit.method->registersSize; + /* Preparation for SSA conversion */ dvmInitializeSSAConversion(&cUnit); @@ -952,6 +941,15 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts, #if defined(WITH_JIT_TUNING) methodStats->nativeSize += cUnit.totalSize; #endif + + /* FIXME - to exercise the method parser, uncomment the following code */ +#if 0 + bool dvmCompileMethod(const Method *method); + if (desc->trace[0].frag.startOffset == 0) { + dvmCompileMethod(desc->method); + } +#endif + return info->codeAddress != NULL; } @@ -1053,255 +1051,730 @@ bool dvmCompilerCanIncludeThisInstruction(const Method *method, } } -/* - * 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(CompilationUnit *cUnit, const Method *method, - JitTranslationInfo *info) +/* Split an existing block from the specified code offset into two */ +static BasicBlock *splitBlock(CompilationUnit *cUnit, + unsigned int codeOffset, + BasicBlock *origBlock) { - const DexCode *dexCode = dvmGetMethodCode(method); - const u2 *codePtr = dexCode->insns; - const u2 *codeEnd = dexCode->insns + dexCode->insnsSize; - int blockID = 0; - unsigned int curOffset = 0; + MIR *insn = origBlock->firstMIRInsn; + while (insn) { + if (insn->offset == codeOffset) break; + insn = insn->next; + } + if (insn == NULL) { + LOGE("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; + + /* Only the top half of split blocks is tagged as BA_CATCH_BLOCK */ + bottomBlock->blockAttributes = origBlock->blockAttributes & ~BA_CATCH_BLOCK; + + /* 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); + } - /* If we've already compiled this trace, just return success */ - if (dvmJitGetCodeAddr(codePtr) && !info->discardResult) { - return true; + /* Handle the fallthrough path */ + bottomBlock->fallThrough = origBlock->fallThrough; + origBlock->fallThrough = bottomBlock; + 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) { + BasicBlock *bb = + (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + if (bb == NULL) break; + dvmCompilerClearBit(bb->predecessors, origBlock->id); + dvmCompilerSetBit(bb->predecessors, bottomBlock->id); + } } - /* Doing method-based compilation */ - cUnit->wholeMethod = true; + origBlock->lastMIRInsn = insn->prev; + /* Only the bottom half of split blocks is tagged as BA_ENDS_WITH_THROW */ + origBlock->blockAttributes &= ~BA_ENDS_WITH_THROW; - BasicBlock *firstBlock = dvmCompilerNewBB(kDalvikByteCode); - firstBlock->id = blockID++; + insn->prev->next = NULL; + insn->prev = NULL; + return bottomBlock; +} - /* Allocate the bit-vector to track the beginning of basic blocks */ - BitVector *bbStartAddr = dvmCompilerAllocBitVector(dexCode->insnsSize+1, - false); - dvmCompilerSetBit(bbStartAddr, 0); +/* + * 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. + */ +static BasicBlock *findBlock(CompilationUnit *cUnit, + unsigned int codeOffset, + bool split, bool create) +{ + 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); + return newBB; + } + } + if (create) { + bb = dvmCompilerNewBB(kDalvikByteCode, cUnit->numBlocks++); + dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb); + bb->startOffset = codeOffset; + return bb; + } + return NULL; +} - int numInvokeTargets = 0; +/* Dump the CFG into a DOT graph */ +void dumpCFG(CompilationUnit *cUnit, const char *dirPrefix) +{ + const Method *method = cUnit->method; + FILE *file; + char* signature = dexProtoCopyMethodDescriptor(&method->prototype); + char *fileName = (char *) dvmCompilerNew( + strlen(dirPrefix) + + strlen(method->clazz->descriptor) + + strlen(method->name) + + strlen(signature) + + strlen(".dot") + 1, true); + sprintf(fileName, "%s%s%s%s.dot", dirPrefix, + method->clazz->descriptor, method->name, signature); + free(signature); /* - * Sequentially go through every instruction first and put them in a single - * basic block. Identify block boundaries at the mean time. + * Convert the special characters into a filesystem- and shell-friendly + * format. */ - while (codePtr < codeEnd) { - MIR *insn = (MIR *)dvmCompilerNew(sizeof(MIR), true); - insn->offset = curOffset; - int width = parseInsn(codePtr, &insn->dalvikInsn, false); - bool isInvoke = false; - const Method *callee; - insn->width = width; + 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 == kMethodEntryBlock) { + fprintf(file, " entry [shape=Mdiamond];\n"); + } else if (bb->blockType == kMethodExitBlock) { + fprintf(file, " exit [shape=Mdiamond];\n"); + } else if (bb->blockType == kDalvikByteCode) { + fprintf(file, " block%04x [shape=%s,label = \"{ \\\n", + bb->startOffset, + bb->blockAttributes & BA_CATCH_BLOCK ? + "Mrecord" : "record"); + if (bb->blockAttributes & BA_CATCH_BLOCK) { + if (bb->exceptionTypeIdx == kDexNoIndex) { + fprintf(file, " {any\\l} |\\\n"); + } else { + fprintf(file, " {throwable type:%x\\l} |\\\n", + bb->exceptionTypeIdx); + } + } + const MIR *mir; + for (mir = bb->firstMIRInsn; mir; mir = mir->next) { + fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset, + dvmCompilerFullDisassembler(cUnit, mir), + mir->next ? " | " : " "); + } + fprintf(file, " }\"];\n\n"); + } else if (bb->blockType == kExceptionHandling) { + char blockName[BLOCK_NAME_LEN]; - /* Terminate when the data section is seen */ - if (width == 0) - break; + dvmGetBlockName(bb, blockName); + fprintf(file, " %s [shape=invhouse];\n", blockName); + } - if (!dvmCompilerCanIncludeThisInstruction(cUnit->method, - &insn->dalvikInsn)) { - return false; + 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); } - dvmCompilerAppendMIR(firstBlock, insn); - /* - * Check whether this is a block ending instruction and whether it - * suggests the start of a new block - */ - unsigned int target = curOffset; + 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); + + BasicBlock *destBlock = + (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + + int succId = 0; + while (true) { + if (destBlock == NULL) break; + BasicBlock *nextBlock = + (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + fprintf(file, " {<f%d> %04x\\l}%s\\\n", + succId++, + destBlock->startOffset, + (nextBlock != NULL) ? " | " : " "); + destBlock = nextBlock; + } + 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) { + BasicBlock *destBlock = + (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + if (destBlock == NULL) break; + + dvmGetBlockName(destBlock, blockName2); + fprintf(file, " succ%04x:f%d:e -> %s:n\n", + bb->startOffset, succId++, + blockName2); + } + } + } + fprintf(file, "\n"); /* - * If findBlockBoundary returns true, it means the current instruction - * is terminating the current block. If it is a branch, the target - * address will be recorded in target. + * If we need to debug the dominator tree, uncomment the following code */ - if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke, - &callee)) { - dvmCompilerSetBit(bbStartAddr, curOffset + width); - /* Each invoke needs a chaining cell block */ - if (isInvoke) { - numInvokeTargets++; - } - /* A branch will end the current block */ - else if (target != curOffset && target != UNKNOWN_TARGET) { - dvmCompilerSetBit(bbStartAddr, target); +#if 0 + 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) { + BasicBlock *succBB = + (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + if (succBB == NULL) break; + if (succBB == bb) { + found = true; + break; + } } } + if (found == false) { + char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN]; + dvmGetBlockName(bb, blockName1); + dvmGetBlockName(predBB, blockName2); + dumpCFG(cUnit, "/data/tombstones/"); + LOGE("Successor %s not found from %s", + blockName1, blockName2); + dvmAbort(); + } + } + return true; +} - codePtr += width; - /* each bit represents 16-bit quantity */ - curOffset += width; +/* 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; } - /* - * The number of blocks will be equal to the number of bits set to 1 in the - * bit vector minus 1, because the bit representing the location after the - * last instruction is set to one. - * - * We also add additional blocks for invoke chaining and the number is - * denoted by numInvokeTargets. - */ - int numBlocks = dvmCountSetBits(bbStartAddr); - if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) { - numBlocks--; + 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); + } } - BasicBlock **blockList; - blockList = cUnit->blockList = (BasicBlock **) - dvmCompilerNew(sizeof(BasicBlock *) * (numBlocks + numInvokeTargets), - true); + /* Iterate over each of the handlers to enqueue the empty Catch blocks */ + offset = dexGetFirstHandlerOffset(pCode); + int handlersSize = dexGetHandlersSize(pCode); - /* - * Register the first block onto the list and start splitting it into - * sub-blocks. - */ - blockList[0] = firstBlock; - cUnit->numBlocks = 1; + for (i = 0; i < handlersSize; i++) { + DexCatchIterator iterator; + dexCatchIteratorInit(&iterator, pCode, offset); - int i; - for (i = 0; i < numBlocks; i++) { - MIR *insn; - BasicBlock *curBB = blockList[i]; - curOffset = curBB->lastMIRInsn->offset; - - for (insn = curBB->firstMIRInsn->next; insn; insn = insn->next) { - /* Found the beginning of a new block, see if it is created yet */ - if (dvmIsBitSet(bbStartAddr, insn->offset)) { - int j; - for (j = 0; j < cUnit->numBlocks; j++) { - if (blockList[j]->firstMIRInsn->offset == insn->offset) - break; - } + for (;;) { + DexCatchHandler* handler = dexCatchIteratorNext(&iterator); - /* Block not split yet - do it now */ - if (j == cUnit->numBlocks) { - BasicBlock *newBB = dvmCompilerNewBB(kDalvikByteCode); - newBB->id = blockID++; - newBB->firstMIRInsn = insn; - newBB->startOffset = insn->offset; - newBB->lastMIRInsn = curBB->lastMIRInsn; - curBB->lastMIRInsn = insn->prev; - insn->prev->next = NULL; - insn->prev = NULL; - - /* - * If the insn is not an unconditional branch, set up the - * fallthrough link. - */ - if (!isUnconditionalBranch(curBB->lastMIRInsn)) { - curBB->fallThrough = newBB; - } - - /* - * Fallthrough block of an invoke instruction needs to be - * aligned to 4-byte boundary (alignment instruction to be - * inserted later. - */ - if (dexGetFlagsFromOpcode(curBB->lastMIRInsn->dalvikInsn.opcode) - & kInstrInvoke) { - newBB->isFallThroughFromInvoke = true; - } - - /* enqueue the new block */ - blockList[cUnit->numBlocks++] = newBB; - break; - } + if (handler == NULL) { + break; } + + BasicBlock *catchBlock = findBlock(cUnit, handler->address, + /* split */ + false, + /* create */ + true); + catchBlock->blockAttributes |= BA_CATCH_BLOCK; + catchBlock->exceptionTypeIdx = handler->typeIdx; } + + offset = dexCatchIteratorGetEndOffset(&iterator, pCode); } +} - if (numBlocks != cUnit->numBlocks) { - LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit->numBlocks); - dvmCompilerAbort(cUnit); +/* 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: + LOGE("Unexpected opcode(%d) with kInstrCanBranch set", + insn->dalvikInsn.opcode); + dvmAbort(); } + BasicBlock *takenBlock = findBlock(cUnit, target, + /* split */ + true, + /* create */ + true); + 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, + /* split */ + false, + /* create */ + true); + 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); + } + } +} - /* Connect the basic blocks through the taken links */ - for (i = 0; i < numBlocks; i++) { - BasicBlock *curBB = blockList[i]; - MIR *insn = curBB->lastMIRInsn; - unsigned int target = insn->offset; - bool isInvoke = false; - const Method *callee = 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 *targetTable; + int i; + + /* + * 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]; + targetTable = (int *) &switchData[4]; + /* + * 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]; + targetTable = (int *) &switchData[2 + size*2]; + } - findBlockBoundary(method, insn, target, &target, &isInvoke, &callee); + if (curBlock->successorBlockList.blockListType != kNotUsed) { + LOGE("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); + dvmInsertGrowableList(&curBlock->successorBlockList.blocks, + (intptr_t) caseBlock); + dvmCompilerSetBit(caseBlock->predecessors, curBlock->id); + } + + /* Fall-through case */ + BasicBlock *fallthroughBlock = findBlock(cUnit, + curOffset + width, + /* split */ + false, + /* create */ + true); + 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); + + curBlock->blockAttributes |= BA_ENDS_WITH_THROW; + /* In try block */ + if (dvmIsBitSet(tryBlockAddr, curOffset)) { + DexCatchIterator iterator; + + if (!dexFindCatchHandler(&iterator, dexCode, curOffset)) { + LOGE("Catch block not found in dexfile for insn %x in %s", + curOffset, method->name); + dvmAbort(); - /* Found a block ended on a branch (not invoke) */ - if (isInvoke == false && target != insn->offset) { - int j; - /* Forward branch */ - if (target > insn->offset) { - j = i + 1; - } else { - /* Backward branch */ - j = 0; - } - for (; j < numBlocks; j++) { - if (blockList[j]->firstMIRInsn->offset == target) { - curBB->taken = blockList[j]; - break; - } - } } + if (curBlock->successorBlockList.blockListType != kNotUsed) { + LOGE("Successor block list already in use: %d", + curBlock->successorBlockList.blockListType); + dvmAbort(); + } + curBlock->successorBlockList.blockListType = kCatch; + dvmInitGrowableList(&curBlock->successorBlockList.blocks, 2); - if (isInvoke) { - BasicBlock *newBB; - /* Monomorphic callee */ - if (callee) { - newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton); - newBB->startOffset = 0; - newBB->containingMethod = callee; - /* Will resolve at runtime */ - } else { - newBB = dvmCompilerNewBB(kChainingCellInvokePredicted); - newBB->startOffset = 0; + for (;;) { + DexCatchHandler* handler = dexCatchIteratorNext(&iterator); + + if (handler == NULL) { + break; } - newBB->id = blockID++; - curBB->taken = newBB; - /* enqueue the new block */ - blockList[cUnit->numBlocks++] = newBB; + + BasicBlock *catchBlock = findBlock(cUnit, handler->address, + /* split */ + false, + /* create */ + false); + + assert(catchBlock->blockAttributes & BA_CATCH_BLOCK); + dvmInsertGrowableList(&curBlock->successorBlockList.blocks, + (intptr_t) catchBlock); + 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); } - if (cUnit->numBlocks != numBlocks + numInvokeTargets) { - LOGE("Expect %d vs %d total blocks\n", numBlocks + numInvokeTargets, - cUnit->numBlocks); - dvmCompilerDumpCompilationUnit(cUnit); - dvmCompilerAbort(cUnit); + /* + * 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); + /* + * 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); + } + } } +} - /* Set the instruction set to use (NOTE: later components may change it) */ - cUnit->instructionSet = dvmCompilerInstructionSet(); +/* + * 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) +{ + 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; - /* Preparation for SSA conversion */ - dvmInitializeSSAConversion(cUnit); + memset(&cUnit, 0, sizeof(cUnit)); + cUnit.method = method; + + /* Initialize the block list */ + dvmInitGrowableList(&cUnit.blockList, 4); - /* SSA analysis */ - dvmCompilerNonLoopAnalysis(cUnit); + /* Allocate the bit-vector to track the beginning of basic blocks */ + BitVector *tryBlockAddr = dvmCompilerAllocBitVector(dexCode->insnsSize, + true /* expandable */); + cUnit.tryBlockAddr = tryBlockAddr; - /* Needs to happen after SSA naming */ - dvmCompilerInitializeRegAlloc(cUnit); + /* Create the default entry and exit blocks and enter them to the list */ + BasicBlock *entryBlock = dvmCompilerNewBB(kMethodEntryBlock, numBlocks++); + BasicBlock *exitBlock = dvmCompilerNewBB(kMethodExitBlock, numBlocks++); - /* Allocate Registers */ - dvmCompilerRegAlloc(cUnit); + cUnit.entryBlock = entryBlock; + cUnit.exitBlock = exitBlock; - /* Convert MIR to LIR, etc. */ - dvmCompilerMIR2LIR(cUnit); + 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; - /* Convert LIR into machine code. */ - dvmCompilerAssembleLIR(cUnit, info); + /* Identify code range in try blocks and set up the empty catch blocks */ + processTryCatchBlocks(&cUnit); - if (cUnit->assemblerStatus != kSuccess) { - return false; + /* 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); + } + } + } 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); + 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) && + !dexIsGoto(flags) && + !(flags & kInstrCanReturn)) { + curBlock->fallThrough = nextBlock; + dvmCompilerSetBit(nextBlock->predecessors, curBlock->id); + } + curBlock = nextBlock; + } } - 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); + if (cUnit.printMe) dumpCFG(&cUnit, "/data/tombstones/"); + + /* Reset the compiler resource pool */ dvmCompilerArenaReset(); - return info->codeAddress != NULL; + return false; } diff --git a/vm/compiler/InlineTransformation.c b/vm/compiler/InlineTransformation.c index d9a6eea82..2cdba18cd 100644 --- a/vm/compiler/InlineTransformation.c +++ b/vm/compiler/InlineTransformation.c @@ -284,14 +284,16 @@ static void tryInlineVirtualCallsite(CompilationUnit *cUnit, void dvmCompilerInlineMIR(CompilationUnit *cUnit) { - int i; bool isRange = false; + GrowableListIterator iterator; + dvmGrowableListIteratorInit(&cUnit->blockList, &iterator); /* * Analyze the basic block containing an invoke to see if it can be inlined */ - for (i = 0; i < cUnit->numBlocks; i++) { - BasicBlock *bb = cUnit->blockList[i]; + while (true) { + BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + if (bb == NULL) break; if (bb->blockType != kDalvikByteCode) continue; MIR *lastMIRInsn = bb->lastMIRInsn; diff --git a/vm/compiler/IntermediateRep.c b/vm/compiler/IntermediateRep.c index 29889005b..db68c3c85 100644 --- a/vm/compiler/IntermediateRep.c +++ b/vm/compiler/IntermediateRep.c @@ -18,10 +18,13 @@ #include "CompilerInternals.h" /* Allocate a new basic block */ -BasicBlock *dvmCompilerNewBB(BBType blockType) +BasicBlock *dvmCompilerNewBB(BBType blockType, int blockId) { BasicBlock *bb = (BasicBlock *)dvmCompilerNew(sizeof(BasicBlock), true); bb->blockType = blockType; + bb->id = blockId; + bb->predecessors = dvmCompilerAllocBitVector(blockId > 32 ? blockId : 32, + true /* expandable */); return bb; } diff --git a/vm/compiler/Loop.c b/vm/compiler/Loop.c index 32d9b09fd..9ee430d42 100644 --- a/vm/compiler/Loop.c +++ b/vm/compiler/Loop.c @@ -38,18 +38,24 @@ */ static void handlePhiPlacement(CompilationUnit *cUnit) { - BasicBlock *entry = cUnit->blockList[0]; - BasicBlock *loopBody = cUnit->blockList[1]; - BasicBlock *loopBranch = cUnit->blockList[2]; + BasicBlock *entry = + (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 0); + BasicBlock *loopBody = + (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 1); + BasicBlock *loopBranch = + (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 2); dvmCopyBitVector(entry->dataFlowInfo->defV, loopBody->dataFlowInfo->liveInV); BitVector *phiV = dvmCompilerAllocBitVector(cUnit->method->registersSize, false); + BitVector *phi2V = dvmCompilerAllocBitVector(cUnit->method->registersSize, + false); dvmIntersectBitVectors(phiV, entry->dataFlowInfo->defV, loopBody->dataFlowInfo->defV); - dvmIntersectBitVectors(phiV, entry->dataFlowInfo->defV, + dvmIntersectBitVectors(phi2V, entry->dataFlowInfo->defV, loopBranch->dataFlowInfo->defV); + dvmUnifyBitVectors(phiV, phiV, phi2V); /* Insert the PHI MIRs */ int i; @@ -66,9 +72,12 @@ static void handlePhiPlacement(CompilationUnit *cUnit) static void fillPhiNodeContents(CompilationUnit *cUnit) { - BasicBlock *entry = cUnit->blockList[0]; - BasicBlock *loopBody = cUnit->blockList[1]; - BasicBlock *loopBranch = cUnit->blockList[2]; + BasicBlock *entry = + (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 0); + BasicBlock *loopBody = + (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 1); + BasicBlock *loopBranch = + (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 2); MIR *mir; for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) { @@ -165,7 +174,8 @@ static void dumpHoistedChecks(CompilationUnit *cUnit) static bool isLoopOptimizable(CompilationUnit *cUnit) { unsigned int i; - BasicBlock *loopBranch = cUnit->blockList[2]; + BasicBlock *loopBranch = + (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 2); LoopAnalysis *loopAnalysis = cUnit->loopAnalysis; if (loopAnalysis->numBasicIV != 1) return false; @@ -290,7 +300,7 @@ static void updateRangeCheckInfo(CompilationUnit *cUnit, int arrayReg, arrayAccessInfo->maxC = (ivInfo->c > 0) ? ivInfo->c : 0; arrayAccessInfo->minC = (ivInfo->c < 0) ? ivInfo->c : 0; dvmInsertGrowableList(loopAnalysis->arrayAccessInfo, - arrayAccessInfo); + (intptr_t) arrayAccessInfo); } break; } @@ -300,7 +310,8 @@ static void updateRangeCheckInfo(CompilationUnit *cUnit, int arrayReg, /* Returns true if the loop body cannot throw any exceptions */ static bool doLoopBodyCodeMotion(CompilationUnit *cUnit) { - BasicBlock *loopBody = cUnit->blockList[1]; + BasicBlock *loopBody = + (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 1); MIR *mir; bool loopBodyCanThrow = false; @@ -387,7 +398,8 @@ static bool doLoopBodyCodeMotion(CompilationUnit *cUnit) static void genHoistedChecks(CompilationUnit *cUnit) { unsigned int i; - BasicBlock *entry = cUnit->blockList[0]; + BasicBlock *entry = + (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 0); LoopAnalysis *loopAnalysis = cUnit->loopAnalysis; int globalMaxC = 0; int globalMinC = 0; @@ -477,21 +489,28 @@ bool dvmCompilerLoopOpt(CompilationUnit *cUnit) LoopAnalysis *loopAnalysis = (LoopAnalysis *)dvmCompilerNew(sizeof(LoopAnalysis), true); - assert(cUnit->blockList[0]->blockType == kTraceEntryBlock); - assert(cUnit->blockList[2]->blockType == kDalvikByteCode); - assert(cUnit->blockList[3]->blockType == kTraceExitBlock); + assert(((BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 0)) + ->blockType == kTraceEntryBlock); + assert(((BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 2)) + ->blockType == kDalvikByteCode); + assert(((BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 3)) + ->blockType == kTraceExitBlock); cUnit->loopAnalysis = loopAnalysis; /* * Find live-in variables to the loop body so that we can fake their * definitions in the entry block. */ - dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerFindLiveIn); + dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerFindLocalLiveIn, + kAllNodes, + false /* isIterative */); /* Insert phi nodes to the loop body */ handlePhiPlacement(cUnit); - dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion); + dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion, + kAllNodes, + false /* isIterative */); fillPhiNodeContents(cUnit); /* Constant propagation */ @@ -500,7 +519,9 @@ bool dvmCompilerLoopOpt(CompilationUnit *cUnit) (int *)dvmCompilerNew(sizeof(int) * cUnit->numSSARegs, true); dvmCompilerDataFlowAnalysisDispatcher(cUnit, - dvmCompilerDoConstantPropagation); + dvmCompilerDoConstantPropagation, + kAllNodes, + false /* isIterative */); DEBUG_LOOP(dumpConstants(cUnit);) /* Find induction variables - basic and dependent */ @@ -509,7 +530,9 @@ bool dvmCompilerLoopOpt(CompilationUnit *cUnit) dvmInitGrowableList(loopAnalysis->ivList, 4); loopAnalysis->isIndVarV = dvmAllocBitVector(cUnit->numSSARegs, false); dvmCompilerDataFlowAnalysisDispatcher(cUnit, - dvmCompilerFindInductionVariables); + dvmCompilerFindInductionVariables, + kAllNodes, + false /* isIterative */); DEBUG_LOOP(dumpIVList(cUnit);) /* If the loop turns out to be non-optimizable, return early */ diff --git a/vm/compiler/MethodSSATransformation.c b/vm/compiler/MethodSSATransformation.c new file mode 100644 index 000000000..fc568910f --- /dev/null +++ b/vm/compiler/MethodSSATransformation.c @@ -0,0 +1,559 @@ +/* + * Copyright (C) 2010 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 "Dataflow.h" +#include "Loop.h" +#include "libdex/DexOpcodes.h" + +/* Enter the node to the dfsOrder list then visit its successors */ +static void recordDFSPreOrder(CompilationUnit *cUnit, BasicBlock *block) +{ + + if (block->visited) return; + block->visited = true; + + /* Enqueue the block id */ + dvmInsertGrowableList(&cUnit->dfsOrder, block->id); + + if (block->taken) recordDFSPreOrder(cUnit, block->taken); + if (block->fallThrough) recordDFSPreOrder(cUnit, block->fallThrough); + if (block->successorBlockList.blockListType != kNotUsed) { + GrowableListIterator iterator; + dvmGrowableListIteratorInit(&block->successorBlockList.blocks, + &iterator); + while (true) { + BasicBlock *succBB = + (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + if (succBB == NULL) break; + recordDFSPreOrder(cUnit, succBB); + } + } + return; +} + +/* Sort the blocks by the Depth-First-Search pre-order */ +static void computeDFSOrder(CompilationUnit *cUnit) +{ + /* Initialize the DFS order list */ + dvmInitGrowableList(&cUnit->dfsOrder, cUnit->numBlocks); + + + dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerClearVisitedFlag, + kAllNodes, + false /* isIterative */); + + recordDFSPreOrder(cUnit, cUnit->entryBlock); + cUnit->numReachableBlocks = cUnit->dfsOrder.numUsed; +} + +/* + * Mark block bit on the per-Dalvik register vector to denote that Dalvik + * register idx is defined in BasicBlock bb. + */ +static bool fillDefBlockMatrix(CompilationUnit *cUnit, BasicBlock *bb) +{ + if (bb->dataFlowInfo == NULL) return false; + + BitVectorIterator iterator; + + dvmBitVectorIteratorInit(bb->dataFlowInfo->defV, &iterator); + while (true) { + int idx = dvmBitVectorIteratorNext(&iterator); + if (idx == -1) break; + /* Block bb defines register idx */ + dvmCompilerSetBit(cUnit->defBlockMatrix[idx], bb->id); + } + return true; +} + +static void computeDefBlockMatrix(CompilationUnit *cUnit) +{ + int numRegisters = cUnit->numDalvikRegisters; + /* Allocate numDalvikRegisters bit vector pointers */ + cUnit->defBlockMatrix = (BitVector **) + dvmCompilerNew(sizeof(BitVector *) * numRegisters, true); + int i; + + /* Initialize numRegister vectors with numBlocks bits each */ + for (i = 0; i < numRegisters; i++) { + cUnit->defBlockMatrix[i] = dvmCompilerAllocBitVector(cUnit->numBlocks, + false); + } + dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerFindLocalLiveIn, + kAllNodes, + false /* isIterative */); + dvmCompilerDataFlowAnalysisDispatcher(cUnit, fillDefBlockMatrix, + kAllNodes, + false /* isIterative */); + + /* + * Also set the incoming parameters as defs in the entry block. + * Only need to handle the parameters for the outer method. + */ + int inReg = cUnit->method->registersSize - cUnit->method->insSize; + for (; inReg < cUnit->method->registersSize; inReg++) { + dvmCompilerSetBit(cUnit->defBlockMatrix[inReg], + cUnit->entryBlock->id); + } +} + +/* Compute the post-order traversal of the CFG */ +static void computeDomPostOrderTraversal(CompilationUnit *cUnit, BasicBlock *bb) +{ + BitVectorIterator bvIterator; + dvmBitVectorIteratorInit(bb->iDominated, &bvIterator); + GrowableList *blockList = &cUnit->blockList; + + /* Iterate through the dominated blocks first */ + while (true) { + int bbIdx = dvmBitVectorIteratorNext(&bvIterator); + if (bbIdx == -1) break; + BasicBlock *dominatedBB = + (BasicBlock *) dvmGrowableListGetElement(blockList, bbIdx); + computeDomPostOrderTraversal(cUnit, dominatedBB); + } + + /* Enter the current block id */ + dvmInsertGrowableList(&cUnit->domPostOrderTraversal, bb->id); + + /* hacky loop detection */ + if (bb->taken && dvmIsBitSet(bb->dominators, bb->taken->id)) { + cUnit->hasLoop = true; + } +} + +/* Worker function to compute the dominance frontier */ +static bool computeDominanceFrontier(CompilationUnit *cUnit, BasicBlock *bb) +{ + GrowableList *blockList = &cUnit->blockList; + + /* Calculate DF_local */ + if (bb->taken && !dvmIsBitSet(bb->taken->dominators, bb->id)) { + dvmSetBit(bb->domFrontier, bb->taken->id); + } + if (bb->fallThrough && + !dvmIsBitSet(bb->fallThrough->dominators, bb->id)) { + dvmSetBit(bb->domFrontier, bb->fallThrough->id); + } + if (bb->successorBlockList.blockListType != kNotUsed) { + GrowableListIterator iterator; + dvmGrowableListIteratorInit(&bb->successorBlockList.blocks, + &iterator); + while (true) { + BasicBlock *succBB = + (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + if (succBB == NULL) break; + if (!dvmIsBitSet(succBB->dominators, bb->id)) { + dvmSetBit(bb->domFrontier, succBB->id); + } + } + } + + /* Calculate DF_up */ + BitVectorIterator bvIterator; + dvmBitVectorIteratorInit(bb->iDominated, &bvIterator); + while (true) { + int dominatedIdx = dvmBitVectorIteratorNext(&bvIterator); + if (dominatedIdx == -1) break; + BasicBlock *dominatedBB = (BasicBlock *) + dvmGrowableListGetElement(blockList, dominatedIdx); + BitVectorIterator dfIterator; + dvmBitVectorIteratorInit(dominatedBB->domFrontier, &dfIterator); + while (true) { + int dfUpIdx = dvmBitVectorIteratorNext(&dfIterator); + if (dfUpIdx == -1) break; + BasicBlock *dfUpBlock = (BasicBlock *) + dvmGrowableListGetElement(blockList, dfUpIdx); + if (!dvmIsBitSet(dfUpBlock->dominators, bb->id)) { + dvmSetBit(bb->domFrontier, dfUpBlock->id); + } + } + } + if (cUnit->printMe) { + char blockName[BLOCK_NAME_LEN]; + dvmGetBlockName(bb, blockName); + dvmDumpBlockBitVector(blockList, blockName, bb->domFrontier, + cUnit->numBlocks); + } + + return true; +} + +/* Worker function for initializing domination-related data structures */ +static bool initializeDominationInfo(CompilationUnit *cUnit, BasicBlock *bb) +{ + int numTotalBlocks = cUnit->blockList.numUsed; + + bb->dominators = dvmCompilerAllocBitVector(numTotalBlocks, + false /* expandable */); + bb->iDominated = dvmCompilerAllocBitVector(numTotalBlocks, + false /* expandable */); + bb->domFrontier = dvmCompilerAllocBitVector(numTotalBlocks, + false /* expandable */); + /* Set all bits in the dominator vector */ + dvmSetInitialBits(bb->dominators, numTotalBlocks); + + return true; +} + +/* Worker function to compute each block's dominators */ +static bool computeBlockDominators(CompilationUnit *cUnit, BasicBlock *bb) +{ + GrowableList *blockList = &cUnit->blockList; + int numTotalBlocks = blockList->numUsed; + BitVector *tempBlockV = cUnit->tempBlockV; + BitVectorIterator bvIterator; + + /* + * The dominator of the entry block has been preset to itself and we need + * to skip the calculation here. + */ + if (bb == cUnit->entryBlock) return false; + + dvmSetInitialBits(tempBlockV, numTotalBlocks); + + /* Iterate through the predecessors */ + dvmBitVectorIteratorInit(bb->predecessors, &bvIterator); + while (true) { + int predIdx = dvmBitVectorIteratorNext(&bvIterator); + if (predIdx == -1) break; + BasicBlock *predBB = (BasicBlock *) dvmGrowableListGetElement( + blockList, predIdx); + /* tempBlockV = tempBlockV ^ dominators */ + dvmIntersectBitVectors(tempBlockV, tempBlockV, predBB->dominators); + } + dvmSetBit(tempBlockV, bb->id); + if (dvmCompareBitVectors(tempBlockV, bb->dominators)) { + dvmCopyBitVector(bb->dominators, tempBlockV); + return true; + } + return false; +} + +/* Worker function to compute the idom */ +static bool computeImmediateDominator(CompilationUnit *cUnit, BasicBlock *bb) +{ + GrowableList *blockList = &cUnit->blockList; + BitVector *tempBlockV = cUnit->tempBlockV; + BitVectorIterator bvIterator; + BasicBlock *iDom; + + if (bb == cUnit->entryBlock) return false; + + dvmCopyBitVector(tempBlockV, bb->dominators); + dvmClearBit(tempBlockV, bb->id); + dvmBitVectorIteratorInit(tempBlockV, &bvIterator); + + /* Should not see any dead block */ + assert(dvmCountSetBits(tempBlockV) != 0); + if (dvmCountSetBits(tempBlockV) == 1) { + iDom = (BasicBlock *) dvmGrowableListGetElement( + blockList, dvmBitVectorIteratorNext(&bvIterator)); + bb->iDom = iDom; + } else { + int iDomIdx = dvmBitVectorIteratorNext(&bvIterator); + assert(iDomIdx != -1); + while (true) { + int nextDom = dvmBitVectorIteratorNext(&bvIterator); + if (nextDom == -1) break; + BasicBlock *nextDomBB = (BasicBlock *) + dvmGrowableListGetElement(blockList, nextDom); + /* iDom dominates nextDom - set new iDom */ + if (dvmIsBitSet(nextDomBB->dominators, iDomIdx)) { + iDomIdx = nextDom; + } + + } + iDom = (BasicBlock *) dvmGrowableListGetElement(blockList, iDomIdx); + /* Set the immediate dominator block for bb */ + bb->iDom = iDom; + } + /* Add bb to the iDominated set of the immediate dominator block */ + dvmCompilerSetBit(iDom->iDominated, bb->id); + return true; +} + +/* Compute dominators, immediate dominator, and dominance fronter */ +static void computeDominators(CompilationUnit *cUnit) +{ + int numReachableBlocks = cUnit->numReachableBlocks; + int numTotalBlocks = cUnit->blockList.numUsed; + + /* Initialize domination-related data structures */ + dvmCompilerDataFlowAnalysisDispatcher(cUnit, initializeDominationInfo, + kReachableNodes, + false /* isIterative */); + + /* Set the dominator for the root node */ + dvmClearAllBits(cUnit->entryBlock->dominators); + dvmSetBit(cUnit->entryBlock->dominators, cUnit->entryBlock->id); + + cUnit->tempBlockV = dvmCompilerAllocBitVector(numTotalBlocks, + false /* expandable */); + dvmCompilerDataFlowAnalysisDispatcher(cUnit, computeBlockDominators, + kPreOrderDFSTraversal, + true /* isIterative */); + + cUnit->entryBlock->iDom = NULL; + dvmCompilerDataFlowAnalysisDispatcher(cUnit, computeImmediateDominator, + kReachableNodes, + false /* isIterative */); + + /* + * Now go ahead and compute the post order traversal based on the + * iDominated sets. + */ + dvmInitGrowableList(&cUnit->domPostOrderTraversal, numReachableBlocks); + computeDomPostOrderTraversal(cUnit, cUnit->entryBlock); + assert(cUnit->domPostOrderTraversal.numUsed == + (unsigned) cUnit->numReachableBlocks); + + /* Now compute the dominance frontier for each block */ + dvmCompilerDataFlowAnalysisDispatcher(cUnit, computeDominanceFrontier, + kPostOrderDOMTraversal, + false /* isIterative */); +} + +/* + * Perform dest U= src1 ^ ~src2 + * This is probably not general enough to be placed in BitVector.[ch]. + */ +static void computeSuccLiveIn(BitVector *dest, + const BitVector *src1, + const BitVector *src2) +{ + if (dest->storageSize != src1->storageSize || + dest->storageSize != src2->storageSize || + dest->expandable != src1->expandable || + dest->expandable != src2->expandable) { + LOGE("Incompatible set properties"); + dvmAbort(); + } + + int i; + for (i = 0; i < dest->storageSize; i++) { + dest->storage[i] |= src1->storage[i] & ~src2->storage[i]; + } +} + +/* + * Iterate through all successor blocks and propagate up the live-in sets. + * The calculated result is used for phi-node pruning - where we only need to + * insert a phi node if the variable is live-in to the block. + */ +static bool computeBlockLiveIns(CompilationUnit *cUnit, BasicBlock *bb) +{ + BitVector *tempDalvikRegisterV = cUnit->tempDalvikRegisterV; + + if (bb->dataFlowInfo == NULL) return false; + dvmCopyBitVector(tempDalvikRegisterV, bb->dataFlowInfo->liveInV); + if (bb->taken && bb->taken->dataFlowInfo) + computeSuccLiveIn(tempDalvikRegisterV, bb->taken->dataFlowInfo->liveInV, + bb->dataFlowInfo->defV); + if (bb->fallThrough && bb->fallThrough->dataFlowInfo) + computeSuccLiveIn(tempDalvikRegisterV, + bb->fallThrough->dataFlowInfo->liveInV, + bb->dataFlowInfo->defV); + if (bb->successorBlockList.blockListType != kNotUsed) { + GrowableListIterator iterator; + dvmGrowableListIteratorInit(&bb->successorBlockList.blocks, + &iterator); + while (true) { + BasicBlock *succBB = + (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + if (succBB == NULL) break; + if (succBB->dataFlowInfo) { + computeSuccLiveIn(tempDalvikRegisterV, + succBB->dataFlowInfo->liveInV, + bb->dataFlowInfo->defV); + } + } + } + if (dvmCompareBitVectors(tempDalvikRegisterV, bb->dataFlowInfo->liveInV)) { + dvmCopyBitVector(bb->dataFlowInfo->liveInV, tempDalvikRegisterV); + return true; + } + return false; +} + +/* Insert phi nodes to for each variable to the dominance frontiers */ +static void insertPhiNodes(CompilationUnit *cUnit) +{ + int dalvikReg; + const GrowableList *blockList = &cUnit->blockList; + BitVector *phiBlocks = + dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false); + BitVector *tmpBlocks = + dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false); + BitVector *inputBlocks = + dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false); + + cUnit->tempDalvikRegisterV = + dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false); + + dvmCompilerDataFlowAnalysisDispatcher(cUnit, computeBlockLiveIns, + kPostOrderDFSTraversal, + true /* isIterative */); + + /* Iterate through each Dalvik register */ + for (dalvikReg = 0; dalvikReg < cUnit->numDalvikRegisters; dalvikReg++) { + bool change; + BitVectorIterator iterator; + + dvmCopyBitVector(inputBlocks, cUnit->defBlockMatrix[dalvikReg]); + dvmClearAllBits(phiBlocks); + /* Calculate the phi blocks for each Dalvik register */ + do { + change = false; + dvmClearAllBits(tmpBlocks); + dvmBitVectorIteratorInit(inputBlocks, &iterator); + while (true) { + int idx = dvmBitVectorIteratorNext(&iterator); + if (idx == -1) break; + BasicBlock *defBB = + (BasicBlock *) dvmGrowableListGetElement(blockList, idx); + /* Merge the dominance frontier to tmpBlocks */ + dvmUnifyBitVectors(tmpBlocks, tmpBlocks, defBB->domFrontier); + } + if (dvmCompareBitVectors(phiBlocks, tmpBlocks)) { + change = true; + dvmCopyBitVector(phiBlocks, tmpBlocks); + + /* + * Iterate through the original blocks plus the new ones in + * the dominance frontier. + */ + dvmCopyBitVector(inputBlocks, phiBlocks); + dvmUnifyBitVectors(inputBlocks, inputBlocks, + cUnit->defBlockMatrix[dalvikReg]); + } + } while (change); + + /* + * Insert a phi node for dalvikReg in the phiBlocks if the Dalvik + * register is in the live-in set. + */ + dvmBitVectorIteratorInit(phiBlocks, &iterator); + while (true) { + int idx = dvmBitVectorIteratorNext(&iterator); + if (idx == -1) break; + BasicBlock *phiBB = + (BasicBlock *) dvmGrowableListGetElement(blockList, idx); + /* Variable will be clobbered before being used - no need for phi */ + if (!dvmIsBitSet(phiBB->dataFlowInfo->liveInV, dalvikReg)) continue; + MIR *phi = (MIR *) dvmCompilerNew(sizeof(MIR), true); + phi->dalvikInsn.opcode = kMirOpPhi; + phi->dalvikInsn.vA = dalvikReg; + phi->offset = phiBB->startOffset; + dvmCompilerPrependMIR(phiBB, phi); + } + } +} + +/* + * Worker function to insert phi-operands with latest SSA names from + * predecessor blocks + */ +static bool insertPhiNodeOperands(CompilationUnit *cUnit, BasicBlock *bb) +{ + BitVector *ssaRegV = cUnit->tempSSARegisterV; + BitVectorIterator bvIterator; + GrowableList *blockList = &cUnit->blockList; + MIR *mir; + + /* Phi nodes are at the beginning of each block */ + for (mir = bb->firstMIRInsn; mir; mir = mir->next) { + if (mir->dalvikInsn.opcode != kMirOpPhi) return true; + int ssaReg = mir->ssaRep->defs[0]; + int encodedDalvikValue = + (int) dvmGrowableListGetElement(cUnit->ssaToDalvikMap, ssaReg); + int dalvikReg = DECODE_REG(encodedDalvikValue); + + dvmClearAllBits(ssaRegV); + + /* Iterate through the predecessors */ + dvmBitVectorIteratorInit(bb->predecessors, &bvIterator); + while (true) { + int predIdx = dvmBitVectorIteratorNext(&bvIterator); + if (predIdx == -1) break; + BasicBlock *predBB = (BasicBlock *) dvmGrowableListGetElement( + blockList, predIdx); + int encodedSSAValue = + predBB->dataFlowInfo->dalvikToSSAMap[dalvikReg]; + int ssaReg = DECODE_REG(encodedSSAValue); + dvmSetBit(ssaRegV, ssaReg); + } + + /* Count the number of SSA registers for a Dalvik register */ + int numUses = dvmCountSetBits(ssaRegV); + mir->ssaRep->numUses = numUses; + mir->ssaRep->uses = + (int *) dvmCompilerNew(sizeof(int) * numUses, false); + mir->ssaRep->fpUse = + (bool *) dvmCompilerNew(sizeof(bool) * numUses, false); + + BitVectorIterator phiIterator; + + dvmBitVectorIteratorInit(ssaRegV, &phiIterator); + int *usePtr = mir->ssaRep->uses; + + /* Set the uses array for the phi node */ + while (true) { + int ssaRegIdx = dvmBitVectorIteratorNext(&phiIterator); + if (ssaRegIdx == -1) break; + *usePtr++ = ssaRegIdx; + } + } + + return true; +} + +/* Perform SSA transformation for the whole method */ +void dvmCompilerMethodSSATransformation(CompilationUnit *cUnit) +{ + /* Compute the DFS order */ + computeDFSOrder(cUnit); + + /* Compute the dominator info */ + computeDominators(cUnit); + + /* Allocate data structures in preparation for SSA conversion */ + dvmInitializeSSAConversion(cUnit); + + /* Find out the "Dalvik reg def x block" relation */ + computeDefBlockMatrix(cUnit); + + /* Insert phi nodes to dominance frontiers for all variables */ + insertPhiNodes(cUnit); + + /* Rename register names by local defs and phi nodes */ + dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion, + kPreOrderDFSTraversal, + false /* isIterative */); + + /* + * Shared temp bit vector used by each block to count the number of defs + * from all the predecessor blocks. + */ + cUnit->tempSSARegisterV = dvmCompilerAllocBitVector(cUnit->numSSARegs, + false); + + /* Insert phi-operands with latest SSA names from predecessor blocks */ + dvmCompilerDataFlowAnalysisDispatcher(cUnit, insertPhiNodeOperands, + kReachableNodes, + false /* isIterative */); +} diff --git a/vm/compiler/Ralloc.c b/vm/compiler/Ralloc.c index 0dd67b740..130ff3cf2 100644 --- a/vm/compiler/Ralloc.c +++ b/vm/compiler/Ralloc.c @@ -25,35 +25,6 @@ typedef struct LiveRange { int last; } LiveRange; -static int computeLiveRange(LiveRange *list, BasicBlock *bb, int seqNum) -{ - MIR *mir; - int i; - - if (bb->blockType != kDalvikByteCode && - bb->blockType != kTraceEntryBlock) - return seqNum; - - for (mir = bb->firstMIRInsn; mir; mir = mir->next) { - SSARepresentation *ssaRep = mir->ssaRep; - mir->seqNum = seqNum; - if (ssaRep) { - for (i=0; i< ssaRep->numUses; i++) { - int reg = ssaRep->uses[i]; - list[reg].first = MIN(list[reg].first, seqNum); - list[reg].active = true; - } - for (i=0; i< ssaRep->numDefs; i++) { - int reg = ssaRep->defs[i]; - list[reg].last = MAX(list[reg].last, seqNum + 1); - list[reg].active = true; - } - seqNum += 2; - } - } - return seqNum; -} - /* * Quick & dirty - make FP usage sticky. This is strictly a hint - local * code generation will handle misses. It might be worthwhile to collaborate @@ -121,7 +92,6 @@ static const RegLocation freshLoc = {kLocDalvikFrame, 0, 0, INVALID_REG, void dvmCompilerRegAlloc(CompilationUnit *cUnit) { int i; - int seqNum = 0; LiveRange *ranges; RegLocation *loc; @@ -133,9 +103,14 @@ void dvmCompilerRegAlloc(CompilationUnit *cUnit) } cUnit->regLocation = loc; + GrowableListIterator iterator; + + dvmGrowableListIteratorInit(&cUnit->blockList, &iterator); /* Do type inference pass */ - for (i=0; i < cUnit->numBlocks; i++) { - inferTypes(cUnit, cUnit->blockList[i]); + while (true) { + BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + if (bb == NULL) break; + inferTypes(cUnit, bb); } if (simpleTrace(cUnit)) { @@ -153,7 +128,6 @@ void dvmCompilerRegAlloc(CompilationUnit *cUnit) ranges = (LiveRange *)dvmCompilerNew(cUnit->numSSARegs * sizeof(*ranges), true); for (i=0; i < cUnit->numSSARegs; i++) ranges[i].active = false; - seqNum = computeLiveRange(ranges, cUnit->blockList[i], seqNum); //TODO: phi squash & linear scan promotion } } diff --git a/vm/compiler/Utility.c b/vm/compiler/Utility.c index 4b942ef40..fe258331f 100644 --- a/vm/compiler/Utility.c +++ b/vm/compiler/Utility.c @@ -82,7 +82,8 @@ retry: LOGI("Total arena pages for JIT: %d", numArenaBlocks); goto retry; } - return NULL; + /* Should not reach here */ + dvmAbort(); } /* Reclaim all the arena blocks allocated so far */ @@ -101,8 +102,8 @@ void dvmInitGrowableList(GrowableList *gList, size_t initLength) { gList->numAllocated = initLength; gList->numUsed = 0; - gList->elemList = (void **) dvmCompilerNew(sizeof(void *) * initLength, - true); + gList->elemList = (intptr_t *) dvmCompilerNew(sizeof(intptr_t) * initLength, + true); } /* Expand the capacity of a growable list */ @@ -114,14 +115,15 @@ static void expandGrowableList(GrowableList *gList) } else { newLength += 128; } - void *newArray = dvmCompilerNew(sizeof(void *) * newLength, true); - memcpy(newArray, gList->elemList, sizeof(void *) * gList->numAllocated); + intptr_t *newArray = + (intptr_t *) dvmCompilerNew(sizeof(intptr_t) * newLength, true); + memcpy(newArray, gList->elemList, sizeof(intptr_t) * gList->numAllocated); gList->numAllocated = newLength; - gList->elemList = (void **)newArray; + gList->elemList = newArray; } /* Insert a new element into the growable list */ -void dvmInsertGrowableList(GrowableList *gList, void *elem) +void dvmInsertGrowableList(GrowableList *gList, intptr_t elem) { assert(gList->numAllocated != 0); if (gList->numUsed == gList->numAllocated) { @@ -130,10 +132,30 @@ void dvmInsertGrowableList(GrowableList *gList, void *elem) gList->elemList[gList->numUsed++] = elem; } +void dvmGrowableListIteratorInit(GrowableList *gList, + GrowableListIterator *iterator) +{ + iterator->list = gList; + iterator->idx = 0; + iterator->size = gList->numUsed; +} + +intptr_t dvmGrowableListIteratorNext(GrowableListIterator *iterator) +{ + assert(iterator->size == iterator->list->numUsed); + if (iterator->idx == iterator->size) return 0; + return iterator->list->elemList[iterator->idx++]; +} + +intptr_t dvmGrowableListGetElement(const GrowableList *gList, size_t idx) +{ + assert(idx < gList->numUsed); + return gList->elemList[idx]; +} + /* Debug Utility - dump a compilation unit */ void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit) { - int i; BasicBlock *bb; char *blockTypeNames[] = { "Normal Chaining Cell", @@ -156,9 +178,13 @@ void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit) cUnit->method->name); LOGD("%d insns", dvmGetMethodInsnsSize(cUnit->method)); LOGD("%d blocks in total", cUnit->numBlocks); + GrowableListIterator iterator; + + dvmGrowableListIteratorInit(&cUnit->blockList, &iterator); - for (i = 0; i < cUnit->numBlocks; i++) { - bb = cUnit->blockList[i]; + while (true) { + bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + if (bb == NULL) break; LOGD("Block %d (%s) (insn %04x - %04x%s)\n", bb->id, blockTypeNames[bb->blockType], @@ -275,7 +301,7 @@ bool dvmCompilerSetBit(BitVector *pBits, int num) assert(num >= 0); if (num >= pBits->storageSize * (int)sizeof(u4) * 8) { if (!pBits->expandable) - return false; + dvmAbort(); /* Round up to word boundaries for "num+1" bits */ int newSize = (num + 1 + 31) >> 5; @@ -292,6 +318,36 @@ bool dvmCompilerSetBit(BitVector *pBits, int num) return true; } +/* + * Mark the specified bit as "unset". + * + * Returns "false" if the bit is outside the range of the vector and we're + * not allowed to expand. + * + * NOTE: this is the sister implementation of dvmClearBit. In this version + * memory is allocated from the compiler arena. + */ +bool dvmCompilerClearBit(BitVector *pBits, int num) +{ + assert(num >= 0); + if (num >= pBits->storageSize * (int)sizeof(u4) * 8) { + LOGE("Trying to clear a bit that is not set in the vector yet!"); + dvmAbort(); + } + + pBits->storage[num >> 5] &= ~(1 << (num & 0x1f)); + return true; +} + +/* + * If set is true, mark all bits as 1. Otherwise mark all bits as 0. + */ +void dvmCompilerMarkAllBits(BitVector *pBits, bool set) +{ + int value = set ? -1 : 0; + memset(pBits->storage, value, pBits->storageSize * (int)sizeof(u4)); +} + void dvmDebugBitVector(char *msg, const BitVector *bv, int length) { int i; @@ -315,3 +371,41 @@ void dvmCompilerAbort(CompilationUnit *cUnit) */ longjmp(*cUnit->bailPtr, 1); } + +void dvmDumpBlockBitVector(const GrowableList *blocks, char *msg, + const BitVector *bv, int length) +{ + int i; + + LOGE("%s", msg); + for (i = 0; i < length; i++) { + if (dvmIsBitSet(bv, i)) { + BasicBlock *bb = + (BasicBlock *) dvmGrowableListGetElement(blocks, i); + char blockName[BLOCK_NAME_LEN]; + dvmGetBlockName(bb, blockName); + LOGE("Bit %d / %s is set", i, blockName); + } + } +} + +void dvmGetBlockName(BasicBlock *bb, char *name) +{ + switch (bb->blockType) { + case kMethodEntryBlock: + snprintf(name, BLOCK_NAME_LEN, "entry"); + break; + case kMethodExitBlock: + snprintf(name, BLOCK_NAME_LEN, "exit"); + break; + case kDalvikByteCode: + snprintf(name, BLOCK_NAME_LEN, "block%04x", bb->startOffset); + break; + case kExceptionHandling: + snprintf(name, BLOCK_NAME_LEN, "exception%04x", bb->startOffset); + break; + default: + snprintf(name, BLOCK_NAME_LEN, "??"); + break; + } +} diff --git a/vm/compiler/codegen/arm/CodegenCommon.c b/vm/compiler/codegen/arm/CodegenCommon.c index 6558f67bf..c29efa640 100644 --- a/vm/compiler/codegen/arm/CodegenCommon.c +++ b/vm/compiler/codegen/arm/CodegenCommon.c @@ -376,7 +376,8 @@ static ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset, pcrLabel->operands[0] = dPC; pcrLabel->operands[1] = dOffset; /* Insert the place holder to the growable list */ - dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel); + dvmInsertGrowableList(&cUnit->pcReconstructionList, + (intptr_t) pcrLabel); } /* Branch to the PC reconstruction code */ branch->generic.target = (LIR *) pcrLabel; diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c index 2a535920f..6473edb50 100644 --- a/vm/compiler/codegen/arm/CodegenDriver.c +++ b/vm/compiler/codegen/arm/CodegenDriver.c @@ -917,7 +917,7 @@ static void genReturnCommon(CompilationUnit *cUnit, MIR *mir) pcrLabel->operands[0] = dPC; pcrLabel->operands[1] = mir->offset; /* Insert the place holder to the growable list */ - dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel); + dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel); /* Branch to the PC reconstruction code */ branch->generic.target = (LIR *) pcrLabel; } @@ -1161,7 +1161,8 @@ static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir, pcrLabel->operands[0] = dPC; pcrLabel->operands[1] = mir->offset; /* Insert the place holder to the growable list */ - dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel); + dvmInsertGrowableList(&cUnit->pcReconstructionList, + (intptr_t) pcrLabel); } /* return through lr+2 - punt to the interpreter */ @@ -3013,7 +3014,8 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, pcrLabel->operands[0] = dPC; pcrLabel->operands[1] = mir->offset; /* Insert the place holder to the growable list */ - dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel); + dvmInsertGrowableList(&cUnit->pcReconstructionList, + (intptr_t) pcrLabel); } /* return through lr+2 - punt to the interpreter */ @@ -3886,7 +3888,7 @@ static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry, (int) (cUnit->method->insns + entry->startOffset); pcrLabel->operands[1] = entry->startOffset; /* Insert the place holder to the growable list */ - dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel); + dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel); /* * Next, create two branches - one branch over to the loop body and the @@ -3939,7 +3941,8 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit) dvmInitGrowableList(&chainingListByType[i], 2); } - BasicBlock **blockList = cUnit->blockList; + GrowableListIterator iterator; + dvmGrowableListIteratorInit(&cUnit->blockList, &iterator); if (cUnit->executionCount) { /* @@ -3976,14 +3979,15 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit) } /* Handle the content in each basic block */ - for (i = 0; i < cUnit->numBlocks; i++) { - blockList[i]->visited = true; + for (i = 0; ; i++) { MIR *mir; + BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator); + if (bb == NULL) break; - labelList[i].operands[0] = blockList[i]->startOffset; + labelList[i].operands[0] = bb->startOffset; - if (blockList[i]->blockType >= kChainingCellGap) { - if (blockList[i]->isFallThroughFromInvoke == true) { + if (bb->blockType >= kChainingCellGap) { + if (bb->isFallThroughFromInvoke == true) { /* Align this block first since it is a return chaining cell */ newLIR0(cUnit, kArmPseudoPseudoAlign4); } @@ -3994,56 +3998,53 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit) dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]); } - if (blockList[i]->blockType == kTraceEntryBlock) { + if (bb->blockType == kTraceEntryBlock) { labelList[i].opcode = kArmPseudoEntryBlock; - if (blockList[i]->firstMIRInsn == NULL) { + if (bb->firstMIRInsn == NULL) { continue; } else { - setupLoopEntryBlock(cUnit, blockList[i], - &labelList[blockList[i]->fallThrough->id]); + setupLoopEntryBlock(cUnit, bb, + &labelList[bb->fallThrough->id]); } - } else if (blockList[i]->blockType == kTraceExitBlock) { + } else if (bb->blockType == kTraceExitBlock) { labelList[i].opcode = kArmPseudoExitBlock; goto gen_fallthrough; - } else if (blockList[i]->blockType == kDalvikByteCode) { + } else if (bb->blockType == kDalvikByteCode) { labelList[i].opcode = kArmPseudoNormalBlockLabel; /* Reset the register state */ dvmCompilerResetRegPool(cUnit); dvmCompilerClobberAllRegs(cUnit); dvmCompilerResetNullCheck(cUnit); } else { - switch (blockList[i]->blockType) { + switch (bb->blockType) { case kChainingCellNormal: labelList[i].opcode = kArmPseudoChainingCellNormal; /* handle the codegen later */ dvmInsertGrowableList( - &chainingListByType[kChainingCellNormal], (void *) i); + &chainingListByType[kChainingCellNormal], i); break; case kChainingCellInvokeSingleton: labelList[i].opcode = kArmPseudoChainingCellInvokeSingleton; labelList[i].operands[0] = - (int) blockList[i]->containingMethod; + (int) bb->containingMethod; /* handle the codegen later */ dvmInsertGrowableList( - &chainingListByType[kChainingCellInvokeSingleton], - (void *) i); + &chainingListByType[kChainingCellInvokeSingleton], i); break; case kChainingCellInvokePredicted: labelList[i].opcode = kArmPseudoChainingCellInvokePredicted; /* handle the codegen later */ dvmInsertGrowableList( - &chainingListByType[kChainingCellInvokePredicted], - (void *) i); + &chainingListByType[kChainingCellInvokePredicted], i); break; case kChainingCellHot: labelList[i].opcode = kArmPseudoChainingCellHot; /* handle the codegen later */ dvmInsertGrowableList( - &chainingListByType[kChainingCellHot], - (void *) i); + &chainingListByType[kChainingCellHot], i); break; case kPCReconstruction: /* Make sure exception handling block is next */ @@ -4068,7 +4069,7 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit) /* handle the codegen later */ dvmInsertGrowableList( &chainingListByType[kChainingCellBackwardBranch], - (void *) i); + i); break; #endif default: @@ -4079,7 +4080,7 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit) ArmLIR *headLIR = NULL; - for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) { + for (mir = bb->firstMIRInsn; mir; mir = mir->next) { dvmCompilerResetRegPool(cUnit); if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) { @@ -4147,7 +4148,7 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit) case kFmt20t: case kFmt30t: notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit, - mir, blockList[i], labelList); + mir, bb, labelList); break; case kFmt10x: notHandled = handleFmt10x(cUnit, mir); @@ -4176,8 +4177,7 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit) notHandled = handleFmt21s(cUnit, mir); break; case kFmt21t: - notHandled = handleFmt21t(cUnit, mir, blockList[i], - labelList); + notHandled = handleFmt21t(cUnit, mir, bb, labelList); break; case kFmt22b: case kFmt22s: @@ -4190,8 +4190,7 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit) notHandled = handleFmt22cs(cUnit, mir); break; case kFmt22t: - notHandled = handleFmt22t(cUnit, mir, blockList[i], - labelList); + notHandled = handleFmt22t(cUnit, mir, bb, labelList); break; case kFmt22x: case kFmt32x: @@ -4205,12 +4204,12 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit) break; case kFmt3rc: case kFmt35c: - notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i], + notHandled = handleFmt35c_3rc(cUnit, mir, bb, labelList); break; case kFmt3rms: case kFmt35ms: - notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i], + notHandled = handleFmt35ms_3rms(cUnit, mir, bb, labelList); break; case kFmt35mi: @@ -4235,7 +4234,7 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit) } } - if (blockList[i]->blockType == kTraceEntryBlock) { + if (bb->blockType == kTraceEntryBlock) { dvmCompilerAppendLIR(cUnit, (LIR *) cUnit->loopAnalysis->branchToBody); dvmCompilerAppendLIR(cUnit, @@ -4256,9 +4255,9 @@ gen_fallthrough: * Check if the block is terminated due to trace length constraint - * insert an unconditional branch to the chaining cell. */ - if (blockList[i]->needFallThroughBranch) { + if (bb->needFallThroughBranch) { genUnconditionalBranch(cUnit, - &labelList[blockList[i]->fallThrough->id]); + &labelList[bb->fallThrough->id]); } } @@ -4279,6 +4278,9 @@ gen_fallthrough: for (j = 0; j < chainingListByType[i].numUsed; j++) { int blockId = blockIdList[j]; + BasicBlock *chainingBlock = + (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, + blockId); /* Align this chaining cell first */ newLIR0(cUnit, kArmPseudoPseudoAlign4); @@ -4287,30 +4289,28 @@ gen_fallthrough: dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]); - switch (blockList[blockId]->blockType) { + switch (chainingBlock->blockType) { case kChainingCellNormal: - handleNormalChainingCell(cUnit, - blockList[blockId]->startOffset); + handleNormalChainingCell(cUnit, chainingBlock->startOffset); break; case kChainingCellInvokeSingleton: handleInvokeSingletonChainingCell(cUnit, - blockList[blockId]->containingMethod); + chainingBlock->containingMethod); break; case kChainingCellInvokePredicted: handleInvokePredictedChainingCell(cUnit); break; case kChainingCellHot: - handleHotChainingCell(cUnit, - blockList[blockId]->startOffset); + handleHotChainingCell(cUnit, chainingBlock->startOffset); break; #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING) case kChainingCellBackwardBranch: handleBackwardBranchChainingCell(cUnit, - blockList[blockId]->startOffset); + chainingBlock->startOffset); break; #endif default: - LOGE("Bad blocktype %d", blockList[blockId]->blockType); + LOGE("Bad blocktype %d", chainingBlock->blockType); dvmCompilerAbort(cUnit); } } diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c index 5d8e3d66e..fb47b03f6 100644 --- a/vm/mterp/out/InterpC-allstubs.c +++ b/vm/mterp/out/InterpC-allstubs.c @@ -3682,7 +3682,7 @@ GOTO_TARGET(returnFromMethod) #endif /* back up to previous frame and see if we hit a break */ - fp = saveArea->prevFrame; + fp = (u4*)saveArea->prevFrame; assert(fp != NULL); if (dvmIsBreakFrame(fp)) { /* bail without popping the method frame from stack */ @@ -3794,7 +3794,7 @@ GOTO_TARGET(exceptionThrown) * the "catch" blocks. */ catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns, - exception, false, (void*)&fp); + exception, false, (void**)(void*)&fp); /* * Restore the stack bounds after an overflow. This isn't going to @@ -4027,7 +4027,7 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, curMethod = methodToCall; methodClassDex = curMethod->clazz->pDvmDex; pc = methodToCall->insns; - fp = self->curFrame = newFp; + self->curFrame = fp = newFp; #ifdef EASY_GDB debugSaveArea = SAVEAREA_FROM_FP(newFp); #endif diff --git a/vm/mterp/out/InterpC-x86-atom.c b/vm/mterp/out/InterpC-x86-atom.c index 587dcd501..87995e934 100644 --- a/vm/mterp/out/InterpC-x86-atom.c +++ b/vm/mterp/out/InterpC-x86-atom.c @@ -1808,7 +1808,7 @@ GOTO_TARGET(returnFromMethod) #endif /* back up to previous frame and see if we hit a break */ - fp = saveArea->prevFrame; + fp = (u4*)saveArea->prevFrame; assert(fp != NULL); if (dvmIsBreakFrame(fp)) { /* bail without popping the method frame from stack */ @@ -1920,7 +1920,7 @@ GOTO_TARGET(exceptionThrown) * the "catch" blocks. */ catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns, - exception, false, (void*)&fp); + exception, false, (void**)(void*)&fp); /* * Restore the stack bounds after an overflow. This isn't going to @@ -2153,7 +2153,7 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, curMethod = methodToCall; methodClassDex = curMethod->clazz->pDvmDex; pc = methodToCall->insns; - fp = self->curFrame = newFp; + self->curFrame = fp = newFp; #ifdef EASY_GDB debugSaveArea = SAVEAREA_FROM_FP(newFp); #endif diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c index 8a7a1d5b6..b5f616e79 100644 --- a/vm/mterp/out/InterpC-x86.c +++ b/vm/mterp/out/InterpC-x86.c @@ -1821,7 +1821,7 @@ GOTO_TARGET(returnFromMethod) #endif /* back up to previous frame and see if we hit a break */ - fp = saveArea->prevFrame; + fp = (u4*)saveArea->prevFrame; assert(fp != NULL); if (dvmIsBreakFrame(fp)) { /* bail without popping the method frame from stack */ @@ -1933,7 +1933,7 @@ GOTO_TARGET(exceptionThrown) * the "catch" blocks. */ catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns, - exception, false, (void*)&fp); + exception, false, (void**)(void*)&fp); /* * Restore the stack bounds after an overflow. This isn't going to @@ -2166,7 +2166,7 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, curMethod = methodToCall; methodClassDex = curMethod->clazz->pDvmDex; pc = methodToCall->insns; - fp = self->curFrame = newFp; + self->curFrame = fp = newFp; #ifdef EASY_GDB debugSaveArea = SAVEAREA_FROM_FP(newFp); #endif |