Improve SPARSE_SWITCH handling in interpreter.

This CL avoids to set "next" instruction twice. We used to first set "next"
instruction to the instruction following the SPARSE_SWITCH. Then, we set it to
the instruction corresponding to the entry we find in the table.

We now set it only once: either we branch or we continue.

Change-Id: Ic93cd0abae00edb1fb952c34bc9031fffc7f4a35
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index 39c8f0e..1e8ee9c 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -891,6 +891,35 @@
   return true;
 }
 
+static inline const Instruction* DoSparseSwitch(const Instruction* inst,
+                                                const ShadowFrame& shadow_frame)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  DCHECK(inst->Opcode() == Instruction::SPARSE_SWITCH);
+  const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
+  int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t());
+  DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
+  uint16_t size = switch_data[1];
+  DCHECK_GT(size, 0);
+  const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
+  DCHECK(IsAligned<4>(keys));
+  const int32_t* entries = keys + size;
+  DCHECK(IsAligned<4>(entries));
+  int lo = 0;
+  int hi = size - 1;
+  while (lo <= hi) {
+    int mid = (lo + hi) / 2;
+    int32_t foundVal = keys[mid];
+    if (test_val < foundVal) {
+      hi = mid - 1;
+    } else if (test_val > foundVal) {
+      lo = mid + 1;
+    } else {
+      return inst->RelativeAt(entries[mid]);
+    }
+  }
+  return inst->Next_3xx();
+}
+
 static inline const Instruction* FindNextInstructionFollowingException(Thread* self,
                                                                        ShadowFrame& shadow_frame,
                                                                        uint32_t dex_pc,
@@ -1427,31 +1456,7 @@
       }
       case Instruction::SPARSE_SWITCH: {
         PREAMBLE();
-        const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
-        int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t());
-        DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
-        uint16_t size = switch_data[1];
-        DCHECK_GT(size, 0);
-        const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
-        DCHECK(IsAligned<4>(keys));
-        const int32_t* entries = keys + size;
-        DCHECK(IsAligned<4>(entries));
-        int lo = 0;
-        int hi = size - 1;
-        const Instruction* current_inst = inst;
-        inst = inst->Next_3xx();
-        while (lo <= hi) {
-          int mid = (lo + hi) / 2;
-          int32_t foundVal = keys[mid];
-          if (test_val < foundVal) {
-            hi = mid - 1;
-          } else if (test_val > foundVal) {
-            lo = mid + 1;
-          } else {
-            inst = current_inst->RelativeAt(entries[mid]);
-            break;
-          }
-        }
+        inst = DoSparseSwitch(inst, shadow_frame);
         break;
       }
       case Instruction::CMPL_FLOAT: {