Implement method inlining for getters/setters

Changes include:
1) Force the trace that ends with an invoke instruction to include
   the next instruction if it is a move-result (because both need
   to be turned into no-ops if callee is inlined).
2) Interpreter entry point/trace builder changes so that return
   target won't automatically be considered as trace starting points
   (to avoid duplicate traces that include the move result
   instructions).
3) Codegen changes to handle getters/setters invoked from both
   monomorphic and polymorphic callsites.
4) Extend/fix self-verification to form identical trace regions and
   handle traces with inlined callees.
5) Apply touchups to the method based parsing - still not in use.

Change-Id: I116b934df01bf9ada6d5a25187510e352bccd13c
diff --git a/vm/Dvm.mk b/vm/Dvm.mk
index 8626375..c624258 100644
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -220,6 +220,7 @@
 	compiler/Compiler.c \
 	compiler/Frontend.c \
 	compiler/Utility.c \
+	compiler/InlineTransformation.c \
 	compiler/IntermediateRep.c \
 	compiler/Dataflow.c \
 	compiler/Loop.c \
diff --git a/vm/Globals.h b/vm/Globals.h
index 7bed2e3..5341d26 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -840,6 +840,10 @@
     int                invokeMonomorphic;
     int                invokePolymorphic;
     int                invokeNative;
+    int                invokeMonoGetterInlined;
+    int                invokeMonoSetterInlined;
+    int                invokePolyGetterInlined;
+    int                invokePolySetterInlined;
     int                returnOp;
     int                icPatchInit;
     int                icPatchLockFree;
diff --git a/vm/Thread.h b/vm/Thread.h
index f00b0df..204135a 100644
--- a/vm/Thread.h
+++ b/vm/Thread.h
@@ -171,6 +171,10 @@
      *             matter)
      */
     void*       inJitCodeCache;
+#if defined(WITH_SELF_VERIFICATION)
+    /* Buffer for register state during self verification */
+    struct ShadowSpace* shadowSpace;
+#endif
 #endif
 
     /* JNI local reference tracking */
@@ -248,11 +252,6 @@
     const u2*   currentPc2;
 #endif
 
-#if defined(WITH_SELF_VERIFICATION)
-    /* Buffer for register state during self verification */
-    struct ShadowSpace* shadowSpace;
-#endif
-
     /* system thread state */
     SystemThread* systemThread;
 } Thread;
diff --git a/vm/compiler/Compiler.c b/vm/compiler/Compiler.c
index 2368dae..2b0ad52 100644
--- a/vm/compiler/Compiler.c
+++ b/vm/compiler/Compiler.c
@@ -95,6 +95,7 @@
     newOrder->pc = pc;
     newOrder->kind = kind;
     newOrder->info = info;
+    newOrder->result.methodCompilationAborted = NULL;
     newOrder->result.codeAddress = NULL;
     newOrder->result.discardResult =
         (kind == kWorkOrderTraceDebug) ? true : false;
@@ -351,9 +352,10 @@
 
     dvmLockMutex(&gDvmJit.compilerLock);
 
-#if defined(WITH_JIT_TUNING)
     /* Track method-level compilation statistics */
     gDvmJit.methodStatsTable =  dvmHashTableCreate(32, NULL);
+
+#if defined(WITH_JIT_TUNING)
     gDvm.verboseShutdown = true;
 #endif
 
@@ -626,8 +628,10 @@
                     }
                     if (aborted || !compileOK) {
                         dvmCompilerArenaReset();
-                        work.result.codeAddress = dvmCompilerGetInterpretTemplate();
-                    } else if (!work.result.discardResult) {
+                    } else if (!work.result.discardResult &&
+                               work.result.codeAddress) {
+                        /* Make sure that proper code addr is installed */
+                        assert(work.result.codeAddress != NULL);
                         dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
                                           work.result.instructionSet);
                     }
diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h
index dae46fc..1d074f2 100644
--- a/vm/compiler/Compiler.h
+++ b/vm/compiler/Compiler.h
@@ -87,6 +87,7 @@
     void *codeAddress;
     JitInstructionSetType instructionSet;
     bool discardResult;         // Used for debugging divergence and IC patching
+    bool methodCompilationAborted;  // Cannot compile the whole method
     Thread *requestingThread;   // For debugging purpose
 } JitTranslationInfo;
 
@@ -141,8 +142,8 @@
     kSVSStart = 1,          // Shadow space set up, running compiled code
     kSVSPunt = 2,           // Exiting compiled code by punting
     kSVSSingleStep = 3,     // Exiting compiled code by single stepping
-    kSVSTraceSelectNoChain = 4,// Exiting compiled code by trace select no chain
-    kSVSTraceSelect = 5,    // Exiting compiled code by trace select
+    kSVSNoProfile = 4,      // Exiting compiled code and don't collect profiles
+    kSVSTraceSelect = 5,    // Exiting compiled code and compile the next pc
     kSVSNormal = 6,         // Exiting compiled code normally
     kSVSNoChain = 7,        // Exiting compiled code by no chain
     kSVSBackwardBranch = 8, // Exiting compiled code with backward branch trace
@@ -158,21 +159,41 @@
 } jitHint;
 
 /*
- * Element of a Jit trace description.  Describes a contiguous
- * sequence of Dalvik byte codes, the last of which can be
- * associated with a hint.
- * Dalvik byte code
+ * Element of a Jit trace description. If the isCode bit is set, it describes
+ * a contiguous sequence of Dalvik byte codes.
  */
 typedef struct {
-    u2    startOffset;       // Starting offset for trace run
+    unsigned isCode:1;       // If set denotes code fragments
     unsigned numInsts:8;     // Number of Byte codes in run
     unsigned runEnd:1;       // Run ends with last byte code
-    jitHint  hint:7;         // Hint to apply to final code of run
+    jitHint  hint:6;         // Hint to apply to final code of run
+    u2    startOffset;       // Starting offset for trace run
 } JitCodeDesc;
 
+/*
+ * A complete list of trace runs passed to the compiler looks like the
+ * following:
+ *   frag1
+ *   frag2
+ *   frag3
+ *   meta1
+ *   meta2
+ *   frag4
+ *
+ * frags 1-4 have the "isCode" field set, and metas 1-2 are plain pointers or
+ * pointers to auxiliary data structures as long as the LSB is null.
+ * The meaning of the meta content is loosely defined. It is usually the code
+ * fragment right before the first meta field (frag3 in this case) to
+ * understand and parse them. Frag4 could be a dummy one with 0 "numInsts" but
+ * the "runEnd" field set.
+ *
+ * For example, if a trace run contains a method inlining target, the class
+ * type of "this" and the currently resolved method pointer are two instances
+ * of meta information stored there.
+ */
 typedef union {
     JitCodeDesc frag;
-    void*       hint;
+    void*       meta;
 } JitTraceRun;
 
 /*
@@ -183,16 +204,42 @@
  */
 typedef struct {
     const Method* method;
-    JitTraceRun trace[];
+    JitTraceRun trace[0];       // Variable-length trace descriptors
 } JitTraceDescription;
 
+typedef enum JitMethodAttributes {
+    kIsCallee = 0,      /* Code is part of a callee (invoked by a hot trace) */
+    kIsHot,             /* Code is part of a hot trace */
+    kIsLeaf,            /* Method is leaf */
+    kIsEmpty,           /* Method is empty */
+    kIsThrowFree,       /* Method doesn't throw */
+    kIsGetter,          /* Method fits the getter pattern */
+    kIsSetter,          /* Method fits the setter pattern */
+} JitMethodAttributes;
+
+#define METHOD_IS_CALLEE        (1 << kIsCallee)
+#define METHOD_IS_HOT           (1 << kIsHot)
+#define METHOD_IS_LEAF          (1 << kIsLeaf)
+#define METHOD_IS_EMPTY         (1 << kIsEmpty)
+#define METHOD_IS_THROW_FREE    (1 << kIsThrowFree)
+#define METHOD_IS_GETTER        (1 << kIsGetter)
+#define METHOD_IS_SETTER        (1 << kIsSetter)
+
 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
+    int attributes;             // attribute vector
 } CompilerMethodStats;
 
+struct CompilationUnit;
+struct BasicBlock;
+struct SSARepresentation;
+struct GrowableList;
+struct JitEntry;
+struct MIR;
+
 bool dvmCompilerSetupCodeCache(void);
 bool dvmCompilerArchInit(void);
 void dvmCompilerArchDump(void);
@@ -200,7 +247,12 @@
 void dvmCompilerShutdown(void);
 bool dvmCompilerWorkEnqueue(const u2* pc, WorkOrderKind kind, void* info);
 void *dvmCheckCodeCache(void *method);
-bool dvmCompileMethod(const Method *method, JitTranslationInfo *info);
+CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
+                                                  bool isCallee);
+bool dvmCompilerCanIncludeThisInstruction(const Method *method,
+                                          const DecodedInstruction *insn);
+bool dvmCompileMethod(struct CompilationUnit *cUnit, const Method *method,
+                      JitTranslationInfo *info);
 bool dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts,
                      JitTranslationInfo *info, jmp_buf *bailPtr);
 void dvmCompilerDumpStats(void);
@@ -208,13 +260,7 @@
 void dvmJitUnchainAll(void);
 void dvmCompilerSortAndPrintTraceProfiles(void);
 void dvmCompilerPerformSafePointChecks(void);
-
-struct CompilationUnit;
-struct BasicBlock;
-struct SSARepresentation;
-struct GrowableList;
-struct JitEntry;
-
+void dvmCompilerInlineMIR(struct CompilationUnit *cUnit);
 void dvmInitializeSSAConversion(struct CompilationUnit *cUnit);
 int dvmConvertSSARegToDalvik(struct CompilationUnit *cUnit, int ssaReg);
 void dvmCompilerLoopOpt(struct CompilationUnit *cUnit);
@@ -227,7 +273,7 @@
                                       struct BasicBlock *bb);
 void dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit,
                                        struct BasicBlock *bb);
-char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn);
+char *dvmCompilerGetDalvikDisassembly(DecodedInstruction *insn, char *note);
 char *dvmCompilerGetSSAString(struct CompilationUnit *cUnit,
                               struct SSARepresentation *ssaRep);
 void dvmCompilerDataFlowAnalysisDispatcher(struct CompilationUnit *cUnit,
diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h
index 2bf243d..21aadec 100644
--- a/vm/compiler/CompilerIR.h
+++ b/vm/compiler/CompilerIR.h
@@ -54,9 +54,11 @@
     kChainingCellGap,
     /* Don't insert new fields between Gap and Last */
     kChainingCellLast = kChainingCellGap + 1,
-    kEntryBlock,
+    kMethodEntryBlock,
+    kTraceEntryBlock,
     kDalvikByteCode,
-    kExitBlock,
+    kTraceExitBlock,
+    kMethodExitBlock,
     kPCReconstruction,
     kExceptionHandling,
 } BBType;
@@ -82,6 +84,7 @@
     kMirOpNullNRangeDownCheck,
     kMirOpLowerBound,
     kMirOpPunt,
+    kMirOpCheckInlinePrediction,        // Gen checks for predicted inlining
     kMirOpLast,
 };
 
@@ -92,12 +95,24 @@
     kMIRNullCheckOnly,
     kMIRIgnoreRangeCheck,
     kMIRRangeCheckOnly,
+    kMIRInlined,                        // Invoke is inlined (ie dead)
+    kMIRInlinedPred,                    // Invoke is inlined via prediction
+    kMIRCallee,                         // Instruction is inlined from callee
 } MIROptimizationFlagPositons;
 
 #define MIR_IGNORE_NULL_CHECK           (1 << kMIRIgnoreNullCheck)
 #define MIR_NULL_CHECK_ONLY             (1 << kMIRNullCheckOnly)
 #define MIR_IGNORE_RANGE_CHECK          (1 << kMIRIgnoreRangeCheck)
 #define MIR_RANGE_CHECK_ONLY            (1 << kMIRRangeCheckOnly)
+#define MIR_INLINED                     (1 << kMIRInlined)
+#define MIR_INLINED_PRED                (1 << kMIRInlinedPred)
+#define MIR_CALLEE                      (1 << kMIRCallee)
+
+typedef struct CallsiteInfo {
+    const ClassObject *clazz;
+    const Method *method;
+    LIR *misPredBranchOver;
+} CallsiteInfo;
 
 typedef struct MIR {
     DecodedInstruction dalvikInsn;
@@ -108,6 +123,12 @@
     struct SSARepresentation *ssaRep;
     int OptimizationFlags;
     int seqNum;
+    union {
+        // Used by the inlined insn from the callee to find the mother method
+        const Method *calleeMethod;
+        // Used by the inlined invoke to find the class and method pointers
+        CallsiteInfo *callsiteInfo;
+    } meta;
 } MIR;
 
 struct BasicBlockDataFlow;
@@ -119,6 +140,7 @@
     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
     MIR *firstMIRInsn;
     MIR *lastMIRInsn;
     struct BasicBlock *fallThrough;
@@ -150,8 +172,10 @@
     bool allSingleStep;
     bool halveInstCount;
     bool executionCount;                // Add code to count trace executions
-    bool hasLoop;
+    bool hasLoop;                       // Contains a loop
+    bool hasInvoke;                     // Contains an invoke instruction
     bool heapMemOp;                     // Mark mem ops for self verification
+    bool wholeMethod;
     int numChainingCells[kChainingCellGap];
     LIR *firstChainingLIR[kChainingCellGap];
     LIR *chainingCellBottom;
@@ -196,6 +220,8 @@
 
 void dvmCompilerPrependMIR(BasicBlock *bb, MIR *mir);
 
+void dvmCompilerInsertMIRAfter(BasicBlock *bb, MIR *currentMIR, MIR *newMIR);
+
 void dvmCompilerAppendLIR(CompilationUnit *cUnit, LIR *lir);
 
 void dvmCompilerInsertLIRBefore(LIR *currentLIR, LIR *newLIR);
diff --git a/vm/compiler/CompilerUtility.h b/vm/compiler/CompilerUtility.h
index 8bb5b4b..551edb8 100644
--- a/vm/compiler/CompilerUtility.h
+++ b/vm/compiler/CompilerUtility.h
@@ -26,6 +26,7 @@
 bool dvmCompilerHeapInit(void);
 
 typedef struct ArenaMemBlock {
+    size_t blockSize;
     size_t bytesAllocated;
     struct ArenaMemBlock *next;
     char ptr[0];
diff --git a/vm/compiler/Dataflow.c b/vm/compiler/Dataflow.c
index e68e174..89c5b35 100644
--- a/vm/compiler/Dataflow.c
+++ b/vm/compiler/Dataflow.c
@@ -234,130 +234,130 @@
     DF_NOP,
 
     // 44 OP_AGET vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
 
     // 45 OP_AGET_WIDE vAA, vBB, vCC
-    DF_DA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+    DF_DA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
 
     // 46 OP_AGET_OBJECT vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
 
     // 47 OP_AGET_BOOLEAN vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
 
     // 48 OP_AGET_BYTE vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
 
     // 49 OP_AGET_CHAR vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
 
     // 4A OP_AGET_SHORT vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0,
+    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
 
     // 4B OP_APUT vAA, vBB, vCC
-    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
 
     // 4C OP_APUT_WIDE vAA, vBB, vCC
-    DF_UA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_2,
+    DF_UA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_2 | DF_IS_SETTER,
 
     // 4D OP_APUT_OBJECT vAA, vBB, vCC
-    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
 
     // 4E OP_APUT_BOOLEAN vAA, vBB, vCC
-    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
 
     // 4F OP_APUT_BYTE vAA, vBB, vCC
-    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
 
     // 50 OP_APUT_CHAR vAA, vBB, vCC
-    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
 
     // 51 OP_APUT_SHORT vAA, vBB, vCC
-    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1,
+    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
 
     // 52 OP_IGET vA, vB, field@CCCC
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_IS_GETTER,
 
     // 53 OP_IGET_WIDE vA, vB, field@CCCC
-    DF_DA_WIDE | DF_UB,
+    DF_DA_WIDE | DF_UB | DF_IS_GETTER,
 
     // 54 OP_IGET_OBJECT vA, vB, field@CCCC
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_IS_GETTER,
 
     // 55 OP_IGET_BOOLEAN vA, vB, field@CCCC
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_IS_GETTER,
 
     // 56 OP_IGET_BYTE vA, vB, field@CCCC
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_IS_GETTER,
 
     // 57 OP_IGET_CHAR vA, vB, field@CCCC
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_IS_GETTER,
 
     // 58 OP_IGET_SHORT vA, vB, field@CCCC
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_IS_GETTER,
 
     // 59 OP_IPUT vA, vB, field@CCCC
-    DF_UA | DF_UB,
+    DF_UA | DF_UB | DF_IS_SETTER,
 
     // 5A OP_IPUT_WIDE vA, vB, field@CCCC
-    DF_UA_WIDE | DF_UB,
+    DF_UA_WIDE | DF_UB | DF_IS_SETTER,
 
     // 5B OP_IPUT_OBJECT vA, vB, field@CCCC
-    DF_UA | DF_UB,
+    DF_UA | DF_UB | DF_IS_SETTER,
 
     // 5C OP_IPUT_BOOLEAN vA, vB, field@CCCC
-    DF_UA | DF_UB,
+    DF_UA | DF_UB | DF_IS_SETTER,
 
     // 5D OP_IPUT_BYTE vA, vB, field@CCCC
-    DF_UA | DF_UB,
+    DF_UA | DF_UB | DF_IS_SETTER,
 
     // 5E OP_IPUT_CHAR vA, vB, field@CCCC
-    DF_UA | DF_UB,
+    DF_UA | DF_UB | DF_IS_SETTER,
 
     // 5F OP_IPUT_SHORT vA, vB, field@CCCC
-    DF_UA | DF_UB,
+    DF_UA | DF_UB | DF_IS_SETTER,
 
     // 60 OP_SGET vAA, field@BBBB
-    DF_DA,
+    DF_DA | DF_IS_GETTER,
 
     // 61 OP_SGET_WIDE vAA, field@BBBB
-    DF_DA_WIDE,
+    DF_DA_WIDE | DF_IS_GETTER,
 
     // 62 OP_SGET_OBJECT vAA, field@BBBB
-    DF_DA,
+    DF_DA | DF_IS_GETTER,
 
     // 63 OP_SGET_BOOLEAN vAA, field@BBBB
-    DF_DA,
+    DF_DA | DF_IS_GETTER,
 
     // 64 OP_SGET_BYTE vAA, field@BBBB
-    DF_DA,
+    DF_DA | DF_IS_GETTER,
 
     // 65 OP_SGET_CHAR vAA, field@BBBB
-    DF_DA,
+    DF_DA | DF_IS_GETTER,
 
     // 66 OP_SGET_SHORT vAA, field@BBBB
-    DF_DA,
+    DF_DA | DF_IS_GETTER,
 
     // 67 OP_SPUT vAA, field@BBBB
-    DF_UA,
+    DF_UA | DF_IS_SETTER,
 
     // 68 OP_SPUT_WIDE vAA, field@BBBB
-    DF_UA_WIDE,
+    DF_UA_WIDE | DF_IS_SETTER,
 
     // 69 OP_SPUT_OBJECT vAA, field@BBBB
-    DF_UA,
+    DF_UA | DF_IS_SETTER,
 
     // 6A OP_SPUT_BOOLEAN vAA, field@BBBB
-    DF_UA,
+    DF_UA | DF_IS_SETTER,
 
     // 6B OP_SPUT_BYTE vAA, field@BBBB
-    DF_UA,
+    DF_UA | DF_IS_SETTER,
 
     // 6C OP_SPUT_CHAR vAA, field@BBBB
-    DF_UA,
+    DF_UA | DF_IS_SETTER,
 
     // 6D OP_SPUT_SHORT vAA, field@BBBB
-    DF_UA,
+    DF_UA | DF_IS_SETTER,
 
     // 6E OP_INVOKE_VIRTUAL {vD, vE, vF, vG, vA}
     DF_FORMAT_35C,
@@ -756,22 +756,22 @@
     DF_NOP,
 
     // F2 OP_IGET_QUICK
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_IS_GETTER,
 
     // F3 OP_IGET_WIDE_QUICK
-    DF_DA_WIDE | DF_UB,
+    DF_DA_WIDE | DF_UB | DF_IS_GETTER,
 
     // F4 OP_IGET_OBJECT_QUICK
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_IS_GETTER,
 
     // F5 OP_IPUT_QUICK
-    DF_UA | DF_UB,
+    DF_UA | DF_UB | DF_IS_SETTER,
 
     // F6 OP_IPUT_WIDE_QUICK
-    DF_UA_WIDE | DF_UB,
+    DF_UA_WIDE | DF_UB | DF_IS_SETTER,
 
     // F7 OP_IPUT_OBJECT_QUICK
-    DF_UA | DF_UB,
+    DF_UA | DF_UB | DF_IS_SETTER,
 
     // F8 OP_INVOKE_VIRTUAL_QUICK
     DF_FORMAT_35C,
@@ -818,7 +818,8 @@
  * 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(DecodedInstruction *insn,
+                                      char *note)
 {
     char buffer[256];
     int opcode = insn->opCode;
@@ -828,36 +829,35 @@
     buffer[0] = 0;
     strcpy(buffer, dexGetOpcodeName(opcode));
 
+    if (note)
+        strcat(buffer, note);
+
     if (dfAttributes & DF_FORMAT_35C) {
         unsigned int i;
         for (i = 0; i < insn->vA; i++) {
             if (i != 0) strcat(buffer, ",");
-            sprintf(buffer + strlen(buffer), " v%d", insn->arg[i]);
+            snprintf(buffer + strlen(buffer), 256, " v%d", insn->arg[i]);
         }
     }
     else if (dfAttributes & DF_FORMAT_3RC) {
-        sprintf(buffer + strlen(buffer),
-                " v%d..v%d", insn->vC, insn->vC + insn->vA - 1);
+        snprintf(buffer + strlen(buffer), 256,
+                 " v%d..v%d", insn->vC, insn->vC + insn->vA - 1);
     }
     else {
         if (dfAttributes & DF_A_IS_REG) {
-            sprintf(buffer + strlen(buffer), " v%d", insn->vA);
+            snprintf(buffer + strlen(buffer), 256, " v%d", insn->vA);
         }
         if (dfAttributes & DF_B_IS_REG) {
-            sprintf(buffer + strlen(buffer),
-                    ", v%d", insn->vB);
+            snprintf(buffer + strlen(buffer), 256, ", v%d", insn->vB);
         }
         else {
-            sprintf(buffer + strlen(buffer),
-                    ", (#%d)", insn->vB);
+            snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn->vB);
         }
         if (dfAttributes & DF_C_IS_REG) {
-            sprintf(buffer + strlen(buffer),
-                    ", v%d", insn->vC);
+            snprintf(buffer + strlen(buffer), 256, ", v%d", insn->vC);
         }
         else {
-            sprintf(buffer + strlen(buffer),
-                    ", (#%d)", insn->vC);
+            snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn->vC);
         }
     }
     int length = strlen(buffer) + 1;
@@ -934,7 +934,7 @@
     BitVector *useV, *defV, *liveInV;
 
     if (bb->blockType != kDalvikByteCode &&
-        bb->blockType != kEntryBlock) {
+        bb->blockType != kTraceEntryBlock) {
         return;
     }
 
@@ -1041,7 +1041,7 @@
 {
     MIR *mir;
 
-    if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock) {
+    if (bb->blockType != kDalvikByteCode && bb->blockType != kTraceEntryBlock) {
         return;
     }
 
@@ -1240,7 +1240,7 @@
     MIR *mir;
 
     if (bb->blockType != kDalvikByteCode &&
-        bb->blockType != kEntryBlock) {
+        bb->blockType != kTraceEntryBlock) {
         return;
     }
 
@@ -1436,7 +1436,7 @@
     for (i = 0; i < cUnit->numBlocks; i++) {
         BasicBlock *bb = cUnit->blockList[i];
         if (bb->blockType == kDalvikByteCode ||
-            bb->blockType == kEntryBlock) {
+            bb->blockType == kTraceEntryBlock) {
             bb->dataFlowInfo = dvmCompilerNew(sizeof(BasicBlockDataFlow), true);
         }
     }
diff --git a/vm/compiler/Dataflow.h b/vm/compiler/Dataflow.h
index 72c8b25..f3d3984 100644
--- a/vm/compiler/Dataflow.h
+++ b/vm/compiler/Dataflow.h
@@ -41,6 +41,8 @@
     kFPA,
     kFPB,
     kFPC,
+    kGetter,
+    kSetter,
 } DataFlowAttributes;
 
 #define DF_NOP                  0
@@ -64,6 +66,8 @@
 #define DF_FP_A                 (1 << kFPA)
 #define DF_FP_B                 (1 << kFPB)
 #define DF_FP_C                 (1 << kFPC)
+#define DF_IS_GETTER            (1 << kGetter)
+#define DF_IS_SETTER            (1 << kSetter)
 
 #define DF_HAS_USES             (DF_UA | DF_UB | DF_UC | DF_UA_WIDE | \
                                  DF_UB_WIDE | DF_UC_WIDE)
@@ -77,6 +81,7 @@
 #define DF_A_IS_REG             (DF_UA | DF_UA_WIDE | DF_DA | DF_DA_WIDE)
 #define DF_B_IS_REG             (DF_UB | DF_UB_WIDE)
 #define DF_C_IS_REG             (DF_UC | DF_UC_WIDE)
+#define DF_IS_GETTER_OR_SETTER  (DF_IS_GETTER | DF_IS_SETTER)
 
 extern int dvmCompilerDataFlowAttributes[kMirOpLast];
 
diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c
index 4db75ad..40da0e1 100644
--- a/vm/compiler/Frontend.c
+++ b/vm/compiler/Frontend.c
@@ -18,6 +18,7 @@
 #include "libdex/OpCode.h"
 #include "interp/Jit.h"
 #include "CompilerInternals.h"
+#include "Dataflow.h"
 
 /*
  * Parse an instruction, return the length of the instruction
@@ -41,7 +42,7 @@
 
     dexDecodeInstruction(gDvm.instrFormat, codePtr, decInsn);
     if (printMe) {
-        char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn);
+        char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn, NULL);
         LOGD("%p: %#06x %s\n", codePtr, opcode, decodedString);
     }
     return insnWidth;
@@ -185,7 +186,6 @@
 /*
  * dvmHashTableLookup() callback
  */
-#if defined(WITH_JIT_TUNING)
 static int compareMethod(const CompilerMethodStats *m1,
                          const CompilerMethodStats *m2)
 {
@@ -193,11 +193,69 @@
 }
 
 /*
+ * Analyze the body of the method to collect high-level information regarding
+ * inlining:
+ * - is empty method?
+ * - is getter/setter?
+ * - can throw exception?
+ *
+ * Currently the inliner only handles getters and setters. When its capability
+ * becomes more sophisticated more information will be retrieved here.
+ */
+static int analyzeInlineTarget(DecodedInstruction *dalvikInsn, int attributes,
+                               int offset)
+{
+    int flags = dexGetInstrFlags(gDvm.instrFlags, dalvikInsn->opCode);
+
+    if ((flags & kInstrInvoke) &&
+        (dalvikInsn->opCode != OP_INVOKE_DIRECT_EMPTY)) {
+        attributes &= ~METHOD_IS_LEAF;
+    }
+
+    if (!(flags & kInstrCanReturn)) {
+        if (!(dvmCompilerDataFlowAttributes[dalvikInsn->opCode] &
+              DF_IS_GETTER)) {
+            attributes &= ~METHOD_IS_GETTER;
+        }
+        if (!(dvmCompilerDataFlowAttributes[dalvikInsn->opCode] &
+              DF_IS_SETTER)) {
+            attributes &= ~METHOD_IS_SETTER;
+        }
+    }
+
+    /*
+     * The expected instruction sequence is setter will never return value and
+     * getter will also do. Clear the bits if the behavior is discovered
+     * otherwise.
+     */
+    if (flags & kInstrCanReturn) {
+        if (dalvikInsn->opCode == OP_RETURN_VOID) {
+            attributes &= ~METHOD_IS_GETTER;
+        }
+        else {
+            attributes &= ~METHOD_IS_SETTER;
+        }
+    }
+
+    if (flags & kInstrCanThrow) {
+        attributes &= ~METHOD_IS_THROW_FREE;
+    }
+
+    if (offset == 0 && dalvikInsn->opCode == OP_RETURN_VOID) {
+        attributes |= METHOD_IS_EMPTY;
+    }
+
+    return attributes;
+}
+
+/*
  * 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.
+ * ratios. If isCallee is true, also analyze each instruction in more details
+ * to see if it is suitable for inlining.
  */
-static CompilerMethodStats *analyzeMethodBody(const Method *method)
+CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
+                                                  bool isCallee)
 {
     const DexCode *dexCode = dvmGetMethodCode(method);
     const u2 *codePtr = dexCode->insns;
@@ -215,22 +273,40 @@
                                          (HashCompareFunc) compareMethod,
                                          false);
 
-    /* Part of this method has been compiled before - just return the entry */
-    if (realMethodEntry != NULL) {
-        return realMethodEntry;
+    /* This method has never been analyzed before - create an entry */
+    if (realMethodEntry == NULL) {
+        realMethodEntry =
+            (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
+        realMethodEntry->method = method;
+
+        dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
+                           realMethodEntry,
+                           (HashCompareFunc) compareMethod,
+                           true);
     }
 
-    /*
-     * First time to compile this method - set up a new entry in the hash table
-     */
-    realMethodEntry =
-        (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
-    realMethodEntry->method = method;
+    /* This method is invoked as a callee and has been analyzed - just return */
+    if ((isCallee == true) && (realMethodEntry->attributes & METHOD_IS_CALLEE))
+        return realMethodEntry;
 
-    dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
-                       realMethodEntry,
-                       (HashCompareFunc) compareMethod,
-                       true);
+    /*
+     * Similarly, return if this method has been compiled before as a hot
+     * method already.
+     */
+    if ((isCallee == false) &&
+        (realMethodEntry->attributes & METHOD_IS_HOT))
+        return realMethodEntry;
+
+    int attributes;
+
+    /* Method hasn't been analyzed for the desired purpose yet */
+    if (isCallee) {
+        /* Aggressively set the attributes until proven otherwise */
+        attributes = METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE |
+                     METHOD_IS_GETTER | METHOD_IS_SETTER;
+    } else {
+        attributes = METHOD_IS_HOT;
+    }
 
     /* Count the number of instructions */
     while (codePtr < codeEnd) {
@@ -241,14 +317,51 @@
         if (width == 0)
             break;
 
+        if (isCallee) {
+            attributes = analyzeInlineTarget(&dalvikInsn, attributes, insnSize);
+        }
+
         insnSize += width;
         codePtr += width;
     }
 
+    /*
+     * Only handle simple getters/setters with one instruction followed by
+     * return
+     */
+    if ((attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) &&
+        (insnSize != 3)) {
+        attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
+    }
+
     realMethodEntry->dalvikSize = insnSize * 2;
+    realMethodEntry->attributes |= attributes;
+
+#if 0
+    /* Uncomment the following to explore various callee patterns */
+    if (attributes & METHOD_IS_THROW_FREE) {
+        LOGE("%s%s is inlinable%s", method->clazz->descriptor, method->name,
+             (attributes & METHOD_IS_EMPTY) ? " empty" : "");
+    }
+
+    if (attributes & METHOD_IS_LEAF) {
+        LOGE("%s%s is leaf %d%s", method->clazz->descriptor, method->name,
+             insnSize, insnSize < 5 ? " (small)" : "");
+    }
+
+    if (attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) {
+        LOGE("%s%s is %s", method->clazz->descriptor, method->name,
+             attributes & METHOD_IS_GETTER ? "getter": "setter");
+    }
+    if (attributes ==
+        (METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE)) {
+        LOGE("%s%s is inlinable non setter/getter", method->clazz->descriptor,
+             method->name);
+    }
+#endif
+
     return realMethodEntry;
 }
-#endif
 
 /*
  * Crawl the stack of the thread that requesed compilation to see if any of the
@@ -305,6 +418,11 @@
 
     /* If we've already compiled this trace, just return success */
     if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
+        /*
+         * Make sure the codeAddress is NULL so that it won't clobber the
+         * existing entry.
+         */
+        info->codeAddress = NULL;
         return true;
     }
 
@@ -313,7 +431,7 @@
 
 #if defined(WITH_JIT_TUNING)
     /* Locate the entry to store compilation statistics for this method */
-    methodStats = analyzeMethodBody(desc->method);
+    methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
 #endif
 
     /* Set the recover buffer pointer */
@@ -325,6 +443,12 @@
     /* Initialize the profile flag */
     cUnit.executionCount = gDvmJit.profile;
 
+    /* Setup the method */
+    cUnit.method = desc->method;
+
+    /* Initialize the PC reconstruction list */
+    dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
+
     /* Identify traces that we don't want to compile */
     if (gDvmJit.methodTable) {
         int len = strlen(desc->method->clazz->descriptor) +
@@ -399,7 +523,7 @@
     }
 
     /* Allocate the entry block */
-    lastBB = startBB = curBB = dvmCompilerNewBB(kEntryBlock);
+    lastBB = startBB = curBB = dvmCompilerNewBB(kTraceEntryBlock);
     curBB->startOffset = curOffset;
     curBB->id = numBlocks++;
 
@@ -434,6 +558,19 @@
         traceSize += width;
         dvmCompilerAppendMIR(curBB, insn);
         cUnit.numInsts++;
+
+        int flags = dexGetInstrFlags(gDvm.instrFlags, insn->dalvikInsn.opCode);
+
+        if ((flags & kInstrInvoke) &&
+            (insn->dalvikInsn.opCode != OP_INVOKE_DIRECT_EMPTY)) {
+            assert(numInsts == 1);
+            CallsiteInfo *callsiteInfo =
+                dvmCompilerNew(sizeof(CallsiteInfo), true);
+            callsiteInfo->clazz = currRun[1].meta;
+            callsiteInfo->method = currRun[2].meta;
+            insn->meta.callsiteInfo = callsiteInfo;
+        }
+
         /* Instruction limit reached - terminate the trace here */
         if (cUnit.numInsts >= numMaxInsts) {
             break;
@@ -442,11 +579,20 @@
             if (currRun->frag.runEnd) {
                 break;
             } else {
+                /* Advance to the next trace description (ie non-meta info) */
+                do {
+                    currRun++;
+                } while (!currRun->frag.isCode);
+
+                /* Dummy end-of-run marker seen */
+                if (currRun->frag.numInsts == 0) {
+                    break;
+                }
+
                 curBB = dvmCompilerNewBB(kDalvikByteCode);
                 lastBB->next = curBB;
                 lastBB = curBB;
                 curBB->id = numBlocks++;
-                currRun++;
                 curOffset = currRun->frag.startOffset;
                 numInsts = currRun->frag.numInsts;
                 curBB->startOffset = curOffset;
@@ -486,6 +632,13 @@
         /* Link the taken and fallthrough blocks */
         BasicBlock *searchBB;
 
+        int flags = dexGetInstrFlags(gDvm.instrFlags,
+                                     lastInsn->dalvikInsn.opCode);
+
+        if (flags & kInstrInvoke) {
+            cUnit.hasInvoke = true;
+        }
+
         /* No backward branch in the trace - start searching the next BB */
         for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
             if (targetOffset == searchBB->startOffset) {
@@ -493,12 +646,18 @@
             }
             if (fallThroughOffset == searchBB->startOffset) {
                 curBB->fallThrough = searchBB;
+
+                /*
+                 * Fallthrough block of an invoke instruction needs to be
+                 * aligned to 4-byte boundary (alignment instruction to be
+                 * inserted later.
+                 */
+                if (flags & kInstrInvoke) {
+                    searchBB->isFallThroughFromInvoke = true;
+                }
             }
         }
 
-        int flags = dexGetInstrFlags(gDvm.instrFlags,
-                                     lastInsn->dalvikInsn.opCode);
-
         /*
          * Some blocks are ended by non-control-flow-change instructions,
          * currently only due to trace length constraint. In this case we need
@@ -523,7 +682,7 @@
             if (cUnit.printMe) {
                 LOGD("Natural loop detected!");
             }
-            exitBB = dvmCompilerNewBB(kExitBlock);
+            exitBB = dvmCompilerNewBB(kTraceExitBlock);
             lastBB->next = exitBB;
             lastBB = exitBB;
 
@@ -698,10 +857,8 @@
 
     BasicBlock **blockList;
 
-    cUnit.method = desc->method;
     cUnit.traceDesc = desc;
     cUnit.numBlocks = numBlocks;
-    dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
     blockList = cUnit.blockList =
         dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
 
@@ -714,10 +871,17 @@
     /* 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();
+
+    /* Inline transformation @ the MIR level */
+    if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
+        dvmCompilerInlineMIR(&cUnit);
+    }
+
     /* Preparation for SSA conversion */
     dvmInitializeSSAConversion(&cUnit);
 
-
     if (cUnit.hasLoop) {
         dvmCompilerLoopOpt(&cUnit);
     }
@@ -731,9 +895,6 @@
         dvmCompilerDumpCompilationUnit(&cUnit);
     }
 
-    /* Set the instruction set to use (NOTE: later components may change it) */
-    cUnit.instructionSet = dvmCompilerInstructionSet();
-
     /* Allocate Registers */
     dvmCompilerRegAlloc(&cUnit);
 
@@ -771,13 +932,112 @@
 }
 
 /*
+ * Since we are including instructions from possibly a cold method into the
+ * current trace, we need to make sure that all the associated information
+ * with the callee is properly initialized. If not, we punt on this inline
+ * target.
+ *
+ * TODO: volatile instructions will handled later.
+ */
+bool dvmCompilerCanIncludeThisInstruction(const Method *method,
+                                          const DecodedInstruction *insn)
+{
+    switch (insn->opCode) {
+        case OP_NEW_INSTANCE:
+        case OP_CHECK_CAST: {
+            ClassObject *classPtr = (void*)
+              (method->clazz->pDvmDex->pResClasses[insn->vB]);
+
+            /* Class hasn't been initialized yet */
+            if (classPtr == NULL) {
+                return false;
+            }
+            return true;
+        }
+        case OP_SGET_OBJECT:
+        case OP_SGET_BOOLEAN:
+        case OP_SGET_CHAR:
+        case OP_SGET_BYTE:
+        case OP_SGET_SHORT:
+        case OP_SGET:
+        case OP_SGET_WIDE:
+        case OP_SPUT_OBJECT:
+        case OP_SPUT_BOOLEAN:
+        case OP_SPUT_CHAR:
+        case OP_SPUT_BYTE:
+        case OP_SPUT_SHORT:
+        case OP_SPUT:
+        case OP_SPUT_WIDE: {
+            void *fieldPtr = (void*)
+              (method->clazz->pDvmDex->pResFields[insn->vB]);
+
+            if (fieldPtr == NULL) {
+                return false;
+            }
+            return true;
+        }
+        case OP_INVOKE_SUPER:
+        case OP_INVOKE_SUPER_RANGE: {
+            int mIndex = method->clazz->pDvmDex->
+                pResMethods[insn->vB]->methodIndex;
+            const Method *calleeMethod = method->clazz->super->vtable[mIndex];
+            if (calleeMethod == NULL) {
+                return false;
+            }
+            return true;
+        }
+        case OP_INVOKE_SUPER_QUICK:
+        case OP_INVOKE_SUPER_QUICK_RANGE: {
+            const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
+            if (calleeMethod == NULL) {
+                return false;
+            }
+            return true;
+        }
+        case OP_INVOKE_STATIC:
+        case OP_INVOKE_STATIC_RANGE:
+        case OP_INVOKE_DIRECT:
+        case OP_INVOKE_DIRECT_RANGE: {
+            const Method *calleeMethod =
+                method->clazz->pDvmDex->pResMethods[insn->vB];
+            if (calleeMethod == NULL) {
+                return false;
+            }
+            return true;
+        }
+        case OP_CONST_CLASS: {
+            void *classPtr = (void*)
+                (method->clazz->pDvmDex->pResClasses[insn->vB]);
+
+            if (classPtr == NULL) {
+                return false;
+            }
+            return true;
+        }
+        case OP_CONST_STRING_JUMBO:
+        case OP_CONST_STRING: {
+            void *strPtr = (void*)
+                (method->clazz->pDvmDex->pResStrings[insn->vB]);
+
+            if (strPtr == NULL) {
+                return false;
+            }
+            return true;
+        }
+        default:
+            return true;
+    }
+}
+
+/*
  * 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, JitTranslationInfo *info)
+bool dvmCompileMethod(CompilationUnit *cUnit, const Method *method,
+                      JitTranslationInfo *info)
 {
     const DexCode *dexCode = dvmGetMethodCode(method);
     const u2 *codePtr = dexCode->insns;
@@ -785,6 +1045,14 @@
     int blockID = 0;
     unsigned int curOffset = 0;
 
+    /* If we've already compiled this trace, just return success */
+    if (dvmJitGetCodeAddr(codePtr) && !info->discardResult) {
+        return true;
+    }
+
+    /* Doing method-based compilation */
+    cUnit->wholeMethod = true;
+
     BasicBlock *firstBlock = dvmCompilerNewBB(kDalvikByteCode);
     firstBlock->id = blockID++;
 
@@ -793,6 +1061,8 @@
                                                        false);
     dvmCompilerSetBit(bbStartAddr, 0);
 
+    int numInvokeTargets = 0;
+
     /*
      * Sequentially go through every instruction first and put them in a single
      * basic block. Identify block boundaries at the mean time.
@@ -808,6 +1078,12 @@
         /* Terminate when the data section is seen */
         if (width == 0)
             break;
+
+        if (!dvmCompilerCanIncludeThisInstruction(cUnit->method,
+						  &insn->dalvikInsn)) {
+            return false;
+        }
+
         dvmCompilerAppendMIR(firstBlock, insn);
         /*
          * Check whether this is a block ending instruction and whether it
@@ -823,7 +1099,12 @@
         if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
                               &callee)) {
             dvmCompilerSetBit(bbStartAddr, curOffset + width);
-            if (target != curOffset) {
+            /* 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);
             }
         }
@@ -837,26 +1118,26 @@
      * 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--;
     }
 
-    CompilationUnit cUnit;
     BasicBlock **blockList;
-
-    memset(&cUnit, 0, sizeof(CompilationUnit));
-    cUnit.method = method;
-    blockList = cUnit.blockList =
-        dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
+    blockList = cUnit->blockList =
+        dvmCompilerNew(sizeof(BasicBlock *) * (numBlocks + numInvokeTargets),
+                       true);
 
     /*
-     * Register the first block onto the list and start split it into block
-     * boundaries from there.
+     * Register the first block onto the list and start splitting it into
+     * sub-blocks.
      */
     blockList[0] = firstBlock;
-    cUnit.numBlocks = 1;
+    cUnit->numBlocks = 1;
 
     int i;
     for (i = 0; i < numBlocks; i++) {
@@ -868,13 +1149,13 @@
             /* 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++) {
+                for (j = 0; j < cUnit->numBlocks; j++) {
                     if (blockList[j]->firstMIRInsn->offset == insn->offset)
                         break;
                 }
 
                 /* Block not split yet - do it now */
-                if (j == cUnit.numBlocks) {
+                if (j == cUnit->numBlocks) {
                     BasicBlock *newBB = dvmCompilerNewBB(kDalvikByteCode);
                     newBB->id = blockID++;
                     newBB->firstMIRInsn = insn;
@@ -892,17 +1173,28 @@
                         curBB->fallThrough = newBB;
                     }
 
+                    /*
+                     * Fallthrough block of an invoke instruction needs to be
+                     * aligned to 4-byte boundary (alignment instruction to be
+                     * inserted later.
+                     */
+                    if (dexGetInstrFlags(gDvm.instrFlags,
+                           curBB->lastMIRInsn->dalvikInsn.opCode) &
+                        kInstrInvoke) {
+                        newBB->isFallThroughFromInvoke = true;
+                    }
+
                     /* enqueue the new block */
-                    blockList[cUnit.numBlocks++] = newBB;
+                    blockList[cUnit->numBlocks++] = newBB;
                     break;
                 }
             }
         }
     }
 
-    if (numBlocks != cUnit.numBlocks) {
-        LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit.numBlocks);
-        dvmCompilerAbort(&cUnit);
+    if (numBlocks != cUnit->numBlocks) {
+        LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit->numBlocks);
+        dvmCompilerAbort(cUnit);
     }
 
     /* Connect the basic blocks through the taken links */
@@ -910,13 +1202,13 @@
         BasicBlock *curBB = blockList[i];
         MIR *insn = curBB->lastMIRInsn;
         unsigned int target = insn->offset;
-        bool isInvoke;
-        const Method *callee;
+        bool isInvoke = false;
+        const Method *callee = NULL;
 
         findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
 
-        /* Found a block ended on a branch */
-        if (target != insn->offset) {
+        /* Found a block ended on a branch (not invoke) */
+        if (isInvoke == false && target != insn->offset) {
             int j;
             /* Forward branch */
             if (target > insn->offset) {
@@ -931,24 +1223,60 @@
                     break;
                 }
             }
+        }
 
-            /* 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);
-                dvmCompilerAbort(&cUnit);
+        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;
             }
+            newBB->id = blockID++;
+            curBB->taken = newBB;
+            /* enqueue the new block */
+            blockList[cUnit->numBlocks++] = newBB;
         }
     }
 
+    if (cUnit->numBlocks != numBlocks + numInvokeTargets) {
+        LOGE("Expect %d vs %d total blocks\n", numBlocks + numInvokeTargets,
+             cUnit->numBlocks);
+        dvmCompilerDumpCompilationUnit(cUnit);
+        dvmCompilerAbort(cUnit);
+    }
+
     /* Set the instruction set to use (NOTE: later components may change it) */
-    cUnit.instructionSet = dvmCompilerInstructionSet();
+    cUnit->instructionSet = dvmCompilerInstructionSet();
 
-    dvmCompilerMIR2LIR(&cUnit);
+    /* Preparation for SSA conversion */
+    dvmInitializeSSAConversion(cUnit);
 
-    dvmCompilerAssembleLIR(&cUnit, info);
+    /* SSA analysis */
+    dvmCompilerNonLoopAnalysis(cUnit);
 
-    dvmCompilerDumpCompilationUnit(&cUnit);
+    /* Needs to happen after SSA naming */
+    dvmCompilerInitializeRegAlloc(cUnit);
+
+    /* Allocate Registers */
+    dvmCompilerRegAlloc(cUnit);
+
+    /* Convert MIR to LIR, etc. */
+    dvmCompilerMIR2LIR(cUnit);
+
+    /* Convert LIR into machine code. */
+    dvmCompilerAssembleLIR(cUnit, info);
+
+    if (cUnit->halveInstCount) {
+        return false;
+    }
+
+    dvmCompilerDumpCompilationUnit(cUnit);
 
     dvmCompilerArenaReset();
 
diff --git a/vm/compiler/InlineTransformation.c b/vm/compiler/InlineTransformation.c
new file mode 100644
index 0000000..6e04cfe
--- /dev/null
+++ b/vm/compiler/InlineTransformation.c
@@ -0,0 +1,349 @@
+/*
+ * 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 "libdex/OpCodeNames.h"
+
+/* Convert the reg id from the callee to the original id passed by the caller */
+static inline u4 convertRegId(const DecodedInstruction *invoke,
+                              const Method *calleeMethod,
+                              int calleeRegId, bool isRange)
+{
+    /* The order in the original arg passing list */
+    int rank = calleeRegId -
+               (calleeMethod->registersSize - calleeMethod->insSize);
+    assert(rank >= 0);
+    if (!isRange) {
+        return invoke->arg[rank];
+    } else {
+        return invoke->vC + rank;
+    }
+}
+
+static void inlineGetter(CompilationUnit *cUnit,
+                         const Method *calleeMethod,
+                         MIR *invokeMIR,
+                         BasicBlock *invokeBB,
+                         bool isPredicted,
+                         bool isRange)
+{
+    BasicBlock *moveResultBB = invokeBB->fallThrough;
+    MIR *moveResultMIR = moveResultBB->firstMIRInsn;
+    MIR *newGetterMIR = dvmCompilerNew(sizeof(MIR), true);
+    DecodedInstruction getterInsn;
+
+    dexDecodeInstruction(gDvm.instrFormat, calleeMethod->insns, &getterInsn);
+
+    if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &getterInsn))
+        return;
+
+    /*
+     * Some getters (especially invoked through interface) are not followed
+     * by a move result.
+     */
+    if ((moveResultMIR == NULL) ||
+        (moveResultMIR->dalvikInsn.opCode != OP_MOVE_RESULT &&
+         moveResultMIR->dalvikInsn.opCode != OP_MOVE_RESULT_OBJECT &&
+         moveResultMIR->dalvikInsn.opCode != OP_MOVE_RESULT_WIDE)) {
+        return;
+    }
+
+    int dfFlags = dvmCompilerDataFlowAttributes[getterInsn.opCode];
+
+    /* Expecting vA to be the destination register */
+    if (dfFlags & DF_UA) {
+        LOGE("opcode %d has DF_UA set (not expected)", getterInsn.opCode);
+        dvmAbort();
+    }
+
+    if (dfFlags & DF_UB) {
+        getterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+                                     getterInsn.vB, isRange);
+    }
+
+    if (dfFlags & DF_UC) {
+        getterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+                                     getterInsn.vC, isRange);
+    }
+
+    getterInsn.vA = moveResultMIR->dalvikInsn.vA;
+
+    /* Now setup the Dalvik instruction with converted src/dst registers */
+    newGetterMIR->dalvikInsn = getterInsn;
+
+    newGetterMIR->width = gDvm.instrWidth[getterInsn.opCode];
+
+    newGetterMIR->OptimizationFlags |= MIR_CALLEE;
+
+    /*
+     * If the getter instruction is about to raise any exception, punt to the
+     * interpreter and re-execute the invoke.
+     */
+    newGetterMIR->offset = invokeMIR->offset;
+
+    newGetterMIR->meta.calleeMethod = calleeMethod;
+
+    dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newGetterMIR);
+
+    if (isPredicted) {
+        MIR *invokeMIRSlow = dvmCompilerNew(sizeof(MIR), true);
+        *invokeMIRSlow = *invokeMIR;
+        invokeMIR->dalvikInsn.opCode = kMirOpCheckInlinePrediction;
+
+        /* Use vC to denote the first argument (ie this) */
+        if (!isRange) {
+            invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
+        }
+
+        moveResultMIR->OptimizationFlags |= MIR_INLINED_PRED;
+
+        dvmCompilerInsertMIRAfter(invokeBB, newGetterMIR, invokeMIRSlow);
+        invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.invokePolyGetterInlined++;
+#endif
+    } else {
+        invokeMIR->OptimizationFlags |= MIR_INLINED;
+        moveResultMIR->OptimizationFlags |= MIR_INLINED;
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.invokeMonoGetterInlined++;
+#endif
+    }
+
+    return;
+}
+
+static void inlineSetter(CompilationUnit *cUnit,
+                         const Method *calleeMethod,
+                         MIR *invokeMIR,
+                         BasicBlock *invokeBB,
+                         bool isPredicted,
+                         bool isRange)
+{
+    MIR *newSetterMIR = dvmCompilerNew(sizeof(MIR), true);
+    DecodedInstruction setterInsn;
+
+    dexDecodeInstruction(gDvm.instrFormat, calleeMethod->insns, &setterInsn);
+
+    if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &setterInsn))
+        return;
+
+    int dfFlags = dvmCompilerDataFlowAttributes[setterInsn.opCode];
+
+    if (dfFlags & DF_UA) {
+        setterInsn.vA = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+                                     setterInsn.vA, isRange);
+
+    }
+
+    if (dfFlags & DF_UB) {
+        setterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+                                     setterInsn.vB, isRange);
+
+    }
+
+    if (dfFlags & DF_UC) {
+        setterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+                                     setterInsn.vC, isRange);
+    }
+
+    /* Now setup the Dalvik instruction with converted src/dst registers */
+    newSetterMIR->dalvikInsn = setterInsn;
+
+    newSetterMIR->width = gDvm.instrWidth[setterInsn.opCode];
+
+    newSetterMIR->OptimizationFlags |= MIR_CALLEE;
+
+    /*
+     * If the setter instruction is about to raise any exception, punt to the
+     * interpreter and re-execute the invoke.
+     */
+    newSetterMIR->offset = invokeMIR->offset;
+
+    newSetterMIR->meta.calleeMethod = calleeMethod;
+
+    dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newSetterMIR);
+
+    if (isPredicted) {
+        MIR *invokeMIRSlow = dvmCompilerNew(sizeof(MIR), true);
+        *invokeMIRSlow = *invokeMIR;
+        invokeMIR->dalvikInsn.opCode = kMirOpCheckInlinePrediction;
+
+        /* Use vC to denote the first argument (ie this) */
+        if (!isRange) {
+            invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
+        }
+
+        dvmCompilerInsertMIRAfter(invokeBB, newSetterMIR, invokeMIRSlow);
+        invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.invokePolySetterInlined++;
+#endif
+    } else {
+        invokeMIR->OptimizationFlags |= MIR_INLINED;
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.invokeMonoSetterInlined++;
+#endif
+    }
+
+    return;
+}
+
+static void tryInlineSingletonCallsite(CompilationUnit *cUnit,
+                                       const Method *calleeMethod,
+                                       MIR *invokeMIR,
+                                       BasicBlock *invokeBB,
+                                       bool isRange)
+{
+    /* Not a Java method */
+    if (dvmIsNativeMethod(calleeMethod)) return;
+
+    CompilerMethodStats *methodStats =
+        dvmCompilerAnalyzeMethodBody(calleeMethod, true);
+
+    /* Empty callee - do nothing */
+    if (methodStats->attributes & METHOD_IS_EMPTY) {
+        /* The original invoke instruction is effectively turned into NOP */
+        invokeMIR->OptimizationFlags |= MIR_INLINED;
+        return;
+    }
+
+    if (methodStats->attributes & METHOD_IS_GETTER) {
+        inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, false, isRange);
+        return;
+    } else if (methodStats->attributes & METHOD_IS_SETTER) {
+        inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, false, isRange);
+        return;
+    }
+}
+
+static void inlineEmptyVirtualCallee(CompilationUnit *cUnit,
+                                     const Method *calleeMethod,
+                                     MIR *invokeMIR,
+                                     BasicBlock *invokeBB)
+{
+    MIR *invokeMIRSlow = dvmCompilerNew(sizeof(MIR), true);
+    *invokeMIRSlow = *invokeMIR;
+    invokeMIR->dalvikInsn.opCode = kMirOpCheckInlinePrediction;
+
+    dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, invokeMIRSlow);
+    invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+}
+
+static void tryInlineVirtualCallsite(CompilationUnit *cUnit,
+                                     const Method *calleeMethod,
+                                     MIR *invokeMIR,
+                                     BasicBlock *invokeBB,
+                                     bool isRange)
+{
+    /* Not a Java method */
+    if (dvmIsNativeMethod(calleeMethod)) return;
+
+    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;
+    }
+
+    if (methodStats->attributes & METHOD_IS_GETTER) {
+        inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, true, isRange);
+        return;
+    } else if (methodStats->attributes & METHOD_IS_SETTER) {
+        inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, true, isRange);
+        return;
+    }
+}
+
+
+void dvmCompilerInlineMIR(CompilationUnit *cUnit)
+{
+    int i;
+    bool isRange = false;
+
+    /*
+     * 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];
+        if (bb->blockType != kDalvikByteCode)
+            continue;
+        MIR *lastMIRInsn = bb->lastMIRInsn;
+        int opCode = lastMIRInsn->dalvikInsn.opCode;
+        int flags = dexGetInstrFlags(gDvm.instrFlags, opCode);
+
+        /* No invoke - continue */
+        if ((flags & kInstrInvoke) == 0)
+            continue;
+
+        /* Not a real invoke - continue */
+        if (opCode == OP_INVOKE_DIRECT_EMPTY)
+            continue;
+
+        const Method *calleeMethod;
+
+        switch (opCode) {
+            case OP_INVOKE_SUPER:
+            case OP_INVOKE_DIRECT:
+            case OP_INVOKE_STATIC:
+            case OP_INVOKE_SUPER_QUICK:
+                calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+                break;
+            case OP_INVOKE_SUPER_RANGE:
+            case OP_INVOKE_DIRECT_RANGE:
+            case OP_INVOKE_STATIC_RANGE:
+            case OP_INVOKE_SUPER_QUICK_RANGE:
+                isRange = true;
+                calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+                break;
+            default:
+                calleeMethod = NULL;
+                break;
+        }
+
+        if (calleeMethod) {
+            tryInlineSingletonCallsite(cUnit, calleeMethod, lastMIRInsn, bb,
+                                       isRange);
+            return;
+        }
+
+        switch (opCode) {
+            case OP_INVOKE_VIRTUAL:
+            case OP_INVOKE_VIRTUAL_QUICK:
+            case OP_INVOKE_INTERFACE:
+                isRange = false;
+                calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+                break;
+            case OP_INVOKE_VIRTUAL_RANGE:
+            case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+            case OP_INVOKE_INTERFACE_RANGE:
+                isRange = true;
+                calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+                break;
+            default:
+                break;
+        }
+
+        if (calleeMethod) {
+            tryInlineVirtualCallsite(cUnit, calleeMethod, lastMIRInsn, bb,
+                                     isRange);
+            return;
+        }
+    }
+}
diff --git a/vm/compiler/IntermediateRep.c b/vm/compiler/IntermediateRep.c
index b3e6490..825a690 100644
--- a/vm/compiler/IntermediateRep.c
+++ b/vm/compiler/IntermediateRep.c
@@ -55,6 +55,22 @@
     }
 }
 
+/* Insert an MIR instruction after the specified MIR */
+void dvmCompilerInsertMIRAfter(BasicBlock *bb, MIR *currentMIR, MIR *newMIR)
+{
+    newMIR->prev = currentMIR;
+    newMIR->next = currentMIR->next;
+    currentMIR->next = newMIR;
+
+    if (newMIR->next) {
+        /* Is not the last MIR in the block */
+        newMIR->next->prev = newMIR;
+    } else {
+        /* Is the last MIR in the block */
+        bb->lastMIRInsn = newMIR;
+    }
+}
+
 /*
  * Append an LIR instruction to the LIR list maintained by a compilation
  * unit
diff --git a/vm/compiler/Loop.c b/vm/compiler/Loop.c
index 53daf17..dede0ee 100644
--- a/vm/compiler/Loop.c
+++ b/vm/compiler/Loop.c
@@ -462,9 +462,9 @@
 {
     LoopAnalysis *loopAnalysis = dvmCompilerNew(sizeof(LoopAnalysis), true);
 
-    assert(cUnit->blockList[0]->blockType == kEntryBlock);
+    assert(cUnit->blockList[0]->blockType == kTraceEntryBlock);
     assert(cUnit->blockList[2]->blockType == kDalvikByteCode);
-    assert(cUnit->blockList[3]->blockType == kExitBlock);
+    assert(cUnit->blockList[3]->blockType == kTraceExitBlock);
 
     cUnit->loopAnalysis = loopAnalysis;
     /*
diff --git a/vm/compiler/Ralloc.c b/vm/compiler/Ralloc.c
index 608b4b3..f227527 100644
--- a/vm/compiler/Ralloc.c
+++ b/vm/compiler/Ralloc.c
@@ -31,7 +31,7 @@
     int i;
 
     if (bb->blockType != kDalvikByteCode &&
-        bb->blockType != kEntryBlock)
+        bb->blockType != kTraceEntryBlock)
         return seqNum;
 
     for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
@@ -64,7 +64,7 @@
 {
     MIR *mir;
     if (bb->blockType != kDalvikByteCode &&
-        bb->blockType != kEntryBlock)
+        bb->blockType != kTraceEntryBlock)
         return;
 
     for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
diff --git a/vm/compiler/Utility.c b/vm/compiler/Utility.c
index 1aff02b..711d4cf 100644
--- a/vm/compiler/Utility.c
+++ b/vm/compiler/Utility.c
@@ -30,6 +30,7 @@
         LOGE("No memory left to create compiler heap memory\n");
         return false;
     }
+    arenaHead->blockSize = ARENA_DEFAULT_SIZE;
     currentArena = arenaHead;
     currentArena->bytesAllocated = 0;
     currentArena->next = NULL;
@@ -44,7 +45,7 @@
     size = (size + 3) & ~3;
 retry:
     /* Normal case - space is available in the current page */
-    if (size + currentArena->bytesAllocated <= ARENA_DEFAULT_SIZE) {
+    if (size + currentArena->bytesAllocated <= currentArena->blockSize) {
         void *ptr;
         ptr = &currentArena->ptr[currentArena->bytesAllocated];
         currentArena->bytesAllocated += size;
@@ -61,15 +62,17 @@
             currentArena = currentArena->next;
             goto retry;
         }
-        /*
-         * If we allocate really large variable-sized data structures that
-         * could go above the limit we need to enhance the allocation
-         * mechanism.
-         */
-        assert(size <= ARENA_DEFAULT_SIZE);
+
+        size_t blockSize = (size < ARENA_DEFAULT_SIZE) ?
+                          ARENA_DEFAULT_SIZE : size;
         /* Time to allocate a new arena */
         ArenaMemBlock *newArena = (ArenaMemBlock *)
-            malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE);
+            malloc(sizeof(ArenaMemBlock) + blockSize);
+        if (newArena == NULL) {
+            LOGE("Arena allocation failure");
+            dvmAbort();
+        }
+        newArena->blockSize = blockSize;
         newArena->bytesAllocated = 0;
         newArena->next = NULL;
         currentArena->next = newArena;
@@ -120,6 +123,7 @@
 /* Insert a new element into the growable list */
 void dvmInsertGrowableList(GrowableList *gList, void *elem)
 {
+    assert(gList->numAllocated != 0);
     if (gList->numUsed == gList->numAllocated) {
         expandGrowableList(gList);
     }
@@ -131,12 +135,34 @@
 {
     int i;
     BasicBlock *bb;
-    LOGD("%d blocks in total\n", cUnit->numBlocks);
+    char *blockTypeNames[] = {
+        "Normal Chaining Cell",
+        "Hot Chaining Cell",
+        "Singleton Chaining Cell",
+        "Predicted Chaining Cell",
+        "Backward Branch",
+        "Chaining Cell Gap",
+        "N/A",
+        "Method Entry Block",
+        "Trace Entry Block",
+        "Code Block",
+        "Trace Exit Block",
+        "Method Exit Block",
+        "PC Reconstruction",
+        "Exception Handling",
+    };
+
+    LOGD("Compiling %s %s", cUnit->method->clazz->descriptor,
+         cUnit->method->name);
+    LOGD("%d insns", dvmGetMethodInsnsSize(cUnit->method));
+    LOGD("%d blocks in total", cUnit->numBlocks);
 
     for (i = 0; i < cUnit->numBlocks; i++) {
         bb = cUnit->blockList[i];
-        LOGD("Block %d (insn %04x - %04x%s)\n",
-             bb->id, bb->startOffset,
+        LOGD("Block %d (%s) (insn %04x - %04x%s)\n",
+             bb->id,
+             blockTypeNames[bb->blockType],
+             bb->startOffset,
              bb->lastMIRInsn ? bb->lastMIRInsn->offset : bb->startOffset,
              bb->lastMIRInsn ? "" : " empty");
         if (bb->taken) {
diff --git a/vm/compiler/codegen/Optimizer.h b/vm/compiler/codegen/Optimizer.h
index 713aa41..d42fe87 100644
--- a/vm/compiler/codegen/Optimizer.h
+++ b/vm/compiler/codegen/Optimizer.h
@@ -28,6 +28,7 @@
     kLoadHoisting,
     kTrackLiveTemps,
     kSuppressLoads,
+    kMethodInlining,
 } optControlVector;
 
 /* Forward declarations */
diff --git a/vm/compiler/codegen/arm/ArchUtility.c b/vm/compiler/codegen/arm/ArchUtility.c
index 2daa871..d5acd13 100644
--- a/vm/compiler/codegen/arm/ArchUtility.c
+++ b/vm/compiler/codegen/arm/ArchUtility.c
@@ -277,7 +277,8 @@
             LOGD("-------- BARRIER");
             break;
         case kArmPseudoExtended:
-            /* intentional fallthrough */
+            LOGD("-------- %s\n", (char *) dest);
+            break;
         case kArmPseudoSSARep:
             DUMP_SSA_REP(LOGD("-------- %s\n", (char *) dest));
             break;
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c
index 832ee0f..c1b08a3 100644
--- a/vm/compiler/codegen/arm/Assemble.c
+++ b/vm/compiler/codegen/arm/Assemble.c
@@ -905,11 +905,13 @@
 static int jitTraceDescriptionSize(const JitTraceDescription *desc)
 {
     int runCount;
+    /* Trace end is always of non-meta type (ie isCode == true) */
     for (runCount = 0; ; runCount++) {
-        if (desc->trace[runCount].frag.runEnd)
+        if (desc->trace[runCount].frag.isCode &&
+            desc->trace[runCount].frag.runEnd)
            break;
     }
-    return sizeof(JitCodeDesc) + ((runCount+1) * sizeof(JitTraceRun));
+    return sizeof(JitTraceDescription) + ((runCount+1) * sizeof(JitTraceRun));
 }
 
 /* Return TRUE if error happens */
@@ -1195,7 +1197,8 @@
     int offset = 0;
     int i;
     ChainCellCounts chainCellCounts;
-    int descSize = jitTraceDescriptionSize(cUnit->traceDesc);
+    int descSize =
+        cUnit->wholeMethod ? 0 : jitTraceDescriptionSize(cUnit->traceDesc);
     int chainingCellGap;
 
     info->instructionSet = cUnit->instructionSet;
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index cd0f18d..37425ad 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -1460,8 +1460,10 @@
             int valOffset = offsetof(StaticField, value);
             int tReg = dvmCompilerAllocTemp(cUnit);
             bool isVolatile;
+            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+                mir->meta.calleeMethod : cUnit->method;
             void *fieldPtr = (void*)
-              (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+              (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
 
             if (fieldPtr == NULL) {
                 LOGE("Unexpected null static field");
@@ -1488,8 +1490,10 @@
         }
         case OP_SGET_WIDE: {
             int valOffset = offsetof(StaticField, value);
+            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+                mir->meta.calleeMethod : cUnit->method;
             void *fieldPtr = (void*)
-              (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+              (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
 
             if (fieldPtr == NULL) {
                 LOGE("Unexpected null static field");
@@ -1517,8 +1521,10 @@
             int valOffset = offsetof(StaticField, value);
             int tReg = dvmCompilerAllocTemp(cUnit);
             bool isVolatile;
-            Field *fieldPtr =
-              (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+                mir->meta.calleeMethod : cUnit->method;
+            void *fieldPtr = (void*)
+              (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
 
             isVolatile = (mir->dalvikInsn.opCode == OP_SPUT_VOLATILE) ||
                          (mir->dalvikInsn.opCode == OP_SPUT_OBJECT_VOLATILE) ||
@@ -1549,8 +1555,10 @@
         case OP_SPUT_WIDE: {
             int tReg = dvmCompilerAllocTemp(cUnit);
             int valOffset = offsetof(StaticField, value);
+            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+                mir->meta.calleeMethod : cUnit->method;
             void *fieldPtr = (void*)
-              (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+              (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
 
             if (fieldPtr == NULL) {
                 LOGE("Unexpected null static field");
@@ -1672,6 +1680,21 @@
     return false;
 }
 
+/*
+ * A typical example of inlined getter/setter from a monomorphic callsite:
+ *
+ * D/dalvikvm(  289): -------- dalvik offset: 0x0000 @ invoke-static (I)
+ * D/dalvikvm(  289): -------- dalvik offset: 0x0000 @ sget-object (C) v0, ...
+ * D/dalvikvm(  289): 0x4427fc22 (0002): ldr     r0, [pc, #56]
+ * D/dalvikvm(  289): 0x4427fc24 (0004): ldr     r1, [r0, #0]
+ * D/dalvikvm(  289): 0x4427fc26 (0006): str     r1, [r5, #0]
+ * D/dalvikvm(  289): 0x4427fc28 (0008): .align4
+ * D/dalvikvm(  289): L0x0003:
+ * D/dalvikvm(  289): -------- dalvik offset: 0x0003 @ move-result-object (I) v0
+ *
+ * Note the invoke-static and move-result-object with the (I) notation are
+ * turned into no-op.
+ */
 static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
 {
     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
@@ -1693,6 +1716,9 @@
         }
         case OP_MOVE_RESULT:
         case OP_MOVE_RESULT_OBJECT: {
+            /* An inlined move result is effectively no-op */
+            if (mir->OptimizationFlags & MIR_INLINED)
+                break;
             RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
             RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
             rlSrc.fp = rlDest.fp;
@@ -1700,6 +1726,9 @@
             break;
         }
         case OP_MOVE_RESULT_WIDE: {
+            /* An inlined move result is effectively no-op */
+            if (mir->OptimizationFlags & MIR_INLINED)
+                break;
             RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
             RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
             rlSrc.fp = rlDest.fp;
@@ -2173,8 +2202,10 @@
         case OP_IPUT_BYTE:
         case OP_IPUT_CHAR:
         case OP_IPUT_SHORT: {
+            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+                mir->meta.calleeMethod : cUnit->method;
             Field *fieldPtr =
-                cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
+                method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
 
             if (fieldPtr == NULL) {
                 LOGE("Unexpected null instance field");
@@ -2714,12 +2745,47 @@
     return false;
 }
 
+/*
+ * See the example of predicted inlining listed before the
+ * genValidationForPredictedInline function. The function here takes care the
+ * branch over at 0x4858de78 and the misprediction target at 0x4858de7a.
+ */
+static void genLandingPadForMispredictedCallee(CompilationUnit *cUnit, MIR *mir,
+                                               BasicBlock *bb,
+                                               ArmLIR *labelList)
+{
+    BasicBlock *fallThrough = bb->fallThrough;
+
+    /* Bypass the move-result block if there is one */
+    if (fallThrough->firstMIRInsn) {
+        assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED);
+        fallThrough = fallThrough->fallThrough;
+    }
+    /* Generate a branch over if the predicted inlining is correct */
+    genUnconditionalBranch(cUnit, &labelList[fallThrough->id]);
+
+    /* Reset the register state */
+    dvmCompilerResetRegPool(cUnit);
+    dvmCompilerClobberAllRegs(cUnit);
+    dvmCompilerResetNullCheck(cUnit);
+
+    /* Target for the slow invoke path */
+    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    /* Hook up the target to the verification branch */
+    mir->meta.callsiteInfo->misPredBranchOver->target = (LIR *) target;
+}
+
 static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
                              ArmLIR *labelList)
 {
     ArmLIR *retChainingCell = NULL;
     ArmLIR *pcrLabel = NULL;
 
+    /* An invoke with the MIR_INLINED is effectively a no-op */
+    if (mir->OptimizationFlags & MIR_INLINED)
+        return false;
+
     if (bb->fallThrough != NULL)
         retChainingCell = &labelList[bb->fallThrough->id];
 
@@ -2737,6 +2803,15 @@
                 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
                 methodIndex;
 
+            /*
+             * If the invoke has non-null misPredBranchOver, we need to generate
+             * the non-inlined version of the invoke here to handle the
+             * mispredicted case.
+             */
+            if (mir->meta.callsiteInfo->misPredBranchOver) {
+                genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+            }
+
             if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
             else
@@ -2754,10 +2829,11 @@
          */
         case OP_INVOKE_SUPER:
         case OP_INVOKE_SUPER_RANGE: {
-            int mIndex = cUnit->method->clazz->pDvmDex->
-                pResMethods[dInsn->vB]->methodIndex;
-            const Method *calleeMethod =
-                cUnit->method->clazz->super->vtable[mIndex];
+            /* Grab the method ptr directly from what the interpreter sees */
+            const Method *calleeMethod = mir->meta.callsiteInfo->method;
+            assert(calleeMethod == cUnit->method->clazz->super->vtable[
+                                     cUnit->method->clazz->pDvmDex->
+                                       pResMethods[dInsn->vB]->methodIndex]);
 
             if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
@@ -2774,8 +2850,10 @@
         /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
         case OP_INVOKE_DIRECT:
         case OP_INVOKE_DIRECT_RANGE: {
-            const Method *calleeMethod =
-                cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
+            /* Grab the method ptr directly from what the interpreter sees */
+            const Method *calleeMethod = mir->meta.callsiteInfo->method;
+            assert(calleeMethod ==
+                   cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
 
             if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
@@ -2792,8 +2870,10 @@
         /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
         case OP_INVOKE_STATIC:
         case OP_INVOKE_STATIC_RANGE: {
-            const Method *calleeMethod =
-                cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
+            /* Grab the method ptr directly from what the interpreter sees */
+            const Method *calleeMethod = mir->meta.callsiteInfo->method;
+            assert(calleeMethod ==
+                   cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
 
             if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
                 genProcessArgsNoRange(cUnit, mir, dInsn,
@@ -2884,8 +2964,14 @@
         case OP_INVOKE_INTERFACE_RANGE: {
             ArmLIR *predChainingCell = &labelList[bb->taken->id];
 
-            /* Ensure that nothing is both live and dirty */
-            dvmCompilerFlushAllRegs(cUnit);
+            /*
+             * If the invoke has non-null misPredBranchOver, we need to generate
+             * the non-inlined version of the invoke here to handle the
+             * mispredicted case.
+             */
+            if (mir->meta.callsiteInfo->misPredBranchOver) {
+                genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+            }
 
             if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
@@ -3044,12 +3130,26 @@
     ArmLIR *predChainingCell = &labelList[bb->taken->id];
     ArmLIR *pcrLabel = NULL;
 
+    /* An invoke with the MIR_INLINED is effectively a no-op */
+    if (mir->OptimizationFlags & MIR_INLINED)
+        return false;
+
     DecodedInstruction *dInsn = &mir->dalvikInsn;
     switch (mir->dalvikInsn.opCode) {
         /* calleeMethod = this->clazz->vtable[BBBB] */
         case OP_INVOKE_VIRTUAL_QUICK_RANGE:
         case OP_INVOKE_VIRTUAL_QUICK: {
             int methodIndex = dInsn->vB;
+
+            /*
+             * If the invoke has non-null misPredBranchOver, we need to generate
+             * the non-inlined version of the invoke here to handle the
+             * mispredicted case.
+             */
+            if (mir->meta.callsiteInfo->misPredBranchOver) {
+                genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+            }
+
             if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
             else
@@ -3064,8 +3164,10 @@
         /* calleeMethod = method->clazz->super->vtable[BBBB] */
         case OP_INVOKE_SUPER_QUICK:
         case OP_INVOKE_SUPER_QUICK_RANGE: {
-            const Method *calleeMethod =
-                cUnit->method->clazz->super->vtable[dInsn->vB];
+            /* Grab the method ptr directly from what the interpreter sees */
+            const Method *calleeMethod = mir->meta.callsiteInfo->method;
+            assert(calleeMethod ==
+                   cUnit->method->clazz->super->vtable[dInsn->vB]);
 
             if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
@@ -3077,8 +3179,6 @@
 
             genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
                                      calleeMethod);
-            /* Handle exceptions using the interpreter */
-            genTrap(cUnit, mir->offset, pcrLabel);
             break;
         }
         default:
@@ -3485,6 +3585,7 @@
     "kMirOpNullNRangeDownCheck",
     "kMirOpLowerBound",
     "kMirOpPunt",
+    "kMirOpCheckInlinePrediction",
 };
 
 /*
@@ -3596,6 +3697,110 @@
                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
 }
 
+/*
+ * vC = this
+ *
+ * A predicted inlining target looks like the following, where instructions
+ * between 0x4858de66 and 0x4858de72 are checking if the predicted class
+ * matches "this", and the verificaion code is generated by this routine.
+ *
+ * (C) means the instruction is inlined from the callee, and (PI) means the
+ * instruction is the predicted inlined invoke, whose corresponding
+ * instructions are still generated to handle the mispredicted case.
+ *
+ * D/dalvikvm(   86): -------- kMirOpCheckInlinePrediction
+ * D/dalvikvm(   86): 0x4858de66 (0002): ldr     r0, [r5, #68]
+ * D/dalvikvm(   86): 0x4858de68 (0004): ldr     r1, [pc, #140]
+ * D/dalvikvm(   86): 0x4858de6a (0006): cmp     r0, #0
+ * D/dalvikvm(   86): 0x4858de6c (0008): beq     0x4858deb2
+ * D/dalvikvm(   86): 0x4858de6e (000a): ldr     r2, [r0, #0]
+ * D/dalvikvm(   86): 0x4858de70 (000c): cmp     r1, r2
+ * D/dalvikvm(   86): 0x4858de72 (000e): bne     0x4858de7a
+ * D/dalvikvm(   86): -------- dalvik offset: 0x004c @ +iget-object-quick (C)
+ * v4, v17, (#8)
+ * D/dalvikvm(   86): 0x4858de74 (0010): ldr     r3, [r0, #8]
+ * D/dalvikvm(   86): 0x4858de76 (0012): str     r3, [r5, #16]
+ * D/dalvikvm(   86): -------- dalvik offset: 0x004c @
+ * +invoke-virtual-quick/range (PI) v17..v17
+ * D/dalvikvm(   86): 0x4858de78 (0014): b       0x4858debc
+ * D/dalvikvm(   86): 0x4858de7a (0016): add     r4,r5,#68
+ * D/dalvikvm(   86): -------- BARRIER
+ * D/dalvikvm(   86): 0x4858de7e (001a): ldmia   r4, <r0>
+ * D/dalvikvm(   86): -------- BARRIER
+ * D/dalvikvm(   86): 0x4858de80 (001c): sub     r7,r5,#24
+ * D/dalvikvm(   86): 0x4858de84 (0020): cmp     r0, #0
+ * D/dalvikvm(   86): 0x4858de86 (0022): beq     0x4858deb6
+ * D/dalvikvm(   86): -------- BARRIER
+ * D/dalvikvm(   86): 0x4858de88 (0024): stmia   r7, <r0>
+ * D/dalvikvm(   86): -------- BARRIER
+ * D/dalvikvm(   86): 0x4858de8a (0026): ldr     r4, [pc, #104]
+ * D/dalvikvm(   86): 0x4858de8c (0028): add     r1, pc, #28
+ * D/dalvikvm(   86): 0x4858de8e (002a): add     r2, pc, #56
+ * D/dalvikvm(   86): 0x4858de90 (002c): blx_1   0x48589198
+ * D/dalvikvm(   86): 0x4858de92 (002e): blx_2   see above
+ * D/dalvikvm(   86): 0x4858de94 (0030): b       0x4858dec8
+ * D/dalvikvm(   86): 0x4858de96 (0032): b       0x4858deb6
+ * D/dalvikvm(   86): 0x4858de98 (0034): ldr     r0, [r7, #72]
+ * D/dalvikvm(   86): 0x4858de9a (0036): cmp     r1, #0
+ * D/dalvikvm(   86): 0x4858de9c (0038): bgt     0x4858dea4
+ * D/dalvikvm(   86): 0x4858de9e (003a): ldr     r7, [r6, #116]
+ * D/dalvikvm(   86): 0x4858dea0 (003c): movs    r1, r6
+ * D/dalvikvm(   86): 0x4858dea2 (003e): blx     r7
+ * D/dalvikvm(   86): 0x4858dea4 (0040): add     r1, pc, #4
+ * D/dalvikvm(   86): 0x4858dea6 (0042): blx_1   0x485890a0
+ * D/dalvikvm(   86): 0x4858dea8 (0044): blx_2   see above
+ * D/dalvikvm(   86): 0x4858deaa (0046): b       0x4858deb6
+ * D/dalvikvm(   86): 0x4858deac (0048): .align4
+ * D/dalvikvm(   86): L0x004f:
+ * D/dalvikvm(   86): -------- dalvik offset: 0x004f @ move-result-object (PI)
+ * v4, (#0), (#0)
+ * D/dalvikvm(   86): 0x4858deac (0048): ldr     r4, [r6, #8]
+ * D/dalvikvm(   86): 0x4858deae (004a): str     r4, [r5, #16]
+ * D/dalvikvm(   86): 0x4858deb0 (004c): b       0x4858debc
+ * D/dalvikvm(   86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c
+ * D/dalvikvm(   86): 0x4858deb2 (004e): ldr     r0, [pc, #64]
+ * D/dalvikvm(   86): 0x4858deb4 (0050): b       0x4858deb8
+ * D/dalvikvm(   86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c
+ * D/dalvikvm(   86): 0x4858deb6 (0052): ldr     r0, [pc, #60]
+ * D/dalvikvm(   86): Exception_Handling:
+ * D/dalvikvm(   86): 0x4858deb8 (0054): ldr     r1, [r6, #100]
+ * D/dalvikvm(   86): 0x4858deba (0056): blx     r1
+ * D/dalvikvm(   86): 0x4858debc (0058): .align4
+ * D/dalvikvm(   86): -------- chaining cell (hot): 0x0050
+ * D/dalvikvm(   86): 0x4858debc (0058): b       0x4858dec0
+ * D/dalvikvm(   86): 0x4858debe (005a): orrs    r0, r0
+ * D/dalvikvm(   86): 0x4858dec0 (005c): ldr     r0, [r6, #112]
+ * D/dalvikvm(   86): 0x4858dec2 (005e): blx     r0
+ * D/dalvikvm(   86): 0x4858dec4 (0060): data    0xefd4(61396)
+ * D/dalvikvm(   86): 0x4858dec6 (0062): data    0x42be(17086)
+ * D/dalvikvm(   86): 0x4858dec8 (0064): .align4
+ * D/dalvikvm(   86): -------- chaining cell (predicted)
+ * D/dalvikvm(   86): 0x4858dec8 (0064): data    0xe7fe(59390)
+ * D/dalvikvm(   86): 0x4858deca (0066): data    0x0000(0)
+ * D/dalvikvm(   86): 0x4858decc (0068): data    0x0000(0)
+ * D/dalvikvm(   86): 0x4858dece (006a): data    0x0000(0)
+ * :
+ */
+static void genValidationForPredictedInline(CompilationUnit *cUnit, MIR *mir)
+{
+    CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
+    RegLocation rlThis = cUnit->regLocation[mir->dalvikInsn.vC];
+
+    rlThis = loadValue(cUnit, rlThis, kCoreReg);
+    int regPredictedClass = dvmCompilerAllocTemp(cUnit);
+    loadConstant(cUnit, regPredictedClass, (int) callsiteInfo->clazz);
+    genNullCheck(cUnit, rlThis.sRegLow, rlThis.lowReg, mir->offset,
+                 NULL);/* null object? */
+    int regActualClass = dvmCompilerAllocTemp(cUnit);
+    loadWordDisp(cUnit, rlThis.lowReg, offsetof(Object, clazz), regActualClass);
+    opRegReg(cUnit, kOpCmp, regPredictedClass, regActualClass);
+    /*
+     * Set the misPredBranchOver target so that it will be generated when the
+     * code for the non-optimized invoke is generated.
+     */
+    callsiteInfo->misPredBranchOver = (LIR *) opCondBranch(cUnit, kArmCondNe);
+}
+
 /* Extended MIR instructions like PHI */
 static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
 {
@@ -3628,6 +3833,10 @@
                                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
             break;
         }
+        case kMirOpCheckInlinePrediction: {
+            genValidationForPredictedInline(cUnit, mir);
+            break;
+        }
         default:
             break;
     }
@@ -3674,7 +3883,7 @@
 {
     DecodedInstruction *decInsn = &mir->dalvikInsn;
     OpCode op = decInsn->opCode;
-    int flags =  dexGetInstrFlags(gDvm.instrFlags, op);
+
     /*
      * All opcodes that can throw exceptions and use the
      * TEMPLATE_THROW_EXCEPTION_COMMON template should be excluded in the trace
@@ -3684,8 +3893,7 @@
             op == OP_NEW_INSTANCE || op == OP_NEW_ARRAY ||
             op == OP_CHECK_CAST || op == OP_MOVE_EXCEPTION ||
             op == OP_FILL_ARRAY_DATA || op == OP_EXECUTE_INLINE ||
-            op == OP_EXECUTE_INLINE_RANGE ||
-            (flags & kInstrInvoke));
+            op == OP_EXECUTE_INLINE_RANGE);
 }
 #endif
 
@@ -3748,13 +3956,7 @@
         labelList[i].operands[0] = blockList[i]->startOffset;
 
         if (blockList[i]->blockType >= kChainingCellGap) {
-            if (blockList[i]->firstMIRInsn != NULL &&
-                ((blockList[i]->firstMIRInsn->dalvikInsn.opCode ==
-                  OP_MOVE_RESULT) ||
-                 (blockList[i]->firstMIRInsn->dalvikInsn.opCode ==
-                  OP_MOVE_RESULT_WIDE) ||
-                 (blockList[i]->firstMIRInsn->dalvikInsn.opCode ==
-                  OP_MOVE_RESULT_OBJECT))) {
+            if (blockList[i]->isFallThroughFromInvoke == true) {
                 /* Align this block first since it is a return chaining cell */
                 newLIR0(cUnit, kArmPseudoPseudoAlign4);
             }
@@ -3765,7 +3967,7 @@
             dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
         }
 
-        if (blockList[i]->blockType == kEntryBlock) {
+        if (blockList[i]->blockType == kTraceEntryBlock) {
             labelList[i].opCode = kArmPseudoEntryBlock;
             if (blockList[i]->firstMIRInsn == NULL) {
                 continue;
@@ -3773,7 +3975,7 @@
               setupLoopEntryBlock(cUnit, blockList[i],
                                   &labelList[blockList[i]->fallThrough->id]);
             }
-        } else if (blockList[i]->blockType == kExitBlock) {
+        } else if (blockList[i]->blockType == kTraceExitBlock) {
             labelList[i].opCode = kArmPseudoExitBlock;
             goto gen_fallthrough;
         } else if (blockList[i]->blockType == kDalvikByteCode) {
@@ -3870,11 +4072,22 @@
             OpCode dalvikOpCode = mir->dalvikInsn.opCode;
             InstructionFormat dalvikFormat =
                 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
+            char *note;
+            if (mir->OptimizationFlags & MIR_INLINED) {
+                note = " (I)";
+            } else if (mir->OptimizationFlags & MIR_INLINED_PRED) {
+                note = " (PI)";
+            } else if (mir->OptimizationFlags & MIR_CALLEE) {
+                note = " (C)";
+            } else {
+                note = NULL;
+            }
+
             ArmLIR *boundaryLIR =
                 newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary,
                         mir->offset,
-                        (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn)
-                       );
+                        (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn,
+                                                              note));
             if (mir->ssaRep) {
                 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
                 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
@@ -4000,7 +4213,7 @@
             }
         }
 
-        if (blockList[i]->blockType == kEntryBlock) {
+        if (blockList[i]->blockType == kTraceEntryBlock) {
             dvmCompilerAppendLIR(cUnit,
                                  (LIR *) cUnit->loopAnalysis->branchToBody);
             dvmCompilerAppendLIR(cUnit,
@@ -4117,9 +4330,6 @@
     }
 
     switch (work->kind) {
-        case kWorkOrderMethod:
-            res = dvmCompileMethod(work->info, &work->result);
-            break;
         case kWorkOrderTrace:
             /* Start compilation with maximally allowed trace length */
             res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result,
diff --git a/vm/compiler/template/armv5te/TEMPLATE_RETURN.S b/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
index 70044c2..b7ab971 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
@@ -23,7 +23,7 @@
 #else
     blxeq   lr                          @ punt to interpreter and compare state
 #endif
-    ldr     r1, .LdvmJitToInterpNoChain @ defined in footer.S
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
     mov     rFP, r10                    @ publish new FP
     ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
     ldr     r8, [r8]                    @ r8<- suspendCount
diff --git a/vm/compiler/template/armv5te/footer.S b/vm/compiler/template/armv5te/footer.S
index 8e66ac6..73fc3d7 100644
--- a/vm/compiler/template/armv5te/footer.S
+++ b/vm/compiler/template/armv5te/footer.S
@@ -76,6 +76,8 @@
     .align  2
 .LdvmAsmInstructionStart:
     .word   dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+    .word   dvmJitToInterpNoChainNoProfile
 .LdvmJitToInterpTraceSelectNoChain:
     .word   dvmJitToInterpTraceSelectNoChain
 .LdvmJitToInterpNoChain:
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
index 0823324..60664fa 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
@@ -101,7 +101,6 @@
  */
 #include "../../../mterp/common/asm-constants.h"
 
-
 /* File: armv5te-vfp/platform.S */
 /*
  * ===========================================================================
@@ -166,7 +165,6 @@
     mov     r0, #1                      @ r0<- 1
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_RETURN
@@ -197,7 +195,7 @@
 #else
     blxeq   lr                          @ punt to interpreter and compare state
 #endif
-    ldr     r1, .LdvmJitToInterpNoChain @ defined in footer.S
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
     mov     rFP, r10                    @ publish new FP
     ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
     ldr     r8, [r8]                    @ r8<- suspendCount
@@ -334,8 +332,6 @@
 
     bx      lr                              @ return to the callee-chaining cell
 
-
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
@@ -468,9 +464,6 @@
 #endif
     mov     pc, r1
 
-
-
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_MUL_LONG
@@ -547,7 +540,6 @@
     mov     r1, r1, asr r2              @  r1<- r1 >> r2
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_USHR_LONG
@@ -569,7 +561,6 @@
     mov     r1, r1, lsr r2              @  r1<- r1 >>> r2
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_ADD_FLOAT_VFP
@@ -919,7 +910,6 @@
     moveq   r0, #0                      @ (equal) r0<- 0
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_CMPL_DOUBLE_VFP
@@ -1226,7 +1216,6 @@
 .Lmemcmp16:
     .word __memcmp16
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_STRING_INDEXOF
@@ -1345,7 +1334,6 @@
     asr   r0, r0, #1
     bx    lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_INTERPRET
@@ -1406,7 +1394,6 @@
 #endif
     bx      r2
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
@@ -1525,6 +1512,8 @@
     .align  2
 .LdvmAsmInstructionStart:
     .word   dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+    .word   dvmJitToInterpNoChainNoProfile
 .LdvmJitToInterpTraceSelectNoChain:
     .word   dvmJitToInterpTraceSelectNoChain
 .LdvmJitToInterpNoChain:
@@ -1552,3 +1541,4 @@
 dmvCompilerTemplateEnd:
 
 #endif /* WITH_JIT */
+
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
index b9a3075..ccdbcca 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
@@ -101,7 +101,6 @@
  */
 #include "../../../mterp/common/asm-constants.h"
 
-
 /* File: armv5te/platform.S */
 /*
  * ===========================================================================
@@ -166,7 +165,6 @@
     mov     r0, #1                      @ r0<- 1
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_RETURN
@@ -197,7 +195,7 @@
 #else
     blxeq   lr                          @ punt to interpreter and compare state
 #endif
-    ldr     r1, .LdvmJitToInterpNoChain @ defined in footer.S
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
     mov     rFP, r10                    @ publish new FP
     ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
     ldr     r8, [r8]                    @ r8<- suspendCount
@@ -334,8 +332,6 @@
 
     bx      lr                              @ return to the callee-chaining cell
 
-
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
@@ -468,9 +464,6 @@
 #endif
     mov     pc, r1
 
-
-
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_CMPG_DOUBLE
@@ -514,7 +507,6 @@
     bx      r11
 
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_CMPL_DOUBLE
@@ -556,7 +548,6 @@
     mvn     r0, #0                            @ r1<- 1 or -1 for NaN
     bx      r11
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_CMPG_FLOAT
@@ -618,8 +609,6 @@
     bx      r11
 
 
-
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_CMPL_FLOAT
@@ -679,8 +668,6 @@
     mvn     r0, #0                            @ r1<- 1 or -1 for NaN
     bx      r11
 
-
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_MUL_LONG
@@ -757,7 +744,6 @@
     mov     r1, r1, asr r2              @  r1<- r1 >> r2
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_USHR_LONG
@@ -779,7 +765,6 @@
     mov     r1, r1, lsr r2              @  r1<- r1 >>> r2
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON
@@ -954,7 +939,6 @@
 .Lmemcmp16:
     .word __memcmp16
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_STRING_INDEXOF
@@ -1073,7 +1057,6 @@
     asr   r0, r0, #1
     bx    lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_INTERPRET
@@ -1134,7 +1117,6 @@
 #endif
     bx      r2
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
@@ -1253,6 +1235,8 @@
     .align  2
 .LdvmAsmInstructionStart:
     .word   dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+    .word   dvmJitToInterpNoChainNoProfile
 .LdvmJitToInterpTraceSelectNoChain:
     .word   dvmJitToInterpTraceSelectNoChain
 .LdvmJitToInterpNoChain:
@@ -1280,3 +1264,4 @@
 dmvCompilerTemplateEnd:
 
 #endif /* WITH_JIT */
+
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
index 008c324..e520056 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
@@ -101,7 +101,6 @@
  */
 #include "../../../mterp/common/asm-constants.h"
 
-
 /* File: armv5te-vfp/platform.S */
 /*
  * ===========================================================================
@@ -166,7 +165,6 @@
     mov     r0, #1                      @ r0<- 1
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_RETURN
@@ -197,7 +195,7 @@
 #else
     blxeq   lr                          @ punt to interpreter and compare state
 #endif
-    ldr     r1, .LdvmJitToInterpNoChain @ defined in footer.S
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
     mov     rFP, r10                    @ publish new FP
     ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
     ldr     r8, [r8]                    @ r8<- suspendCount
@@ -334,8 +332,6 @@
 
     bx      lr                              @ return to the callee-chaining cell
 
-
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
@@ -468,9 +464,6 @@
 #endif
     mov     pc, r1
 
-
-
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_MUL_LONG
@@ -547,7 +540,6 @@
     mov     r1, r1, asr r2              @  r1<- r1 >> r2
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_USHR_LONG
@@ -569,7 +561,6 @@
     mov     r1, r1, lsr r2              @  r1<- r1 >>> r2
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_ADD_FLOAT_VFP
@@ -919,7 +910,6 @@
     moveq   r0, #0                      @ (equal) r0<- 0
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_CMPL_DOUBLE_VFP
@@ -1226,7 +1216,6 @@
 .Lmemcmp16:
     .word __memcmp16
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_STRING_INDEXOF
@@ -1345,7 +1334,6 @@
     asr   r0, r0, #1
     bx    lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_INTERPRET
@@ -1406,7 +1394,6 @@
 #endif
     bx      r2
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
@@ -1525,6 +1512,8 @@
     .align  2
 .LdvmAsmInstructionStart:
     .word   dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+    .word   dvmJitToInterpNoChainNoProfile
 .LdvmJitToInterpTraceSelectNoChain:
     .word   dvmJitToInterpTraceSelectNoChain
 .LdvmJitToInterpNoChain:
@@ -1552,3 +1541,4 @@
 dmvCompilerTemplateEnd:
 
 #endif /* WITH_JIT */
+
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
index 5441057..87a0691 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
@@ -101,7 +101,6 @@
  */
 #include "../../../mterp/common/asm-constants.h"
 
-
 /* File: armv5te-vfp/platform.S */
 /*
  * ===========================================================================
@@ -166,7 +165,6 @@
     mov     r0, #1                      @ r0<- 1
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_RETURN
@@ -197,7 +195,7 @@
 #else
     blxeq   lr                          @ punt to interpreter and compare state
 #endif
-    ldr     r1, .LdvmJitToInterpNoChain @ defined in footer.S
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
     mov     rFP, r10                    @ publish new FP
     ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
     ldr     r8, [r8]                    @ r8<- suspendCount
@@ -334,8 +332,6 @@
 
     bx      lr                              @ return to the callee-chaining cell
 
-
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
@@ -468,9 +464,6 @@
 #endif
     mov     pc, r1
 
-
-
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_MUL_LONG
@@ -547,7 +540,6 @@
     mov     r1, r1, asr r2              @  r1<- r1 >> r2
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_USHR_LONG
@@ -569,7 +561,6 @@
     mov     r1, r1, lsr r2              @  r1<- r1 >>> r2
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_ADD_FLOAT_VFP
@@ -919,7 +910,6 @@
     moveq   r0, #0                      @ (equal) r0<- 0
     bx      lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_CMPL_DOUBLE_VFP
@@ -1226,7 +1216,6 @@
 .Lmemcmp16:
     .word __memcmp16
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_STRING_INDEXOF
@@ -1345,7 +1334,6 @@
     asr   r0, r0, #1
     bx    lr
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_INTERPRET
@@ -1406,7 +1394,6 @@
 #endif
     bx      r2
 
-
 /* ------------------------------ */
     .balign 4
     .global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
@@ -1525,6 +1512,8 @@
     .align  2
 .LdvmAsmInstructionStart:
     .word   dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+    .word   dvmJitToInterpNoChainNoProfile
 .LdvmJitToInterpTraceSelectNoChain:
     .word   dvmJitToInterpTraceSelectNoChain
 .LdvmJitToInterpNoChain:
@@ -1552,3 +1541,4 @@
 dmvCompilerTemplateEnd:
 
 #endif /* WITH_JIT */
+
diff --git a/vm/interp/Interp.c b/vm/interp/Interp.c
index daaf0c0..ab61882 100644
--- a/vm/interp/Interp.c
+++ b/vm/interp/Interp.c
@@ -1285,7 +1285,13 @@
 #endif
     };
 
-    assert(self->inJitCodeCache == NULL);
+    /*
+     * If the previous VM left the code cache through single-stepping the
+     * inJitCodeCache flag will be set when the VM is re-entered (for example,
+     * in self-verification mode we single-step NEW_INSTANCE which may re-enter
+     * the VM through findClassFromLoaderNoInit). Because of that, we cannot
+     * assert that self->inJitCodeCache is NULL here.
+     */
 #endif
 
 
diff --git a/vm/interp/Jit.c b/vm/interp/Jit.c
index 0665dcd..4129e8a 100644
--- a/vm/interp/Jit.c
+++ b/vm/interp/Jit.c
@@ -135,7 +135,7 @@
  * Return a pointer to the shadow space for JIT to restore state.
  */
 void* dvmSelfVerificationRestoreState(const u2* pc, const void* fp,
-                                      SelfVerificationState exitPoint)
+                                      SelfVerificationState exitState)
 {
     Thread *self = dvmThreadSelf();
     ShadowSpace *shadowSpace = self->shadowSpace;
@@ -143,6 +143,7 @@
     InterpState *realGlue = shadowSpace->glue;
     shadowSpace->endPC = pc;
     shadowSpace->endShadowFP = fp;
+    shadowSpace->jitExitState = exitState;
 
     //LOGD("### selfVerificationRestoreState(%d) pc: 0x%x fp: 0x%x endPC: 0x%x",
     //    self->threadId, (int)shadowSpace->startPC, (int)shadowSpace->fp,
@@ -161,7 +162,7 @@
 
     // Move the resume [ND]PC from the shadow space to the real space so that
     // the debug interpreter can return to the translation
-    if (exitPoint == kSVSSingleStep) {
+    if (exitState == kSVSSingleStep) {
         realGlue->jitResumeNPC = shadowSpace->interpState.jitResumeNPC;
         realGlue->jitResumeDPC = shadowSpace->interpState.jitResumeDPC;
     } else {
@@ -170,10 +171,10 @@
     }
 
     // Special case when punting after a single instruction
-    if (exitPoint == kSVSPunt && pc == shadowSpace->startPC) {
+    if (exitState == kSVSPunt && pc == shadowSpace->startPC) {
         shadowSpace->selfVerificationState = kSVSIdle;
     } else {
-        shadowSpace->selfVerificationState = exitPoint;
+        shadowSpace->selfVerificationState = exitState;
     }
 
     return shadowSpace;
@@ -477,6 +478,9 @@
         LOGD("JIT: Invoke: %d mono, %d poly, %d native, %d return",
              gDvmJit.invokeMonomorphic, gDvmJit.invokePolymorphic,
              gDvmJit.invokeNative, gDvmJit.returnOp);
+        LOGD("JIT: Inline: %d mgetter, %d msetter, %d pgetter, %d psetter",
+             gDvmJit.invokeMonoGetterInlined, gDvmJit.invokeMonoSetterInlined,
+             gDvmJit.invokePolyGetterInlined, gDvmJit.invokePolySetterInlined);
         LOGD("JIT: Total compilation time: %llu ms", gDvmJit.jitTime / 1000);
         LOGD("JIT: Avg unit compilation time: %llu us",
              gDvmJit.jitTime / gDvmJit.numCompilations);
@@ -607,8 +611,32 @@
 }
 
 /*
+ * Append the class ptr of "this" and the current method ptr to the current
+ * trace. That is, the trace runs will contain the following components:
+ *  + trace run that ends with an invoke (existing entry)
+ *  + thisClass (new)
+ *  + calleeMethod (new)
+ */
+static void insertClassMethodInfo(InterpState* interpState,
+                                  const ClassObject* thisClass,
+                                  const Method* calleeMethod,
+                                  const DecodedInstruction* insn)
+{
+    int currTraceRun = ++interpState->currTraceRun;
+    interpState->trace[currTraceRun].meta = (void *) thisClass;
+    currTraceRun = ++interpState->currTraceRun;
+    interpState->trace[currTraceRun].meta = (void *) calleeMethod;
+}
+
+/*
  * Check if the next instruction following the invoke is a move-result and if
- * so add it to the trace.
+ * so add it to the trace. That is, this will add the trace run that includes
+ * the move-result to the trace list.
+ *
+ *  + trace run that ends with an invoke (existing entry)
+ *  + thisClass (existing entry)
+ *  + calleeMethod (existing entry)
+ *  + move result (new)
  *
  * lastPC, len, offset are all from the preceding invoke instruction
  */
@@ -631,6 +659,7 @@
     interpState->trace[currTraceRun].frag.numInsts = 1;
     interpState->trace[currTraceRun].frag.runEnd = false;
     interpState->trace[currTraceRun].frag.hint = kJitHintNone;
+    interpState->trace[currTraceRun].frag.isCode = true;
     interpState->totalTraceLen++;
 
     interpState->currRunLen = dexGetInstrOrTableWidthAbs(gDvm.instrWidth,
@@ -653,11 +682,14 @@
  * because returns cannot throw in a way that causes problems for the
  * translated code.
  */
-int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState)
+int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState,
+                const ClassObject* thisClass, const Method* curMethod)
 {
     int flags, len;
     int switchInterp = false;
     bool debugOrProfile = dvmDebuggerOrProfilerActive();
+    /* Stay in the dbg interpreter for the next instruction */
+    bool stayOneMoreInst = false;
 
     /*
      * Bug 2710533 - dalvik crash when disconnecting debugger
@@ -711,6 +743,7 @@
                 interpState->trace[currTraceRun].frag.numInsts = 0;
                 interpState->trace[currTraceRun].frag.runEnd = false;
                 interpState->trace[currTraceRun].frag.hint = kJitHintNone;
+                interpState->trace[currTraceRun].frag.isCode = true;
             }
             interpState->trace[interpState->currTraceRun].frag.numInsts++;
             interpState->totalTraceLen++;
@@ -742,10 +775,14 @@
 #endif
 
                 /*
+                 * If the current invoke is a {virtual,interface}, get the
+                 * current class/method pair into the trace as well.
                  * If the next instruction is a variant of move-result, insert
-                 * it to the trace as well.
+                 * it to the trace too.
                  */
                 if (flags & kInstrInvoke) {
+                    insertClassMethodInfo(interpState, thisClass, curMethod,
+                                          &decInsn);
                     insertMoveResult(lastPC, len, offset, interpState);
                 }
             }
@@ -764,6 +801,18 @@
             if ((flags & kInstrCanReturn) != kInstrCanReturn) {
                 break;
             }
+            else {
+                /*
+                 * Last instruction is a return - stay in the dbg interpreter
+                 * for one more instruction if it is a non-void return, since
+                 * we don't want to start a trace with move-result as the first
+                 * instruction (which is already included in the trace
+                 * containing the invoke.
+                 */
+                if (decInsn.opCode != OP_RETURN_VOID) {
+                    stayOneMoreInst = true;
+                }
+            }
             /* NOTE: intentional fallthrough for returns */
         case kJitTSelectEnd:
             {
@@ -774,9 +823,25 @@
                     switchInterp = true;
                     break;
                 }
+
+                int lastTraceDesc = interpState->currTraceRun;
+
+                /* Extend a new empty desc if the last slot is meta info */
+                if (!interpState->trace[lastTraceDesc].frag.isCode) {
+                    lastTraceDesc = ++interpState->currTraceRun;
+                    interpState->trace[lastTraceDesc].frag.startOffset = 0;
+                    interpState->trace[lastTraceDesc].frag.numInsts = 0;
+                    interpState->trace[lastTraceDesc].frag.hint = kJitHintNone;
+                    interpState->trace[lastTraceDesc].frag.isCode = true;
+                }
+
+                /* Mark the end of the trace runs */
+                interpState->trace[lastTraceDesc].frag.runEnd = true;
+
                 JitTraceDescription* desc =
                    (JitTraceDescription*)malloc(sizeof(JitTraceDescription) +
                      sizeof(JitTraceRun) * (interpState->currTraceRun+1));
+
                 if (desc == NULL) {
                     LOGE("Out of memory in trace selection");
                     dvmJitStopTranslationRequests();
@@ -784,8 +849,7 @@
                     switchInterp = true;
                     break;
                 }
-                interpState->trace[interpState->currTraceRun].frag.runEnd =
-                     true;
+
                 desc->method = interpState->method;
                 memcpy((char*)&(desc->trace[0]),
                     (char*)&(interpState->trace[0]),
@@ -859,7 +923,7 @@
      */
      assert(switchInterp == false || interpState->jitState == kJitDone ||
             interpState->jitState == kJitNot);
-     return switchInterp && !debugOrProfile;
+     return switchInterp && !debugOrProfile && !stayOneMoreInst;
 }
 
 JitEntry *dvmFindJitEntry(const u2* pc)
@@ -1095,6 +1159,7 @@
                 interpState->trace[0].frag.numInsts = 0;
                 interpState->trace[0].frag.runEnd = false;
                 interpState->trace[0].frag.hint = kJitHintNone;
+                interpState->trace[0].frag.isCode = true;
                 interpState->lastPC = 0;
                 break;
             /*
diff --git a/vm/interp/Jit.h b/vm/interp/Jit.h
index 9d17a52..6101f54 100644
--- a/vm/interp/Jit.h
+++ b/vm/interp/Jit.h
@@ -43,7 +43,8 @@
     const u2* startPC;          /* starting pc of jitted region */
     const void* fp;             /* starting fp of jitted region */
     void* glue;                 /* starting glue of jitted region */
-    SelfVerificationState selfVerificationState;  /* self verification state */
+    SelfVerificationState jitExitState;  /* exit point for JIT'ed code */
+    SelfVerificationState selfVerificationState;  /* current SV running state */
     const u2* endPC;            /* ending pc of jitted region */
     void* shadowFP;       /* pointer to fp in shadow space */
     InterpState interpState;    /* copy of interpState */
@@ -108,7 +109,8 @@
     void*               codeAddress;    /* Code address of native translation */
 } JitEntry;
 
-int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState);
+int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState,
+                const ClassObject *callsiteClass, const Method* curMethod);
 void* dvmJitGetCodeAddr(const u2* dPC);
 bool dvmJitCheckTraceRequest(Thread* self, InterpState* interpState);
 void dvmJitStopTranslationRequests(void);
diff --git a/vm/mterp/armv5te/entry.S b/vm/mterp/armv5te/entry.S
index 881c0e0..eddac53 100644
--- a/vm/mterp/armv5te/entry.S
+++ b/vm/mterp/armv5te/entry.S
@@ -68,14 +68,27 @@
 
 #if defined(WITH_JIT)
 .LentryInstr:
-    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    ldr     r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
     /* Entry is always a possible trace start */
     GET_JIT_PROF_TABLE(r0)
     FETCH_INST()
-    mov    r1, #0                       @ prepare the value for the new state
-    str    r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
-    cmp    r0,#0
-    bne    common_updateProfile
+    mov     r1, #0                      @ prepare the value for the new state
+    str     r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+    cmp     r0,#0                       @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     common_updateProfile        @ profiling is enabled
+#else
+    ldr     r2, [r10, #offThread_shadowSpace]   @ to find out the jit exit state
+    beq     1f                          @ profiling is disabled
+    ldr     r3, [r2, #offShadowSpace_jitExitState]  @ jit exit state
+    cmp     r3, #kSVSTraceSelect        @ hot trace following?
+    moveq   r2,#kJitTSelectRequestHot   @ ask for trace selection
+    beq     common_selectTrace          @ go build the trace
+    cmp     r3, #kSVSNoProfile          @ don't profile the next instruction?
+    beq     1f                          @ intrepret the next instruction
+    b       common_updateProfile        @ collect profiles
+#endif
+1:
     GET_INST_OPCODE(ip)
     GOTO_OPCODE(ip)
 #else
diff --git a/vm/mterp/armv5te/footer.S b/vm/mterp/armv5te/footer.S
index 72eb5ce..3212126 100644
--- a/vm/mterp/armv5te/footer.S
+++ b/vm/mterp/armv5te/footer.S
@@ -27,12 +27,21 @@
     mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
     b      jitSVShadowRunEnd            @ doesn't return
 
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoProfile            @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
     .global dvmJitToInterpTraceSelectNoChain
 dvmJitToInterpTraceSelectNoChain:
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     mov    r0,rPC                       @ pass our target PC
-    mov    r2,#kSVSTraceSelectNoChain   @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -41,7 +50,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -50,7 +59,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -59,7 +68,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSNormal               @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -68,7 +77,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     mov    r0,rPC                       @ pass our target PC
     mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 #else
@@ -133,9 +142,9 @@
     str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
     mov    r1, rPC                  @ arg1 of translation may need this
     mov    lr, #0                   @  in case target is HANDLER_INTERPRET
-    cmp    r0,#0
+    cmp    r0,#0                    @ !0 means translation exists
     bxne   r0                       @ continue native execution if so
-    b      2f
+    b      2f                       @ branch over to use the interpreter
 
 /*
  * Return from the translation cache and immediately request
@@ -212,6 +221,29 @@
  * Return from the translation cache to the interpreter to do method invocation.
  * Check if translation exists for the callee, but don't chain to it.
  */
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC
+    bl     dvmJitGetCodeAddr        @ Is there a translation?
+    str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+    EXPORT_PC()
+    adrl   rIBASE, dvmAsmInstructionStart
+    FETCH_INST()
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
     .global dvmJitToInterpNoChain
 dvmJitToInterpNoChain:
 #if defined(WITH_JIT_TUNING)
@@ -239,6 +271,7 @@
     FETCH_INST()
     GET_JIT_PROF_TABLE(r0)
     @ NOTE: intended fallthrough
+
 /*
  * Common code to update potential trace start counter, and initiate
  * a trace-build if appropriate.  On entry, rPC should point to the
@@ -779,15 +812,12 @@
     str     rFP, [r3, #offThread_curFrame]  @ self->curFrame = fp
 #if defined(WITH_JIT)
     ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
-    GET_JIT_PROF_TABLE(r0)
     mov     rPC, r9                     @ publish new rPC
     str     r1, [rGLUE, #offGlue_methodClassDex]
     str     r10, [r3, #offThread_inJitCodeCache]  @ may return to JIT'ed land
     cmp     r10, #0                      @ caller is compiled code
     blxne   r10
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    cmp     r0,#0
-    bne     common_updateProfile
     GOTO_OPCODE(ip)                     @ jump to next instruction
 #else
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
diff --git a/vm/mterp/c/gotoTargets.c b/vm/mterp/c/gotoTargets.c
index 842171d..b17fb80 100644
--- a/vm/mterp/c/gotoTargets.c
+++ b/vm/mterp/c/gotoTargets.c
@@ -154,6 +154,10 @@
         assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
         methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisPtr->clazz;
+#endif
+
 #if 0
         if (dvmIsAbstractMethod(methodToCall)) {
             /*
@@ -305,6 +309,10 @@
 
         thisClass = thisPtr->clazz;
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisClass;
+#endif
+
         /*
          * Given a class and a method index, find the Method* with the
          * actual code we want to execute.
@@ -419,6 +427,10 @@
         if (!checkForNull(thisPtr))
             GOTO_exceptionThrown();
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisPtr->clazz;
+#endif
+
         /*
          * Combine the object we found with the vtable offset in the
          * method.
diff --git a/vm/mterp/common/asm-constants.h b/vm/mterp/common/asm-constants.h
index bcff8f0..475b897 100644
--- a/vm/mterp/common/asm-constants.h
+++ b/vm/mterp/common/asm-constants.h
@@ -184,12 +184,13 @@
 
   /* ShadowSpace fields */
 #if defined(WITH_JIT) && defined(WITH_SELF_VERIFICATION)
-MTERP_OFFSET(offShadowSpace_startPC, ShadowSpace, startPC, 0)
-MTERP_OFFSET(offShadowSpace_fp, ShadowSpace, fp, 4)
-MTERP_OFFSET(offShadowSpace_glue, ShadowSpace, glue, 8)
-MTERP_OFFSET(offShadowSpace_svState, ShadowSpace, selfVerificationState, 12)
-MTERP_OFFSET(offShadowSpace_shadowFP, ShadowSpace, shadowFP, 20)
-MTERP_OFFSET(offShadowSpace_interpState, ShadowSpace, interpState, 24)
+MTERP_OFFSET(offShadowSpace_startPC,     ShadowSpace, startPC, 0)
+MTERP_OFFSET(offShadowSpace_fp,          ShadowSpace, fp, 4)
+MTERP_OFFSET(offShadowSpace_glue,        ShadowSpace, glue, 8)
+MTERP_OFFSET(offShadowSpace_jitExitState,ShadowSpace, jitExitState, 12)
+MTERP_OFFSET(offShadowSpace_svState,     ShadowSpace, selfVerificationState, 16)
+MTERP_OFFSET(offShadowSpace_shadowFP,    ShadowSpace, shadowFP, 24)
+MTERP_OFFSET(offShadowSpace_interpState, ShadowSpace, interpState, 32)
 #endif
 
 /* InstField fields */
@@ -226,6 +227,16 @@
 
 #if defined(WITH_JIT)
 MTERP_OFFSET(offThread_inJitCodeCache,  Thread, inJitCodeCache, 76)
+#if defined(WITH_SELF_VERIFICATION)
+MTERP_OFFSET(offThread_shadowSpace,     Thread, shadowSpace, 80)
+#ifdef USE_INDIRECT_REF
+MTERP_OFFSET(offThread_jniLocal_topCookie, \
+                                Thread, jniLocalRefTable.segmentState.all, 84)
+#else
+MTERP_OFFSET(offThread_jniLocal_topCookie, \
+                                Thread, jniLocalRefTable.nextEntry, 84)
+#endif
+#else
 #ifdef USE_INDIRECT_REF
 MTERP_OFFSET(offThread_jniLocal_topCookie, \
                                 Thread, jniLocalRefTable.segmentState.all, 80)
@@ -233,6 +244,7 @@
 MTERP_OFFSET(offThread_jniLocal_topCookie, \
                                 Thread, jniLocalRefTable.nextEntry, 80)
 #endif
+#endif
 #else
 #ifdef USE_INDIRECT_REF
 MTERP_OFFSET(offThread_jniLocal_topCookie, \
@@ -313,7 +325,7 @@
 MTERP_CONSTANT(kSVSStart, 1)
 MTERP_CONSTANT(kSVSPunt, 2)
 MTERP_CONSTANT(kSVSSingleStep, 3)
-MTERP_CONSTANT(kSVSTraceSelectNoChain, 4)
+MTERP_CONSTANT(kSVSNoProfile, 4)
 MTERP_CONSTANT(kSVSTraceSelect, 5)
 MTERP_CONSTANT(kSVSNormal, 6)
 MTERP_CONSTANT(kSVSNoChain, 7)
diff --git a/vm/mterp/out/InterpAsm-armv4t.S b/vm/mterp/out/InterpAsm-armv4t.S
index d82272f..5ce80ff 100644
--- a/vm/mterp/out/InterpAsm-armv4t.S
+++ b/vm/mterp/out/InterpAsm-armv4t.S
@@ -320,14 +320,27 @@
 
 #if defined(WITH_JIT)
 .LentryInstr:
-    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    ldr     r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
     /* Entry is always a possible trace start */
     GET_JIT_PROF_TABLE(r0)
     FETCH_INST()
-    mov    r1, #0                       @ prepare the value for the new state
-    str    r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
-    cmp    r0,#0
-    bne    common_updateProfile
+    mov     r1, #0                      @ prepare the value for the new state
+    str     r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+    cmp     r0,#0                       @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     common_updateProfile        @ profiling is enabled
+#else
+    ldr     r2, [r10, #offThread_shadowSpace]   @ to find out the jit exit state
+    beq     1f                          @ profiling is disabled
+    ldr     r3, [r2, #offShadowSpace_jitExitState]  @ jit exit state
+    cmp     r3, #kSVSTraceSelect        @ hot trace following?
+    moveq   r2,#kJitTSelectRequestHot   @ ask for trace selection
+    beq     common_selectTrace          @ go build the trace
+    cmp     r3, #kSVSNoProfile          @ don't profile the next instruction?
+    beq     1f                          @ intrepret the next instruction
+    b       common_updateProfile        @ collect profiles
+#endif
+1:
     GET_INST_OPCODE(ip)
     GOTO_OPCODE(ip)
 #else
@@ -9862,12 +9875,21 @@
     mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
     b      jitSVShadowRunEnd            @ doesn't return
 
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoProfile            @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
     .global dvmJitToInterpTraceSelectNoChain
 dvmJitToInterpTraceSelectNoChain:
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     mov    r0,rPC                       @ pass our target PC
-    mov    r2,#kSVSTraceSelectNoChain   @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9876,7 +9898,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9885,7 +9907,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9894,7 +9916,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSNormal               @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9903,7 +9925,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     mov    r0,rPC                       @ pass our target PC
     mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 #else
@@ -9968,9 +9990,9 @@
     str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
     mov    r1, rPC                  @ arg1 of translation may need this
     mov    lr, #0                   @  in case target is HANDLER_INTERPRET
-    cmp    r0,#0
+    cmp    r0,#0                    @ !0 means translation exists
     bxne   r0                       @ continue native execution if so
-    b      2f
+    b      2f                       @ branch over to use the interpreter
 
 /*
  * Return from the translation cache and immediately request
@@ -10047,6 +10069,29 @@
  * Return from the translation cache to the interpreter to do method invocation.
  * Check if translation exists for the callee, but don't chain to it.
  */
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC
+    bl     dvmJitGetCodeAddr        @ Is there a translation?
+    str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+    EXPORT_PC()
+    adrl   rIBASE, dvmAsmInstructionStart
+    FETCH_INST()
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
     .global dvmJitToInterpNoChain
 dvmJitToInterpNoChain:
 #if defined(WITH_JIT_TUNING)
@@ -10074,6 +10119,7 @@
     FETCH_INST()
     GET_JIT_PROF_TABLE(r0)
     @ NOTE: intended fallthrough
+
 /*
  * Common code to update potential trace start counter, and initiate
  * a trace-build if appropriate.  On entry, rPC should point to the
@@ -10614,15 +10660,12 @@
     str     rFP, [r3, #offThread_curFrame]  @ self->curFrame = fp
 #if defined(WITH_JIT)
     ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
-    GET_JIT_PROF_TABLE(r0)
     mov     rPC, r9                     @ publish new rPC
     str     r1, [rGLUE, #offGlue_methodClassDex]
     str     r10, [r3, #offThread_inJitCodeCache]  @ may return to JIT'ed land
     cmp     r10, #0                      @ caller is compiled code
     blxne   r10
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    cmp     r0,#0
-    bne     common_updateProfile
     GOTO_OPCODE(ip)                     @ jump to next instruction
 #else
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
diff --git a/vm/mterp/out/InterpAsm-armv5te-vfp.S b/vm/mterp/out/InterpAsm-armv5te-vfp.S
index 633a32d..6421454 100644
--- a/vm/mterp/out/InterpAsm-armv5te-vfp.S
+++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S
@@ -320,14 +320,27 @@
 
 #if defined(WITH_JIT)
 .LentryInstr:
-    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    ldr     r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
     /* Entry is always a possible trace start */
     GET_JIT_PROF_TABLE(r0)
     FETCH_INST()
-    mov    r1, #0                       @ prepare the value for the new state
-    str    r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
-    cmp    r0,#0
-    bne    common_updateProfile
+    mov     r1, #0                      @ prepare the value for the new state
+    str     r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+    cmp     r0,#0                       @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     common_updateProfile        @ profiling is enabled
+#else
+    ldr     r2, [r10, #offThread_shadowSpace]   @ to find out the jit exit state
+    beq     1f                          @ profiling is disabled
+    ldr     r3, [r2, #offShadowSpace_jitExitState]  @ jit exit state
+    cmp     r3, #kSVSTraceSelect        @ hot trace following?
+    moveq   r2,#kJitTSelectRequestHot   @ ask for trace selection
+    beq     common_selectTrace          @ go build the trace
+    cmp     r3, #kSVSNoProfile          @ don't profile the next instruction?
+    beq     1f                          @ intrepret the next instruction
+    b       common_updateProfile        @ collect profiles
+#endif
+1:
     GET_INST_OPCODE(ip)
     GOTO_OPCODE(ip)
 #else
@@ -9400,12 +9413,21 @@
     mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
     b      jitSVShadowRunEnd            @ doesn't return
 
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoProfile            @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
     .global dvmJitToInterpTraceSelectNoChain
 dvmJitToInterpTraceSelectNoChain:
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     mov    r0,rPC                       @ pass our target PC
-    mov    r2,#kSVSTraceSelectNoChain   @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9414,7 +9436,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9423,7 +9445,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9432,7 +9454,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSNormal               @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9441,7 +9463,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     mov    r0,rPC                       @ pass our target PC
     mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 #else
@@ -9506,9 +9528,9 @@
     str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
     mov    r1, rPC                  @ arg1 of translation may need this
     mov    lr, #0                   @  in case target is HANDLER_INTERPRET
-    cmp    r0,#0
+    cmp    r0,#0                    @ !0 means translation exists
     bxne   r0                       @ continue native execution if so
-    b      2f
+    b      2f                       @ branch over to use the interpreter
 
 /*
  * Return from the translation cache and immediately request
@@ -9585,6 +9607,29 @@
  * Return from the translation cache to the interpreter to do method invocation.
  * Check if translation exists for the callee, but don't chain to it.
  */
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC
+    bl     dvmJitGetCodeAddr        @ Is there a translation?
+    str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+    EXPORT_PC()
+    adrl   rIBASE, dvmAsmInstructionStart
+    FETCH_INST()
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
     .global dvmJitToInterpNoChain
 dvmJitToInterpNoChain:
 #if defined(WITH_JIT_TUNING)
@@ -9612,6 +9657,7 @@
     FETCH_INST()
     GET_JIT_PROF_TABLE(r0)
     @ NOTE: intended fallthrough
+
 /*
  * Common code to update potential trace start counter, and initiate
  * a trace-build if appropriate.  On entry, rPC should point to the
@@ -10152,15 +10198,12 @@
     str     rFP, [r3, #offThread_curFrame]  @ self->curFrame = fp
 #if defined(WITH_JIT)
     ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
-    GET_JIT_PROF_TABLE(r0)
     mov     rPC, r9                     @ publish new rPC
     str     r1, [rGLUE, #offGlue_methodClassDex]
     str     r10, [r3, #offThread_inJitCodeCache]  @ may return to JIT'ed land
     cmp     r10, #0                      @ caller is compiled code
     blxne   r10
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    cmp     r0,#0
-    bne     common_updateProfile
     GOTO_OPCODE(ip)                     @ jump to next instruction
 #else
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S
index 66f3a3d..f756471 100644
--- a/vm/mterp/out/InterpAsm-armv5te.S
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -320,14 +320,27 @@
 
 #if defined(WITH_JIT)
 .LentryInstr:
-    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    ldr     r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
     /* Entry is always a possible trace start */
     GET_JIT_PROF_TABLE(r0)
     FETCH_INST()
-    mov    r1, #0                       @ prepare the value for the new state
-    str    r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
-    cmp    r0,#0
-    bne    common_updateProfile
+    mov     r1, #0                      @ prepare the value for the new state
+    str     r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+    cmp     r0,#0                       @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     common_updateProfile        @ profiling is enabled
+#else
+    ldr     r2, [r10, #offThread_shadowSpace]   @ to find out the jit exit state
+    beq     1f                          @ profiling is disabled
+    ldr     r3, [r2, #offShadowSpace_jitExitState]  @ jit exit state
+    cmp     r3, #kSVSTraceSelect        @ hot trace following?
+    moveq   r2,#kJitTSelectRequestHot   @ ask for trace selection
+    beq     common_selectTrace          @ go build the trace
+    cmp     r3, #kSVSNoProfile          @ don't profile the next instruction?
+    beq     1f                          @ intrepret the next instruction
+    b       common_updateProfile        @ collect profiles
+#endif
+1:
     GET_INST_OPCODE(ip)
     GOTO_OPCODE(ip)
 #else
@@ -9858,12 +9871,21 @@
     mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
     b      jitSVShadowRunEnd            @ doesn't return
 
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoProfile            @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
     .global dvmJitToInterpTraceSelectNoChain
 dvmJitToInterpTraceSelectNoChain:
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     mov    r0,rPC                       @ pass our target PC
-    mov    r2,#kSVSTraceSelectNoChain   @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9872,7 +9894,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9881,7 +9903,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9890,7 +9912,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSNormal               @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9899,7 +9921,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     mov    r0,rPC                       @ pass our target PC
     mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 #else
@@ -9964,9 +9986,9 @@
     str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
     mov    r1, rPC                  @ arg1 of translation may need this
     mov    lr, #0                   @  in case target is HANDLER_INTERPRET
-    cmp    r0,#0
+    cmp    r0,#0                    @ !0 means translation exists
     bxne   r0                       @ continue native execution if so
-    b      2f
+    b      2f                       @ branch over to use the interpreter
 
 /*
  * Return from the translation cache and immediately request
@@ -10043,6 +10065,29 @@
  * Return from the translation cache to the interpreter to do method invocation.
  * Check if translation exists for the callee, but don't chain to it.
  */
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC
+    bl     dvmJitGetCodeAddr        @ Is there a translation?
+    str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+    EXPORT_PC()
+    adrl   rIBASE, dvmAsmInstructionStart
+    FETCH_INST()
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
     .global dvmJitToInterpNoChain
 dvmJitToInterpNoChain:
 #if defined(WITH_JIT_TUNING)
@@ -10070,6 +10115,7 @@
     FETCH_INST()
     GET_JIT_PROF_TABLE(r0)
     @ NOTE: intended fallthrough
+
 /*
  * Common code to update potential trace start counter, and initiate
  * a trace-build if appropriate.  On entry, rPC should point to the
@@ -10610,15 +10656,12 @@
     str     rFP, [r3, #offThread_curFrame]  @ self->curFrame = fp
 #if defined(WITH_JIT)
     ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
-    GET_JIT_PROF_TABLE(r0)
     mov     rPC, r9                     @ publish new rPC
     str     r1, [rGLUE, #offGlue_methodClassDex]
     str     r10, [r3, #offThread_inJitCodeCache]  @ may return to JIT'ed land
     cmp     r10, #0                      @ caller is compiled code
     blxne   r10
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    cmp     r0,#0
-    bne     common_updateProfile
     GOTO_OPCODE(ip)                     @ jump to next instruction
 #else
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
diff --git a/vm/mterp/out/InterpAsm-armv7-a-neon.S b/vm/mterp/out/InterpAsm-armv7-a-neon.S
index e837dda..a08d936 100644
--- a/vm/mterp/out/InterpAsm-armv7-a-neon.S
+++ b/vm/mterp/out/InterpAsm-armv7-a-neon.S
@@ -330,14 +330,27 @@
 
 #if defined(WITH_JIT)
 .LentryInstr:
-    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    ldr     r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
     /* Entry is always a possible trace start */
     GET_JIT_PROF_TABLE(r0)
     FETCH_INST()
-    mov    r1, #0                       @ prepare the value for the new state
-    str    r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
-    cmp    r0,#0
-    bne    common_updateProfile
+    mov     r1, #0                      @ prepare the value for the new state
+    str     r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+    cmp     r0,#0                       @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     common_updateProfile        @ profiling is enabled
+#else
+    ldr     r2, [r10, #offThread_shadowSpace]   @ to find out the jit exit state
+    beq     1f                          @ profiling is disabled
+    ldr     r3, [r2, #offShadowSpace_jitExitState]  @ jit exit state
+    cmp     r3, #kSVSTraceSelect        @ hot trace following?
+    moveq   r2,#kJitTSelectRequestHot   @ ask for trace selection
+    beq     common_selectTrace          @ go build the trace
+    cmp     r3, #kSVSNoProfile          @ don't profile the next instruction?
+    beq     1f                          @ intrepret the next instruction
+    b       common_updateProfile        @ collect profiles
+#endif
+1:
     GET_INST_OPCODE(ip)
     GOTO_OPCODE(ip)
 #else
@@ -9334,12 +9347,21 @@
     mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
     b      jitSVShadowRunEnd            @ doesn't return
 
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoProfile            @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
     .global dvmJitToInterpTraceSelectNoChain
 dvmJitToInterpTraceSelectNoChain:
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     mov    r0,rPC                       @ pass our target PC
-    mov    r2,#kSVSTraceSelectNoChain   @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9348,7 +9370,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9357,7 +9379,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9366,7 +9388,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSNormal               @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9375,7 +9397,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     mov    r0,rPC                       @ pass our target PC
     mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 #else
@@ -9440,9 +9462,9 @@
     str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
     mov    r1, rPC                  @ arg1 of translation may need this
     mov    lr, #0                   @  in case target is HANDLER_INTERPRET
-    cmp    r0,#0
+    cmp    r0,#0                    @ !0 means translation exists
     bxne   r0                       @ continue native execution if so
-    b      2f
+    b      2f                       @ branch over to use the interpreter
 
 /*
  * Return from the translation cache and immediately request
@@ -9519,6 +9541,29 @@
  * Return from the translation cache to the interpreter to do method invocation.
  * Check if translation exists for the callee, but don't chain to it.
  */
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC
+    bl     dvmJitGetCodeAddr        @ Is there a translation?
+    str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+    EXPORT_PC()
+    adrl   rIBASE, dvmAsmInstructionStart
+    FETCH_INST()
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
     .global dvmJitToInterpNoChain
 dvmJitToInterpNoChain:
 #if defined(WITH_JIT_TUNING)
@@ -9546,6 +9591,7 @@
     FETCH_INST()
     GET_JIT_PROF_TABLE(r0)
     @ NOTE: intended fallthrough
+
 /*
  * Common code to update potential trace start counter, and initiate
  * a trace-build if appropriate.  On entry, rPC should point to the
@@ -10086,15 +10132,12 @@
     str     rFP, [r3, #offThread_curFrame]  @ self->curFrame = fp
 #if defined(WITH_JIT)
     ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
-    GET_JIT_PROF_TABLE(r0)
     mov     rPC, r9                     @ publish new rPC
     str     r1, [rGLUE, #offGlue_methodClassDex]
     str     r10, [r3, #offThread_inJitCodeCache]  @ may return to JIT'ed land
     cmp     r10, #0                      @ caller is compiled code
     blxne   r10
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    cmp     r0,#0
-    bne     common_updateProfile
     GOTO_OPCODE(ip)                     @ jump to next instruction
 #else
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
diff --git a/vm/mterp/out/InterpAsm-armv7-a.S b/vm/mterp/out/InterpAsm-armv7-a.S
index dc33638..213c513 100644
--- a/vm/mterp/out/InterpAsm-armv7-a.S
+++ b/vm/mterp/out/InterpAsm-armv7-a.S
@@ -330,14 +330,27 @@
 
 #if defined(WITH_JIT)
 .LentryInstr:
-    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    ldr     r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
     /* Entry is always a possible trace start */
     GET_JIT_PROF_TABLE(r0)
     FETCH_INST()
-    mov    r1, #0                       @ prepare the value for the new state
-    str    r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
-    cmp    r0,#0
-    bne    common_updateProfile
+    mov     r1, #0                      @ prepare the value for the new state
+    str     r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+    cmp     r0,#0                       @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     common_updateProfile        @ profiling is enabled
+#else
+    ldr     r2, [r10, #offThread_shadowSpace]   @ to find out the jit exit state
+    beq     1f                          @ profiling is disabled
+    ldr     r3, [r2, #offShadowSpace_jitExitState]  @ jit exit state
+    cmp     r3, #kSVSTraceSelect        @ hot trace following?
+    moveq   r2,#kJitTSelectRequestHot   @ ask for trace selection
+    beq     common_selectTrace          @ go build the trace
+    cmp     r3, #kSVSNoProfile          @ don't profile the next instruction?
+    beq     1f                          @ intrepret the next instruction
+    b       common_updateProfile        @ collect profiles
+#endif
+1:
     GET_INST_OPCODE(ip)
     GOTO_OPCODE(ip)
 #else
@@ -9334,12 +9347,21 @@
     mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
     b      jitSVShadowRunEnd            @ doesn't return
 
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoProfile            @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
     .global dvmJitToInterpTraceSelectNoChain
 dvmJitToInterpTraceSelectNoChain:
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     mov    r0,rPC                       @ pass our target PC
-    mov    r2,#kSVSTraceSelectNoChain   @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9348,7 +9370,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9357,7 +9379,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9366,7 +9388,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     ldr    r0,[lr, #-1]                 @ pass our target PC
     mov    r2,#kSVSNormal               @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 
@@ -9375,7 +9397,7 @@
     ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
     mov    r0,rPC                       @ pass our target PC
     mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
-    mov    r3, #0
+    mov    r3, #0                       @ 0 means !inJitCodeCache
     str    r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
     b      jitSVShadowRunEnd            @ doesn't return
 #else
@@ -9440,9 +9462,9 @@
     str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
     mov    r1, rPC                  @ arg1 of translation may need this
     mov    lr, #0                   @  in case target is HANDLER_INTERPRET
-    cmp    r0,#0
+    cmp    r0,#0                    @ !0 means translation exists
     bxne   r0                       @ continue native execution if so
-    b      2f
+    b      2f                       @ branch over to use the interpreter
 
 /*
  * Return from the translation cache and immediately request
@@ -9519,6 +9541,29 @@
  * Return from the translation cache to the interpreter to do method invocation.
  * Check if translation exists for the callee, but don't chain to it.
  */
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC
+    bl     dvmJitGetCodeAddr        @ Is there a translation?
+    str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+    EXPORT_PC()
+    adrl   rIBASE, dvmAsmInstructionStart
+    FETCH_INST()
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
     .global dvmJitToInterpNoChain
 dvmJitToInterpNoChain:
 #if defined(WITH_JIT_TUNING)
@@ -9546,6 +9591,7 @@
     FETCH_INST()
     GET_JIT_PROF_TABLE(r0)
     @ NOTE: intended fallthrough
+
 /*
  * Common code to update potential trace start counter, and initiate
  * a trace-build if appropriate.  On entry, rPC should point to the
@@ -10086,15 +10132,12 @@
     str     rFP, [r3, #offThread_curFrame]  @ self->curFrame = fp
 #if defined(WITH_JIT)
     ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
-    GET_JIT_PROF_TABLE(r0)
     mov     rPC, r9                     @ publish new rPC
     str     r1, [rGLUE, #offGlue_methodClassDex]
     str     r10, [r3, #offThread_inJitCodeCache]  @ may return to JIT'ed land
     cmp     r10, #0                      @ caller is compiled code
     blxne   r10
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    cmp     r0,#0
-    bne     common_updateProfile
     GOTO_OPCODE(ip)                     @ jump to next instruction
 #else
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c
index 4a7a5a9..3656713 100644
--- a/vm/mterp/out/InterpC-allstubs.c
+++ b/vm/mterp/out/InterpC-allstubs.c
@@ -3288,6 +3288,10 @@
         assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
         methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisPtr->clazz;
+#endif
+
 #if 0
         if (dvmIsAbstractMethod(methodToCall)) {
             /*
@@ -3439,6 +3443,10 @@
 
         thisClass = thisPtr->clazz;
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisClass;
+#endif
+
         /*
          * Given a class and a method index, find the Method* with the
          * actual code we want to execute.
@@ -3553,6 +3561,10 @@
         if (!checkForNull(thisPtr))
             GOTO_exceptionThrown();
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisPtr->clazz;
+#endif
+
         /*
          * Combine the object we found with the vtable offset in the
          * method.
diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index 44916fb..47b3d7f 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -425,8 +425,10 @@
     checkDebugAndProf(pc, fp, self, curMethod, &debugIsMethodEntry)
 
 #if defined(WITH_JIT)
-#define CHECK_JIT_BOOL() (dvmCheckJit(pc, self, interpState))
-#define CHECK_JIT_VOID() (dvmCheckJit(pc, self, interpState))
+#define CHECK_JIT_BOOL() (dvmCheckJit(pc, self, interpState, callsiteClass,\
+                          methodToCall))
+#define CHECK_JIT_VOID() (dvmCheckJit(pc, self, interpState, callsiteClass,\
+                          methodToCall))
 #define ABORT_JIT_TSELECT() (dvmJitAbortTraceSelect(interpState))
 #else
 #define CHECK_JIT_BOOL() (false)
@@ -1493,6 +1495,14 @@
          interpState->method->name);
 #endif
 #if INTERP_TYPE == INTERP_DBG
+    const ClassObject* callsiteClass = NULL;
+
+#if defined(WITH_SELF_VERIFICATION)
+    if (interpState->jitState != kJitSelfVerification) {
+        interpState->self->shadowSpace->jitExitState = kSVSIdle;
+    }
+#endif
+
     /* Check to see if we've got a trace selection request. */
     if (
          /*
@@ -3572,6 +3582,10 @@
         assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
         methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisPtr->clazz;
+#endif
+
 #if 0
         if (dvmIsAbstractMethod(methodToCall)) {
             /*
@@ -3723,6 +3737,10 @@
 
         thisClass = thisPtr->clazz;
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisClass;
+#endif
+
         /*
          * Given a class and a method index, find the Method* with the
          * actual code we want to execute.
@@ -3837,6 +3855,10 @@
         if (!checkForNull(thisPtr))
             GOTO_exceptionThrown();
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisPtr->clazz;
+#endif
+
         /*
          * Combine the object we found with the vtable offset in the
          * method.
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index e863abe..165c032 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -1232,6 +1232,14 @@
          interpState->method->name);
 #endif
 #if INTERP_TYPE == INTERP_DBG
+    const ClassObject* callsiteClass = NULL;
+
+#if defined(WITH_SELF_VERIFICATION)
+    if (interpState->jitState != kJitSelfVerification) {
+        interpState->self->shadowSpace->jitExitState = kSVSIdle;
+    }
+#endif
+
     /* Check to see if we've got a trace selection request. */
     if (
          /*
@@ -3311,6 +3319,10 @@
         assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
         methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisPtr->clazz;
+#endif
+
 #if 0
         if (dvmIsAbstractMethod(methodToCall)) {
             /*
@@ -3462,6 +3474,10 @@
 
         thisClass = thisPtr->clazz;
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisClass;
+#endif
+
         /*
          * Given a class and a method index, find the Method* with the
          * actual code we want to execute.
@@ -3576,6 +3592,10 @@
         if (!checkForNull(thisPtr))
             GOTO_exceptionThrown();
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisPtr->clazz;
+#endif
+
         /*
          * Combine the object we found with the vtable offset in the
          * method.
diff --git a/vm/mterp/out/InterpC-x86-atom.c b/vm/mterp/out/InterpC-x86-atom.c
index 46e25b0..3b85384 100644
--- a/vm/mterp/out/InterpC-x86-atom.c
+++ b/vm/mterp/out/InterpC-x86-atom.c
@@ -1482,6 +1482,10 @@
         assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
         methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisPtr->clazz;
+#endif
+
 #if 0
         if (dvmIsAbstractMethod(methodToCall)) {
             /*
@@ -1633,6 +1637,10 @@
 
         thisClass = thisPtr->clazz;
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisClass;
+#endif
+
         /*
          * Given a class and a method index, find the Method* with the
          * actual code we want to execute.
@@ -1747,6 +1755,10 @@
         if (!checkForNull(thisPtr))
             GOTO_exceptionThrown();
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisPtr->clazz;
+#endif
+
         /*
          * Combine the object we found with the vtable offset in the
          * method.
diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c
index 6fc1ce1..ec07691 100644
--- a/vm/mterp/out/InterpC-x86.c
+++ b/vm/mterp/out/InterpC-x86.c
@@ -1419,6 +1419,10 @@
         assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
         methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisPtr->clazz;
+#endif
+
 #if 0
         if (dvmIsAbstractMethod(methodToCall)) {
             /*
@@ -1570,6 +1574,10 @@
 
         thisClass = thisPtr->clazz;
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisClass;
+#endif
+
         /*
          * Given a class and a method index, find the Method* with the
          * actual code we want to execute.
@@ -1684,6 +1692,10 @@
         if (!checkForNull(thisPtr))
             GOTO_exceptionThrown();
 
+#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG)
+        callsiteClass = thisPtr->clazz;
+#endif
+
         /*
          * Combine the object we found with the vtable offset in the
          * method.
diff --git a/vm/mterp/portable/entry.c b/vm/mterp/portable/entry.c
index b2ec1d8..6b989a2 100644
--- a/vm/mterp/portable/entry.c
+++ b/vm/mterp/portable/entry.c
@@ -46,6 +46,14 @@
          interpState->method->name);
 #endif
 #if INTERP_TYPE == INTERP_DBG
+    const ClassObject* callsiteClass = NULL;
+
+#if defined(WITH_SELF_VERIFICATION)
+    if (interpState->jitState != kJitSelfVerification) {
+        interpState->self->shadowSpace->jitExitState = kSVSIdle;
+    }
+#endif
+
     /* Check to see if we've got a trace selection request. */
     if (
          /*
diff --git a/vm/mterp/portable/portdbg.c b/vm/mterp/portable/portdbg.c
index 76b7637..65349e9 100644
--- a/vm/mterp/portable/portdbg.c
+++ b/vm/mterp/portable/portdbg.c
@@ -5,8 +5,10 @@
     checkDebugAndProf(pc, fp, self, curMethod, &debugIsMethodEntry)
 
 #if defined(WITH_JIT)
-#define CHECK_JIT_BOOL() (dvmCheckJit(pc, self, interpState))
-#define CHECK_JIT_VOID() (dvmCheckJit(pc, self, interpState))
+#define CHECK_JIT_BOOL() (dvmCheckJit(pc, self, interpState, callsiteClass,\
+                          methodToCall))
+#define CHECK_JIT_VOID() (dvmCheckJit(pc, self, interpState, callsiteClass,\
+                          methodToCall))
 #define ABORT_JIT_TSELECT() (dvmJitAbortTraceSelect(interpState))
 #else
 #define CHECK_JIT_BOOL() (false)