Collect per-method code size statistics to show compiled vs overall Dalvik portion and total native code size.
diff --git a/vm/Globals.h b/vm/Globals.h
index 1d3460e..d43a77e 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -690,6 +690,9 @@
     /* Compiled code cache */
     void* codeCache;
 
+    /* Bytes used by the code templates */
+    unsigned int templateSize;
+
     /* Bytes already used in the code cache */
     unsigned int codeCacheByteUsed;
 
@@ -716,6 +719,9 @@
 
     /* Flag to count trace execution */
     bool profile;
+
+    /* Table to track the overall and trace statistics of hot methods */
+    HashTable*  methodStatsTable;
 };
 
 extern struct DvmJitGlobals gDvmJit;
diff --git a/vm/compiler/Compiler.c b/vm/compiler/Compiler.c
index 9473834..f70b978 100644
--- a/vm/compiler/Compiler.c
+++ b/vm/compiler/Compiler.c
@@ -169,6 +169,8 @@
     memcpy((void *) gDvmJit.codeCache,
            (void *) dvmCompilerTemplateStart,
            templateSize);
+
+    gDvmJit.templateSize = templateSize;
     gDvmJit.codeCacheByteUsed = templateSize;
 
     /* Flush dcache and invalidate the icache to maintain coherence */
@@ -224,6 +226,9 @@
         goto fail;
     }
 
+    /* Track method-level compilation statistics */
+    gDvmJit.methodStatsTable =  dvmHashTableCreate(32, NULL);
+
     dvmUnlockMutex(&gDvmJit.compilerLock);
 
     return true;
diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h
index 1ab6687..093d48a 100644
--- a/vm/compiler/Compiler.h
+++ b/vm/compiler/Compiler.h
@@ -84,6 +84,13 @@
     JitTraceRun trace[];
 } JitTraceDescription;
 
+typedef struct CompilerMethodStats {
+    const Method *method;       // Used as hash entry signature
+    int dalvikSize;             // # of bytes for dalvik bytecodes
+    int compiledDalvikSize;     // # of compiled dalvik bytecodes
+    int nativeSize;             // # of bytes for produced native code
+} CompilerMethodStats;
+
 bool dvmCompilerSetupCodeCache(void);
 bool dvmCompilerArchInit(void);
 void dvmCompilerArchDump(void);
@@ -91,7 +98,7 @@
 void dvmCompilerShutdown(void);
 bool dvmCompilerWorkEnqueue(const u2* pc, WorkOrderKind kind, void* info);
 void *dvmCheckCodeCache(void *method);
-void *dvmCompileMethod(Method *method);
+void *dvmCompileMethod(const Method *method);
 void *dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts);
 void dvmCompilerDumpStats(void);
 void dvmCompilerDrainQueue(void);
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();
diff --git a/vm/compiler/Utility.c b/vm/compiler/Utility.c
index 54f6971..b0c40e6 100644
--- a/vm/compiler/Utility.c
+++ b/vm/compiler/Utility.c
@@ -154,17 +154,56 @@
 }
 
 /*
+ * dvmHashForeach callback.
+ */
+static int dumpMethodStats(void *compilerMethodStats, void *totalMethodStats)
+{
+    CompilerMethodStats *methodStats =
+        (CompilerMethodStats *) compilerMethodStats;
+    CompilerMethodStats *totalStats =
+        (CompilerMethodStats *) totalMethodStats;
+    const Method *method = methodStats->method;
+
+    totalStats->dalvikSize += methodStats->dalvikSize;
+    totalStats->compiledDalvikSize += methodStats->compiledDalvikSize;
+    totalStats->nativeSize += methodStats->nativeSize;
+
+    int limit = (methodStats->dalvikSize >> 2) * 3;
+
+    /* If over 3/4 of the Dalvik code is compiled, print something */
+    if (methodStats->compiledDalvikSize >= limit) {
+        LOGD("Method stats: %s%s, %d/%d (compiled/total Dalvik), %d (native)",
+             method->clazz->descriptor, method->name,
+             methodStats->compiledDalvikSize,
+             methodStats->dalvikSize,
+             methodStats->nativeSize);
+    }
+    return 0;
+}
+
+/*
  * Dump the current stats of the compiler, including number of bytes used in
  * the code cache, arena size, and work queue length, and various JIT stats.
  */
 void dvmCompilerDumpStats(void)
 {
-    LOGD("%d compilations using %d bytes",
-         gDvmJit.numCompilations, gDvmJit.codeCacheByteUsed);
+    CompilerMethodStats totalMethodStats;
+
+    memset(&totalMethodStats, 0, sizeof(CompilerMethodStats));
+    LOGD("%d compilations using %d + %d bytes",
+         gDvmJit.numCompilations,
+         gDvmJit.templateSize,
+         gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
     LOGD("Compiler arena uses %d blocks (%d bytes each)",
          numArenaBlocks, ARENA_DEFAULT_SIZE);
     LOGD("Compiler work queue length is %d/%d", gDvmJit.compilerQueueLength,
          gDvmJit.compilerMaxQueued);
     dvmJitStats();
     dvmCompilerArchDump();
+    dvmHashForeach(gDvmJit.methodStatsTable, dumpMethodStats,
+                   &totalMethodStats);
+    LOGD("Code size stats: %d/%d (compiled/total Dalvik), %d (native)",
+         totalMethodStats.compiledDalvikSize,
+         totalMethodStats.dalvikSize,
+         totalMethodStats.nativeSize);
 }
diff --git a/vm/compiler/codegen/armv5te/Codegen.c b/vm/compiler/codegen/armv5te/Codegen.c
index b272e48..10589e1 100644
--- a/vm/compiler/codegen/armv5te/Codegen.c
+++ b/vm/compiler/codegen/armv5te/Codegen.c
@@ -3228,7 +3228,7 @@
         }
     }
     if (strlen(buf)) {
-        LOGD("dalvik.vm.jitop = %s", buf);
+        LOGD("dalvik.vm.jit.op = %s", buf);
     }
 }