Collect per-method code size statistics to show compiled vs overall Dalvik portion and total native code size.
diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c
index c8f3abc..76d9312 100644
--- a/vm/compiler/Frontend.c
+++ b/vm/compiler/Frontend.c
@@ -30,19 +30,9 @@
OpCode opcode = instr & 0xff;
int insnWidth;
- // Need to check if this is a real NOP or a pseudo opcode
+ // Don't parse instruction data
if (opcode == OP_NOP && instr != 0) {
- if (instr == kPackedSwitchSignature) {
- insnWidth = 4 + codePtr[1] * 2;
- } else if (instr == kSparseSwitchSignature) {
- insnWidth = 2 + codePtr[1] * 4;
- } else if (instr == kArrayDataSignature) {
- int width = codePtr[1];
- int size = codePtr[2] | (codePtr[3] << 16);
- // The plus 1 is to round up for odd size and width
- insnWidth = 4 + ((size * width) + 1) / 2;
- }
- insnWidth = 0;
+ return 0;
} else {
insnWidth = gDvm.instrWidth[opcode];
if (insnWidth < 0) {
@@ -88,7 +78,7 @@
const Method *calleeMethod =
caller->clazz->super->vtable[mIndex];
- if (!dvmIsNativeMethod(calleeMethod)) {
+ if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
*target = (unsigned int) calleeMethod->insns;
}
*isInvoke = true;
@@ -100,7 +90,7 @@
const Method *calleeMethod =
caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
- if (!dvmIsNativeMethod(calleeMethod)) {
+ if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
*target = (unsigned int) calleeMethod->insns;
}
*isInvoke = true;
@@ -112,7 +102,7 @@
const Method *calleeMethod =
caller->clazz->super->vtable[insn->dalvikInsn.vB];
- if (!dvmIsNativeMethod(calleeMethod)) {
+ if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
*target = (unsigned int) calleeMethod->insns;
}
*isInvoke = true;
@@ -123,7 +113,7 @@
case OP_INVOKE_DIRECT_RANGE: {
const Method *calleeMethod =
caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
- if (!dvmIsNativeMethod(calleeMethod)) {
+ if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
*target = (unsigned int) calleeMethod->insns;
}
*isInvoke = true;
@@ -179,6 +169,72 @@
}
/*
+ * dvmHashTableLookup() callback
+ */
+static int compareMethod(const CompilerMethodStats *m1,
+ const CompilerMethodStats *m2)
+{
+ return (int) m1->method - (int) m2->method;
+}
+
+/*
+ * Analyze each method whose traces are ever compiled. Collect a variety of
+ * statistics like the ratio of exercised vs overall code and code bloat
+ * ratios.
+ */
+static CompilerMethodStats *analyzeMethodBody(const Method *method)
+{
+ const DexCode *dexCode = dvmGetMethodCode(method);
+ const u2 *codePtr = dexCode->insns;
+ const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
+ int insnSize = 0;
+ int hashValue = dvmComputeUtf8Hash(method->name);
+
+ CompilerMethodStats dummyMethodEntry; // For hash table lookup
+ CompilerMethodStats *realMethodEntry; // For hash table storage
+
+ /* For lookup only */
+ dummyMethodEntry.method = method;
+ realMethodEntry = dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
+ &dummyMethodEntry,
+ (HashCompareFunc) compareMethod,
+ false);
+
+ /* Part of this method has been compiled before - just return the entry */
+ if (realMethodEntry != NULL) {
+ return realMethodEntry;
+ }
+
+ /*
+ * First time to compile this method - set up a new entry in the hash table
+ */
+ realMethodEntry =
+ (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
+ realMethodEntry->method = method;
+
+ dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
+ realMethodEntry,
+ (HashCompareFunc) compareMethod,
+ true);
+
+ /* Count the number of instructions */
+ while (codePtr < codeEnd) {
+ DecodedInstruction dalvikInsn;
+ int width = parseInsn(codePtr, &dalvikInsn, false);
+
+ /* Terminate when the data section is seen */
+ if (width == 0)
+ break;
+
+ insnSize += width;
+ codePtr += width;
+ }
+
+ realMethodEntry->dalvikSize = insnSize * 2;
+ return realMethodEntry;
+}
+
+/*
* Main entry point to start trace compilation. Basic blocks are constructed
* first and they will be passed to the codegen routines to convert Dalvik
* bytecode into machine code.
@@ -190,15 +246,19 @@
unsigned int curOffset = currRun->frag.startOffset;
unsigned int numInsts = currRun->frag.numInsts;
const u2 *codePtr = dexCode->insns + curOffset;
- int traceSize = 0;
+ int traceSize = 0; // # of half-words
const u2 *startCodePtr = codePtr;
BasicBlock *startBB, *curBB, *lastBB;
int numBlocks = 0;
static int compilationId;
CompilationUnit cUnit;
- memset(&cUnit, 0, sizeof(CompilationUnit));
+ CompilerMethodStats *methodStats;
compilationId++;
+ memset(&cUnit, 0, sizeof(CompilationUnit));
+
+ /* Locate the entry to store compilation statistics for this method */
+ methodStats = analyzeMethodBody(desc->method);
cUnit.registerScoreboard.nullCheckedRegs =
dvmAllocBitVector(desc->method->registersSize, false);
@@ -292,6 +352,9 @@
insn = dvmCompilerNew(sizeof(MIR),false);
insn->offset = curOffset;
width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
+
+ /* The trace should never incude instruction data */
+ assert(width);
insn->width = width;
traceSize += width;
dvmCompilerAppendMIR(curBB, insn);
@@ -320,6 +383,9 @@
}
}
+ /* Convert # of half-word to bytes */
+ methodStats->compiledDalvikSize += traceSize * 2;
+
/*
* Now scan basic blocks containing real code to connect the
* taken/fallthrough links. Also create chaining cells for code not included
@@ -478,6 +544,7 @@
* translation's entry point.
*/
if (!cUnit.halveInstCount) {
+ methodStats->nativeSize += cUnit.totalSize;
return cUnit.baseAddr + cUnit.headerSize;
/* Halve the instruction count and retry again */
@@ -493,7 +560,7 @@
* TODO: implementation will be revisited when the trace builder can provide
* whole-method traces.
*/
-void *dvmCompileMethod(Method *method)
+void *dvmCompileMethod(const Method *method)
{
const DexCode *dexCode = dvmGetMethodCode(method);
const u2 *codePtr = dexCode->insns;
@@ -520,6 +587,9 @@
const Method *callee;
insn->width = width;
+ /* Terminate when the data section is seen */
+ if (width == 0)
+ break;
dvmCompilerAppendMIR(firstBlock, insn);
/*
* Check whether this is a block ending instruction and whether it
@@ -590,6 +660,7 @@
BasicBlock *newBB = dvmCompilerNewBB(DALVIK_BYTECODE);
newBB->id = blockID++;
newBB->firstMIRInsn = insn;
+ newBB->startOffset = insn->offset;
newBB->lastMIRInsn = curBB->lastMIRInsn;
curBB->lastMIRInsn = insn->prev;
insn->prev->next = NULL;
@@ -645,7 +716,8 @@
}
}
- if (j == numBlocks) {
+ /* Don't create dummy block for the callee yet */
+ if (j == numBlocks && !isInvoke) {
LOGE("Target not found for insn %x: expect target %x\n",
curBB->lastMIRInsn->offset, target);
dvmAbort();