Optimize instruction data fetch in interpreter.

The computed goto implementation prevents the compiler from detecting we are
loading the first 16 bits of instruction twice: first one to get the opcode and
second one to fetch first instruction's operand(s) like vA and vB.

We now load the 16 bits into a local variable and decode opcode and operands
from this variable. And do the same in the switch-based implementation for
consistency.

The performance improvement is 5% in average on benchmark applications suite.

Also remove unused "Thread* self" parameter from DoIGetQuick and DoIPutQuick.

Bug: 10703860
Change-Id: I83026ed6e78f642ac3dcdc6edbb6056fe012005f
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 794891e..ec1f942 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -123,12 +123,12 @@
 // specialization.
 template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
 static bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
-                       const Instruction* inst)
+                       const Instruction* inst, uint16_t inst_data)
     NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
 
 template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
 static inline bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
-                              const Instruction* inst) {
+                              const Instruction* inst, uint16_t inst_data) {
   bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
   uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   ArtField* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
@@ -142,13 +142,13 @@
   if (is_static) {
     obj = f->GetDeclaringClass();
   } else {
-    obj = shadow_frame.GetVRegReference(inst->VRegB_22c());
+    obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(), f, true);
       return false;
     }
   }
-  uint32_t vregA = is_static ? inst->VRegA_21c() : inst->VRegA_22c();
+  uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
   switch (field_type) {
     case Primitive::kPrimBoolean:
       shadow_frame.SetVReg(vregA, f->GetBoolean(obj));
@@ -180,14 +180,12 @@
 // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
 // specialization.
 template<Primitive::Type field_type>
-static bool DoIGetQuick(Thread* self, ShadowFrame& shadow_frame,
-                       const Instruction* inst)
+static bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data)
     NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
 
 template<Primitive::Type field_type>
-static inline bool DoIGetQuick(Thread* self, ShadowFrame& shadow_frame,
-                               const Instruction* inst) {
-  Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c());
+static inline bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
+  Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
   if (UNLIKELY(obj == NULL)) {
     // We lost the reference to the field index so we cannot get a more
     // precised exception message.
@@ -196,7 +194,7 @@
   }
   MemberOffset field_offset(inst->VRegC_22c());
   const bool is_volatile = false;  // iget-x-quick only on non volatile fields.
-  const uint32_t vregA = inst->VRegA_22c();
+  const uint32_t vregA = inst->VRegA_22c(inst_data);
   switch (field_type) {
     case Primitive::kPrimInt:
       shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetField32(field_offset, is_volatile)));
@@ -217,12 +215,12 @@
 // specialization.
 template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
 static bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
-                       const Instruction* inst)
+                       const Instruction* inst, uint16_t inst_data)
     NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
 
 template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
 static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
-                              const Instruction* inst) {
+                              const Instruction* inst, uint16_t inst_data) {
   bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
   uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   ArtField* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
@@ -236,14 +234,14 @@
   if (is_static) {
     obj = f->GetDeclaringClass();
   } else {
-    obj = shadow_frame.GetVRegReference(inst->VRegB_22c());
+    obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(),
                                               f, false);
       return false;
     }
   }
-  uint32_t vregA = is_static ? inst->VRegA_21c() : inst->VRegA_22c();
+  uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
   switch (field_type) {
     case Primitive::kPrimBoolean:
       f->SetBoolean(obj, shadow_frame.GetVReg(vregA));
@@ -275,14 +273,12 @@
 // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
 // specialization.
 template<Primitive::Type field_type>
-static bool DoIPutQuick(Thread* self, ShadowFrame& shadow_frame,
-                       const Instruction* inst)
+static bool DoIPutQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data)
     NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
 
 template<Primitive::Type field_type>
-static inline bool DoIPutQuick(Thread* self, ShadowFrame& shadow_frame,
-                               const Instruction* inst) {
-  Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c());
+static inline bool DoIPutQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
+  Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
   if (UNLIKELY(obj == NULL)) {
     // We lost the reference to the field index so we cannot get a more
     // precised exception message.
@@ -291,7 +287,7 @@
   }
   MemberOffset field_offset(inst->VRegC_22c());
   const bool is_volatile = false;  // iput-x-quick only on non volatile fields.
-  const uint32_t vregA = inst->VRegA_22c();
+  const uint32_t vregA = inst->VRegA_22c(inst_data);
   switch (field_type) {
     case Primitive::kPrimInt:
       obj->SetField32(field_offset, shadow_frame.GetVReg(vregA), is_volatile);
@@ -387,14 +383,14 @@
 // Returns true on success, otherwise throws an exception and returns false.
 template <bool is_range, bool do_access_check>
 bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
-                             Thread* self, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
+                      Thread* self, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
 
-static inline int32_t DoPackedSwitch(const Instruction* inst,
-                                     const ShadowFrame& shadow_frame)
+static inline int32_t DoPackedSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
+                                     uint16_t inst_data)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   DCHECK(inst->Opcode() == Instruction::PACKED_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());
+  int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
   DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
   uint16_t size = switch_data[1];
   DCHECK_GT(size, 0);
@@ -412,12 +408,12 @@
   }
 }
 
-static inline int32_t DoSparseSwitch(const Instruction* inst,
-                                     const ShadowFrame& shadow_frame)
+static inline int32_t DoSparseSwitch(const Instruction* inst, const ShadowFrame& shadow_frame,
+                                     uint16_t inst_data)
     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());
+  int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data));
   DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
   uint16_t size = switch_data[1];
   DCHECK_GT(size, 0);