MethodHandles: Fix invalid DCHECKS

Updates test 713-varhandle-invokers to demonstrate the problem and
fixes incorrect vreg count checks in the VarHandle invoker path for
MethodHandles.

Fix: 216456099
Test: art/test/run-test --host 713
Test: adb shell shell setprop persist.sys.dalvik.vm.lib.2 libartd.so
Test: atest CtsLibcoreTestCases:libcore.java.lang.invoke
Test: atest CtsLibcoreOjTestCases:test.java.lang.invoke
Change-Id: I3c2b6d7569b733b308c142073ea62a875feadb1c
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index aa456f5..2f24abf 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -957,9 +957,8 @@
                                            const InstructionOperands* const operands,
                                            JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  DCHECK_EQ(operands->GetNumberOfOperands(), static_cast<uint32_t>(vh_type->GetNumberOfPTypes()));
-  DCHECK_EQ(operands->GetNumberOfOperands(),
-            static_cast<uint32_t>(callsite_type->GetNumberOfPTypes()));
+  DCHECK_EQ(operands->GetNumberOfOperands(), vh_type->NumberOfVRegs());
+  DCHECK_EQ(operands->GetNumberOfOperands(), callsite_type->NumberOfVRegs());
   if (!vh->IsAccessModeSupported(access_mode)) {
     ThrowUnsupportedOperationException();
     return false;
@@ -1041,8 +1040,6 @@
   Handle<mirror::MethodType> callsite_type_without_varhandle =
       hs.NewHandle(mirror::MethodType::CloneWithoutLeadingParameter(self, callsite_type.Get()));
   NoReceiverInstructionOperands varhandle_operands(operands);
-  DCHECK_EQ(static_cast<int32_t>(varhandle_operands.GetNumberOfOperands()),
-            callsite_type_without_varhandle->GetPTypes()->GetLength());
   return DoVarHandleInvokeTranslationUnchecked(self,
                                                shadow_frame,
                                                access_mode,
diff --git a/test/713-varhandle-invokers/expected-stdout.txt b/test/713-varhandle-invokers/expected-stdout.txt
index a62d366..c0dfd03 100644
--- a/test/713-varhandle-invokers/expected-stdout.txt
+++ b/test/713-varhandle-invokers/expected-stdout.txt
@@ -1,4 +1,5 @@
-fieldVarHandleExactInvokerTest
+Main$FieldVarHandleExactInvokerTest
+Main$LongFieldVarHandleExactInvokerTest
 fieldVarHandleInvokerTest
 DivergenceExactInvokerTest
 DivergenceInvokerTest
diff --git a/test/713-varhandle-invokers/src/Main.java b/test/713-varhandle-invokers/src/Main.java
index baa04e9..041463d 100644
--- a/test/713-varhandle-invokers/src/Main.java
+++ b/test/713-varhandle-invokers/src/Main.java
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
+import static java.lang.invoke.MethodHandles.lookup;
+import static java.lang.invoke.MethodType.methodType;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
 import java.lang.invoke.VarHandle;
 import java.lang.invoke.WrongMethodTypeException;
 
@@ -46,47 +48,51 @@
         failAssertion(sb.toString());
     }
 
+    private static void assertEquals(boolean expected, boolean actual) {
+        if (expected != actual) {
+            failAssertEquals(expected, actual);
+        }
+    }
+
     private static void assertEquals(int expected, int actual) {
         if (expected != actual) {
             failAssertEquals(expected, actual);
         }
     }
 
+    private static void assertEquals(long expected, long actual) {
+        if (expected != actual) {
+            failAssertEquals(expected, actual);
+        }
+    }
+
     private static void assertEquals(float expected, float actual) {
         if (expected != actual) {
             failAssertEquals(expected, actual);
         }
     }
 
-    private static void assertEquals(double expected, double actual) {
-        if (expected != actual) {
-            failAssertEquals(expected, actual);
-        }
-    }
-
     static class FieldVarHandleExactInvokerTest {
+        private static final Class<?> THIS_CLASS = FieldVarHandleExactInvokerTest.class;
         private static final VarHandle fieldVarHandle;
+
         int field;
 
         static {
             try {
-                fieldVarHandle =
-                        MethodHandles.lookup()
-                                .findVarHandle(
-                                        FieldVarHandleExactInvokerTest.class, "field", int.class);
+                fieldVarHandle = lookup().findVarHandle(THIS_CLASS, "field", int.class);
             } catch (Exception e) {
                 throw new TestSetupError("Failed to lookup of field", e);
             }
         }
 
         void run() throws Throwable {
-            System.out.println("fieldVarHandleExactInvokerTest");
+            System.out.println(THIS_CLASS.getName());
 
             MethodHandle invokerMethodHandle =
                     MethodHandles.varHandleExactInvoker(
                             VarHandle.AccessMode.GET_AND_SET,
-                            MethodType.methodType(
-                                    int.class, FieldVarHandleExactInvokerTest.class, int.class));
+                            methodType(int.class, THIS_CLASS, int.class));
 
             field = 3;
             assertEquals(3, (int) invokerMethodHandle.invokeExact(fieldVarHandle, this, 4));
@@ -170,15 +176,55 @@
         }
     }
 
+    static class LongFieldVarHandleExactInvokerTest {
+        private static final Class<?> THIS_CLASS = LongFieldVarHandleExactInvokerTest.class;
+
+        private static final VarHandle fieldVarHandle;
+
+        private static final long CANARY = 0x0123456789abcdefL;
+
+        long field = 0L;
+
+        static {
+            try {
+                fieldVarHandle = lookup().findVarHandle(THIS_CLASS, "field", long.class);
+            } catch (Exception e) {
+                throw new TestSetupError("Failed to lookup of field", e);
+            }
+        }
+
+        void run() throws Throwable {
+            System.out.println(THIS_CLASS.getName());
+
+            MethodHandle invokerMethodHandle =
+                    MethodHandles.varHandleExactInvoker(
+                            VarHandle.AccessMode.COMPARE_AND_SET,
+                            methodType(boolean.class, THIS_CLASS, long.class, long.class));
+            checkCompareAndSet(invokerMethodHandle, 0L, CANARY);
+            checkCompareAndSet(invokerMethodHandle, 1L, 1L);
+            checkCompareAndSet(invokerMethodHandle, CANARY, ~CANARY);
+            checkCompareAndSet(invokerMethodHandle, ~CANARY, 0L);
+        }
+
+        private void checkCompareAndSet(MethodHandle compareAndSet, long oldValue, long newValue)
+                throws Throwable {
+            final boolean expectSuccess = (oldValue == field);
+            final long oldFieldValue = field;
+            assertEquals(
+                    expectSuccess,
+                    (boolean) compareAndSet.invoke(fieldVarHandle, this, oldValue, newValue));
+            assertEquals(expectSuccess ? newValue : oldFieldValue, field);
+        }
+    }
+
     static class FieldVarHandleInvokerTest {
+        private static final Class<?> THIS_CLASS = FieldVarHandleInvokerTest.class;
         private static final VarHandle fieldVarHandle;
         int field;
 
         static {
             try {
-                fieldVarHandle =
-                        MethodHandles.lookup()
-                                .findVarHandle(FieldVarHandleInvokerTest.class, "field", int.class);
+                fieldVarHandle = lookup().findVarHandle(THIS_CLASS, "field", int.class);
             } catch (Exception e) {
                 throw new TestSetupError("Failed to lookup of field", e);
             }
@@ -189,8 +235,7 @@
             MethodHandle invokerMethodHandle =
                     MethodHandles.varHandleInvoker(
                             VarHandle.AccessMode.GET_AND_SET,
-                            MethodType.methodType(
-                                    int.class, FieldVarHandleInvokerTest.class, int.class));
+                            methodType(int.class, THIS_CLASS, int.class));
 
             field = 3;
             int oldField = (int) invokerMethodHandle.invoke(fieldVarHandle, this, 4);
@@ -315,7 +360,7 @@
             MethodHandle exactInvoker =
                     MethodHandles.varHandleExactInvoker(
                             VarHandle.AccessMode.COMPARE_AND_EXCHANGE,
-                            MethodType.methodType(
+                            methodType(
                                     float.class,
                                     float[].class,
                                     int.class,
@@ -389,7 +434,7 @@
             MethodHandle invoker =
                     MethodHandles.varHandleInvoker(
                             VarHandle.AccessMode.COMPARE_AND_EXCHANGE,
-                            MethodType.methodType(
+                            methodType(
                                     float.class,
                                     float[].class,
                                     int.class,
@@ -433,12 +478,11 @@
                 MethodHandle unsupportedInvoker =
                         MethodHandles.varHandleInvoker(
                                 VarHandle.AccessMode.GET_AND_BITWISE_OR,
-                                MethodType.methodType(
-                                        float.class, float[].class, int.class, float.class));
+                                methodType(float.class, float[].class, int.class, float.class));
                 old =
                         (float)
                                 unsupportedInvoker.invoke(
-                                    floatsArrayVarHandle, floatsArray, 0, 2.71f);
+                                        floatsArrayVarHandle, floatsArray, 0, 2.71f);
                 assertUnreachable();
             } catch (UnsupportedOperationException expected) {
             }
@@ -447,6 +491,7 @@
 
     public static void main(String[] args) throws Throwable {
         new FieldVarHandleExactInvokerTest().run();
+        new LongFieldVarHandleExactInvokerTest().run();
         new FieldVarHandleInvokerTest().run();
         new DivergenceExactInvokerTest().run();
         new DivergenceInvokerTest().run();