}
/*
+ * 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)
}
/*
- * 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)
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;
+}
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);
* 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 */
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*/
compiler/InlineTransformation.c \
compiler/IntermediateRep.c \
compiler/Dataflow.c \
+ compiler/MethodSSATransformation.c \
compiler/Loop.c \
compiler/Ralloc.c \
interp/Jit.c
#endif
;
-
/*
* Return a newly-allocated string in which all occurrences of '.' have
* been changed to '/'. If we find a '/' in the original string, NULL
#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
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);
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);
kMethodExitBlock,
kPCReconstruction,
kExceptionHandling,
+ kCatchEntry,
} BBType;
typedef struct ChainCellCounts {
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;
typedef struct CompilationUnit {
int numInsts;
int numBlocks;
- BasicBlock **blockList;
+ GrowableList blockList;
const Method *method;
const JitTraceDescription *traceDesc;
LIR *firstLIRInsn;
* 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)
#define HEAP_ACCESS_SHADOW(_state)
#endif
-BasicBlock *dvmCompilerNewBB(BBType blockType);
+BasicBlock *dvmCompilerNewBB(BBType blockType, int blockId);
void dvmCompilerAppendMIR(BasicBlock *bb, MIR *mir);
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 */
};
/* 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);
}
* 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, ",");
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);
}
}
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
}
/* 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);
}
* 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 =
}
}
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 */
cUnit->dalvikToSSAMap[dalvikReg] = newD2SMapping;
int newS2DMapping = ENCODE_REG_SUB(dalvikReg, dalvikSub);
- dvmInsertGrowableList(cUnit->ssaToDalvikMap, (void *) newS2DMapping);
+ dvmInsertGrowableList(cUnit->ssaToDalvikMap, newS2DMapping);
defs[regIndex] = ssaReg;
}
}
/* 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 *)
}
}
+ /*
+ * 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 */
cUnit->constantValues[ssaReg] = value;
}
-void dvmCompilerDoConstantPropagation(CompilationUnit *cUnit, BasicBlock *bb)
+bool dvmCompilerDoConstantPropagation(CompilationUnit *cUnit, BasicBlock *bb)
{
MIR *mir;
BitVector *isConstantV = cUnit->isConstantV;
}
}
/* 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;
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 */
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;
}
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 */
* 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));
}
/*
/*
* 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);
}
}
+/* 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 */);
}
#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
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
/* 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) +
}
/* 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",
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;
* 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) {
}
/* 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;
}
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;
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;
/* 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 &&
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 */
#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,
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();
dvmCompilerInlineMIR(&cUnit);
}
+ cUnit.numDalvikRegisters = cUnit.method->registersSize;
+
/* Preparation for SSA conversion */
dvmInitializeSSAConversion(&cUnit);
#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;
}
}
}
-/*
- * 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;
}
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;
#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;
}
*/
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;
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) {
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;
arrayAccessInfo->maxC = (ivInfo->c > 0) ? ivInfo->c : 0;
arrayAccessInfo->minC = (ivInfo->c < 0) ? ivInfo->c : 0;
dvmInsertGrowableList(loopAnalysis->arrayAccessInfo,
- arrayAccessInfo);
+ (intptr_t) arrayAccessInfo);
}
break;
}
/* 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;
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;
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 */
(int *)dvmCompilerNew(sizeof(int) * cUnit->numSSARegs,
true);
dvmCompilerDataFlowAnalysisDispatcher(cUnit,
- dvmCompilerDoConstantPropagation);
+ dvmCompilerDoConstantPropagation,
+ kAllNodes,
+ false /* isIterative */);
DEBUG_LOOP(dumpConstants(cUnit);)
/* Find induction variables - basic and dependent */
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 */
--- /dev/null
+/*
+ * 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 */);
+}
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
void dvmCompilerRegAlloc(CompilationUnit *cUnit)
{
int i;
- int seqNum = 0;
LiveRange *ranges;
RegLocation *loc;
}
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)) {
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
}
}
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 */
{
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 */
} 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) {
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",
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],
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;
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;
*/
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;
+ }
+}
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;
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;
}
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 */
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 */
(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
dvmInitGrowableList(&chainingListByType[i], 2);
}
- BasicBlock **blockList = cUnit->blockList;
+ GrowableListIterator iterator;
+ dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
if (cUnit->executionCount) {
/*
}
/* 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);
}
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 */
/* handle the codegen later */
dvmInsertGrowableList(
&chainingListByType[kChainingCellBackwardBranch],
- (void *) i);
+ i);
break;
#endif
default:
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)) {
case kFmt20t:
case kFmt30t:
notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
- mir, blockList[i], labelList);
+ mir, bb, labelList);
break;
case kFmt10x:
notHandled = handleFmt10x(cUnit, mir);
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:
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:
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:
}
}
- if (blockList[i]->blockType == kTraceEntryBlock) {
+ if (bb->blockType == kTraceEntryBlock) {
dvmCompilerAppendLIR(cUnit,
(LIR *) cUnit->loopAnalysis->branchToBody);
dvmCompilerAppendLIR(cUnit,
* 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]);
}
}
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);
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);
}
}
#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 */
* 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
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
#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 */
* 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
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
#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 */
* 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
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