Argument conversions for setter/getter MethodHandles.

Test: m test-art-host-run-test-959-invoke-polymorphic-accessors
Bug: 30550796

Change-Id: I9898605fc9f9f8a80f47f9559f3ccb99b02b07c8
diff --git a/test/959-invoke-polymorphic-accessors/src/Main.java b/test/959-invoke-polymorphic-accessors/src/Main.java
new file mode 100644
index 0000000..824a436
--- /dev/null
+++ b/test/959-invoke-polymorphic-accessors/src/Main.java
@@ -0,0 +1,897 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.WrongMethodTypeException;
+
+public class Main {
+
+    public static class ValueHolder {
+        public boolean m_z = false;
+        public byte m_b = 0;
+        public char m_c = 'a';
+        public short m_s = 0;
+        public int m_i = 0;
+        public float m_f = 0.0f;
+        public double m_d = 0.0;
+        public long m_j = 0;
+        public String m_l = "a";
+
+        public static boolean s_z;
+        public static byte s_b;
+        public static char s_c;
+        public static short s_s;
+        public static int s_i;
+        public static float s_f;
+        public static double s_d;
+        public static long s_j;
+        public static String s_l;
+
+        public final int m_fi = 0xa5a5a5a5;
+        public static final int s_fi = 0x5a5a5a5a;
+    }
+
+    public static class Tester {
+        public static void assertActualAndExpectedMatch(boolean actual, boolean expected)
+                throws AssertionError {
+            if (actual != expected) {
+                throw new AssertionError("Actual != Expected (" + actual + " != " + expected + ")");
+            }
+        }
+
+        public static void assertTrue(boolean value) throws AssertionError {
+            if (!value) {
+                throw new AssertionError("Value is not true");
+            }
+        }
+
+        public static void unreachable() throws Throwable{
+            throw new Error("unreachable");
+        }
+    }
+
+    public static class InvokeExactTester extends Tester {
+        private enum PrimitiveType {
+            Boolean,
+            Byte,
+            Char,
+            Short,
+            Int,
+            Long,
+            Float,
+            Double,
+            String,
+        }
+
+        private enum AccessorType {
+            IPUT,
+            SPUT,
+            IGET,
+            SGET,
+        }
+
+        static void setByte(MethodHandle m, ValueHolder v, byte value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                if (v == null) {
+                    m.invokeExact(value);
+                }
+                else {
+                    m.invokeExact(v, value);
+                }
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void setByte(MethodHandle m, byte value, boolean expectFailure) throws Throwable {
+            setByte(m, null, value, expectFailure);
+        }
+
+        static void getByte(MethodHandle m, ValueHolder v, byte value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                final byte got;
+                if (v == null) {
+                    got = (byte)m.invokeExact();
+                } else {
+                    got = (byte)m.invokeExact(v);
+                }
+                assertTrue(got == value);
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void getByte(MethodHandle m, byte value, boolean expectFailure) throws Throwable {
+            getByte(m, null, value, expectFailure);
+        }
+
+        static void setChar(MethodHandle m, ValueHolder v, char value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                if (v == null) {
+                    m.invokeExact(value);
+                }
+                else {
+                    m.invokeExact(v, value);
+                }
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void setChar(MethodHandle m, char value, boolean expectFailure) throws Throwable {
+            setChar(m, null, value, expectFailure);
+        }
+
+        static void getChar(MethodHandle m, ValueHolder v, char value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                final char got;
+                if (v == null) {
+                    got = (char)m.invokeExact();
+                } else {
+                    got = (char)m.invokeExact(v);
+                }
+                assertTrue(got == value);
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void getChar(MethodHandle m, char value, boolean expectFailure) throws Throwable {
+            getChar(m, null, value, expectFailure);
+        }
+
+        static void setShort(MethodHandle m, ValueHolder v, short value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                if (v == null) {
+                    m.invokeExact(value);
+                }
+                else {
+                    m.invokeExact(v, value);
+                }
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void setShort(MethodHandle m, short value, boolean expectFailure) throws Throwable {
+            setShort(m, null, value, expectFailure);
+        }
+
+        static void getShort(MethodHandle m, ValueHolder v, short value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                final short got = (v == null) ? (short)m.invokeExact() : (short)m.invokeExact(v);
+                assertTrue(got == value);
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void getShort(MethodHandle m, short value, boolean expectFailure) throws Throwable {
+            getShort(m, null, value, expectFailure);
+        }
+
+        static void setInt(MethodHandle m, ValueHolder v, int value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                if (v == null) {
+                    m.invokeExact(value);
+                }
+                else {
+                    m.invokeExact(v, value);
+                }
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void setInt(MethodHandle m, int value, boolean expectFailure) throws Throwable {
+            setInt(m, null, value, expectFailure);
+        }
+
+        static void getInt(MethodHandle m, ValueHolder v, int value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                final int got = (v == null) ? (int)m.invokeExact() : (int)m.invokeExact(v);
+                assertTrue(got == value);
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void getInt(MethodHandle m, int value, boolean expectFailure) throws Throwable {
+            getInt(m, null, value, expectFailure);
+        }
+
+        static void setLong(MethodHandle m, ValueHolder v, long value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                if (v == null) {
+                    m.invokeExact(value);
+                }
+                else {
+                    m.invokeExact(v, value);
+                }
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void setLong(MethodHandle m, long value, boolean expectFailure) throws Throwable {
+            setLong(m, null, value, expectFailure);
+        }
+
+        static void getLong(MethodHandle m, ValueHolder v, long value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                final long got = (v == null) ? (long)m.invokeExact() : (long)m.invokeExact(v);
+                assertTrue(got == value);
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void getLong(MethodHandle m, long value, boolean expectFailure) throws Throwable {
+            getLong(m, null, value, expectFailure);
+        }
+
+        static void setFloat(MethodHandle m, ValueHolder v, float value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                if (v == null) {
+                    m.invokeExact(value);
+                }
+                else {
+                    m.invokeExact(v, value);
+                }
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void setFloat(MethodHandle m, float value, boolean expectFailure) throws Throwable {
+            setFloat(m, null, value, expectFailure);
+        }
+
+        static void getFloat(MethodHandle m, ValueHolder v, float value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                final float got = (v == null) ? (float)m.invokeExact() : (float)m.invokeExact(v);
+                assertTrue(got == value);
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void getFloat(MethodHandle m, float value, boolean expectFailure) throws Throwable {
+            getFloat(m, null, value, expectFailure);
+        }
+
+        static void setDouble(MethodHandle m, ValueHolder v, double value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                if (v == null) {
+                    m.invokeExact(value);
+                }
+                else {
+                    m.invokeExact(v, value);
+                }
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void setDouble(MethodHandle m, double value, boolean expectFailure)
+                throws Throwable {
+            setDouble(m, null, value, expectFailure);
+        }
+
+        static void getDouble(MethodHandle m, ValueHolder v, double value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                final double got = (v == null) ? (double)m.invokeExact() : (double)m.invokeExact(v);
+                assertTrue(got == value);
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void getDouble(MethodHandle m, double value, boolean expectFailure)
+                throws Throwable {
+            getDouble(m, null, value, expectFailure);
+        }
+
+        static void setString(MethodHandle m, ValueHolder v, String value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                if (v == null) {
+                    m.invokeExact(value);
+                }
+                else {
+                    m.invokeExact(v, value);
+                }
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void setString(MethodHandle m, String value, boolean expectFailure)
+                throws Throwable {
+            setString(m, null, value, expectFailure);
+        }
+
+        static void getString(MethodHandle m, ValueHolder v, String value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                final String got = (v == null) ? (String)m.invokeExact() : (String)m.invokeExact(v);
+                assertTrue(got.equals(value));
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void getString(MethodHandle m, String value, boolean expectFailure)
+                throws Throwable {
+            getString(m, null, value, expectFailure);
+        }
+
+        static void setBoolean(MethodHandle m, ValueHolder v, boolean value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                if (v == null) {
+                    m.invokeExact(value);
+                }
+                else {
+                    m.invokeExact(v, value);
+                }
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void setBoolean(MethodHandle m, boolean value, boolean expectFailure)
+                throws Throwable {
+            setBoolean(m, null, value, expectFailure);
+        }
+
+        static void getBoolean(MethodHandle m, ValueHolder v, boolean value, boolean expectFailure)
+                throws Throwable {
+            boolean exceptionThrown = false;
+            try {
+                final boolean got =
+                        (v == null) ? (boolean)m.invokeExact() : (boolean)m.invokeExact(v);
+                assertTrue(got == value);
+            }
+            catch (WrongMethodTypeException e) {
+                exceptionThrown = true;
+            }
+            assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+        }
+
+        static void getBoolean(MethodHandle m, boolean value, boolean expectFailure)
+                throws Throwable {
+            getBoolean(m, null, value, expectFailure);
+        }
+
+        static boolean resultFor(PrimitiveType actualType, PrimitiveType expectedType,
+                                 AccessorType actualAccessor,
+                                 AccessorType expectedAccessor) {
+            return (actualType != expectedType) || (actualAccessor != expectedAccessor);
+        }
+
+        static void tryAccessor(MethodHandle methodHandle,
+                                ValueHolder valueHolder,
+                                PrimitiveType primitive,
+                                Object value,
+                                AccessorType accessor) throws Throwable {
+            boolean booleanValue =
+                    value instanceof Boolean ? ((Boolean)value).booleanValue() : false;
+            setBoolean(methodHandle, valueHolder, booleanValue,
+                       resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.IPUT));
+            setBoolean(methodHandle, booleanValue,
+                       resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.SPUT));
+            getBoolean(methodHandle, valueHolder, booleanValue,
+                       resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.IGET));
+            getBoolean(methodHandle, booleanValue,
+                       resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.SGET));
+
+            byte byteValue = value instanceof Byte ? ((Byte)value).byteValue() : (byte)0;
+            setByte(methodHandle, valueHolder, byteValue,
+                    resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.IPUT));
+            setByte(methodHandle, byteValue,
+                    resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.SPUT));
+            getByte(methodHandle, valueHolder, byteValue,
+                    resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.IGET));
+            getByte(methodHandle, byteValue,
+                    resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.SGET));
+
+            char charValue = value instanceof Character ? ((Character)value).charValue() : 'z';
+            setChar(methodHandle, valueHolder, charValue,
+                    resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.IPUT));
+            setChar(methodHandle, charValue,
+                    resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.SPUT));
+            getChar(methodHandle, valueHolder, charValue,
+                    resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.IGET));
+            getChar(methodHandle, charValue,
+                    resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.SGET));
+
+            short shortValue = value instanceof Short ? ((Short)value).shortValue() : (short)0;
+            setShort(methodHandle, valueHolder, shortValue,
+                     resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.IPUT));
+            setShort(methodHandle, shortValue,
+                    resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.SPUT));
+            getShort(methodHandle, valueHolder, shortValue,
+                     resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.IGET));
+            getShort(methodHandle, shortValue,
+                    resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.SGET));
+
+            int intValue = value instanceof Integer ? ((Integer)value).intValue() : -1;
+            setInt(methodHandle, valueHolder, intValue,
+                   resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.IPUT));
+            setInt(methodHandle, intValue,
+                   resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.SPUT));
+            getInt(methodHandle, valueHolder, intValue,
+                   resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.IGET));
+            getInt(methodHandle, intValue,
+                   resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.SGET));
+
+            long longValue = value instanceof Long ? ((Long)value).longValue() : (long)-1;
+            setLong(methodHandle, valueHolder, longValue,
+                    resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.IPUT));
+            setLong(methodHandle, longValue,
+                    resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.SPUT));
+            getLong(methodHandle, valueHolder, longValue,
+                    resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.IGET));
+            getLong(methodHandle, longValue,
+                    resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.SGET));
+
+            float floatValue = value instanceof Float ? ((Float)value).floatValue() : -1.0f;
+            setFloat(methodHandle, valueHolder, floatValue,
+                    resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.IPUT));
+            setFloat(methodHandle, floatValue,
+                    resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.SPUT));
+            getFloat(methodHandle, valueHolder, floatValue,
+                    resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.IGET));
+            getFloat(methodHandle, floatValue,
+                     resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.SGET));
+
+            double doubleValue = value instanceof Double ? ((Double)value).doubleValue() : -1.0;
+            setDouble(methodHandle, valueHolder, doubleValue,
+                      resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.IPUT));
+            setDouble(methodHandle, doubleValue,
+                      resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.SPUT));
+            getDouble(methodHandle, valueHolder, doubleValue,
+                      resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.IGET));
+            getDouble(methodHandle, doubleValue,
+                      resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.SGET));
+
+            String stringValue = value instanceof String ? ((String) value) : "No Spock, no";
+            setString(methodHandle, valueHolder, stringValue,
+                      resultFor(primitive, PrimitiveType.String, accessor, AccessorType.IPUT));
+            setString(methodHandle, stringValue,
+                      resultFor(primitive, PrimitiveType.String, accessor, AccessorType.SPUT));
+            getString(methodHandle, valueHolder, stringValue,
+                      resultFor(primitive, PrimitiveType.String, accessor, AccessorType.IGET));
+            getString(methodHandle, stringValue,
+                      resultFor(primitive, PrimitiveType.String, accessor, AccessorType.SGET));
+        }
+
+        public static void main() throws Throwable {
+            ValueHolder valueHolder = new ValueHolder();
+            MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+            boolean [] booleans = { false, true, false };
+            for (boolean b : booleans) {
+                Boolean boxed = new Boolean(b);
+                tryAccessor(lookup.findSetter(ValueHolder.class, "m_z", boolean.class),
+                            valueHolder, PrimitiveType.Boolean, boxed, AccessorType.IPUT);
+                tryAccessor(lookup.findGetter(ValueHolder.class, "m_z", boolean.class),
+                            valueHolder, PrimitiveType.Boolean, boxed, AccessorType.IGET);
+                assertTrue(valueHolder.m_z == b);
+                tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_z", boolean.class),
+                            valueHolder, PrimitiveType.Boolean, boxed, AccessorType.SPUT);
+                tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_z", boolean.class),
+                            valueHolder, PrimitiveType.Boolean, boxed, AccessorType.SGET);
+                assertTrue(ValueHolder.s_z == b);
+            }
+
+            byte [] bytes = { (byte)0x73, (byte)0xfe };
+            for (byte b : bytes) {
+                Byte boxed = new Byte(b);
+                tryAccessor(lookup.findSetter(ValueHolder.class, "m_b", byte.class),
+                            valueHolder, PrimitiveType.Byte, boxed, AccessorType.IPUT);
+                tryAccessor(lookup.findGetter(ValueHolder.class, "m_b", byte.class),
+                            valueHolder, PrimitiveType.Byte, boxed, AccessorType.IGET);
+                assertTrue(valueHolder.m_b == b);
+                tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_b", byte.class),
+                            valueHolder, PrimitiveType.Byte, boxed, AccessorType.SPUT);
+                tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_b", byte.class),
+                            valueHolder, PrimitiveType.Byte, boxed, AccessorType.SGET);
+                assertTrue(ValueHolder.s_b == b);
+            }
+
+            char [] chars = { 'a', 'b', 'c' };
+            for (char c : chars) {
+                Character boxed = new Character(c);
+                tryAccessor(lookup.findSetter(ValueHolder.class, "m_c", char.class),
+                            valueHolder, PrimitiveType.Char, boxed, AccessorType.IPUT);
+                tryAccessor(lookup.findGetter(ValueHolder.class, "m_c", char.class),
+                            valueHolder, PrimitiveType.Char, boxed, AccessorType.IGET);
+                assertTrue(valueHolder.m_c == c);
+                tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_c", char.class),
+                            valueHolder, PrimitiveType.Char, boxed, AccessorType.SPUT);
+                tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_c", char.class),
+                            valueHolder, PrimitiveType.Char, boxed, AccessorType.SGET);
+                assertTrue(ValueHolder.s_c == c);
+            }
+
+            short [] shorts = { (short)0x1234, (short)0x4321 };
+            for (short s : shorts) {
+                Short boxed = new Short(s);
+                tryAccessor(lookup.findSetter(ValueHolder.class, "m_s", short.class),
+                            valueHolder, PrimitiveType.Short, boxed, AccessorType.IPUT);
+                tryAccessor(lookup.findGetter(ValueHolder.class, "m_s", short.class),
+                            valueHolder, PrimitiveType.Short, boxed, AccessorType.IGET);
+                assertTrue(valueHolder.m_s == s);
+                tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_s", short.class),
+                            valueHolder, PrimitiveType.Short, boxed, AccessorType.SPUT);
+                tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_s", short.class),
+                            valueHolder, PrimitiveType.Short, boxed, AccessorType.SGET);
+                assertTrue(ValueHolder.s_s == s);
+            }
+
+            int [] ints = { -100000000, 10000000 };
+            for (int i : ints) {
+                Integer boxed = new Integer(i);
+                tryAccessor(lookup.findSetter(ValueHolder.class, "m_i", int.class),
+                            valueHolder, PrimitiveType.Int, boxed, AccessorType.IPUT);
+                tryAccessor(lookup.findGetter(ValueHolder.class, "m_i", int.class),
+                            valueHolder, PrimitiveType.Int, boxed, AccessorType.IGET);
+                assertTrue(valueHolder.m_i == i);
+                tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_i", int.class),
+                            valueHolder, PrimitiveType.Int, boxed, AccessorType.SPUT);
+                tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_i", int.class),
+                            valueHolder, PrimitiveType.Int, boxed, AccessorType.SGET);
+                assertTrue(ValueHolder.s_i == i);
+            }
+
+            float [] floats = { 0.99f, -1.23e-17f };
+            for (float f : floats) {
+                Float boxed = new Float(f);
+                tryAccessor(lookup.findSetter(ValueHolder.class, "m_f", float.class),
+                            valueHolder, PrimitiveType.Float, boxed, AccessorType.IPUT);
+                tryAccessor(lookup.findGetter(ValueHolder.class, "m_f", float.class),
+                            valueHolder, PrimitiveType.Float, boxed, AccessorType.IGET);
+                assertTrue(valueHolder.m_f == f);
+                tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_f", float.class),
+                            valueHolder, PrimitiveType.Float, boxed, AccessorType.SPUT);
+                tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_f", float.class),
+                            valueHolder, PrimitiveType.Float, boxed, AccessorType.SGET);
+                assertTrue(ValueHolder.s_f == f);
+            }
+
+            double [] doubles = { 0.44444444444e37, -0.555555555e-37 };
+            for (double d : doubles) {
+                Double boxed = new Double(d);
+                tryAccessor(lookup.findSetter(ValueHolder.class, "m_d", double.class),
+                            valueHolder, PrimitiveType.Double, boxed, AccessorType.IPUT);
+                tryAccessor(lookup.findGetter(ValueHolder.class, "m_d", double.class),
+                            valueHolder, PrimitiveType.Double, boxed, AccessorType.IGET);
+                assertTrue(valueHolder.m_d == d);
+                tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_d", double.class),
+                            valueHolder, PrimitiveType.Double, boxed, AccessorType.SPUT);
+                tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_d", double.class),
+                            valueHolder, PrimitiveType.Double, boxed, AccessorType.SGET);
+                assertTrue(ValueHolder.s_d == d);
+            }
+
+            long [] longs = { 0x0123456789abcdefl, 0xfedcba9876543210l };
+            for (long j : longs) {
+                Long boxed = new Long(j);
+                tryAccessor(lookup.findSetter(ValueHolder.class, "m_j", long.class),
+                            valueHolder, PrimitiveType.Long, boxed, AccessorType.IPUT);
+                tryAccessor(lookup.findGetter(ValueHolder.class, "m_j", long.class),
+                            valueHolder, PrimitiveType.Long, boxed, AccessorType.IGET);
+                assertTrue(valueHolder.m_j == j);
+                tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_j", long.class),
+                            valueHolder, PrimitiveType.Long, boxed, AccessorType.SPUT);
+                tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_j", long.class),
+                            valueHolder, PrimitiveType.Long, boxed, AccessorType.SGET);
+                assertTrue(ValueHolder.s_j == j);
+            }
+
+            String [] strings = { "octopus", "crab" };
+            for (String s : strings) {
+                tryAccessor(lookup.findSetter(ValueHolder.class, "m_l", String.class),
+                            valueHolder, PrimitiveType.String, s, AccessorType.IPUT);
+                tryAccessor(lookup.findGetter(ValueHolder.class, "m_l", String.class),
+                            valueHolder, PrimitiveType.String, s, AccessorType.IGET);
+                assertTrue(s.equals(valueHolder.m_l));
+                tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_l", String.class),
+                            valueHolder, PrimitiveType.String, s, AccessorType.SPUT);
+                tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_l", String.class),
+                            valueHolder, PrimitiveType.String, s, AccessorType.SGET);
+                assertTrue(s.equals(ValueHolder.s_l));
+            }
+
+            System.out.println("Passed MethodHandle.invokeExact() tests for accessors.");
+        }
+    }
+
+    public static class FindAccessorTester extends Tester {
+        public static void main() throws Throwable {
+            // NB having a static field test here is essential for
+            // this test. MethodHandles need to ensure the class
+            // (ValueHolder) is initialized. This happens in the
+            // invoke-polymorphic dispatch.
+            MethodHandles.Lookup lookup = MethodHandles.lookup();
+            try {
+                MethodHandle mh = lookup.findStaticGetter(ValueHolder.class, "s_fi", int.class);
+                int initialValue = (int)mh.invokeExact();
+                System.out.println(initialValue);
+            } catch (NoSuchFieldException e) { unreachable(); }
+            try {
+                MethodHandle mh = lookup.findStaticSetter(ValueHolder.class, "s_i", int.class);
+                mh.invokeExact(0);
+            } catch (NoSuchFieldException e) { unreachable(); }
+            try {
+                lookup.findStaticGetter(ValueHolder.class, "s_fi", byte.class);
+                unreachable();
+            } catch (NoSuchFieldException e) {}
+            try {
+                lookup.findGetter(ValueHolder.class, "s_fi", byte.class);
+                unreachable();
+            } catch (NoSuchFieldException e) {}
+            try {
+                lookup.findStaticSetter(ValueHolder.class, "s_fi", int.class);
+                unreachable();
+            } catch (IllegalAccessException e) {}
+
+            lookup.findGetter(ValueHolder.class, "m_fi", int.class);
+            try {
+                lookup.findGetter(ValueHolder.class, "m_fi", byte.class);
+                unreachable();
+            } catch (NoSuchFieldException e) {}
+            try {
+                lookup.findStaticGetter(ValueHolder.class, "m_fi", byte.class);
+                unreachable();
+            } catch (NoSuchFieldException e) {}
+            try {
+                lookup.findSetter(ValueHolder.class, "m_fi", int.class);
+                unreachable();
+            } catch (IllegalAccessException e) {}
+
+            System.out.println("Passed MethodHandles.Lookup tests for accessors.");
+        }
+    }
+
+    public static class InvokeTester extends Tester {
+        private static void testStaticGetter() throws Throwable {
+            MethodHandles.Lookup lookup = MethodHandles.lookup();
+            MethodHandle h0 = lookup.findStaticGetter(ValueHolder.class, "s_fi", int.class);
+            h0.invoke();
+            Number t = (Number)h0.invoke();
+            int u = (int)h0.invoke();
+            Integer v = (Integer)h0.invoke();
+            long w = (long)h0.invoke();
+            try {
+                byte x = (byte)h0.invoke();
+                unreachable();
+            } catch (WrongMethodTypeException e) {}
+            try {
+                String y = (String)h0.invoke();
+                unreachable();
+            } catch (WrongMethodTypeException e) {}
+            try {
+                Long z = (Long)h0.invoke();
+                unreachable();
+            } catch (WrongMethodTypeException e) {}
+        }
+
+        private static void testMemberGetter() throws Throwable {
+            ValueHolder valueHolder = new ValueHolder();
+            MethodHandles.Lookup lookup = MethodHandles.lookup();
+            MethodHandle h0 = lookup.findGetter(ValueHolder.class, "m_fi", int.class);
+            h0.invoke(valueHolder);
+            Number t = (Number)h0.invoke(valueHolder);
+            int u = (int)h0.invoke(valueHolder);
+            Integer v = (Integer)h0.invoke(valueHolder);
+            long w = (long)h0.invoke(valueHolder);
+            try {
+                byte x = (byte)h0.invoke(valueHolder);
+                unreachable();
+            } catch (WrongMethodTypeException e) {}
+            try {
+                String y = (String)h0.invoke(valueHolder);
+                unreachable();
+            } catch (WrongMethodTypeException e) {}
+            try {
+                Long z = (Long)h0.invoke(valueHolder);
+                unreachable();
+            } catch (WrongMethodTypeException e) {}
+        }
+
+        private static void testMemberSetter() throws Throwable {
+            ValueHolder valueHolder = new ValueHolder();
+            MethodHandles.Lookup lookup = MethodHandles.lookup();
+            MethodHandle h0 = lookup.findSetter(ValueHolder.class, "m_f", float.class);
+            h0.invoke(valueHolder, 0.22f);
+            h0.invoke(valueHolder, new Float(1.11f));
+            Number floatNumber = new Float(0.88f);
+            h0.invoke(valueHolder, floatNumber);
+            assertTrue(valueHolder.m_f == floatNumber.floatValue());
+
+            try {
+              h0.invoke(valueHolder, (Float)null);
+              unreachable();
+            } catch (NullPointerException e) {}
+
+            h0.invoke(valueHolder, (byte)1);
+            h0.invoke(valueHolder, (short)2);
+            h0.invoke(valueHolder, 3);
+            h0.invoke(valueHolder, 4l);
+            try {
+                h0.invoke(valueHolder, 0.33);
+                unreachable();
+            } catch (WrongMethodTypeException e) {}
+            try {
+                Number doubleNumber = new Double(0.89);
+                h0.invoke(valueHolder, doubleNumber);
+                unreachable();
+            } catch (ClassCastException e) {}
+            try {
+                Number doubleNumber = null;
+                h0.invoke(valueHolder, doubleNumber);
+                unreachable();
+            } catch (NullPointerException e) {}
+            try {
+                // Mismatched return type - float != void
+                float tmp = (float)h0.invoke(valueHolder, 0.45f);
+                assertTrue(tmp == 0.0);
+            } catch (Exception e) { unreachable(); }
+            try {
+                h0.invoke(valueHolder, "bam");
+                unreachable();
+            } catch (WrongMethodTypeException e) {}
+            try {
+                String s = null;
+                h0.invoke(valueHolder, s);
+                unreachable();
+            } catch (WrongMethodTypeException e) {}
+        }
+
+        private static void testStaticSetter() throws Throwable {
+            MethodHandles.Lookup lookup = MethodHandles.lookup();
+            MethodHandle h0 = lookup.findStaticSetter(ValueHolder.class, "s_f", float.class);
+            h0.invoke(0.22f);
+            h0.invoke(new Float(1.11f));
+            Number floatNumber = new Float(0.88f);
+            h0.invoke(floatNumber);
+            assertTrue(ValueHolder.s_f == floatNumber.floatValue());
+
+            try {
+              h0.invoke((Float)null);
+              unreachable();
+            } catch (NullPointerException e) {}
+
+            h0.invoke((byte)1);
+            h0.invoke((short)2);
+            h0.invoke(3);
+            h0.invoke(4l);
+            try {
+                h0.invoke(0.33);
+                unreachable();
+            } catch (WrongMethodTypeException e) {}
+            try {
+                Number doubleNumber = new Double(0.89);
+                h0.invoke(doubleNumber);
+                unreachable();
+            } catch (ClassCastException e) {}
+            try {
+                Number doubleNumber = new Double(1.01);
+                doubleNumber = (doubleNumber.doubleValue() != 0.1) ? null : doubleNumber;
+                h0.invoke(doubleNumber);
+                unreachable();
+            } catch (NullPointerException e) {}
+            try {
+                // Mismatched return type - float != void
+                float tmp = (float)h0.invoke(0.45f);
+                assertTrue(tmp == 0.0);
+            } catch (Exception e) { unreachable(); }
+            try {
+                h0.invoke("bam");
+                unreachable();
+            } catch (WrongMethodTypeException e) {}
+            try {
+                String s = null;
+                h0.invoke(s);
+                unreachable();
+            } catch (WrongMethodTypeException e) {}
+        }
+
+        public static void main() throws Throwable{
+            testStaticGetter();
+            testMemberGetter();
+            testStaticSetter();
+            testMemberSetter();
+            System.out.println("Passed MethodHandle.invoke() tests for accessors.");
+        }
+    }
+
+    public static void main(String[] args) throws Throwable {
+        // FindAccessor test should be the first test class in this
+        // file to ensure class initialization test is run.
+        FindAccessorTester.main();
+        InvokeExactTester.main();
+        InvokeTester.main();
+    }
+}