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/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)){