More Quick compiler restructuring

Yet another round of compiler restructuring to remove references to
MIR and BasicBlock structures in the lower levels of code generation.
Eliminating these will make it easer to share code with the
LLVM-IR -> LIR lowering pass.

This time I'm focusing on the Invokes and special-cased inlined
intrinsics.  Note that this CL includes a somewhat subtle difference
in handling MOVE_RETURNs following an INVOKE.  Previously, we fused
INVOKEs and MOVE_RETURNs for inlined intrinsics.  To simplify the
world, we're now fusing all INVOKE/MOVE_RETURN pairs (though it shouldn't
impact the codegen non-inlined invokes.

Changes in latest patch set: Two of the old intrinsic generators
did not fuse the following MOVE_RESULT, so the results were dropped
on the floor.  Also, allowed match of MOVE_RESULT_OBJECT (which
previously had not been matched because no inline intrisic used it
as a return value).

Change-Id: I93fec0cd557398ad7b04bdcc0393f27d3644913d
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index e9a2656..5b92af1 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -84,6 +84,22 @@
   ArenaBitVector* bv;
 };
 
+struct InvokeInfo {
+  int numArgWords;      // Note: word count, not arg count
+  RegLocation* args;    // One for each word of arguments
+  RegLocation result;   // Eventual target of MOVE_RESULT
+  int optFlags;
+  InvokeType type;
+  uint32_t dexIdx;
+  uint32_t methodIdx;
+  uintptr_t directCode;
+  uintptr_t directMethod;
+  RegLocation target;    // Target of following move_result
+  bool skipThis;
+  bool isRange;
+  int offset;            // Dalvik offset
+};
+
  /*
  * Data structure tracking the mapping between a Dalvik register (pair) and a
  * native register (pair). The idea is to reuse the previously loaded value
@@ -755,8 +771,7 @@
 
 void oatInsertLIRAfter(LIR* currentLIR, LIR* newLIR);
 
-MIR* oatFindMoveResult(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
-                       bool wide);
+MIR* oatFindMoveResult(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir);
 /* Debug Utilities */
 void oatDumpCompilationUnit(CompilationUnit* cUnit);
 
diff --git a/src/compiler/Dataflow.cc b/src/compiler/Dataflow.cc
index 3483d5b..8196ce9 100644
--- a/src/compiler/Dataflow.cc
+++ b/src/compiler/Dataflow.cc
@@ -1683,16 +1683,13 @@
  * opcodes or incoming arcs.  However, if the result of the invoke is not
  * used, a move-result may not be present.
  */
-MIR* oatFindMoveResult(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
-                     bool wide)
+MIR* oatFindMoveResult(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir)
 {
   BasicBlock* tbb = bb;
   mir = advanceMIR(cUnit, &tbb, mir, NULL, false);
   while (mir != NULL) {
-    if (!wide && mir->dalvikInsn.opcode == Instruction::MOVE_RESULT) {
-      break;
-    }
-    if (wide && mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_WIDE) {
+    if ((mir->dalvikInsn.opcode == Instruction::MOVE_RESULT) ||
+        (mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_WIDE)) {
       break;
     }
     // Keep going if pseudo op, otherwise terminate
diff --git a/src/compiler/Ralloc.cc b/src/compiler/Ralloc.cc
index bc0c6de..e1689a6 100644
--- a/src/compiler/Ralloc.cc
+++ b/src/compiler/Ralloc.cc
@@ -86,6 +86,7 @@
   SSARepresentation* res = NULL;
   for (; mir; mir = mir->next) {
     if ((mir->dalvikInsn.opcode == Instruction::MOVE_RESULT) ||
+        (mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) ||
         (mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_WIDE)) {
       res = mir->ssaRep;
       break;
diff --git a/src/compiler/codegen/GenCommon.cc b/src/compiler/codegen/GenCommon.cc
index 2bd9333..2ca9046 100644
--- a/src/compiler/codegen/GenCommon.cc
+++ b/src/compiler/codegen/GenCommon.cc
@@ -23,8 +23,7 @@
  * be applicable to most targets.  Only mid-level support utilities
  * and "op" calls may be used here.
  */
-void genInvoke(CompilationUnit* cUnit, BasicBlock* bb,  MIR* mir,
-         InvokeType type, bool isRange);
+void genInvoke(CompilationUnit* cUnit, InvokeInfo* info);
 #if defined(TARGET_ARM)
 LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide);
 bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
@@ -870,12 +869,10 @@
     oatResetRegPool(cUnit);
     oatResetDefTracking(cUnit);
     LIR* lab = intrinsicLabel[i];
-    MIR* mir = (MIR*)lab->operands[0];
-    InvokeType type = (InvokeType)lab->operands[1];
-    BasicBlock* bb = (BasicBlock*)lab->operands[3];
-    cUnit->currentDalvikOffset = mir->offset;
+    InvokeInfo* info = (InvokeInfo*)lab->operands[0];
+    cUnit->currentDalvikOffset = info->offset;
     oatAppendLIR(cUnit, lab);
-    genInvoke(cUnit, bb, mir, type, false /* isRange */);
+    genInvoke(cUnit, info);
     LIR* resumeLab = (LIR*)lab->operands[2];
     if (resumeLab != NULL) {
       opUnconditionalBranch(cUnit, resumeLab);
diff --git a/src/compiler/codegen/GenInvoke.cc b/src/compiler/codegen/GenInvoke.cc
index b22cd1a..21ccae7 100644
--- a/src/compiler/codegen/GenInvoke.cc
+++ b/src/compiler/codegen/GenInvoke.cc
@@ -24,7 +24,7 @@
  * and "op" calls may be used here.
  */
 
-typedef int (*NextCallInsn)(CompilationUnit*, MIR*, int, uint32_t dexIdx,
+typedef int (*NextCallInsn)(CompilationUnit*, InvokeInfo*, int, uint32_t dexIdx,
                             uint32_t methodIdx, uintptr_t directCode,
                             uintptr_t directMethod, InvokeType type);
 LIR* opCondBranch(CompilationUnit* cUnit, ConditionCode cc, LIR* target);
@@ -133,7 +133,7 @@
  * Bit of a hack here - in the absence of a real scheduling pass,
  * emit the next instruction in static & direct invoke sequences.
  */
-int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
+int nextSDCallInsn(CompilationUnit* cUnit, InvokeInfo* info,
                    int state, uint32_t dexIdx, uint32_t unused,
                    uintptr_t directCode, uintptr_t directMethod,
                    InvokeType type)
@@ -241,7 +241,7 @@
  * Note also that we'll load the first argument ("this") into
  * rARG1 here rather than the standard loadArgRegs.
  */
-int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
+int nextVCallInsn(CompilationUnit* cUnit, InvokeInfo* info,
                   int state, uint32_t dexIdx, uint32_t methodIdx,
                   uintptr_t unused, uintptr_t unused2, InvokeType unused3)
 {
@@ -252,11 +252,11 @@
    */
   switch (state) {
     case 0:  // Get "this" [set rARG1]
-      rlArg = oatGetSrc(cUnit, mir, 0);
+      rlArg = info->args[0];
       loadValueDirectFixed(cUnit, rlArg, rARG1);
       break;
     case 1: // Is "this" null? [use rARG1]
-      genNullCheck(cUnit, oatSSASrc(mir,0), rARG1, mir->optimizationFlags);
+      genNullCheck(cUnit, info->args[0].sRegLow, rARG1, info->optFlags);
       // get this->klass_ [use rARG1, set rINVOKE_TGT]
       loadWordDisp(cUnit, rARG1, Object::ClassOffset().Int32Value(),
                    rINVOKE_TGT);
@@ -281,7 +281,7 @@
   return state + 1;
 }
 
-int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir, int trampoline,
+int nextInvokeInsnSP(CompilationUnit* cUnit, InvokeInfo* info, int trampoline,
                      int state, uint32_t dexIdx, uint32_t methodIdx)
 {
   /*
@@ -300,62 +300,63 @@
   return -1;
 }
 
-int nextStaticCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+int nextStaticCallInsnSP(CompilationUnit* cUnit, InvokeInfo* info,
                          int state, uint32_t dexIdx, uint32_t methodIdx,
                          uintptr_t unused, uintptr_t unused2,
                          InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+  return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0);
 }
 
-int nextDirectCallInsnSP(CompilationUnit* cUnit, MIR* mir, int state,
+int nextDirectCallInsnSP(CompilationUnit* cUnit, InvokeInfo* info, int state,
                          uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused,
                          uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+  return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0);
 }
 
-int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir, int state,
+int nextSuperCallInsnSP(CompilationUnit* cUnit, InvokeInfo* info, int state,
                         uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused,
                         uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+  return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0);
 }
 
-int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir, int state,
+int nextVCallInsnSP(CompilationUnit* cUnit, InvokeInfo* info, int state,
                     uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused,
                     uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+  return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0);
 }
 
 /*
  * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
  * which will locate the target and continue on via a tail call.
  */
-int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir, int state,
+int nextInterfaceCallInsn(CompilationUnit* cUnit, InvokeInfo* info, int state,
                           uint32_t dexIdx, uint32_t unused, uintptr_t unused2,
                           uintptr_t unused3, InvokeType unused4)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+  return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0);
 }
 
-int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit, MIR* mir,
-                                         int state, uint32_t dexIdx,
-                                         uint32_t unused, uintptr_t unused2,
-                                         uintptr_t unused3, InvokeType unused4)
+int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
+                                         InvokeInfo* info, int state,
+                                         uint32_t dexIdx, uint32_t unused,
+                                         uintptr_t unused2, uintptr_t unused3,
+                                         InvokeType unused4)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+  return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0);
 }
 
-int loadArgRegs(CompilationUnit* cUnit, MIR* mir, DecodedInstruction* dInsn,
-                int callState, NextCallInsn nextCallInsn, uint32_t dexIdx,
+int loadArgRegs(CompilationUnit* cUnit, InvokeInfo* info, int callState,
+                NextCallInsn nextCallInsn, uint32_t dexIdx,
                 uint32_t methodIdx, uintptr_t directCode,
                 uintptr_t directMethod, InvokeType type, bool skipThis)
 {
@@ -366,8 +367,8 @@
     nextReg++;
     nextArg++;
   }
-  for (; (nextReg <= lastArgReg) && (nextArg < mir->ssaRep->numUses); nextReg++) {
-    RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
+  for (; (nextReg <= lastArgReg) && (nextArg < info->numArgWords); nextReg++) {
+    RegLocation rlArg = info->args[nextArg++];
     rlArg = oatUpdateRawLoc(cUnit, rlArg);
     if (rlArg.wide && (nextReg <= rARG2)) {
       loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
@@ -377,7 +378,7 @@
       rlArg.wide = false;
       loadValueDirectFixed(cUnit, rlArg, nextReg);
     }
-    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
+    callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx,
                  directCode, directMethod, type);
   }
   return callState;
@@ -390,8 +391,8 @@
  * the target method pointer.  Note, this may also be called
  * for "range" variants if the number of arguments is 5 or fewer.
  */
-int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
-                         DecodedInstruction* dInsn, int callState,
+int genDalvikArgsNoRange(CompilationUnit* cUnit, InvokeInfo* info,
+                         int callState,
                          LIR** pcrLabel, NextCallInsn nextCallInsn,
                          uint32_t dexIdx, uint32_t methodIdx,
                          uintptr_t directCode, uintptr_t directMethod,
@@ -400,19 +401,19 @@
   RegLocation rlArg;
 
   /* If no arguments, just return */
-  if (dInsn->vA == 0)
+  if (info->numArgWords == 0)
     return callState;
 
-  callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
+  callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx,
                            directCode, directMethod, type);
 
-  DCHECK_LE(dInsn->vA, 5U);
-  if (dInsn->vA > 3) {
-    uint32_t nextUse = 3;
+  DCHECK_LE(info->numArgWords, 5);
+  if (info->numArgWords > 3) {
+    int32_t nextUse = 3;
     //Detect special case of wide arg spanning arg3/arg4
-    RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
-    RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
-    RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
+    RegLocation rlUse0 = info->args[0];
+    RegLocation rlUse1 = info->args[1];
+    RegLocation rlUse2 = info->args[2];
     if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
       rlUse2.wide) {
       int reg = -1;
@@ -424,20 +425,20 @@
         // rARG2 & rARG3 can safely be used here
         reg = rARG3;
         loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
-        callState = nextCallInsn(cUnit, mir, callState, dexIdx,
+        callState = nextCallInsn(cUnit, info, callState, dexIdx,
                                  methodIdx, directCode, directMethod, type);
       }
       storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
       storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
-      callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
+      callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx,
                                directCode, directMethod, type);
       nextUse++;
     }
     // Loop through the rest
-    while (nextUse < dInsn->vA) {
+    while (nextUse < info->numArgWords) {
       int lowReg;
       int highReg = -1;
-      rlArg = oatGetRawSrc(cUnit, mir, nextUse);
+      rlArg = info->args[nextUse];
       rlArg = oatUpdateRawLoc(cUnit, rlArg);
       if (rlArg.location == kLocPhysReg) {
         lowReg = rlArg.lowReg;
@@ -450,7 +451,7 @@
         } else {
           loadValueDirectFixed(cUnit, rlArg, lowReg);
         }
-        callState = nextCallInsn(cUnit, mir, callState, dexIdx,
+        callState = nextCallInsn(cUnit, info, callState, dexIdx,
                                  methodIdx, directCode, directMethod, type);
       }
       int outsOffset = (nextUse + 1) * 4;
@@ -461,18 +462,18 @@
         storeWordDisp(cUnit, rSP, outsOffset, lowReg);
         nextUse++;
       }
-      callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
+      callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx,
                                directCode, directMethod, type);
     }
   }
 
-  callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
+  callState = loadArgRegs(cUnit, info, callState, nextCallInsn,
                           dexIdx, methodIdx, directCode, directMethod,
                           type, skipThis);
 
   if (pcrLabel) {
-    *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), rARG1,
-                             mir->optimizationFlags);
+    *pcrLabel = genNullCheck(cUnit, info->args[0].sRegLow, rARG1,
+                             info->optFlags);
   }
   return callState;
 }
@@ -492,40 +493,27 @@
  *       Pass arg0, arg1 & arg2 in rARG1-rARG3
  *
  */
-int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
-                       DecodedInstruction* dInsn, int callState,
+int genDalvikArgsRange(CompilationUnit* cUnit, InvokeInfo* info, int callState,
                        LIR** pcrLabel, NextCallInsn nextCallInsn,
                        uint32_t dexIdx, uint32_t methodIdx,
                        uintptr_t directCode, uintptr_t directMethod,
                        InvokeType type, bool skipThis)
 {
-  int firstArg = dInsn->vC;
-  int numArgs = dInsn->vA;
 
   // If we can treat it as non-range (Jumbo ops will use range form)
-  if (numArgs <= 5)
-    return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
+  if (info->numArgWords <= 5)
+    return genDalvikArgsNoRange(cUnit, info, callState, pcrLabel,
                                 nextCallInsn, dexIdx, methodIdx,
                                 directCode, directMethod, type, skipThis);
   /*
-   * Make sure range list doesn't span the break between in normal
-   * Dalvik vRegs and the ins.
-   */
-  int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
-  int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
-  if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
-    LOG(FATAL) << "Argument list spanned locals & args";
-  }
-
-  /*
    * First load the non-register arguments.  Both forms expect all
    * of the source arguments to be in their home frame location, so
    * scan the sReg names and flush any that have been promoted to
    * frame backing storage.
    */
   // Scan the rest of the args - if in physReg flush to memory
-  for (int nextArg = 0; nextArg < numArgs;) {
-    RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
+  for (int nextArg = 0; nextArg < info->numArgWords;) {
+    RegLocation loc = info->args[nextArg];
     if (loc.wide) {
       loc = oatUpdateLocWide(cUnit, loc);
       if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
@@ -543,87 +531,81 @@
     }
   }
 
-  int startOffset = oatSRegOffset(cUnit,
-    cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
+  int startOffset = oatSRegOffset(cUnit, info->args[3].sRegLow);
   int outsOffset = 4 /* Method* */ + (3 * 4);
 #if defined(TARGET_MIPS) || defined(TARGET_X86)
   // Generate memcpy
   opRegRegImm(cUnit, kOpAdd, rARG0, rSP, outsOffset);
   opRegRegImm(cUnit, kOpAdd, rARG1, rSP, startOffset);
   callRuntimeHelperRegRegImm(cUnit, ENTRYPOINT_OFFSET(pMemcpy),
-                             rARG0, rARG1, (numArgs - 3) * 4);
+                             rARG0, rARG1, (info->numArgWords - 3) * 4);
 #else
-  if (numArgs >= 20) {
+  if (info->numArgWords >= 20) {
     // Generate memcpy
     opRegRegImm(cUnit, kOpAdd, rARG0, rSP, outsOffset);
     opRegRegImm(cUnit, kOpAdd, rARG1, rSP, startOffset);
     callRuntimeHelperRegRegImm(cUnit, ENTRYPOINT_OFFSET(pMemcpy),
-                               rARG0, rARG1, (numArgs - 3) * 4);
+                               rARG0, rARG1, (info->numArgWords - 3) * 4);
   } else {
     // Use vldm/vstm pair using rARG3 as a temp
-    int regsLeft = std::min(numArgs - 3, 16);
-    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
+    int regsLeft = std::min(info->numArgWords - 3, 16);
+    callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx,
                              directCode, directMethod, type);
     opRegRegImm(cUnit, kOpAdd, rARG3, rSP, startOffset);
     LIR* ld = newLIR3(cUnit, kThumb2Vldms, rARG3, fr0, regsLeft);
     //TUNING: loosen barrier
     ld->defMask = ENCODE_ALL;
     setMemRefType(ld, true /* isLoad */, kDalvikReg);
-    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
+    callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx,
                              directCode, directMethod, type);
     opRegRegImm(cUnit, kOpAdd, rARG3, rSP, 4 /* Method* */ + (3 * 4));
-    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
+    callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx,
                              directCode, directMethod, type);
     LIR* st = newLIR3(cUnit, kThumb2Vstms, rARG3, fr0, regsLeft);
     setMemRefType(st, false /* isLoad */, kDalvikReg);
     st->defMask = ENCODE_ALL;
-    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
+    callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx,
                              directCode, directMethod, type);
 
   }
 #endif
 
-  callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
+  callState = loadArgRegs(cUnit, info, callState, nextCallInsn,
                           dexIdx, methodIdx, directCode, directMethod,
                           type, skipThis);
 
-  callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
+  callState = nextCallInsn(cUnit, info, callState, dexIdx, methodIdx,
                            directCode, directMethod, type);
   if (pcrLabel) {
-    *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), rARG1,
-                             mir->optimizationFlags);
+    *pcrLabel = genNullCheck(cUnit, info->args[0].sRegLow, rARG1,
+                             info->optFlags);
   }
   return callState;
 }
 
-RegLocation inlineTarget(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir)
+RegLocation inlineTarget(CompilationUnit* cUnit, InvokeInfo* info)
 {
   RegLocation res;
-  mir = oatFindMoveResult(cUnit, bb, mir, false);
-  if (mir == NULL) {
+  if (info->result.location == kLocInvalid) {
     res = oatGetReturn(cUnit, false);
   } else {
-    res = oatGetDest(cUnit, mir, 0);
-    mir->dalvikInsn.opcode = Instruction::NOP;
+    res = info->result;
   }
   return res;
 }
 
-RegLocation inlineTargetWide(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir)
+RegLocation inlineTargetWide(CompilationUnit* cUnit, InvokeInfo* info)
 {
   RegLocation res;
-  mir = oatFindMoveResult(cUnit, bb, mir, true);
-  if (mir == NULL) {
+  if (info->result.location == kLocInvalid) {
     res = oatGetReturnWide(cUnit, false);
   } else {
-    res = oatGetDestWide(cUnit, mir, 0, 1);
-    mir->dalvikInsn.opcode = Instruction::NOP;
+    res = info->result;
   }
   return res;
 }
 
-bool genInlinedCharAt(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
-            InvokeType type, bool isRange)
+bool genInlinedCharAt(CompilationUnit* cUnit, InvokeInfo* info)
 {
 #if defined(TARGET_ARM)
   // Location of reference to data array
@@ -635,15 +617,15 @@
   // Start of char data with array_
   int dataOffset = Array::DataOffset(sizeof(uint16_t)).Int32Value();
 
-  RegLocation rlObj = oatGetSrc(cUnit, mir, 0);
-  RegLocation rlIdx = oatGetSrc(cUnit, mir, 1);
+  RegLocation rlObj = info->args[0];
+  RegLocation rlIdx = info->args[1];
   rlObj = loadValue(cUnit, rlObj, kCoreReg);
   rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
   int regMax;
   int regOff = oatAllocTemp(cUnit);
   int regPtr = oatAllocTemp(cUnit);
-  genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->optimizationFlags);
-  bool rangeCheck = (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK));
+  genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, info->optFlags);
+  bool rangeCheck = (!(info->optFlags & MIR_IGNORE_RANGE_CHECK));
   if (rangeCheck) {
     regMax = oatAllocTemp(cUnit);
     loadWordDisp(cUnit, rlObj.lowReg, countOffset, regMax);
@@ -653,7 +635,7 @@
   LIR* launchPad = NULL;
   if (rangeCheck) {
     // Set up a launch pad to allow retry in case of bounds violation */
-    launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (int)mir, type);
+    launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (uintptr_t)info);
     oatInsertGrowableList(cUnit, &cUnit->intrinsicLaunchpads,
                           (intptr_t)launchPad);
     opRegReg(cUnit, kOpCmp, rlIdx.lowReg, regMax);
@@ -662,7 +644,7 @@
   }
   opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
   opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg);
-  RegLocation rlDest = inlineTarget(cUnit, bb, mir);
+  RegLocation rlDest = inlineTarget(cUnit, info);
   RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
   loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf);
   oatFreeTemp(cUnit, regOff);
@@ -670,25 +652,23 @@
   storeValue(cUnit, rlDest, rlResult);
   if (rangeCheck) {
     launchPad->operands[2] = 0;  // no resumption
-    launchPad->operands[3] = (uintptr_t)bb;
   }
   // Record that we've already inlined & null checked
-  mir->optimizationFlags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
+  info->optFlags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
   return true;
 #else
   return false;
 #endif
 }
 
-bool genInlinedMinMaxInt(CompilationUnit *cUnit, BasicBlock* bb, MIR *mir,
-             bool isMin)
+bool genInlinedMinMaxInt(CompilationUnit *cUnit, InvokeInfo* info, bool isMin)
 {
 #if defined(TARGET_ARM)
-  RegLocation rlSrc1 = oatGetSrc(cUnit, mir, 0);
-  RegLocation rlSrc2 = oatGetSrc(cUnit, mir, 1);
+  RegLocation rlSrc1 = info->args[0];
+  RegLocation rlSrc2 = info->args[1];
   rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
   rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
-  RegLocation rlDest = inlineTarget(cUnit, bb, mir);
+  RegLocation rlDest = inlineTarget(cUnit, info);
   RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
   opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
   opIT(cUnit, (isMin) ? kArmCondGt : kArmCondLt, "E");
@@ -703,16 +683,16 @@
 }
 
 // Generates an inlined String.isEmpty or String.length.
-bool genInlinedStringIsEmptyOrLength(CompilationUnit* cUnit,
-                                     BasicBlock* bb, MIR* mir, bool isEmpty)
+bool genInlinedStringIsEmptyOrLength(CompilationUnit* cUnit, InvokeInfo* info,
+                                     bool isEmpty)
 {
 #if defined(TARGET_ARM)
   // dst = src.length();
-  RegLocation rlObj = oatGetSrc(cUnit, mir, 0);
+  RegLocation rlObj = info->args[0];
   rlObj = loadValue(cUnit, rlObj, kCoreReg);
-  RegLocation rlDest = inlineTarget(cUnit, bb, mir);
+  RegLocation rlDest = inlineTarget(cUnit, info);
   RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-  genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->optimizationFlags);
+  genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, info->optFlags);
   loadWordDisp(cUnit, rlObj.lowReg, String::CountOffset().Int32Value(),
                rlResult.lowReg);
   if (isEmpty) {
@@ -728,12 +708,12 @@
 #endif
 }
 
-bool genInlinedAbsInt(CompilationUnit *cUnit, BasicBlock* bb, MIR *mir)
+bool genInlinedAbsInt(CompilationUnit *cUnit, InvokeInfo* info)
 {
 #if defined(TARGET_ARM)
-  RegLocation rlSrc = oatGetSrc(cUnit, mir, 0);
+  RegLocation rlSrc = info->args[0];
   rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
-  RegLocation rlDest = inlineTarget(cUnit, bb, mir);
+  RegLocation rlDest = inlineTarget(cUnit, info);
   RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
   int signReg = oatAllocTemp(cUnit);
   // abs(x) = y<=x>>31, (x+y)^y.
@@ -747,12 +727,12 @@
 #endif
 }
 
-bool genInlinedAbsLong(CompilationUnit *cUnit, BasicBlock* bb, MIR *mir)
+bool genInlinedAbsLong(CompilationUnit *cUnit, InvokeInfo* info)
 {
 #if defined(TARGET_ARM)
-  RegLocation rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+  RegLocation rlSrc = info->args[0];
   rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
-  RegLocation rlDest = inlineTargetWide(cUnit, bb, mir);
+  RegLocation rlDest = inlineTargetWide(cUnit, info);
   RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
   int signReg = oatAllocTemp(cUnit);
   // abs(x) = y<=x>>31, (x+y)^y.
@@ -768,11 +748,11 @@
 #endif
 }
 
-bool genInlinedFloatCvt(CompilationUnit *cUnit, BasicBlock* bb, MIR *mir)
+bool genInlinedFloatCvt(CompilationUnit *cUnit, InvokeInfo* info)
 {
 #if defined(TARGET_ARM)
-  RegLocation rlSrc = oatGetSrc(cUnit, mir, 0);
-  RegLocation rlDest = inlineTarget(cUnit, bb, mir);
+  RegLocation rlSrc = info->args[0];
+  RegLocation rlDest = inlineTarget(cUnit, info);
   storeValue(cUnit, rlDest, rlSrc);
   return true;
 #else
@@ -780,11 +760,11 @@
 #endif
 }
 
-bool genInlinedDoubleCvt(CompilationUnit *cUnit, BasicBlock* bb, MIR *mir)
+bool genInlinedDoubleCvt(CompilationUnit *cUnit, InvokeInfo* info)
 {
 #if defined(TARGET_ARM)
-  RegLocation rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
-  RegLocation rlDest = inlineTargetWide(cUnit, bb, mir);
+  RegLocation rlSrc = info->args[0];
+  RegLocation rlDest = inlineTargetWide(cUnit, info);
   storeValueWide(cUnit, rlDest, rlSrc);
   return true;
 #else
@@ -796,8 +776,8 @@
  * Fast string.indexOf(I) & (II).  Tests for simple case of char <= 0xffff,
  * otherwise bails to standard library code.
  */
-bool genInlinedIndexOf(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
-                       InvokeType type, bool zeroBased)
+bool genInlinedIndexOf(CompilationUnit* cUnit, InvokeInfo* info,
+                       bool zeroBased)
 {
 #if defined(TARGET_ARM)
 
@@ -807,9 +787,9 @@
   int regChar = rARG1;
   int regStart = rARG2;
 
-  RegLocation rlObj = oatGetSrc(cUnit, mir, 0);
-  RegLocation rlChar = oatGetSrc(cUnit, mir, 1);
-  RegLocation rlStart = oatGetSrc(cUnit, mir, 2);
+  RegLocation rlObj = info->args[0];
+  RegLocation rlChar = info->args[1];
+  RegLocation rlStart = info->args[2];
   loadValueDirectFixed(cUnit, rlObj, regPtr);
   loadValueDirectFixed(cUnit, rlChar, regChar);
   if (zeroBased) {
@@ -818,17 +798,19 @@
     loadValueDirectFixed(cUnit, rlStart, regStart);
   }
   int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pIndexOf));
-  genNullCheck(cUnit, rlObj.sRegLow, regPtr, mir->optimizationFlags);
-  LIR* launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (int)mir, type);
+  genNullCheck(cUnit, rlObj.sRegLow, regPtr, info->optFlags);
+  LIR* launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (uintptr_t)info);
   oatInsertGrowableList(cUnit, &cUnit->intrinsicLaunchpads,
               (intptr_t)launchPad);
   opCmpImmBranch(cUnit, kCondGt, regChar, 0xFFFF, launchPad);
   opReg(cUnit, kOpBlx, rTgt);
   LIR* resumeTgt = newLIR0(cUnit, kPseudoTargetLabel);
   launchPad->operands[2] = (uintptr_t)resumeTgt;
-  launchPad->operands[3] = (uintptr_t)bb;
   // Record that we've already inlined & null checked
-  mir->optimizationFlags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
+  info->optFlags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
+  RegLocation rlReturn = oatGetReturn(cUnit, false);
+  RegLocation rlDest = inlineTarget(cUnit, info);
+  storeValue(cUnit, rlDest, rlReturn);
   return true;
 #else
   return false;
@@ -836,8 +818,7 @@
 }
 
 /* Fast string.compareTo(Ljava/lang/string;)I. */
-bool genInlinedStringCompareTo(CompilationUnit* cUnit, BasicBlock* bb,
-                               MIR* mir, InvokeType type)
+bool genInlinedStringCompareTo(CompilationUnit* cUnit, InvokeInfo* info)
 {
 #if defined(TARGET_ARM)
   oatClobberCalleeSave(cUnit);
@@ -845,32 +826,34 @@
   int regThis = rARG0;
   int regCmp = rARG1;
 
-  RegLocation rlThis = oatGetSrc(cUnit, mir, 0);
-  RegLocation rlCmp = oatGetSrc(cUnit, mir, 1);
+  RegLocation rlThis = info->args[0];
+  RegLocation rlCmp = info->args[1];
   loadValueDirectFixed(cUnit, rlThis, regThis);
   loadValueDirectFixed(cUnit, rlCmp, regCmp);
   int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pStringCompareTo));
-  genNullCheck(cUnit, rlThis.sRegLow, regThis, mir->optimizationFlags);
+  genNullCheck(cUnit, rlThis.sRegLow, regThis, info->optFlags);
   //TUNING: check if rlCmp.sRegLow is already null checked
-  LIR* launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (int)mir, type);
+  LIR* launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (uintptr_t)info);
   oatInsertGrowableList(cUnit, &cUnit->intrinsicLaunchpads,
                         (intptr_t)launchPad);
   opCmpImmBranch(cUnit, kCondEq, regCmp, 0, launchPad);
   opReg(cUnit, kOpBlx, rTgt);
   launchPad->operands[2] = 0;  // No return possible
-  launchPad->operands[3] = (uintptr_t)bb;
   // Record that we've already inlined & null checked
-  mir->optimizationFlags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
+  info->optFlags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
+  RegLocation rlReturn = oatGetReturn(cUnit, false);
+  RegLocation rlDest = inlineTarget(cUnit, info);
+  storeValue(cUnit, rlDest, rlReturn);
   return true;
 #else
   return false;
 #endif
 }
 
-bool genIntrinsic(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
-                  InvokeType type, bool isRange)
+bool genIntrinsic(CompilationUnit* cUnit, InvokeInfo* info)
 {
-  if ((mir->optimizationFlags & MIR_INLINED) || isRange)  {
+  if ((info->optFlags & MIR_INLINED) || info->isRange ||
+      (info->result.location == kLocInvalid))  {
     return false;
   }
   /*
@@ -883,48 +866,48 @@
    * method.  By doing this during basic block construction, we can also
    * take advantage of/generate new useful dataflow info.
    */
-  std::string tgtMethod(PrettyMethod(mir->dalvikInsn.vB, *cUnit->dex_file));
+  std::string tgtMethod(PrettyMethod(info->methodIdx, *cUnit->dex_file));
   if (tgtMethod.compare("char java.lang.String.charAt(int)") == 0) {
-    return genInlinedCharAt(cUnit, bb, mir, type, isRange);
+    return genInlinedCharAt(cUnit, info);
   }
   if (tgtMethod.compare("int java.lang.Math.min(int, int)") == 0) {
-    return genInlinedMinMaxInt(cUnit, bb, mir, true /* isMin */);
+    return genInlinedMinMaxInt(cUnit, info, true /* isMin */);
   }
   if (tgtMethod.compare("int java.lang.Math.max(int, int)") == 0) {
-    return genInlinedMinMaxInt(cUnit, bb, mir, false /* isMin */);
+    return genInlinedMinMaxInt(cUnit, info, false /* isMin */);
   }
   if (tgtMethod.compare("int java.lang.String.length()") == 0) {
-    return genInlinedStringIsEmptyOrLength(cUnit, bb, mir, false /* isEmpty */);
+    return genInlinedStringIsEmptyOrLength(cUnit, info, false /* isEmpty */);
   }
   if (tgtMethod.compare("boolean java.lang.String.isEmpty()") == 0) {
-    return genInlinedStringIsEmptyOrLength(cUnit, bb, mir, true /* isEmpty */);
+    return genInlinedStringIsEmptyOrLength(cUnit, info, true /* isEmpty */);
   }
   if (tgtMethod.compare("int java.lang.Math.abs(int)") == 0) {
-    return genInlinedAbsInt(cUnit, bb, mir);
+    return genInlinedAbsInt(cUnit, info);
   }
   if (tgtMethod.compare("long java.lang.Math.abs(long)") == 0) {
-    return genInlinedAbsLong(cUnit, bb, mir);
+    return genInlinedAbsLong(cUnit, info);
   }
   if (tgtMethod.compare("int java.lang.Float.floatToRawIntBits(float)") == 0) {
-    return genInlinedFloatCvt(cUnit, bb, mir);
+    return genInlinedFloatCvt(cUnit, info);
   }
   if (tgtMethod.compare("float java.lang.Float.intBitsToFloat(int)") == 0) {
-    return genInlinedFloatCvt(cUnit, bb, mir);
+    return genInlinedFloatCvt(cUnit, info);
   }
   if (tgtMethod.compare("long java.lang.Double.doubleToRawLongBits(double)") == 0) {
-    return genInlinedDoubleCvt(cUnit, bb, mir);
+    return genInlinedDoubleCvt(cUnit, info);
   }
   if (tgtMethod.compare("double java.lang.Double.longBitsToDouble(long)") == 0) {
-    return genInlinedDoubleCvt(cUnit, bb, mir);
+    return genInlinedDoubleCvt(cUnit, info);
   }
   if (tgtMethod.compare("int java.lang.String.indexOf(int, int)") == 0) {
-    return genInlinedIndexOf(cUnit, bb, mir, type, false /* base 0 */);
+    return genInlinedIndexOf(cUnit, info, false /* base 0 */);
   }
   if (tgtMethod.compare("int java.lang.String.indexOf(int)") == 0) {
-    return genInlinedIndexOf(cUnit, bb, mir, type, true /* base 0 */);
+    return genInlinedIndexOf(cUnit, info, true /* base 0 */);
   }
   if (tgtMethod.compare("int java.lang.String.compareTo(java.lang.String)") == 0) {
-    return genInlinedStringCompareTo(cUnit, bb, mir, type);
+    return genInlinedStringCompareTo(cUnit, info);
   }
   return false;
 }
diff --git a/src/compiler/codegen/MethodBitcode.cc b/src/compiler/codegen/MethodBitcode.cc
index 4ada78c..3b6b087 100644
--- a/src/compiler/codegen/MethodBitcode.cc
+++ b/src/compiler/codegen/MethodBitcode.cc
@@ -336,7 +336,7 @@
   rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
   if (attrs & DF_UA) {
     if (attrs & DF_A_WIDE) {
-      rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg, nextSreg + 1);
+      rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg);
       nextSreg+= 2;
     } else {
       rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
@@ -345,7 +345,7 @@
   }
   if (attrs & DF_UB) {
     if (attrs & DF_B_WIDE) {
-      rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg, nextSreg + 1);
+      rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg);
       nextSreg+= 2;
     } else {
       rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
@@ -354,16 +354,16 @@
   }
   if (attrs & DF_UC) {
     if (attrs & DF_C_WIDE) {
-      rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg, nextSreg + 1);
+      rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg);
     } else {
       rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
     }
   }
   if (attrs & DF_DA) {
     if (attrs & DF_A_WIDE) {
-      rlDest = oatGetDestWide(cUnit, mir, 0, 1);
+      rlDest = oatGetDestWide(cUnit, mir);
     } else {
-      rlDest = oatGetDest(cUnit, mir, 0);
+      rlDest = oatGetDest(cUnit, mir);
       if (rlDest.ref) {
         objectDefinition = true;
       }
@@ -993,7 +993,7 @@
       for (int i = 0; i < mir->ssaRep->numUses; i++) {
         RegLocation loc;
         if (rlDest.wide) {
-           loc = oatGetSrcWide(cUnit, mir, i, i+1);
+           loc = oatGetSrcWide(cUnit, mir, i);
            i++;
         } else {
            loc = oatGetSrc(cUnit, mir, i);
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
index 15dbedd..1707a89 100644
--- a/src/compiler/codegen/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -53,14 +53,12 @@
   return res;
 }
 
-void genInvoke(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
-               InvokeType type, bool isRange)
+void genInvoke(CompilationUnit* cUnit, InvokeInfo* info)
 {
-  if (genIntrinsic(cUnit, bb, mir, type, isRange)) {
+  if (genIntrinsic(cUnit, info)) {
     return;
   }
-  DecodedInstruction* dInsn = &mir->dalvikInsn;
-  InvokeType originalType = type;  // avoiding mutation by ComputeInvokeInfo
+  InvokeType originalType = info->type;  // avoiding mutation by ComputeInvokeInfo
   int callState = 0;
   LIR* nullCk;
   LIR** pNullCk = NULL;
@@ -74,52 +72,52 @@
                            cUnit->code_item, cUnit->method_idx,
                            cUnit->access_flags);
 
-  uint32_t dexMethodIdx = dInsn->vB;
+  uint32_t dexMethodIdx = info->methodIdx;
   int vtableIdx;
   uintptr_t directCode;
   uintptr_t directMethod;
   bool skipThis;
   bool fastPath =
-    cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, &mUnit, type,
+    cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, &mUnit, info->type,
                                        vtableIdx, directCode,
                                        directMethod)
     && !SLOW_INVOKE_PATH;
-  if (type == kInterface) {
+  if (info->type == kInterface) {
     nextCallInsn = fastPath ? nextInterfaceCallInsn
         : nextInterfaceCallInsnWithAccessCheck;
     skipThis = false;
-  } else if (type == kDirect) {
+  } else if (info->type == kDirect) {
     if (fastPath) {
       pNullCk = &nullCk;
     }
     nextCallInsn = fastPath ? nextSDCallInsn : nextDirectCallInsnSP;
     skipThis = false;
-  } else if (type == kStatic) {
+  } else if (info->type == kStatic) {
     nextCallInsn = fastPath ? nextSDCallInsn : nextStaticCallInsnSP;
     skipThis = false;
-  } else if (type == kSuper) {
+  } else if (info->type == kSuper) {
     DCHECK(!fastPath);  // Fast path is a direct call.
     nextCallInsn = nextSuperCallInsnSP;
     skipThis = false;
   } else {
-    DCHECK_EQ(type, kVirtual);
+    DCHECK_EQ(info->type, kVirtual);
     nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
     skipThis = fastPath;
   }
-  if (!isRange) {
-    callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
+  if (!info->isRange) {
+    callState = genDalvikArgsNoRange(cUnit, info, callState, pNullCk,
                                      nextCallInsn, dexMethodIdx,
                                      vtableIdx, directCode, directMethod,
                                      originalType, skipThis);
   } else {
-    callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
+    callState = genDalvikArgsRange(cUnit, info, callState, pNullCk,
                                    nextCallInsn, dexMethodIdx, vtableIdx,
                                    directCode, directMethod, originalType,
                                    skipThis);
   }
   // Finish up any of the call sequence not interleaved in arg loading
   while (callState >= 0) {
-    callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx,
+    callState = nextCallInsn(cUnit, info, callState, dexMethodIdx,
                              vtableIdx, directCode, directMethod,
                              originalType);
   }
@@ -129,11 +127,11 @@
 #if !defined(TARGET_X86)
   opReg(cUnit, kOpBlx, rINVOKE_TGT);
 #else
-  if (fastPath && type != kInterface) {
+  if (fastPath && info->type != kInterface) {
     opMem(cUnit, kOpBlx, rARG0, Method::GetCodeOffset().Int32Value());
   } else {
     int trampoline = 0;
-    switch (type) {
+    switch (info->type) {
     case kInterface:
       trampoline = fastPath ? ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline)
           : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
@@ -158,6 +156,48 @@
 #endif
 
   oatClobberCalleeSave(cUnit);
+  if (info->result.location != kLocInvalid) {
+    // We have a following MOVE_RESULT - do it now.
+    if (info->result.wide) {
+      RegLocation retLoc = oatGetReturnWide(cUnit, false);
+      storeValueWide(cUnit, info->result, retLoc);
+    } else {
+      RegLocation retLoc = oatGetReturn(cUnit, false);
+      storeValue(cUnit, info->result, retLoc);
+    }
+  }
+}
+
+/*
+ * Build an array of location records for the incoming arguments.
+ * Note: one location record per word of arguments, with dummy
+ * high-word loc for wide arguments.  Also pull up any following
+ * MOVE_RESULT and incorporate it into the invoke.
+ */
+InvokeInfo* newInvokeInfo(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
+                          InvokeType type, bool isRange)
+{
+  InvokeInfo* info = (InvokeInfo*)oatNew(cUnit, sizeof(InvokeInfo), true,
+                                         kAllocMisc);
+  MIR* moveResultMIR = oatFindMoveResult(cUnit, bb, mir);
+  if (moveResultMIR == NULL) {
+    info->result.location = kLocInvalid;
+  } else {
+    info->result = oatGetRawDest(cUnit, moveResultMIR);
+    moveResultMIR->dalvikInsn.opcode = Instruction::NOP;
+  }
+  info->numArgWords = mir->ssaRep->numUses;
+  info->args = (info->numArgWords == 0) ? NULL : (RegLocation*)
+      oatNew(cUnit, sizeof(RegLocation) * info->numArgWords, false, kAllocMisc);
+  for (int i = 0; i < info->numArgWords; i++) {
+    info->args[i] = oatGetRawSrc(cUnit, mir, i);
+  }
+  info->optFlags = mir->optimizationFlags;
+  info->type = type;
+  info->isRange = isRange;
+  info->methodIdx = mir->dalvikInsn.vB;
+  info->offset = mir->offset;
+  return info;
 }
 
 /*
@@ -185,7 +225,7 @@
   rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
   if (attrs & DF_UA) {
     if (attrs & DF_A_WIDE) {
-      rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg, nextSreg + 1);
+      rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg);
       nextSreg+= 2;
     } else {
       rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
@@ -194,7 +234,7 @@
   }
   if (attrs & DF_UB) {
     if (attrs & DF_B_WIDE) {
-      rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg, nextSreg + 1);
+      rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg);
       nextSreg+= 2;
     } else {
       rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
@@ -203,16 +243,16 @@
   }
   if (attrs & DF_UC) {
     if (attrs & DF_C_WIDE) {
-      rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg, nextSreg + 1);
+      rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg);
     } else {
       rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
     }
   }
   if (attrs & DF_DA) {
     if (attrs & DF_A_WIDE) {
-      rlDest = oatGetDestWide(cUnit, mir, 0, 1);
+      rlDest = oatGetDestWide(cUnit, mir);
     } else {
-      rlDest = oatGetDest(cUnit, mir, 0);
+      rlDest = oatGetDest(cUnit, mir);
     }
   }
   switch (opcode) {
@@ -570,38 +610,38 @@
       break;
 
     case Instruction::INVOKE_STATIC_RANGE:
-      genInvoke(cUnit, bb, mir, kStatic, true /*range*/);
+      genInvoke(cUnit, newInvokeInfo(cUnit, bb, mir, kStatic, true));
       break;
     case Instruction::INVOKE_STATIC:
-      genInvoke(cUnit, bb, mir, kStatic, false /*range*/);
+      genInvoke(cUnit, newInvokeInfo(cUnit, bb, mir, kStatic, false));
       break;
 
     case Instruction::INVOKE_DIRECT:
-      genInvoke(cUnit, bb,  mir, kDirect, false /*range*/);
+      genInvoke(cUnit, newInvokeInfo(cUnit, bb, mir, kDirect, false));
       break;
     case Instruction::INVOKE_DIRECT_RANGE:
-      genInvoke(cUnit, bb, mir, kDirect, true /*range*/);
+      genInvoke(cUnit, newInvokeInfo(cUnit, bb, mir, kDirect, true));
       break;
 
     case Instruction::INVOKE_VIRTUAL:
-      genInvoke(cUnit, bb, mir, kVirtual, false /*range*/);
+      genInvoke(cUnit, newInvokeInfo(cUnit, bb, mir, kVirtual, false));
       break;
     case Instruction::INVOKE_VIRTUAL_RANGE:
-      genInvoke(cUnit, bb, mir, kVirtual, true /*range*/);
+      genInvoke(cUnit, newInvokeInfo(cUnit, bb, mir, kVirtual, true));
       break;
 
     case Instruction::INVOKE_SUPER:
-      genInvoke(cUnit, bb, mir, kSuper, false /*range*/);
+      genInvoke(cUnit, newInvokeInfo(cUnit, bb, mir, kSuper, false));
       break;
     case Instruction::INVOKE_SUPER_RANGE:
-      genInvoke(cUnit, bb, mir, kSuper, true /*range*/);
+      genInvoke(cUnit, newInvokeInfo(cUnit, bb, mir, kSuper, true));
       break;
 
     case Instruction::INVOKE_INTERFACE:
-      genInvoke(cUnit, bb, mir, kInterface, false /*range*/);
+      genInvoke(cUnit, newInvokeInfo(cUnit, bb, mir, kInterface, false));
       break;
     case Instruction::INVOKE_INTERFACE_RANGE:
-      genInvoke(cUnit, bb, mir, kInterface, true /*range*/);
+      genInvoke(cUnit, newInvokeInfo(cUnit, bb, mir, kInterface, true));
       break;
 
     case Instruction::NEG_INT:
@@ -796,7 +836,7 @@
     }
     case kMirOpCopy: {
       RegLocation rlSrc = oatGetSrc(cUnit, mir, 0);
-      RegLocation rlDest = oatGetDest(cUnit, mir, 0);
+      RegLocation rlDest = oatGetDest(cUnit, mir);
       storeValue(cUnit, rlDest, rlSrc);
       break;
     }
diff --git a/src/compiler/codegen/Ralloc.h b/src/compiler/codegen/Ralloc.h
index c0b6068..8c3887a 100644
--- a/src/compiler/codegen/Ralloc.h
+++ b/src/compiler/codegen/Ralloc.h
@@ -107,17 +107,18 @@
 extern void oatMarkDefWide(CompilationUnit* cUnit, RegLocation rl,
                            LIR* start, LIR* finish);
 
-extern RegLocation oatGetSrcWide(CompilationUnit* cUnit, MIR* mir,
-                                 int low, int high);
 
-extern RegLocation oatGetDestWide(CompilationUnit* cUnit, MIR* mir,
-                                  int low, int high);
 // Get the LocRecord associated with an SSA name use.
 extern RegLocation oatGetSrc(CompilationUnit* cUnit, MIR* mir, int num);
+extern RegLocation oatGetSrcWide(CompilationUnit* cUnit, MIR* mir, int low);
+// Non-width checking version
 extern RegLocation oatGetRawSrc(CompilationUnit* cUnit, MIR* mir, int num);
 
 // Get the LocRecord associated with an SSA name def.
-extern RegLocation oatGetDest(CompilationUnit* cUnit, MIR* mir, int num);
+extern RegLocation oatGetDest(CompilationUnit* cUnit, MIR* mir);
+extern RegLocation oatGetDestWide(CompilationUnit* cUnit, MIR* mir);
+// Non-width checking version
+extern RegLocation oatGetRawDest(CompilationUnit* cUnit, MIR* mir);
 
 extern RegLocation oatGetReturnWide(CompilationUnit* cUnit, bool isDouble);
 
diff --git a/src/compiler/codegen/RallocUtil.cc b/src/compiler/codegen/RallocUtil.cc
index 14b4159..e2f2cd6 100644
--- a/src/compiler/codegen/RallocUtil.cc
+++ b/src/compiler/codegen/RallocUtil.cc
@@ -1005,35 +1005,43 @@
   return loc;
 }
 
-extern RegLocation oatGetDest(CompilationUnit* cUnit, MIR* mir, int num)
+extern RegLocation oatGetRawSrc(CompilationUnit* cUnit, MIR* mir, int num)
 {
-  RegLocation res = cUnit->regLocation[mir->ssaRep->defs[num]];
+  DCHECK(num < mir->ssaRep->numUses);
+  RegLocation res = cUnit->regLocation[mir->ssaRep->uses[num]];
+  DCHECK(!res.wide || num < (mir->ssaRep->numUses - 1));
+  return res;
+}
+extern RegLocation oatGetRawDest(CompilationUnit* cUnit, MIR* mir)
+{
+  DCHECK(mir->ssaRep->numDefs > 0);
+  RegLocation res = cUnit->regLocation[mir->ssaRep->defs[0]];
+  DCHECK(!res.wide || mir->ssaRep->numDefs == 2);
+  return res;
+}
+extern RegLocation oatGetDest(CompilationUnit* cUnit, MIR* mir)
+{
+  RegLocation res = oatGetRawDest(cUnit, mir);
   DCHECK(!res.wide);
   return res;
 }
 extern RegLocation oatGetSrc(CompilationUnit* cUnit, MIR* mir, int num)
 {
-  RegLocation res = cUnit->regLocation[mir->ssaRep->uses[num]];
+  RegLocation res = oatGetRawSrc(cUnit, mir, num);
   DCHECK(!res.wide);
   return res;
 }
-extern RegLocation oatGetRawSrc(CompilationUnit* cUnit, MIR* mir, int num)
+extern RegLocation oatGetDestWide(CompilationUnit* cUnit, MIR* mir)
 {
-  RegLocation res = cUnit->regLocation[mir->ssaRep->uses[num]];
-  return res;
-}
-extern RegLocation oatGetDestWide(CompilationUnit* cUnit, MIR* mir,
-                  int low, int high)
-{
-  RegLocation res = cUnit->regLocation[mir->ssaRep->defs[low]];
+  RegLocation res = oatGetRawDest(cUnit, mir);
   DCHECK(res.wide);
   return res;
 }
 
 extern RegLocation oatGetSrcWide(CompilationUnit* cUnit, MIR* mir,
-                 int low, int high)
+                 int low)
 {
-  RegLocation res = cUnit->regLocation[mir->ssaRep->uses[low]];
+  RegLocation res = oatGetRawSrc(cUnit, mir, low);
   DCHECK(res.wide);
   return res;
 }
diff --git a/src/compiler/codegen/arm/FP/Thumb2VFP.cc b/src/compiler/codegen/arm/FP/Thumb2VFP.cc
index fb14aec..1b67ecb 100644
--- a/src/compiler/codegen/arm/FP/Thumb2VFP.cc
+++ b/src/compiler/codegen/arm/FP/Thumb2VFP.cc
@@ -167,8 +167,8 @@
   RegLocation rlSrc1;
   RegLocation rlSrc2;
   if (isDouble) {
-    rlSrc1 = oatGetSrcWide(cUnit, mir, 0, 1);
-    rlSrc2 = oatGetSrcWide(cUnit, mir, 2, 3);
+    rlSrc1 = oatGetSrcWide(cUnit, mir, 0);
+    rlSrc2 = oatGetSrcWide(cUnit, mir, 2);
     rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
     rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
     newLIR2(cUnit, kThumb2Vcmpd, S2D(rlSrc1.lowReg, r1Src2.highReg),
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 9ec470c..579aa43 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -182,7 +182,7 @@
   RegLocation rlObj;
   lockLiveArgs(cUnit, mir);
   if (longOrDouble) {
-    rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+    rlSrc = oatGetSrcWide(cUnit, mir, 0);
     rlObj = oatGetSrc(cUnit, mir, 2);
   } else {
     rlSrc = oatGetSrc(cUnit, mir, 0);
@@ -210,7 +210,7 @@
   RegLocation rlDest;
   bool wide = (mir->ssaRep->numUses == 2);
   if (wide) {
-    rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+    rlSrc = oatGetSrcWide(cUnit, mir, 0);
     rlDest = oatGetReturnWide(cUnit, false);
   } else {
     rlSrc = oatGetSrc(cUnit, mir, 0);
@@ -657,8 +657,8 @@
   LIR* labelList = (LIR*)cUnit->blockLabelList;
   LIR* taken = &labelList[bb->taken->id];
   LIR* notTaken = &labelList[bb->fallThrough->id];
-  RegLocation rlSrc1 = oatGetSrcWide(cUnit, mir, 0, 1);
-  RegLocation rlSrc2 = oatGetSrcWide(cUnit, mir, 2, 3);
+  RegLocation rlSrc1 = oatGetSrcWide(cUnit, mir, 0);
+  RegLocation rlSrc2 = oatGetSrcWide(cUnit, mir, 2);
   rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
   rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
   ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);