Include move-result into the same trace as the invoke.

In preparation for method inlining implementation. Example trace:

D/dalvikvm(  708): Compiler: Building trace for fibonacci, offset 0x10
D/dalvikvm(  708): 0x426b6fa8: 0x0016 const-wide/16 v0, (#2), (#0)
D/dalvikvm(  708): 0x426b6fac: 0x009c sub-long v0, v7, v0
D/dalvikvm(  708): 0x426b6fb0: 0x0070 invoke-direct v6, v0, v1
D/dalvikvm(  708): 0x426b6fb6: 0x000b move-result-wide v0, (#0), (#0)
D/dalvikvm(  708): TRACEINFO (3): 0x426b6f88 Lcom/android/unit_tests/PerformanceTests$FibonacciSlow;fibonacci 0x10 8 of 32, 7 blocks
D/dalvikvm(  708): 7 blocks in total
D/dalvikvm(  708): Block 0 (insn 0010 - 0010 empty)
D/dalvikvm(  708):   Fallthrough : block 1 (0010)
D/dalvikvm(  708): Block 1 (insn 0010 - 0014)
D/dalvikvm(  708):   Taken branch: block 3 (0000)
D/dalvikvm(  708):   Fallthrough : block 2 (0017)
D/dalvikvm(  708): Block 2 (insn 0017 - 0017)
D/dalvikvm(  708):   Fallthrough : block 4 (0018)
D/dalvikvm(  708): Block 3 (insn 0000 - 0000 empty)
D/dalvikvm(  708): Block 4 (insn 0018 - 0018 empty)
D/dalvikvm(  708): Block 5 (insn 0000 - 0000 empty)
D/dalvikvm(  708): Block 6 (insn 0000 - 0000 empty)

Once implemented the inliner will consume the invoke-direct and
move-result-wide instructions altogether.

Change-Id: I4e0e6283989a468d9edf01cf26f644d2d8d7ec64
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index dbb85c9..a28e411 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -3646,6 +3646,16 @@
         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))) {
+                /* Align this block first since it is a return chaining cell */
+                newLIR0(cUnit, kArmPseudoPseudoAlign4);
+            }
             /*
              * Append the label pseudo LIR first. Chaining cells will be handled
              * separately afterwards.
diff --git a/vm/interp/Jit.c b/vm/interp/Jit.c
index b9f7410..6f76a86 100644
--- a/vm/interp/Jit.c
+++ b/vm/interp/Jit.c
@@ -606,6 +606,37 @@
 }
 
 /*
+ * Check if the next instruction following the invoke is a move-result and if
+ * so add it to the trace.
+ *
+ * lastPC, len, offset are all from the preceding invoke instruction
+ */
+static void insertMoveResult(const u2 *lastPC, int len, int offset,
+                             InterpState *interpState)
+{
+    DecodedInstruction nextDecInsn;
+    const u2 *moveResultPC = lastPC + len;
+
+    dexDecodeInstruction(gDvm.instrFormat, moveResultPC, &nextDecInsn);
+    if ((nextDecInsn.opCode != OP_MOVE_RESULT) &&
+        (nextDecInsn.opCode != OP_MOVE_RESULT_WIDE) &&
+        (nextDecInsn.opCode != OP_MOVE_RESULT_OBJECT))
+        return;
+
+    /* We need to start a new trace run */
+    int currTraceRun = ++interpState->currTraceRun;
+    interpState->currRunHead = moveResultPC;
+    interpState->trace[currTraceRun].frag.startOffset = offset + len;
+    interpState->trace[currTraceRun].frag.numInsts = 1;
+    interpState->trace[currTraceRun].frag.runEnd = false;
+    interpState->trace[currTraceRun].frag.hint = kJitHintNone;
+    interpState->totalTraceLen++;
+
+    interpState->currRunLen = dexGetInstrOrTableWidthAbs(gDvm.instrWidth,
+                                                         moveResultPC);
+}
+
+/*
  * Adds to the current trace request one instruction at a time, just
  * before that instruction is interpreted.  This is the primary trace
  * selection function.  NOTE: return instruction are handled a little
@@ -676,8 +707,15 @@
             interpState->totalTraceLen++;
             interpState->currRunLen += len;
 
+            /*
+             * If the last instruction is an invoke, we will try to sneak in
+             * the move-result* (if existent) into a separate trace run.
+             */
+            int needReservedRun = (flags & kInstrInvoke) ? 1 : 0;
+
             /* Will probably never hit this with the current trace buildier */
-            if (interpState->currTraceRun == (MAX_JIT_RUN_LEN - 1)) {
+            if (interpState->currTraceRun ==
+                (MAX_JIT_RUN_LEN - 1 - needReservedRun)) {
                 interpState->jitState = kJitTSelectEnd;
             }
 
@@ -690,9 +728,17 @@
                              kInstrInvoke)) != 0)) {
                     interpState->jitState = kJitTSelectEnd;
 #if defined(SHOW_TRACE)
-            LOGD("TraceGen: ending on %s, basic block end",
-                 getOpcodeName(decInsn.opCode));
+                LOGD("TraceGen: ending on %s, basic block end",
+                     getOpcodeName(decInsn.opCode));
 #endif
+
+                /*
+                 * If the next instruction is a variant of move-result, insert
+                 * it to the trace as well.
+                 */
+                if (flags & kInstrInvoke) {
+                    insertMoveResult(lastPC, len, offset, interpState);
+                }
             }
             /* Break on throw or self-loop */
             if ((decInsn.opCode == OP_THROW) || (lastPC == pc)){