MethodHandles: Support and tests for invokeWithArguments.

Tracks libcore change a8cf0bffdb9e9cf031efd0d3c8b5645d45963562.

Test: make test-art-host
Change-Id: I65fbf3a82b629585324c477bdce6dabd63ae408e
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 7b6c0dc..c311542 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -743,6 +743,8 @@
   MethodHandleImplOffsets() : CheckOffsets<mirror::MethodHandleImpl>(
       false, "Ljava/lang/invoke/MethodHandle;") {
     addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, art_field_or_method_), "artFieldOrMethod");
+    addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, cached_spread_invoker_),
+              "cachedSpreadInvoker");
     addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, handle_kind_), "handleKind");
     addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, nominal_type_), "nominalType");
     addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, method_type_), "type");
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
index abe999a..2f26a22 100644
--- a/runtime/mirror/method_handle_impl.h
+++ b/runtime/mirror/method_handle_impl.h
@@ -84,10 +84,12 @@
   static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
+  // NOTE: cached_spread_invoker_ isn't used by the runtime.
+  HeapReference<mirror::MethodHandle> cached_spread_invoker_;
   HeapReference<mirror::MethodType> nominal_type_;
   HeapReference<mirror::MethodType> method_type_;
-  uint64_t art_field_or_method_;
   uint32_t handle_kind_;
+  uint64_t art_field_or_method_;
 
  private:
   static MemberOffset NominalTypeOffset() {
diff --git a/test/957-methodhandle-transforms/expected.txt b/test/957-methodhandle-transforms/expected.txt
index 154051f..383ccd9 100644
--- a/test/957-methodhandle-transforms/expected.txt
+++ b/test/957-methodhandle-transforms/expected.txt
@@ -47,3 +47,6 @@
 a: a, b:1.0, c: 2.0, d: 3.0
 a: a, b:1.0, c: 2.0
 a: a, b:1.0, c: 2.0
+a: a, b:b, c: c
+a: a, b:b, c: c
+a: a, b:43
diff --git a/test/957-methodhandle-transforms/src/Main.java b/test/957-methodhandle-transforms/src/Main.java
index 3271108..d0bd816 100644
--- a/test/957-methodhandle-transforms/src/Main.java
+++ b/test/957-methodhandle-transforms/src/Main.java
@@ -36,6 +36,7 @@
     testInvokers();
     testSpreaders_reference();
     testSpreaders_primitive();
+    testInvokeWithArguments();
   }
 
   public static void testThrowException() throws Throwable {
@@ -1223,6 +1224,34 @@
     assertEquals(51, ret);
   }
 
+  public static void testInvokeWithArguments() throws Throwable {
+    MethodType methodType = MethodType.methodType(int.class,
+        new Class<?>[] { String.class, String.class, String.class });
+    MethodHandle handle = MethodHandles.lookup().findStatic(
+        Main.class, "spreadReferences", methodType);
+
+    Object ret = handle.invokeWithArguments(new Object[] { "a", "b", "c"});
+    assertEquals(42, (int) ret);
+    handle.invokeWithArguments(new String[] { "a", "b", "c" });
+    assertEquals(42, (int) ret);
+
+    // Pass in an array that's too small. Should throw an IAE.
+    try {
+      handle.invokeWithArguments(new Object[] { "a", "b" });
+      fail();
+    } catch (IllegalArgumentException expected) {
+    }
+
+    // Test implicit unboxing.
+    MethodType methodType2 = MethodType.methodType(int.class,
+        new Class<?>[] { String.class, int.class });
+    MethodHandle handle2 = MethodHandles.lookup().findStatic(
+        Main.class, "spreadReferences_Unbox", methodType2);
+
+    ret = (int) handle2.invokeWithArguments(new Object[] { "a", 43 });
+    assertEquals(43, (int) ret);
+  }
+
   public static void fail() {
     System.out.println("FAIL");
     Thread.dumpStack();