Add runtime support for method based compilation.

Enhanced code cache management to accommodate both trace and method
compilations. Also implemented a hacky dispatch routine for virtual
leaf methods.

Microbenchmark showed 3x speedup in leaf method invocation.

Change-Id: I79d95b7300ba993667b3aa221c1df9c7b0583521
diff --git a/vm/compiler/Compiler.c b/vm/compiler/Compiler.c
index a1e3d0e..6cd7eb5 100644
--- a/vm/compiler/Compiler.c
+++ b/vm/compiler/Compiler.c
@@ -644,6 +644,7 @@
                                 work.result.codeAddress) {
                             dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
                                               work.result.instructionSet,
+                                              false, /* not method entry */
                                               work.result.profileCodeSize);
                         }
                     }
diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h
index d29520d..b0ad7b4 100644
--- a/vm/compiler/Compiler.h
+++ b/vm/compiler/Compiler.h
@@ -215,6 +215,7 @@
     kIsThrowFree,       /* Method doesn't throw */
     kIsGetter,          /* Method fits the getter pattern */
     kIsSetter,          /* Method fits the setter pattern */
+    kCannotCompile,     /* Method cannot be compiled */
 } JitMethodAttributes;
 
 #define METHOD_IS_CALLEE        (1 << kIsCallee)
@@ -224,6 +225,7 @@
 #define METHOD_IS_THROW_FREE    (1 << kIsThrowFree)
 #define METHOD_IS_GETTER        (1 << kIsGetter)
 #define METHOD_IS_SETTER        (1 << kIsSetter)
+#define METHOD_CANNOT_COMPILE   (1 << kCannotCompile)
 
 /* Vectors to provide optimization hints */
 typedef enum JitOptimizationHints {
@@ -267,7 +269,7 @@
                                                   bool isCallee);
 bool dvmCompilerCanIncludeThisInstruction(const Method *method,
                                           const DecodedInstruction *insn);
-bool dvmCompileMethod(const Method *method);
+bool dvmCompileMethod(const Method *method, JitTranslationInfo *info);
 bool dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts,
                      JitTranslationInfo *info, jmp_buf *bailPtr, int optHints);
 void dvmCompilerDumpStats(void);
@@ -275,7 +277,8 @@
 void dvmJitUnchainAll(void);
 void dvmCompilerSortAndPrintTraceProfiles(void);
 void dvmCompilerPerformSafePointChecks(void);
-void dvmCompilerInlineMIR(struct CompilationUnit *cUnit);
+void dvmCompilerInlineMIR(struct CompilationUnit *cUnit,
+                          JitTranslationInfo *info);
 void dvmInitializeSSAConversion(struct CompilationUnit *cUnit);
 int dvmConvertSSARegToDalvik(const struct CompilationUnit *cUnit, int ssaReg);
 bool dvmCompilerLoopOpt(struct CompilationUnit *cUnit);
diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h
index 54d41a5..dd1d441 100644
--- a/vm/compiler/CompilerIR.h
+++ b/vm/compiler/CompilerIR.h
@@ -99,6 +99,7 @@
     kMIRInlined,                        // Invoke is inlined (ie dead)
     kMIRInlinedPred,                    // Invoke is inlined via prediction
     kMIRCallee,                         // Instruction is inlined from callee
+    kMIRInvokeMethodJIT,                // Callee is JIT'ed as a whole method
 } MIROptimizationFlagPositons;
 
 #define MIR_IGNORE_NULL_CHECK           (1 << kMIRIgnoreNullCheck)
@@ -108,6 +109,7 @@
 #define MIR_INLINED                     (1 << kMIRInlined)
 #define MIR_INLINED_PRED                (1 << kMIRInlinedPred)
 #define MIR_CALLEE                      (1 << kMIRCallee)
+#define MIR_INVOKE_METHOD_JIT           (1 << kMIRInvokeMethodJIT)
 
 typedef struct CallsiteInfo {
     const ClassObject *clazz;
@@ -209,7 +211,6 @@
     bool hasLoop;                       // Contains a loop
     bool hasInvoke;                     // Contains an invoke instruction
     bool heapMemOp;                     // Mark mem ops for self verification
-    bool wholeMethod;
     int profileCodeSize;                // Size of the profile prefix in bytes
     int numChainingCells[kChainingCellGap];
     LIR *firstChainingLIR[kChainingCellGap];
@@ -243,10 +244,12 @@
     const u2 *switchOverflowPad;
 
     /* New fields only for method-based compilation */
+    bool methodJitMode;
     int numReachableBlocks;
     int numDalvikRegisters;             // method->registersSize + inlined
     BasicBlock *entryBlock;
     BasicBlock *exitBlock;
+    BasicBlock *curBlock;
     GrowableList dfsOrder;
     GrowableList domPostOrderTraversal;
     BitVector *tryBlockAddr;
@@ -255,6 +258,7 @@
     BitVector *tempDalvikRegisterV;
     BitVector *tempSSARegisterV;        // numSSARegs
     bool printSSANames;
+    void *blockLabelList;
 } CompilationUnit;
 
 #if defined(WITH_SELF_VERIFICATION)
diff --git a/vm/compiler/Dataflow.c b/vm/compiler/Dataflow.c
index ba1b8fd..d935fd5 100644
--- a/vm/compiler/Dataflow.c
+++ b/vm/compiler/Dataflow.c
@@ -1592,7 +1592,7 @@
     char buffer[256];
     int opcode = insn->opcode;
     int dfAttributes = dvmCompilerDataFlowAttributes[opcode];
-    int flags = dexGetFlagsFromOpcode(insn->opcode);
+    int flags;
     char *ret;
 
     buffer[0] = 0;
@@ -1603,8 +1603,10 @@
         else {
             sprintf(buffer, "Opcode 0x%x", opcode);
         }
+        flags = 0;
     } else {
         strcpy(buffer, dexGetOpcodeName(opcode));
+        flags = dexGetFlagsFromOpcode(insn->opcode);
     }
 
     if (note)
@@ -1630,7 +1632,8 @@
                 offset = (int) insn->vA;
                 break;
             default:
-                LOGE("Unexpected branch format: %d", dalvikFormat);
+                LOGE("Unexpected branch format %d / opcode %#x", dalvikFormat,
+                     opcode);
                 dvmAbort();
                 break;
         }
diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c
index 1095225..c4dbf27 100644
--- a/vm/compiler/Frontend.c
+++ b/vm/compiler/Frontend.c
@@ -288,11 +288,12 @@
 
     /* For lookup only */
     dummyMethodEntry.method = method;
-    realMethodEntry =
-        (CompilerMethodStats *) dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
-                                                   &dummyMethodEntry,
-                                                   (HashCompareFunc) compareMethod,
-                                                   false);
+    realMethodEntry = (CompilerMethodStats *)
+        dvmHashTableLookup(gDvmJit.methodStatsTable,
+                           hashValue,
+                           &dummyMethodEntry,
+                           (HashCompareFunc) compareMethod,
+                           false);
 
     /* This method has never been analyzed before - create an entry */
     if (realMethodEntry == NULL) {
@@ -440,7 +441,7 @@
 #endif
 
     /* If we've already compiled this trace, just return success */
-    if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
+    if (dvmJitGetTraceAddr(startCodePtr) && !info->discardResult) {
         /*
          * Make sure the codeAddress is NULL so that it won't clobber the
          * existing entry.
@@ -588,11 +589,12 @@
         int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
 
         if (flags & kInstrInvoke) {
+            const Method *calleeMethod = (const Method *) currRun[2].meta;
             assert(numInsts == 1);
             CallsiteInfo *callsiteInfo =
                 (CallsiteInfo *)dvmCompilerNew(sizeof(CallsiteInfo), true);
             callsiteInfo->clazz = (ClassObject *)currRun[1].meta;
-            callsiteInfo->method = (Method *)currRun[2].meta;
+            callsiteInfo->method = calleeMethod;
             insn->meta.callsiteInfo = callsiteInfo;
         }
 
@@ -870,7 +872,7 @@
 
     /* Inline transformation @ the MIR level */
     if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
-        dvmCompilerInlineMIR(&cUnit);
+        dvmCompilerInlineMIR(&cUnit, info);
     }
 
     cUnit.numDalvikRegisters = cUnit.method->registersSize;
@@ -921,6 +923,7 @@
     } while (cUnit.assemblerStatus == kRetryAll);
 
     if (cUnit.printMe) {
+        LOGD("Trace Dalvik PC: %p", startCodePtr);
         dvmCompilerCodegenDump(&cUnit);
         LOGD("End %s%s, %d Dalvik instructions",
              desc->method->clazz->descriptor, desc->method->name,
@@ -941,14 +944,6 @@
     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;
 }
 
@@ -1671,7 +1666,7 @@
  * TODO: implementation will be revisited when the trace builder can provide
  * whole-method traces.
  */
-bool dvmCompileMethod(const Method *method)
+bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
 {
     CompilationUnit cUnit;
     const DexCode *dexCode = dvmGetMethodCode(method);
@@ -1680,12 +1675,27 @@
     int numBlocks = 0;
     unsigned int curOffset = 0;
 
+    /* Method already compiled */
+    if (dvmJitGetMethodAddr(codePtr)) {
+        info->codeAddress = NULL;
+        return false;
+    }
+
     memset(&cUnit, 0, sizeof(cUnit));
     cUnit.method = method;
 
+    cUnit.methodJitMode = true;
+
     /* Initialize the block list */
     dvmInitGrowableList(&cUnit.blockList, 4);
 
+    /*
+     * FIXME - PC reconstruction list won't be needed after the codegen routines
+     * are enhanced to true method mode.
+     */
+    /* Initialize the PC reconstruction list */
+    dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
+
     /* Allocate the bit-vector to track the beginning of basic blocks */
     BitVector *tryBlockAddr = dvmCompilerAllocBitVector(dexCode->insnsSize,
                                                         true /* expandable */);
@@ -1789,6 +1799,10 @@
         }
     }
 
+    if (cUnit.printMe) {
+        dvmCompilerDumpCompilationUnit(&cUnit);
+    }
+
     /* Adjust this value accordingly once inlining is performed */
     cUnit.numDalvikRegisters = cUnit.method->registersSize;
 
@@ -1802,10 +1816,41 @@
     /* Perform SSA transformation for the whole method */
     dvmCompilerMethodSSATransformation(&cUnit);
 
-    if (cUnit.printMe) dumpCFG(&cUnit, "/data/tombstones/");
+    dvmCompilerInitializeRegAlloc(&cUnit);  // Needs to happen after SSA naming
 
-    /* Reset the compiler resource pool */
-    dvmCompilerArenaReset();
+    /* Allocate Registers using simple local allocation scheme */
+    dvmCompilerLocalRegAlloc(&cUnit);
+
+    /* Convert MIR to LIR, etc. */
+    dvmCompilerMethodMIR2LIR(&cUnit);
+
+    // Debugging only
+    //dumpCFG(&cUnit, "/data/tombstones/");
+
+    /* Method is not empty */
+    if (cUnit.firstLIRInsn) {
+        /* Convert LIR into machine code. Loop for recoverable retries */
+        do {
+            dvmCompilerAssembleLIR(&cUnit, info);
+            cUnit.assemblerRetries++;
+            if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
+                LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
+                      cUnit.assemblerStatus);
+        } while (cUnit.assemblerStatus == kRetryAll);
+
+        if (cUnit.printMe) {
+            dvmCompilerCodegenDump(&cUnit);
+        }
+
+        if (info->codeAddress) {
+            dvmJitSetCodeAddr(dexCode->insns, info->codeAddress,
+                              info->instructionSet, true, 0);
+            /*
+             * Clear the codeAddress for the enclosing trace to reuse the info
+             */
+            info->codeAddress = NULL;
+        }
+    }
 
     return false;
 }
diff --git a/vm/compiler/InlineTransformation.c b/vm/compiler/InlineTransformation.c
index cab790c..6cf2d43 100644
--- a/vm/compiler/InlineTransformation.c
+++ b/vm/compiler/InlineTransformation.c
@@ -34,7 +34,7 @@
     }
 }
 
-static void inlineGetter(CompilationUnit *cUnit,
+static bool inlineGetter(CompilationUnit *cUnit,
                          const Method *calleeMethod,
                          MIR *invokeMIR,
                          BasicBlock *invokeBB,
@@ -49,7 +49,7 @@
     dexDecodeInstruction(calleeMethod->insns, &getterInsn);
 
     if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &getterInsn))
-        return;
+        return false;
 
     /*
      * Some getters (especially invoked through interface) are not followed
@@ -59,7 +59,7 @@
         (moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT &&
          moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT_OBJECT &&
          moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT_WIDE)) {
-        return;
+        return false;
     }
 
     int dfFlags = dvmCompilerDataFlowAttributes[getterInsn.opcode];
@@ -124,10 +124,10 @@
 #endif
     }
 
-    return;
+    return true;
 }
 
-static void inlineSetter(CompilationUnit *cUnit,
+static bool inlineSetter(CompilationUnit *cUnit,
                          const Method *calleeMethod,
                          MIR *invokeMIR,
                          BasicBlock *invokeBB,
@@ -140,7 +140,7 @@
     dexDecodeInstruction(calleeMethod->insns, &setterInsn);
 
     if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &setterInsn))
-        return;
+        return false;
 
     int dfFlags = dvmCompilerDataFlowAttributes[setterInsn.opcode];
 
@@ -205,17 +205,17 @@
 #endif
     }
 
-    return;
+    return true;
 }
 
-static void tryInlineSingletonCallsite(CompilationUnit *cUnit,
+static bool tryInlineSingletonCallsite(CompilationUnit *cUnit,
                                        const Method *calleeMethod,
                                        MIR *invokeMIR,
                                        BasicBlock *invokeBB,
                                        bool isRange)
 {
     /* Not a Java method */
-    if (dvmIsNativeMethod(calleeMethod)) return;
+    if (dvmIsNativeMethod(calleeMethod)) return false;
 
     CompilerMethodStats *methodStats =
         dvmCompilerAnalyzeMethodBody(calleeMethod, true);
@@ -229,19 +229,20 @@
          * the PC reconstruction or chaining cell).
          */
         invokeBB->needFallThroughBranch = true;
-        return;
+        return true;
     }
 
     if (methodStats->attributes & METHOD_IS_GETTER) {
-        inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, false, isRange);
-        return;
+        return inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, false,
+                            isRange);
     } else if (methodStats->attributes & METHOD_IS_SETTER) {
-        inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, false, isRange);
-        return;
+        return inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, false,
+                            isRange);
     }
+    return false;
 }
 
-static void inlineEmptyVirtualCallee(CompilationUnit *cUnit,
+static bool inlineEmptyVirtualCallee(CompilationUnit *cUnit,
                                      const Method *calleeMethod,
                                      MIR *invokeMIR,
                                      BasicBlock *invokeBB)
@@ -252,37 +253,39 @@
 
     dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, invokeMIRSlow);
     invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+    return true;
 }
 
-static void tryInlineVirtualCallsite(CompilationUnit *cUnit,
+static bool tryInlineVirtualCallsite(CompilationUnit *cUnit,
                                      const Method *calleeMethod,
                                      MIR *invokeMIR,
                                      BasicBlock *invokeBB,
                                      bool isRange)
 {
     /* Not a Java method */
-    if (dvmIsNativeMethod(calleeMethod)) return;
+    if (dvmIsNativeMethod(calleeMethod)) return false;
 
     CompilerMethodStats *methodStats =
         dvmCompilerAnalyzeMethodBody(calleeMethod, true);
 
     /* Empty callee - do nothing by checking the clazz pointer */
     if (methodStats->attributes & METHOD_IS_EMPTY) {
-        inlineEmptyVirtualCallee(cUnit, calleeMethod, invokeMIR, invokeBB);
-        return;
+        return inlineEmptyVirtualCallee(cUnit, calleeMethod, invokeMIR,
+                                        invokeBB);
     }
 
     if (methodStats->attributes & METHOD_IS_GETTER) {
-        inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, true, isRange);
-        return;
+        return inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, true,
+                            isRange);
     } else if (methodStats->attributes & METHOD_IS_SETTER) {
-        inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, true, isRange);
-        return;
+        return inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, true,
+                            isRange);
     }
+    return false;
 }
 
 
-void dvmCompilerInlineMIR(CompilationUnit *cUnit)
+void dvmCompilerInlineMIR(CompilationUnit *cUnit, JitTranslationInfo *info)
 {
     bool isRange = false;
     GrowableListIterator iterator;
@@ -337,8 +340,30 @@
         }
 
         if (calleeMethod) {
-            tryInlineSingletonCallsite(cUnit, calleeMethod, lastMIRInsn, bb,
-                                       isRange);
+            bool inlined = tryInlineSingletonCallsite(cUnit, calleeMethod,
+                                                      lastMIRInsn, bb, isRange);
+            if (!inlined &&
+                !(gDvmJit.disableOpt & (1 << kMethodJit)) &&
+                !dvmIsNativeMethod(calleeMethod)) {
+                CompilerMethodStats *methodStats =
+                    dvmCompilerAnalyzeMethodBody(calleeMethod, true);
+                if ((methodStats->attributes & METHOD_IS_LEAF) &&
+                    !(methodStats->attributes & METHOD_CANNOT_COMPILE)) {
+                    /* Callee has been previously compiled */
+                    if (dvmJitGetMethodAddr(calleeMethod->insns)) {
+                        lastMIRInsn->OptimizationFlags |= MIR_INVOKE_METHOD_JIT;
+                    } else {
+                        /* Compile the callee first */
+                        dvmCompileMethod(calleeMethod, info);
+                        if (dvmJitGetMethodAddr(calleeMethod->insns)) {
+                            lastMIRInsn->OptimizationFlags |=
+                                MIR_INVOKE_METHOD_JIT;
+                        } else {
+                            methodStats->attributes |= METHOD_CANNOT_COMPILE;
+                        }
+                    }
+                }
+            }
             return;
         }
 
@@ -360,8 +385,30 @@
         }
 
         if (calleeMethod) {
-            tryInlineVirtualCallsite(cUnit, calleeMethod, lastMIRInsn, bb,
-                                     isRange);
+            bool inlined = tryInlineVirtualCallsite(cUnit, calleeMethod,
+                                                    lastMIRInsn, bb, isRange);
+            if (!inlined &&
+                !(gDvmJit.disableOpt & (1 << kMethodJit)) &&
+                !dvmIsNativeMethod(calleeMethod)) {
+                CompilerMethodStats *methodStats =
+                    dvmCompilerAnalyzeMethodBody(calleeMethod, true);
+                if ((methodStats->attributes & METHOD_IS_LEAF) &&
+                    !(methodStats->attributes & METHOD_CANNOT_COMPILE)) {
+                    /* Callee has been previously compiled */
+                    if (dvmJitGetMethodAddr(calleeMethod->insns)) {
+                        lastMIRInsn->OptimizationFlags |= MIR_INVOKE_METHOD_JIT;
+                    } else {
+                        /* Compile the callee first */
+                        dvmCompileMethod(calleeMethod, info);
+                        if (dvmJitGetMethodAddr(calleeMethod->insns)) {
+                            lastMIRInsn->OptimizationFlags |=
+                                MIR_INVOKE_METHOD_JIT;
+                        } else {
+                            methodStats->attributes |= METHOD_CANNOT_COMPILE;
+                        }
+                    }
+                }
+            }
             return;
         }
     }
diff --git a/vm/compiler/MethodSSATransformation.c b/vm/compiler/MethodSSATransformation.c
index 60eea33..eaee24a 100644
--- a/vm/compiler/MethodSSATransformation.c
+++ b/vm/compiler/MethodSSATransformation.c
@@ -29,8 +29,8 @@
     /* 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->taken) recordDFSPreOrder(cUnit, block->taken);
     if (block->successorBlockList.blockListType != kNotUsed) {
         GrowableListIterator iterator;
         dvmGrowableListIteratorInit(&block->successorBlockList.blocks,
@@ -185,13 +185,6 @@
             }
         }
     }
-    if (cUnit->printMe) {
-        char blockName[BLOCK_NAME_LEN];
-        dvmGetBlockName(bb, blockName);
-        dvmDumpBlockBitVector(blockList, blockName, bb->domFrontier,
-                              cUnit->numBlocks);
-    }
-
     return true;
 }
 
@@ -399,11 +392,11 @@
     int dalvikReg;
     const GrowableList *blockList = &cUnit->blockList;
     BitVector *phiBlocks =
-        dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false);
+        dvmCompilerAllocBitVector(cUnit->numBlocks, false);
     BitVector *tmpBlocks =
-        dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false);
+        dvmCompilerAllocBitVector(cUnit->numBlocks, false);
     BitVector *inputBlocks =
-        dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false);
+        dvmCompilerAllocBitVector(cUnit->numBlocks, false);
 
     cUnit->tempDalvikRegisterV =
         dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false);
diff --git a/vm/compiler/codegen/CompilerCodegen.h b/vm/compiler/codegen/CompilerCodegen.h
index 70a2bbd..9cd4847 100644
--- a/vm/compiler/codegen/CompilerCodegen.h
+++ b/vm/compiler/codegen/CompilerCodegen.h
@@ -28,6 +28,9 @@
 /* Lower middle-level IR to low-level IR */
 void dvmCompilerMIR2LIR(CompilationUnit *cUnit);
 
+/* Lower middle-level IR to low-level IR for the whole method */
+void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit);
+
 /* Assemble LIR into machine code */
 void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info);
 
diff --git a/vm/compiler/codegen/Optimizer.h b/vm/compiler/codegen/Optimizer.h
index d42fe87..2b05476 100644
--- a/vm/compiler/codegen/Optimizer.h
+++ b/vm/compiler/codegen/Optimizer.h
@@ -29,6 +29,7 @@
     kTrackLiveTemps,
     kSuppressLoads,
     kMethodInlining,
+    kMethodJit,
 } optControlVector;
 
 /* Forward declarations */
diff --git a/vm/compiler/codegen/arm/ArchFactory.c b/vm/compiler/codegen/arm/ArchFactory.c
index 581ba39..805a6fc 100644
--- a/vm/compiler/codegen/arm/ArchFactory.c
+++ b/vm/compiler/codegen/arm/ArchFactory.c
@@ -32,7 +32,21 @@
                                TGT_LIR *pcrLabel)
 {
     TGT_LIR *branch = genCmpImmBranch(cUnit, cond, reg, checkValue);
-    return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+    if (cUnit->methodJitMode) {
+        BasicBlock *bb = cUnit->curBlock;
+        if (bb->taken) {
+            ArmLIR  *exceptionLabel = (ArmLIR *) cUnit->blockLabelList;
+            exceptionLabel += bb->taken->id;
+            branch->generic.target = (LIR *) exceptionLabel;
+            return exceptionLabel;
+        } else {
+            LOGE("Catch blocks not handled yet");
+            dvmAbort();
+            return NULL;
+        }
+    } else {
+        return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+    }
 }
 
 /*
diff --git a/vm/compiler/codegen/arm/ArchUtility.c b/vm/compiler/codegen/arm/ArchUtility.c
index 7a4d307..5af4f3b 100644
--- a/vm/compiler/codegen/arm/ArchUtility.c
+++ b/vm/compiler/codegen/arm/ArchUtility.c
@@ -195,9 +195,10 @@
                        }
                        break;
                    case 't':
-                       sprintf(tbuf,"0x%08x",
+                       sprintf(tbuf,"0x%08x (L%p)",
                                (int) baseAddr + lir->generic.offset + 4 +
-                               (operand << 1));
+                               (operand << 1),
+                               lir->generic.target);
                        break;
                    case 'u': {
                        int offset_1 = lir->operands[0];
@@ -302,8 +303,6 @@
         case kArmPseudoSSARep:
             DUMP_SSA_REP(LOGD("-------- %s\n", (char *) dest));
             break;
-        case kArmPseudoTargetLabel:
-            break;
         case kArmPseudoChainingCellBackwardBranch:
             LOGD("-------- chaining cell (backward branch): 0x%04x\n", dest);
             break;
@@ -344,8 +343,9 @@
         case kArmPseudoEHBlockLabel:
             LOGD("Exception_Handling:\n");
             break;
+        case kArmPseudoTargetLabel:
         case kArmPseudoNormalBlockLabel:
-            LOGD("L%#06x:\n", dest);
+            LOGD("L%p:\n", lir);
             break;
         default:
             if (lir->isNop && !dumpNop) {
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c
index 577f683..efae8fd 100644
--- a/vm/compiler/codegen/arm/Assemble.c
+++ b/vm/compiler/codegen/arm/Assemble.c
@@ -1032,6 +1032,17 @@
 
             lir->operands[0] = (delta >> 12) & 0x7ff;
             NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff;
+        } else if (lir->opcode == kThumbBl1) {
+            assert(NEXT_LIR(lir)->opcode == kThumbBl2);
+            /* Both curPC and target are Thumb */
+            intptr_t curPC = startAddr + lir->generic.offset + 4;
+            intptr_t target = lir->operands[1];
+
+            int delta = target - curPC;
+            assert((delta >= -(1<<22)) && (delta <= ((1<<22)-2)));
+
+            lir->operands[0] = (delta >> 12) & 0x7ff;
+            NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff;
         }
 
         ArmEncodingMap *encoder = &EncodingMap[lir->opcode];
@@ -1213,8 +1224,8 @@
     int i;
     ChainCellCounts chainCellCounts;
     int descSize =
-        cUnit->wholeMethod ? 0 : jitTraceDescriptionSize(cUnit->traceDesc);
-    int chainingCellGap;
+        cUnit->methodJitMode ? 0 : jitTraceDescriptionSize(cUnit->traceDesc);
+    int chainingCellGap = 0;
 
     info->instructionSet = cUnit->instructionSet;
 
@@ -1240,30 +1251,34 @@
     /* Const values have to be word aligned */
     offset = (offset + 3) & ~3;
 
-    /*
-     * Get the gap (# of u4) between the offset of chaining cell count and
-     * the bottom of real chaining cells. If the translation has chaining
-     * cells, the gap is guaranteed to be multiples of 4.
-     */
-    chainingCellGap = (offset - cUnit->chainingCellBottom->offset) >> 2;
-
-    /* Add space for chain cell counts & trace description */
     u4 chainCellOffset = offset;
-    ArmLIR *chainCellOffsetLIR = (ArmLIR *) cUnit->chainCellOffsetLIR;
-    assert(chainCellOffsetLIR);
-    assert(chainCellOffset < 0x10000);
-    assert(chainCellOffsetLIR->opcode == kArm16BitData &&
-           chainCellOffsetLIR->operands[0] == CHAIN_CELL_OFFSET_TAG);
+    ArmLIR *chainCellOffsetLIR = NULL;
 
-    /*
-     * Adjust the CHAIN_CELL_OFFSET_TAG LIR's offset to remove the
-     * space occupied by the pointer to the trace profiling counter.
-     */
-    chainCellOffsetLIR->operands[0] = chainCellOffset - 4;
+    if (!cUnit->methodJitMode) {
+        /*
+         * Get the gap (# of u4) between the offset of chaining cell count and
+         * the bottom of real chaining cells. If the translation has chaining
+         * cells, the gap is guaranteed to be multiples of 4.
+         */
+        chainingCellGap = (offset - cUnit->chainingCellBottom->offset) >> 2;
 
-    offset += sizeof(chainCellCounts) + descSize;
+        /* Add space for chain cell counts & trace description */
+        chainCellOffsetLIR = (ArmLIR *) cUnit->chainCellOffsetLIR;
+        assert(chainCellOffsetLIR);
+        assert(chainCellOffset < 0x10000);
+        assert(chainCellOffsetLIR->opcode == kArm16BitData &&
+               chainCellOffsetLIR->operands[0] == CHAIN_CELL_OFFSET_TAG);
 
-    assert((offset & 0x3) == 0);  /* Should still be word aligned */
+        /*
+         * Adjust the CHAIN_CELL_OFFSET_TAG LIR's offset to remove the
+         * space occupied by the pointer to the trace profiling counter.
+         */
+        chainCellOffsetLIR->operands[0] = chainCellOffset - 4;
+
+        offset += sizeof(chainCellCounts) + descSize;
+
+        assert((offset & 0x3) == 0);  /* Should still be word aligned */
+    }
 
     /* Set up offsets for literals */
     cUnit->dataOffset = offset;
@@ -1301,8 +1316,10 @@
             break;
         case kRetryAll:
             if (cUnit->assemblerRetries < MAX_ASSEMBLER_RETRIES) {
-                /* Restore pristine chain cell marker on retry */
-                chainCellOffsetLIR->operands[0] = CHAIN_CELL_OFFSET_TAG;
+                if (!cUnit->methodJitMode) {
+                    /* Restore pristine chain cell marker on retry */
+                    chainCellOffsetLIR->operands[0] = CHAIN_CELL_OFFSET_TAG;
+                }
                 return;
             }
             /* Too many retries - reset and try cutting the trace in half */
@@ -1351,21 +1368,24 @@
     memcpy((char*)cUnit->baseAddr, cUnit->codeBuffer, chainCellOffset);
     gDvmJit.numCompilations++;
 
-    /* Install the chaining cell counts */
-    for (i=0; i< kChainingCellGap; i++) {
-        chainCellCounts.u.count[i] = cUnit->numChainingCells[i];
+    if (!cUnit->methodJitMode) {
+        /* Install the chaining cell counts */
+        for (i=0; i< kChainingCellGap; i++) {
+            chainCellCounts.u.count[i] = cUnit->numChainingCells[i];
+        }
+
+        /* Set the gap number in the chaining cell count structure */
+        chainCellCounts.u.count[kChainingCellGap] = chainingCellGap;
+
+        memcpy((char*)cUnit->baseAddr + chainCellOffset, &chainCellCounts,
+               sizeof(chainCellCounts));
+
+        /* Install the trace description */
+        memcpy((char*) cUnit->baseAddr + chainCellOffset +
+                       sizeof(chainCellCounts),
+               cUnit->traceDesc, descSize);
     }
 
-    /* Set the gap number in the chaining cell count structure */
-    chainCellCounts.u.count[kChainingCellGap] = chainingCellGap;
-
-    memcpy((char*)cUnit->baseAddr + chainCellOffset, &chainCellCounts,
-           sizeof(chainCellCounts));
-
-    /* Install the trace description */
-    memcpy((char*)cUnit->baseAddr + chainCellOffset + sizeof(chainCellCounts),
-           cUnit->traceDesc, descSize);
-
     /* Write the literals directly into the code cache */
     installDataContent(cUnit);
 
@@ -1609,7 +1629,7 @@
         PROTECT_CODE_CACHE(cell, sizeof(*cell));
         goto done;
     }
-    int tgtAddr = (int) dvmJitGetCodeAddr(method->insns);
+    int tgtAddr = (int) dvmJitGetTraceAddr(method->insns);
 
     /*
      * Compilation not made yet for the callee. Reset the counter to a small
@@ -1808,14 +1828,16 @@
 
         for (i = 0; i < gDvmJit.jitTableSize; i++) {
             if (gDvmJit.pJitEntryTable[i].dPC &&
-                   gDvmJit.pJitEntryTable[i].codeAddress &&
-                   (gDvmJit.pJitEntryTable[i].codeAddress !=
-                    dvmCompilerGetInterpretTemplate())) {
+                !gDvmJit.pJitEntryTable[i].u.info.isMethodEntry &&
+                gDvmJit.pJitEntryTable[i].codeAddress &&
+                (gDvmJit.pJitEntryTable[i].codeAddress !=
+                 dvmCompilerGetInterpretTemplate())) {
                 u4* lastAddress;
                 lastAddress =
                       dvmJitUnchain(gDvmJit.pJitEntryTable[i].codeAddress);
                 if (lowAddress == NULL ||
-                      (u4*)gDvmJit.pJitEntryTable[i].codeAddress < lowAddress)
+                      (u4*)gDvmJit.pJitEntryTable[i].codeAddress <
+                      lowAddress)
                     lowAddress = lastAddress;
                 if (lastAddress > highAddress)
                     highAddress = lastAddress;
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index f017b31..8e1b09c 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -904,24 +904,28 @@
 /* Perform the actual operation for OP_RETURN_* */
 static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
 {
-    genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
-        TEMPLATE_RETURN_PROF :
-        TEMPLATE_RETURN);
+    if (!cUnit->methodJitMode) {
+        genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+            TEMPLATE_RETURN_PROF :
+            TEMPLATE_RETURN);
 #if defined(WITH_JIT_TUNING)
-    gDvmJit.returnOp++;
+        gDvmJit.returnOp++;
 #endif
-    int dPC = (int) (cUnit->method->insns + mir->offset);
-    /* Insert branch, but defer setting of target */
-    ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
-    /* Set up the place holder to reconstruct this Dalvik PC */
-    ArmLIR *pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
-    pcrLabel->opcode = kArmPseudoPCReconstructionCell;
-    pcrLabel->operands[0] = dPC;
-    pcrLabel->operands[1] = mir->offset;
-    /* Insert the place holder to the growable list */
-    dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel);
-    /* Branch to the PC reconstruction code */
-    branch->generic.target = (LIR *) pcrLabel;
+        int dPC = (int) (cUnit->method->insns + mir->offset);
+        /* Insert branch, but defer setting of target */
+        ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
+        /* Set up the place holder to reconstruct this Dalvik PC */
+        ArmLIR *pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+        pcrLabel->opcode = kArmPseudoPCReconstructionCell;
+        pcrLabel->operands[0] = dPC;
+        pcrLabel->operands[1] = mir->offset;
+        /* Insert the place holder to the growable list */
+        dvmInsertGrowableList(&cUnit->pcReconstructionList,
+                              (intptr_t) pcrLabel);
+        /* Branch to the PC reconstruction code */
+        branch->generic.target = (LIR *) pcrLabel;
+    }
+    /* TODO: Move result to InterpState for non-void returns */
 }
 
 static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
@@ -3197,6 +3201,25 @@
     return false;
 }
 
+/* "this" pointer is already in r0 */
+static void genValidationForMethodCallee(CompilationUnit *cUnit, MIR *mir,
+                                            ArmLIR **classCheck)
+{
+    CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
+    dvmCompilerLockAllTemps(cUnit);
+
+    loadConstant(cUnit, r1, (int) callsiteInfo->clazz);
+
+    loadWordDisp(cUnit, r0, offsetof(Object, clazz), r2);
+    /* Branch to the slow path if classes are not equal */
+    opRegReg(cUnit, kOpCmp, r1, r2);
+    /*
+     * Set the misPredBranchOver target so that it will be generated when the
+     * code for the non-optimized invoke is generated.
+     */
+    *classCheck = opCondBranch(cUnit, kArmCondNe);
+}
+
 static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
                                BasicBlock *bb, ArmLIR *labelList)
 {
@@ -3229,6 +3252,29 @@
             else
                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
 
+
+            if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
+                const Method *calleeMethod = mir->meta.callsiteInfo->method;
+                void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
+                if (calleeAddr) {
+                    ArmLIR *classCheck;
+                    cUnit->printMe = true;
+                    genValidationForMethodCallee(cUnit, mir, &classCheck);
+                    newLIR2(cUnit, kThumbBl1, (int) calleeAddr,
+                            (int) calleeAddr);
+                    newLIR2(cUnit, kThumbBl2, (int) calleeAddr,
+                            (int) calleeAddr);
+                    genUnconditionalBranch(cUnit, retChainingCell);
+
+                    /* Target of slow path */
+                    ArmLIR *slowPathLabel = newLIR0(cUnit,
+                                                    kArmPseudoTargetLabel);
+
+                    slowPathLabel->defMask = ENCODE_ALL;
+                    classCheck->generic.target = (LIR *) slowPathLabel;
+                }
+            }
+
             genInvokeVirtualCommon(cUnit, mir, methodIndex,
                                    retChainingCell,
                                    predChainingCell,
diff --git a/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c b/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c
index f584ce7..c857fa5 100644
--- a/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c
+++ b/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c
@@ -79,6 +79,10 @@
         LOGE("InterpState.jitToInterpEntries size overflow");
         dvmAbort();
     }
+
+    /* No method JIT for Thumb backend */
+    gDvmJit.disableOpt |= (1 << kMethodJit);
+
     return true;
 }
 
diff --git a/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c b/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c
index d17965d..a2d77ea 100644
--- a/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c
+++ b/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c
@@ -49,5 +49,8 @@
 /* MIR2LIR dispatcher and architectural independent codegen routines */
 #include "../CodegenDriver.c"
 
+/* Dummy driver for method-based JIT */
+#include "../armv5te/MethodCodegenDriver.c"
+
 /* Architecture manifest */
 #include "ArchVariant.c"
diff --git a/vm/compiler/codegen/arm/armv5te/ArchVariant.c b/vm/compiler/codegen/arm/armv5te/ArchVariant.c
index cf48d4e..0f16839 100644
--- a/vm/compiler/codegen/arm/armv5te/ArchVariant.c
+++ b/vm/compiler/codegen/arm/armv5te/ArchVariant.c
@@ -79,6 +79,10 @@
         LOGE("InterpState.jitToInterpEntries size overflow");
         dvmAbort();
     }
+
+    /* No method JIT for Thumb backend */
+    gDvmJit.disableOpt |= (1 << kMethodJit);
+
     return true;
 }
 
diff --git a/vm/compiler/codegen/arm/armv5te/Codegen.c b/vm/compiler/codegen/arm/armv5te/Codegen.c
index 03c1435..f74d968 100644
--- a/vm/compiler/codegen/arm/armv5te/Codegen.c
+++ b/vm/compiler/codegen/arm/armv5te/Codegen.c
@@ -49,5 +49,8 @@
 /* MIR2LIR dispatcher and architectural independent codegen routines */
 #include "../CodegenDriver.c"
 
+/* Dummy driver for method-based JIT */
+#include "MethodCodegenDriver.c"
+
 /* Architecture manifest */
 #include "ArchVariant.c"
diff --git a/vm/compiler/codegen/arm/armv5te/MethodCodegenDriver.c b/vm/compiler/codegen/arm/armv5te/MethodCodegenDriver.c
new file mode 100644
index 0000000..20779f3
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv5te/MethodCodegenDriver.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit)
+{
+    LOGE("Method-based JIT not supported for the v5te target");
+    dvmAbort();
+}
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c b/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c
index 7fcf031..3df1095 100644
--- a/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c
+++ b/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c
@@ -74,6 +74,10 @@
         LOGE("InterpState.jitToInterpEntries size overflow");
         dvmAbort();
     }
+
+    /* FIXME - comment out the following to enable method-based JIT */
+    gDvmJit.disableOpt |= (1 << kMethodJit);
+
     return true;
 }
 
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c b/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
index f0b7722..439add5 100644
--- a/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
+++ b/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
@@ -49,5 +49,8 @@
 /* MIR2LIR dispatcher and architectural independent codegen routines */
 #include "../CodegenDriver.c"
 
+/* Driver for method-based JIT */
+#include "MethodCodegenDriver.c"
+
 /* Architecture manifest */
 #include "ArchVariant.c"
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.c b/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.c
new file mode 100644
index 0000000..c25ab83
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+/* Handle the content in each basic block */
+static bool methodBlockCodeGen(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    MIR *mir;
+    ArmLIR *labelList = (ArmLIR *) cUnit->blockLabelList;
+    int blockId = bb->id;
+
+    cUnit->curBlock = bb;
+    labelList[blockId].operands[0] = bb->startOffset;
+
+    /* Insert the block label */
+    labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
+    dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
+
+    dvmCompilerClobberAllRegs(cUnit);
+    dvmCompilerResetNullCheck(cUnit);
+
+    ArmLIR *headLIR = NULL;
+
+    if (bb->blockType == kMethodEntryBlock) {
+        opImm(cUnit, kOpPush, (1 << rlr | 1 << rFP));
+        opRegImm(cUnit, kOpSub, rFP,
+                 sizeof(StackSaveArea) + cUnit->method->registersSize * 4);
+
+    } else if (bb->blockType == kMethodExitBlock) {
+        opImm(cUnit, kOpPop, (1 << rpc | 1 << rFP));
+    }
+
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+
+        dvmCompilerResetRegPool(cUnit);
+        if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
+            dvmCompilerClobberAllRegs(cUnit);
+        }
+
+        if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
+            dvmCompilerResetDefTracking(cUnit);
+        }
+
+        Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+        InstructionFormat dalvikFormat =
+            dexGetFormatFromOpcode(dalvikOpcode);
+
+        ArmLIR *boundaryLIR;
+
+        /*
+         * Don't generate the boundary LIR unless we are debugging this
+         * trace or we need a scheduling barrier.
+         */
+        if (headLIR == NULL || cUnit->printMe == true) {
+            boundaryLIR =
+                newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary,
+                        mir->offset,
+                        (int) dvmCompilerGetDalvikDisassembly(
+                            &mir->dalvikInsn, ""));
+            /* Remember the first LIR for this block */
+            if (headLIR == NULL) {
+                headLIR = boundaryLIR;
+                /* Set the first boundaryLIR as a scheduling barrier */
+                headLIR->defMask = ENCODE_ALL;
+            }
+        }
+
+        /* Don't generate the SSA annotation unless verbose mode is on */
+        if (cUnit->printMe && mir->ssaRep) {
+            char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
+            newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
+        }
+
+        bool notHandled;
+        switch (dalvikFormat) {
+            case kFmt10t:
+            case kFmt20t:
+            case kFmt30t:
+                notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
+                          mir, bb, labelList);
+                break;
+            case kFmt10x:
+                notHandled = handleFmt10x(cUnit, mir);
+                break;
+            case kFmt11n:
+            case kFmt31i:
+                notHandled = handleFmt11n_Fmt31i(cUnit, mir);
+                break;
+            case kFmt11x:
+                notHandled = handleFmt11x(cUnit, mir);
+                break;
+            case kFmt12x:
+                notHandled = handleFmt12x(cUnit, mir);
+                break;
+            case kFmt20bc:
+            case kFmt40sc:
+                notHandled = handleFmt20bc_Fmt40sc(cUnit, mir);
+                break;
+            case kFmt21c:
+            case kFmt31c:
+            case kFmt41c:
+                notHandled = handleFmt21c_Fmt31c_Fmt41c(cUnit, mir);
+                break;
+            case kFmt21h:
+                notHandled = handleFmt21h(cUnit, mir);
+                break;
+            case kFmt21s:
+                notHandled = handleFmt21s(cUnit, mir);
+                break;
+            case kFmt21t:
+                notHandled = handleFmt21t(cUnit, mir, bb, labelList);
+                break;
+            case kFmt22b:
+            case kFmt22s:
+                notHandled = handleFmt22b_Fmt22s(cUnit, mir);
+                break;
+            case kFmt22c:
+            case kFmt52c:
+                notHandled = handleFmt22c_Fmt52c(cUnit, mir);
+                break;
+            case kFmt22cs:
+                notHandled = handleFmt22cs(cUnit, mir);
+                break;
+            case kFmt22t:
+                notHandled = handleFmt22t(cUnit, mir, bb, labelList);
+                break;
+            case kFmt22x:
+            case kFmt32x:
+                notHandled = handleFmt22x_Fmt32x(cUnit, mir);
+                break;
+            case kFmt23x:
+                notHandled = handleFmt23x(cUnit, mir);
+                break;
+            case kFmt31t:
+                notHandled = handleFmt31t(cUnit, mir);
+                break;
+            case kFmt3rc:
+            case kFmt35c:
+            case kFmt5rc:
+                notHandled = handleFmt35c_3rc_5rc(cUnit, mir, bb,
+                                              labelList);
+                break;
+            case kFmt3rms:
+            case kFmt35ms:
+                notHandled = handleFmt35ms_3rms(cUnit, mir, bb,
+                                                labelList);
+                break;
+            case kFmt35mi:
+            case kFmt3rmi:
+                notHandled = handleExecuteInline(cUnit, mir);
+                break;
+            case kFmt51l:
+                notHandled = handleFmt51l(cUnit, mir);
+                break;
+            default:
+                notHandled = true;
+                break;
+        }
+
+        /* FIXME - to be implemented */
+        if (notHandled == true && dalvikOpcode >= kNumPackedOpcodes) {
+            notHandled = false;
+        }
+
+        if (notHandled) {
+            LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
+                 mir->offset,
+                 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
+                 dalvikFormat);
+            dvmCompilerAbort(cUnit);
+            break;
+        }
+    }
+
+    if (headLIR) {
+        /*
+         * Eliminate redundant loads/stores and delay stores into later
+         * slots
+         */
+        dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
+                                           cUnit->lastLIRInsn);
+
+        /*
+         * Generate an unconditional branch to the fallthrough block.
+         */
+        if (bb->fallThrough) {
+            genUnconditionalBranch(cUnit,
+                                   &labelList[bb->fallThrough->id]);
+        }
+    }
+    return false;
+}
+
+void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit)
+{
+    // FIXME - enable method compilation for selected routines here
+    if (strcmp(cUnit->method->name, "add")) return;
+
+    /* Used to hold the labels of each block */
+    cUnit->blockLabelList =
+        (void *) dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
+
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
+                                          kPreOrderDFSTraversal,
+                                          false /* isIterative */);
+
+    dvmCompilerApplyGlobalOptimizations(cUnit);
+
+    // FIXME - temporarily enable verbose printing for all methods
+    cUnit->printMe = true;
+
+#if defined(WITH_SELF_VERIFICATION)
+    selfVerificationBranchInsertPass(cUnit);
+#endif
+}
diff --git a/vm/compiler/codegen/arm/armv7-a/ArchVariant.c b/vm/compiler/codegen/arm/armv7-a/ArchVariant.c
index 7fcf031..3df1095 100644
--- a/vm/compiler/codegen/arm/armv7-a/ArchVariant.c
+++ b/vm/compiler/codegen/arm/armv7-a/ArchVariant.c
@@ -74,6 +74,10 @@
         LOGE("InterpState.jitToInterpEntries size overflow");
         dvmAbort();
     }
+
+    /* FIXME - comment out the following to enable method-based JIT */
+    gDvmJit.disableOpt |= (1 << kMethodJit);
+
     return true;
 }
 
diff --git a/vm/compiler/codegen/arm/armv7-a/Codegen.c b/vm/compiler/codegen/arm/armv7-a/Codegen.c
index 05dda0c..36771ef 100644
--- a/vm/compiler/codegen/arm/armv7-a/Codegen.c
+++ b/vm/compiler/codegen/arm/armv7-a/Codegen.c
@@ -49,5 +49,8 @@
 /* MIR2LIR dispatcher and architectural independent codegen routines */
 #include "../CodegenDriver.c"
 
+/* Driver for method-based JIT */
+#include "../armv7-a-neon/MethodCodegenDriver.c"
+
 /* Architecture manifest */
 #include "ArchVariant.c"