ART: Simplify MethodHandle invocations

Use an operand iterator rather than passing arguments for both
range and varargs operands.

Test: art/test.py --host -j32
Change-Id: Ia42398773bd3732d917e19c25aa431b1e1369320
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 5a5d571..8eb31c1 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -299,17 +299,14 @@
 
 namespace {
 
-template <bool is_range>
 inline void CopyArgumentsFromCallerFrame(const ShadowFrame& caller_frame,
                                          ShadowFrame* callee_frame,
-                                         const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                                         uint32_t first_arg,
-                                         const size_t first_dst_reg,
-                                         const size_t num_regs)
+                                         const InstructionOperands* const operands,
+                                         const size_t first_dst_reg)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  for (size_t i = 0; i < num_regs; ++i) {
+  for (size_t i = 0; i < operands->GetNumberOfOperands(); ++i) {
     size_t dst_reg = first_dst_reg + i;
-    size_t src_reg = is_range ? (first_arg + i) : args[i];
+    size_t src_reg = operands->GetOperand(i);
     // Uint required, so that sign extension does not make this wrong on 64-bit systems
     uint32_t src_value = caller_frame.GetVReg(src_reg);
     ObjPtr<mirror::Object> o = caller_frame.GetVRegReference<kVerifyNone>(src_reg);
@@ -324,15 +321,13 @@
   }
 }
 
-template <bool is_range>
 inline bool ConvertAndCopyArgumentsFromCallerFrame(
     Thread* self,
     Handle<mirror::MethodType> callsite_type,
     Handle<mirror::MethodType> callee_type,
     const ShadowFrame& caller_frame,
-    const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-    uint32_t first_arg,
-    uint32_t first_dst_reg,
+    uint32_t first_dest_reg,
+    const InstructionOperands* const operands,
     ShadowFrame* callee_frame)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ObjPtr<mirror::ObjectArray<mirror::Class>> from_types(callsite_type->GetPTypes());
@@ -344,15 +339,14 @@
     return false;
   }
 
-  ShadowFrameGetter<is_range> getter(first_arg, args, caller_frame);
-  ShadowFrameSetter setter(callee_frame, first_dst_reg);
-
-  return PerformConversions<ShadowFrameGetter<is_range>, ShadowFrameSetter>(self,
-                                                                            callsite_type,
-                                                                            callee_type,
-                                                                            &getter,
-                                                                            &setter,
-                                                                            num_method_params);
+  ShadowFrameGetter getter(operands, caller_frame);
+  ShadowFrameSetter setter(callee_frame, first_dest_reg);
+  return PerformConversions<ShadowFrameGetter, ShadowFrameSetter>(self,
+                                                                  callsite_type,
+                                                                  callee_type,
+                                                                  &getter,
+                                                                  &setter,
+                                                                  num_method_params);
 }
 
 inline bool IsInvoke(const mirror::MethodHandle::Kind handle_kind) {
@@ -406,14 +400,12 @@
   return false;
 }
 
-template <bool is_range>
 static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
                                             Handle<mirror::MethodType> callsite_type,
                                             Handle<mirror::MethodType> target_type,
                                             Thread* self,
                                             ShadowFrame& shadow_frame,
-                                            const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                                            uint32_t first_arg,
+                                            const InstructionOperands* const operands,
                                             JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
   // Compute method information.
   const DexFile::CodeItem* code_item = called_method->GetCodeItem();
@@ -455,12 +447,10 @@
     if (callsite_type->IsExactMatch(target_type.Get())) {
       // This is an exact invoke, we can take the fast path of just copying all
       // registers without performing any argument conversions.
-      CopyArgumentsFromCallerFrame<is_range>(shadow_frame,
-                                             new_shadow_frame,
-                                             args,
-                                             first_arg,
-                                             first_dest_reg,
-                                             num_input_regs);
+      CopyArgumentsFromCallerFrame(shadow_frame,
+                                   new_shadow_frame,
+                                   operands,
+                                   first_dest_reg);
     } else {
       // This includes the case where we're entering this invoke-polymorphic
       // from a transformer method. In that case, the callsite_type will contain
@@ -471,7 +461,7 @@
         is_caller_transformer = true;
         // The emulated stack frame is the first and only argument when we're coming
         // through from a transformer.
-        size_t first_arg_register = (is_range) ? first_arg : args[0];
+        size_t first_arg_register = operands->GetOperand(0);
         ObjPtr<mirror::EmulatedStackFrame> emulated_stack_frame(
             reinterpret_cast<mirror::EmulatedStackFrame*>(
                 shadow_frame.GetVRegReference(first_arg_register)));
@@ -488,14 +478,13 @@
           ThrowWrongMethodTypeException(target_type.Get(), callsite_type.Get());
           return false;
         }
-        if (!ConvertAndCopyArgumentsFromCallerFrame<is_range>(self,
-                                                              callsite_type,
-                                                              target_type,
-                                                              shadow_frame,
-                                                              args,
-                                                              first_arg,
-                                                              first_dest_reg,
-                                                              new_shadow_frame)) {
+        if (!ConvertAndCopyArgumentsFromCallerFrame(self,
+                                                    callsite_type,
+                                                    target_type,
+                                                    shadow_frame,
+                                                    first_dest_reg,
+                                                    operands,
+                                                    new_shadow_frame)) {
           DCHECK(self->IsExceptionPending());
           result->SetL(0);
           return false;
@@ -521,7 +510,7 @@
   // we need to copy the result back out to the emulated stack frame.
   if (is_caller_transformer) {
     StackHandleScope<2> hs(self);
-    size_t first_callee_register = is_range ? (first_arg) : args[0];
+    size_t first_callee_register = operands->GetOperand(0);
     Handle<mirror::EmulatedStackFrame> emulated_stack_frame(
         hs.NewHandle(reinterpret_cast<mirror::EmulatedStackFrame*>(
             shadow_frame.GetVRegReference(first_callee_register))));
@@ -541,15 +530,13 @@
   return ConvertReturnValue(callsite_type, target_type, result);
 }
 
-template <bool is_range>
 static inline bool MethodHandleInvokeTransform(ArtMethod* called_method,
                                                Handle<mirror::MethodType> callsite_type,
                                                Handle<mirror::MethodType> callee_type,
                                                Thread* self,
                                                ShadowFrame& shadow_frame,
                                                Handle<mirror::MethodHandle> receiver,
-                                               const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                                               uint32_t first_arg,
+                                               const InstructionOperands* const operands,
                                                JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   // This can be fixed to two, because the method we're calling here
@@ -578,16 +565,15 @@
     // If we're entering this transformer from another transformer, we can pass
     // through the handle directly to the callee, instead of having to
     // instantiate a new stack frame based on the shadow frame.
-    size_t first_callee_register = is_range ? first_arg : args[0];
+    size_t first_callee_register = operands->GetOperand(0);
     sf.Assign(reinterpret_cast<mirror::EmulatedStackFrame*>(
         shadow_frame.GetVRegReference(first_callee_register)));
   } else {
-    sf.Assign(mirror::EmulatedStackFrame::CreateFromShadowFrameAndArgs<is_range>(self,
-                                                                                 callsite_type,
-                                                                                 callee_type,
-                                                                                 shadow_frame,
-                                                                                 first_arg,
-                                                                                 args));
+    sf.Assign(mirror::EmulatedStackFrame::CreateFromShadowFrameAndArgs(self,
+                                                                       callsite_type,
+                                                                       callee_type,
+                                                                       shadow_frame,
+                                                                       operands));
 
     // Something went wrong while creating the emulated stack frame, we should
     // throw the pending exception.
@@ -699,13 +685,11 @@
   return target_method;
 }
 
-template <bool is_range>
 bool DoInvokePolymorphicMethod(Thread* self,
                                ShadowFrame& shadow_frame,
                                Handle<mirror::MethodHandle> method_handle,
                                Handle<mirror::MethodType> callsite_type,
-                               const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                               uint32_t first_arg,
+                               const InstructionOperands* const operands,
                                JValue* result)
   REQUIRES_SHARED(Locks::mutator_lock_) {
   StackHandleScope<1> hs(self);
@@ -718,7 +702,7 @@
   // point because they would have been performed on our behalf at the point
   // of creation of the method handle.
   ArtMethod* target_method = method_handle->GetTargetMethod();
-  uint32_t receiver_reg = is_range ? first_arg: args[0];
+  uint32_t receiver_reg = (operands->GetNumberOfOperands() > 0) ? operands->GetOperand(0) : 0u;
   ArtMethod* called_method = RefineTargetMethod(self,
                                                 shadow_frame,
                                                 handle_kind,
@@ -743,24 +727,22 @@
     Handle<mirror::MethodType> callee_type =
         (handle_kind == mirror::MethodHandle::Kind::kInvokeCallSiteTransform) ? callsite_type
         : handle_type;
-    return MethodHandleInvokeTransform<is_range>(called_method,
-                                                 callsite_type,
-                                                 callee_type,
-                                                 self,
-                                                 shadow_frame,
-                                                 method_handle /* receiver */,
-                                                 args,
-                                                 first_arg,
-                                                 result);
+    return MethodHandleInvokeTransform(called_method,
+                                       callsite_type,
+                                       callee_type,
+                                       self,
+                                       shadow_frame,
+                                       method_handle /* receiver */,
+                                       operands,
+                                       result);
   } else {
-    return MethodHandleInvokeMethod<is_range>(called_method,
-                                              callsite_type,
-                                              handle_type,
-                                              self,
-                                              shadow_frame,
-                                              args,
-                                              first_arg,
-                                              result);
+    return MethodHandleInvokeMethod(called_method,
+                                    callsite_type,
+                                    handle_type,
+                                    self,
+                                    shadow_frame,
+                                    operands,
+                                    result);
   }
 }
 
@@ -884,23 +866,21 @@
   return field_value;
 }
 
-template <bool is_range, bool do_conversions>
+template <bool do_conversions>
 bool MethodHandleFieldAccess(Thread* self,
                              ShadowFrame& shadow_frame,
                              Handle<mirror::MethodHandle> method_handle,
                              Handle<mirror::MethodType> callsite_type,
-                             const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                             uint32_t first_arg,
+                             const InstructionOperands* const operands,
                              JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
   StackHandleScope<1> hs(self);
   Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
   const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
   ArtField* field = method_handle->GetTargetField();
   Primitive::Type field_type = field->GetTypeAsPrimitiveType();
-
   switch (handle_kind) {
     case mirror::MethodHandle::kInstanceGet: {
-      size_t obj_reg = is_range ? first_arg : args[0];
+      size_t obj_reg = operands->GetOperand(0);
       ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(obj_reg);
       MethodHandleFieldGet(self, shadow_frame, obj, field, field_type, result);
       if (do_conversions && !ConvertReturnValue(callsite_type, handle_type, result)) {
@@ -923,8 +903,8 @@
       return true;
     }
     case mirror::MethodHandle::kInstancePut: {
-      size_t obj_reg = is_range ? first_arg : args[0];
-      size_t value_reg = is_range ? (first_arg + 1) : args[1];
+      size_t obj_reg = operands->GetOperand(0);
+      size_t value_reg = operands->GetOperand(1);
       const size_t kPTypeIndex = 1;
       // Use ptypes instead of field type since we may be unboxing a reference for a primitive
       // field. The field type is incorrect for this case.
@@ -948,7 +928,7 @@
         DCHECK(self->IsExceptionPending());
         return false;
       }
-      size_t value_reg = is_range ? first_arg : args[0];
+      size_t value_reg = operands->GetOperand(0);
       const size_t kPTypeIndex = 0;
       // Use ptypes instead of field type since we may be unboxing a reference for a primitive
       // field. The field type is incorrect for this case.
@@ -971,13 +951,11 @@
   }
 }
 
-template <bool is_range>
 static inline bool MethodHandleInvokeInternal(Thread* self,
                                               ShadowFrame& shadow_frame,
                                               Handle<mirror::MethodHandle> method_handle,
                                               Handle<mirror::MethodType> callsite_type,
-                                              const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                                              uint32_t first_arg,
+                                              const InstructionOperands* const operands,
                                               JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
@@ -989,32 +967,28 @@
       return false;
     }
     const bool do_convert = true;
-    return MethodHandleFieldAccess<is_range, do_convert>(
+    return MethodHandleFieldAccess<do_convert>(
         self,
         shadow_frame,
         method_handle,
         callsite_type,
-        args,
-        first_arg,
+        operands,
         result);
   }
-  return DoInvokePolymorphicMethod<is_range>(self,
-                                             shadow_frame,
-                                             method_handle,
-                                             callsite_type,
-                                             args,
-                                             first_arg,
-                                             result);
+  return DoInvokePolymorphicMethod(self,
+                                   shadow_frame,
+                                   method_handle,
+                                   callsite_type,
+                                   operands,
+                                   result);
 }
 
-template <bool is_range>
 static inline bool MethodHandleInvokeExactInternal(
     Thread* self,
     ShadowFrame& shadow_frame,
     Handle<mirror::MethodHandle> method_handle,
     Handle<mirror::MethodType> callsite_type,
-    const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-    uint32_t first_arg,
+    const InstructionOperands* const operands,
     JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   StackHandleScope<1> hs(self);
@@ -1027,29 +1001,27 @@
   const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
   if (IsFieldAccess(handle_kind)) {
     const bool do_convert = false;
-    return MethodHandleFieldAccess<is_range, do_convert>(self,
-                                                         shadow_frame,
-                                                         method_handle,
-                                                         callsite_type,
-                                                         args,
-                                                         first_arg,
-                                                         result);
+    return MethodHandleFieldAccess<do_convert>(self,
+                                               shadow_frame,
+                                               method_handle,
+                                               callsite_type,
+                                               operands,
+                                               result);
   }
 
   // Slow-path check.
   if (IsInvokeTransform(handle_kind) || IsCallerTransformer(callsite_type)) {
-    return DoInvokePolymorphicMethod<is_range>(self,
-                                               shadow_frame,
-                                               method_handle,
-                                               callsite_type,
-                                               args,
-                                               first_arg,
-                                               result);
+    return DoInvokePolymorphicMethod(self,
+                                     shadow_frame,
+                                     method_handle,
+                                     callsite_type,
+                                     operands,
+                                     result);
   }
 
   // On the fast-path. This is equivalent to DoCallPolymoprhic without the conversion paths.
   ArtMethod* target_method = method_handle->GetTargetMethod();
-  uint32_t receiver_reg = is_range ? first_arg : args[0];
+  uint32_t receiver_reg = (operands->GetNumberOfOperands() > 0) ? operands->GetOperand(0) : 0u;
   ArtMethod* called_method = RefineTargetMethod(self,
                                                 shadow_frame,
                                                 handle_kind,
@@ -1085,12 +1057,10 @@
   ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
       CREATE_SHADOW_FRAME(num_regs, &shadow_frame, called_method, /* dex pc */ 0);
   ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
-  CopyArgumentsFromCallerFrame<is_range>(shadow_frame,
-                                         new_shadow_frame,
-                                         args,
-                                         first_arg,
-                                         first_dest_reg,
-                                         num_input_regs);
+  CopyArgumentsFromCallerFrame(shadow_frame,
+                               new_shadow_frame,
+                               operands,
+                               first_dest_reg);
   self->EndAssertNoThreadSuspension(old_cause);
 
   bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
@@ -1110,43 +1080,37 @@
 
 }  // namespace
 
-template <bool is_range>
-inline bool MethodHandleInvoke(Thread* self,
-                                 ShadowFrame& shadow_frame,
-                                 Handle<mirror::MethodHandle> method_handle,
-                                 Handle<mirror::MethodType> callsite_type,
-                                 const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                                 uint32_t first_arg,
-                                 JValue* result)
+bool MethodHandleInvoke(Thread* self,
+                       ShadowFrame& shadow_frame,
+                       Handle<mirror::MethodHandle> method_handle,
+                       Handle<mirror::MethodType> callsite_type,
+                       const InstructionOperands* const operands,
+                       JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   if (UNLIKELY(callsite_type->IsExactMatch(method_handle->GetMethodType()))) {
     // A non-exact invoke that can be invoked exactly.
-    return MethodHandleInvokeExactInternal<is_range>(self,
-                                                     shadow_frame,
-                                                     method_handle,
-                                                     callsite_type,
-                                                     args,
-                                                     first_arg,
-                                                     result);
+    return MethodHandleInvokeExactInternal(self,
+                                           shadow_frame,
+                                           method_handle,
+                                           callsite_type,
+                                           operands,
+                                           result);
   } else {
-    return MethodHandleInvokeInternal<is_range>(self,
-                                                shadow_frame,
-                                                method_handle,
-                                                callsite_type,
-                                                args,
-                                                first_arg,
-                                                result);
+    return MethodHandleInvokeInternal(self,
+                                      shadow_frame,
+                                      method_handle,
+                                      callsite_type,
+                                      operands,
+                                      result);
   }
 }
 
-template <bool is_range>
 bool MethodHandleInvokeExact(Thread* self,
-                               ShadowFrame& shadow_frame,
-                               Handle<mirror::MethodHandle> method_handle,
-                               Handle<mirror::MethodType> callsite_type,
-                               const uint32_t (&args)[Instruction::kMaxVarArgRegs],
-                               uint32_t first_arg,
-                               JValue* result)
+                             ShadowFrame& shadow_frame,
+                             Handle<mirror::MethodHandle> method_handle,
+                             Handle<mirror::MethodType> callsite_type,
+                             const InstructionOperands* const operands,
+                             JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   // We need to check the nominal type of the handle in addition to the
   // real type. The "nominal" type is present when MethodHandle.asType is
@@ -1160,39 +1124,20 @@
     }
     if (LIKELY(!nominal_type->IsExactMatch(method_handle->GetMethodType()))) {
       // Different nominal type means we have to treat as non-exact.
-      return MethodHandleInvokeInternal<is_range>(self,
-                                           shadow_frame,
-                                           method_handle,
-                                           callsite_type,
-                                           args,
-                                           first_arg,
-                                           result);
+      return MethodHandleInvokeInternal(self,
+                                        shadow_frame,
+                                        method_handle,
+                                        callsite_type,
+                                        operands,
+                                        result);
     }
   }
-  return MethodHandleInvokeExactInternal<is_range>(self,
-                                                   shadow_frame,
-                                                   method_handle,
-                                                   callsite_type,
-                                                   args,
-                                                   first_arg,
-                                                   result);
+  return MethodHandleInvokeExactInternal(self,
+                                         shadow_frame,
+                                         method_handle,
+                                         callsite_type,
+                                         operands,
+                                         result);
 }
 
-#define EXPLICIT_DO_METHOD_HANDLE_METHOD(_name, _is_range)       \
-  template REQUIRES_SHARED(Locks::mutator_lock_)                 \
-  bool MethodHandle##_name<_is_range>(                           \
-      Thread* self,                                              \
-      ShadowFrame& shadow_frame,                                 \
-      Handle<mirror::MethodHandle> method_handle,                \
-      Handle<mirror::MethodType> callsite_type,                  \
-      const uint32_t (&args)[Instruction::kMaxVarArgRegs],       \
-      uint32_t first_arg,                                        \
-      JValue* result)
-
-EXPLICIT_DO_METHOD_HANDLE_METHOD(Invoke, true);
-EXPLICIT_DO_METHOD_HANDLE_METHOD(Invoke, false);
-EXPLICIT_DO_METHOD_HANDLE_METHOD(InvokeExact, true);
-EXPLICIT_DO_METHOD_HANDLE_METHOD(InvokeExact, false);
-#undef EXPLICIT_DO_METHOD_HANDLE_METHOD
-
 }  // namespace art