Merge "Speed up DHPublicKeyTest; make DHPrivateKeyTest consistent."
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleAccessorsTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleAccessorsTest.java
new file mode 100644
index 0000000..a9f6802
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleAccessorsTest.java
@@ -0,0 +1,922 @@
+/*
+ * Copyright (C) 2017 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
+ */
+
+package libcore.java.lang.invoke;
+
+import junit.framework.TestCase;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.WrongMethodTypeException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class MethodHandleAccessorsTest extends junit.framework.TestCase {
+    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;
+    }
+
+    private static enum PrimitiveType {
+        Boolean,
+        Byte,
+        Char,
+        Short,
+        Int,
+        Long,
+        Float,
+        Double,
+        String,
+    }
+
+    private static 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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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;
+        }
+        assertEquals(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 void testBooleanSettersAndGetters() 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);
+        }
+    }
+
+    public void testByteSettersAndGetters() throws Throwable {
+        ValueHolder valueHolder = new ValueHolder();
+        MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+        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);
+        }
+    }
+
+    public void testCharSettersAndGetters() throws Throwable {
+        ValueHolder valueHolder = new ValueHolder();
+        MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+        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);
+        }
+    }
+
+    public void testShortSettersAndGetters() throws Throwable {
+        ValueHolder valueHolder = new ValueHolder();
+        MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+        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);
+        }
+    }
+
+    public void testIntSettersAndGetters() throws Throwable {
+        ValueHolder valueHolder = new ValueHolder();
+        MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+        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);
+        }
+    }
+
+    public void testFloatSettersAndGetters() throws Throwable {
+        ValueHolder valueHolder = new ValueHolder();
+        MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+        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);
+        }
+    }
+
+    public void testDoubleSettersAndGetters() throws Throwable {
+        ValueHolder valueHolder = new ValueHolder();
+        MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+        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);
+        }
+    }
+
+    public void testLongSettersAndGetters() throws Throwable {
+        ValueHolder valueHolder = new ValueHolder();
+        MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+        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);
+        }
+    }
+
+    public void testStringSettersAndGetters() throws Throwable {
+        ValueHolder valueHolder = new ValueHolder();
+        MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+        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));
+        }
+    }
+
+    public void testLookup() 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) { fail(); }
+        try {
+            MethodHandle mh = lookup.findStaticSetter(ValueHolder.class, "s_i", int.class);
+            mh.invokeExact(0);
+        } catch (NoSuchFieldException e) { fail(); }
+        try {
+            lookup.findStaticGetter(ValueHolder.class, "s_fi", byte.class);
+            fail();
+        } catch (NoSuchFieldException e) {}
+        try {
+            lookup.findGetter(ValueHolder.class, "s_fi", byte.class);
+            fail();
+        } catch (NoSuchFieldException e) {}
+        try {
+            lookup.findStaticSetter(ValueHolder.class, "s_fi", int.class);
+            fail();
+        } catch (IllegalAccessException e) {}
+
+        lookup.findGetter(ValueHolder.class, "m_fi", int.class);
+        try {
+            lookup.findGetter(ValueHolder.class, "m_fi", byte.class);
+            fail();
+        } catch (NoSuchFieldException e) {}
+        try {
+            lookup.findStaticGetter(ValueHolder.class, "m_fi", byte.class);
+            fail();
+        } catch (NoSuchFieldException e) {}
+        try {
+            lookup.findSetter(ValueHolder.class, "m_fi", int.class);
+            fail();
+        } catch (IllegalAccessException e) {}
+    }
+
+    public 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();
+            fail();
+        } catch (WrongMethodTypeException e) {}
+        try {
+            String y = (String)h0.invoke();
+            fail();
+        } catch (WrongMethodTypeException e) {}
+        try {
+            Long z = (Long)h0.invoke();
+            fail();
+        } catch (WrongMethodTypeException e) {}
+    }
+
+    public 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);
+            fail();
+        } catch (WrongMethodTypeException e) {}
+        try {
+            String y = (String)h0.invoke(valueHolder);
+            fail();
+        } catch (WrongMethodTypeException e) {}
+        try {
+            Long z = (Long)h0.invoke(valueHolder);
+            fail();
+        } catch (WrongMethodTypeException e) {}
+    }
+
+    /*package*/ static Number getDoubleAsNumber() {
+        return new Double(1.4e77);
+    }
+    /*package*/ static Number getFloatAsNumber() {
+        return new Float(7.77);
+    }
+    /*package*/ static Object getFloatAsObject() {
+        return new Float(-7.77);
+    }
+
+    public 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 = getFloatAsNumber();
+        h0.invoke(valueHolder, floatNumber);
+        assertTrue(valueHolder.m_f == floatNumber.floatValue());
+        Object objNumber = getFloatAsObject();
+        h0.invoke(valueHolder, objNumber);
+        assertTrue(valueHolder.m_f == ((Float) objNumber).floatValue());
+        try {
+            h0.invoke(valueHolder, (Float)null);
+            fail();
+        } catch (NullPointerException e) {}
+
+        h0.invoke(valueHolder, (byte)1);
+        h0.invoke(valueHolder, (short)2);
+        h0.invoke(valueHolder, 3);
+        h0.invoke(valueHolder, 4l);
+
+        assertTrue(null == (Object) h0.invoke(valueHolder, 33));
+        assertTrue(0.0f == (float) h0.invoke(valueHolder, 33));
+        assertTrue(0l == (long) h0.invoke(valueHolder, 33));
+
+        try {
+            h0.invoke(valueHolder, 0.33);
+            fail();
+        } catch (WrongMethodTypeException e) {}
+        try {
+            Number doubleNumber = getDoubleAsNumber();
+            h0.invoke(valueHolder, doubleNumber);
+            fail();
+        } catch (ClassCastException e) {}
+        try {
+            Number doubleNumber = null;
+            h0.invoke(valueHolder, doubleNumber);
+            fail();
+        } catch (NullPointerException e) {}
+        try {
+            // Mismatched return type - float != void
+            float tmp = (float)h0.invoke(valueHolder, 0.45f);
+            assertTrue(tmp == 0.0);
+        } catch (Exception e) { fail(); }
+        try {
+            h0.invoke(valueHolder, "bam");
+            fail();
+        } catch (WrongMethodTypeException e) {}
+        try {
+            String s = null;
+            h0.invoke(valueHolder, s);
+            fail();
+        } catch (WrongMethodTypeException e) {}
+    }
+
+    public 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);
+            fail();
+        } catch (NullPointerException e) {}
+
+        h0.invoke((byte)1);
+        h0.invoke((short)2);
+        h0.invoke(3);
+        h0.invoke(4l);
+
+        assertTrue(null == (Object) h0.invoke(33));
+        assertTrue(0.0f == (float) h0.invoke(33));
+        assertTrue(0l == (long) h0.invoke(33));
+
+        try {
+            h0.invoke(0.33);
+            fail();
+        } catch (WrongMethodTypeException e) {}
+        try {
+            Number doubleNumber = getDoubleAsNumber();
+            h0.invoke(doubleNumber);
+            fail();
+        } catch (ClassCastException e) {}
+        try {
+            Number doubleNumber = new Double(1.01);
+            doubleNumber = (doubleNumber.doubleValue() != 0.1) ? null : doubleNumber;
+            h0.invoke(doubleNumber);
+            fail();
+        } catch (NullPointerException e) {}
+        try {
+            // Mismatched return type - float != void
+            float tmp = (float)h0.invoke(0.45f);
+            assertTrue(tmp == 0.0);
+        } catch (Exception e) { fail(); }
+        try {
+            h0.invoke("bam");
+            fail();
+        } catch (WrongMethodTypeException e) {}
+        try {
+            String s = null;
+            h0.invoke(s);
+            fail();
+        } catch (WrongMethodTypeException e) {}
+    }
+}
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
new file mode 100644
index 0000000..4c65161
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
@@ -0,0 +1,1636 @@
+/*
+ * Copyright (C) 2017 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
+ */
+
+package libcore.java.lang.invoke;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.WrongMethodTypeException;
+import java.util.ArrayList;
+
+import junit.framework.TestCase;
+
+public class MethodHandleCombinersTest extends TestCase {
+
+    public static void testThrowException() throws Throwable {
+        MethodHandle handle = MethodHandles.throwException(String.class,
+                IllegalArgumentException.class);
+
+        if (handle.type().returnType() != String.class) {
+            fail("Unexpected return type for handle: " + handle +
+                    " [ " + handle.type() + "]");
+        }
+
+        final IllegalArgumentException iae = new IllegalArgumentException("boo!");
+        try {
+            handle.invoke(iae);
+            fail("Expected an exception of type: java.lang.IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            if (expected != iae) {
+                fail("Wrong exception: expected " + iae + " but was " + expected);
+            }
+        }
+    }
+
+    public static void dropArguments_delegate(String message, long message2) {
+        assertEquals("foo", message);
+        assertEquals(42l, message2);
+    }
+
+    public static void testDropArguments() throws Throwable {
+        MethodHandle delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                "dropArguments_delegate",
+                MethodType.methodType(void.class, new Class<?>[]{String.class, long.class}));
+
+        MethodHandle transform = MethodHandles.dropArguments(
+                delegate, 0, int.class, Object.class);
+
+        // The transformer will accept two additional arguments at position zero.
+        try {
+            transform.invokeExact("foo", 42l);
+            fail();
+        } catch (WrongMethodTypeException expected) {
+        }
+
+        transform.invokeExact(45, new Object(), "foo", 42l);
+        transform.invoke(45, new Object(), "foo", 42l);
+
+        // Additional arguments at position 1.
+        transform = MethodHandles.dropArguments(delegate, 1, int.class, Object.class);
+        transform.invokeExact("foo", 45, new Object(), 42l);
+        transform.invoke("foo", 45, new Object(), 42l);
+
+        // Additional arguments at position 2.
+        transform = MethodHandles.dropArguments(delegate, 2, int.class, Object.class);
+        transform.invokeExact("foo", 42l, 45, new Object());
+        transform.invoke("foo", 42l, 45, new Object());
+
+        // Note that we still perform argument conversions even for the arguments that
+        // are subsequently dropped.
+        try {
+            transform.invoke("foo", 42l, 45l, new Object());
+            fail();
+        } catch (WrongMethodTypeException expected) {
+        } catch (IllegalArgumentException expected) {
+            // TODO(narayan): We currently throw the wrong type of exception here,
+            // it's IAE and should be WMTE instead.
+        }
+
+        // Check that asType works as expected.
+        transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class);
+        transform = transform.asType(MethodType.methodType(void.class,
+                new Class<?>[]{short.class, Object.class, String.class, long.class}));
+        transform.invokeExact((short) 45, new Object(), "foo", 42l);
+
+        // Invalid argument location, should not be allowed.
+        try {
+            MethodHandles.dropArguments(delegate, -1, int.class, Object.class);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        // Invalid argument location, should not be allowed.
+        try {
+            MethodHandles.dropArguments(delegate, 3, int.class, Object.class);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        try {
+            MethodHandles.dropArguments(delegate, 1, void.class);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    public static String testCatchException_target(String arg1, long arg2, String exceptionMessage)
+            throws Throwable {
+        if (exceptionMessage != null) {
+            throw new IllegalArgumentException(exceptionMessage);
+        }
+
+        assertEquals(null, exceptionMessage);
+        assertEquals(42l, arg2);
+        return "target";
+    }
+
+    public static String testCatchException_handler(IllegalArgumentException iae, String arg1,
+                                                    long arg2,
+                                                    String exMsg) {
+        // Check that the thrown exception has the right message.
+        assertEquals("exceptionMessage", iae.getMessage());
+        // Check the other arguments.
+        assertEquals("foo", arg1);
+        assertEquals(42, arg2);
+        assertEquals("exceptionMessage", exMsg);
+
+        return "handler1";
+    }
+
+    public static String testCatchException_handler2(IllegalArgumentException iae, String arg1) {
+        assertEquals("exceptionMessage", iae.getMessage());
+        assertEquals("foo", arg1);
+
+        return "handler2";
+    }
+
+    public static void testCatchException() throws Throwable {
+        MethodHandle target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                "testCatchException_target",
+                MethodType
+                        .methodType(String.class, new Class<?>[]{String.class, long.class, String.class}));
+
+        MethodHandle handler = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                "testCatchException_handler",
+                MethodType.methodType(String.class, new Class<?>[]{IllegalArgumentException.class,
+                        String.class, long.class, String.class}));
+
+        MethodHandle adapter = MethodHandles.catchException(target, IllegalArgumentException.class,
+                handler);
+
+        String returnVal = null;
+
+        // These two should end up calling the target always. We're passing a null exception
+        // message here, which means the target will not throw.
+        returnVal = (String) adapter.invoke("foo", 42, null);
+        assertEquals("target", returnVal);
+        returnVal = (String) adapter.invokeExact("foo", 42l, (String) null);
+        assertEquals("target", returnVal);
+
+        // We're passing a non-null exception message here, which means the target will throw,
+        // which in turn means that the handler must be called for the next two invokes.
+        returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
+        assertEquals("handler1", returnVal);
+        returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
+        assertEquals("handler1", returnVal);
+
+        handler = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                "testCatchException_handler2",
+                MethodType.methodType(String.class, new Class<?>[]{IllegalArgumentException.class,
+                        String.class}));
+        adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
+
+        returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
+        assertEquals("handler2", returnVal);
+        returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
+        assertEquals("handler2", returnVal);
+
+        // Test that the type of the invoke doesn't matter. Here we call
+        // IllegalArgumentException.toString() on the exception that was thrown by
+        // the target.
+        handler = MethodHandles.lookup().findVirtual(IllegalArgumentException.class,
+                "toString", MethodType.methodType(String.class));
+        adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
+
+        returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
+        assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
+        returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
+        assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
+
+        // Check that asType works as expected.
+        adapter = MethodHandles.catchException(target, IllegalArgumentException.class,
+                handler);
+        adapter = adapter.asType(MethodType.methodType(String.class,
+                new Class<?>[]{String.class, int.class, String.class}));
+        returnVal = (String) adapter.invokeExact("foo", 42, "exceptionMessage");
+        assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
+    }
+
+    public static boolean testGuardWithTest_test(String arg1, long arg2) {
+        return "target".equals(arg1) && 42 == arg2;
+    }
+
+    public static String testGuardWithTest_target(String arg1, long arg2, int arg3) {
+        // Make sure that the test passed.
+        assertTrue(testGuardWithTest_test(arg1, arg2));
+        // Make sure remaining arguments were passed through unmodified.
+        assertEquals(56, arg3);
+
+        return "target";
+    }
+
+    public static String testGuardWithTest_fallback(String arg1, long arg2, int arg3) {
+        // Make sure that the test failed.
+        assertTrue(!testGuardWithTest_test(arg1, arg2));
+        // Make sure remaining arguments were passed through unmodified.
+        assertEquals(56, arg3);
+
+        return "fallback";
+    }
+
+    public static void testGuardWithTest() throws Throwable {
+        MethodHandle test = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                "testGuardWithTest_test",
+                MethodType.methodType(boolean.class, new Class<?>[]{String.class, long.class}));
+
+        final MethodType type = MethodType.methodType(String.class,
+                new Class<?>[]{String.class, long.class, int.class});
+
+        final MethodHandle target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                "testGuardWithTest_target", type);
+        final MethodHandle fallback = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                "testGuardWithTest_fallback", type);
+
+        MethodHandle adapter = MethodHandles.guardWithTest(test, target, fallback);
+
+        String returnVal = null;
+
+        returnVal = (String) adapter.invoke("target", 42, 56);
+        assertEquals("target", returnVal);
+        returnVal = (String) adapter.invokeExact("target", 42l, 56);
+        assertEquals("target", returnVal);
+
+        returnVal = (String) adapter.invoke("fallback", 42l, 56);
+        assertEquals("fallback", returnVal);
+        returnVal = (String) adapter.invoke("target", 46l, 56);
+        assertEquals("fallback", returnVal);
+        returnVal = (String) adapter.invokeExact("target", 42l, 56);
+        assertEquals("target", returnVal);
+
+        // Check that asType works as expected.
+        adapter = adapter.asType(MethodType.methodType(String.class,
+                new Class<?>[]{String.class, int.class, int.class}));
+        returnVal = (String) adapter.invokeExact("target", 42, 56);
+        assertEquals("target", returnVal);
+    }
+
+    public static void testArrayElementGetter() throws Throwable {
+        MethodHandle getter = MethodHandles.arrayElementGetter(int[].class);
+
+        {
+            int[] array = new int[1];
+            array[0] = 42;
+            int value = (int) getter.invoke(array, 0);
+            assertEquals(42, value);
+
+            try {
+                value = (int) getter.invoke(array, -1);
+                fail();
+            } catch (ArrayIndexOutOfBoundsException expected) {
+            }
+
+            try {
+                value = (int) getter.invoke(null, -1);
+                fail();
+            } catch (NullPointerException expected) {
+            }
+        }
+
+        {
+            getter = MethodHandles.arrayElementGetter(long[].class);
+            long[] array = new long[1];
+            array[0] = 42;
+            long value = (long) getter.invoke(array, 0);
+            assertEquals(42l, value);
+        }
+
+        {
+            getter = MethodHandles.arrayElementGetter(short[].class);
+            short[] array = new short[1];
+            array[0] = 42;
+            short value = (short) getter.invoke(array, 0);
+            assertEquals((short) 42, value);
+        }
+
+        {
+            getter = MethodHandles.arrayElementGetter(char[].class);
+            char[] array = new char[1];
+            array[0] = 42;
+            char value = (char) getter.invoke(array, 0);
+            assertEquals((char) 42, value);
+        }
+
+        {
+            getter = MethodHandles.arrayElementGetter(byte[].class);
+            byte[] array = new byte[1];
+            array[0] = (byte) 0x8;
+            byte value = (byte) getter.invoke(array, 0);
+            assertEquals((byte) 0x8, value);
+        }
+
+        {
+            getter = MethodHandles.arrayElementGetter(boolean[].class);
+            boolean[] array = new boolean[1];
+            array[0] = true;
+            boolean value = (boolean) getter.invoke(array, 0);
+            assertTrue(value);
+        }
+
+        {
+            getter = MethodHandles.arrayElementGetter(float[].class);
+            float[] array = new float[1];
+            array[0] = 42.0f;
+            float value = (float) getter.invoke(array, 0);
+            assertEquals(42.0f, value);
+        }
+
+        {
+            getter = MethodHandles.arrayElementGetter(double[].class);
+            double[] array = new double[1];
+            array[0] = 42.0;
+            double value = (double) getter.invoke(array, 0);
+            assertEquals(42.0, value);
+        }
+
+        {
+            getter = MethodHandles.arrayElementGetter(String[].class);
+            String[] array = new String[3];
+            array[0] = "42";
+            array[1] = "48";
+            array[2] = "54";
+            String value = (String) getter.invoke(array, 0);
+            assertEquals("42", value);
+            value = (String) getter.invoke(array, 1);
+            assertEquals("48", value);
+            value = (String) getter.invoke(array, 2);
+            assertEquals("54", value);
+        }
+    }
+
+    public static void testArrayElementSetter() throws Throwable {
+        MethodHandle setter = MethodHandles.arrayElementSetter(int[].class);
+
+        {
+            int[] array = new int[2];
+            setter.invoke(array, 0, 42);
+            setter.invoke(array, 1, 43);
+
+            assertEquals(42, array[0]);
+            assertEquals(43, array[1]);
+
+            try {
+                setter.invoke(array, -1, 42);
+                fail();
+            } catch (ArrayIndexOutOfBoundsException expected) {
+            }
+
+            try {
+                setter.invoke(null, 0, 42);
+                fail();
+            } catch (NullPointerException expected) {
+            }
+        }
+
+        {
+            setter = MethodHandles.arrayElementSetter(long[].class);
+            long[] array = new long[1];
+            setter.invoke(array, 0, 42l);
+            assertEquals(42l, array[0]);
+        }
+
+        {
+            setter = MethodHandles.arrayElementSetter(short[].class);
+            short[] array = new short[1];
+            setter.invoke(array, 0, (short) 42);
+            assertEquals((short) 42, array[0]);
+        }
+
+        {
+            setter = MethodHandles.arrayElementSetter(char[].class);
+            char[] array = new char[1];
+            setter.invoke(array, 0, (char) 42);
+            assertEquals((char) 42, array[0]);
+        }
+
+        {
+            setter = MethodHandles.arrayElementSetter(byte[].class);
+            byte[] array = new byte[1];
+            setter.invoke(array, 0, (byte) 0x8);
+            assertEquals((byte) 0x8, array[0]);
+        }
+
+        {
+            setter = MethodHandles.arrayElementSetter(boolean[].class);
+            boolean[] array = new boolean[1];
+            setter.invoke(array, 0, true);
+            assertTrue(array[0]);
+        }
+
+        {
+            setter = MethodHandles.arrayElementSetter(float[].class);
+            float[] array = new float[1];
+            setter.invoke(array, 0, 42.0f);
+            assertEquals(42.0f, array[0]);
+        }
+
+        {
+            setter = MethodHandles.arrayElementSetter(double[].class);
+            double[] array = new double[1];
+            setter.invoke(array, 0, 42.0);
+            assertEquals(42.0, array[0]);
+        }
+
+        {
+            setter = MethodHandles.arrayElementSetter(String[].class);
+            String[] array = new String[3];
+            setter.invoke(array, 0, "42");
+            setter.invoke(array, 1, "48");
+            setter.invoke(array, 2, "54");
+            assertEquals("42", array[0]);
+            assertEquals("48", array[1]);
+            assertEquals("54", array[2]);
+        }
+    }
+
+    public static void testIdentity() throws Throwable {
+        {
+            MethodHandle identity = MethodHandles.identity(boolean.class);
+            boolean value = (boolean) identity.invoke(false);
+            assertFalse(value);
+        }
+
+        {
+            MethodHandle identity = MethodHandles.identity(byte.class);
+            byte value = (byte) identity.invoke((byte) 0x8);
+            assertEquals((byte) 0x8, value);
+        }
+
+        {
+            MethodHandle identity = MethodHandles.identity(char.class);
+            char value = (char) identity.invoke((char) -56);
+            assertEquals((char) -56, value);
+        }
+
+        {
+            MethodHandle identity = MethodHandles.identity(short.class);
+            short value = (short) identity.invoke((short) -59);
+            assertEquals((short) -59, value);
+        }
+
+        {
+            MethodHandle identity = MethodHandles.identity(int.class);
+            int value = (int) identity.invoke(52);
+            assertEquals((int) 52, value);
+        }
+
+        {
+            MethodHandle identity = MethodHandles.identity(long.class);
+            long value = (long) identity.invoke(-76l);
+            assertEquals(-76l, value);
+        }
+
+        {
+            MethodHandle identity = MethodHandles.identity(float.class);
+            float value = (float) identity.invoke(56.0f);
+            assertEquals(56.0f, value);
+        }
+
+        {
+            MethodHandle identity = MethodHandles.identity(double.class);
+            double value = (double) identity.invoke((double) 72.0);
+            assertEquals(72.0, value);
+        }
+
+        {
+            MethodHandle identity = MethodHandles.identity(String.class);
+            String value = (String) identity.invoke("bazman");
+            assertEquals("bazman", value);
+        }
+    }
+
+    public static void testConstant() throws Throwable {
+        // int constants.
+        {
+            MethodHandle constant = MethodHandles.constant(int.class, 56);
+            assertEquals(56, (int) constant.invoke());
+
+            // short constant values are converted to int.
+            constant = MethodHandles.constant(int.class, (short) 52);
+            assertEquals(52, (int) constant.invoke());
+
+            // char constant values are converted to int.
+            constant = MethodHandles.constant(int.class, (char) 'b');
+            assertEquals('b', (int) constant.invoke());
+
+            // int constant values are converted to int.
+            constant = MethodHandles.constant(int.class, (byte) 0x1);
+            assertEquals(0x1, (int) constant.invoke());
+
+            // boolean, float, double and long primitive constants are not convertible
+            // to int, so the handle creation must fail with a CCE.
+            try {
+                MethodHandles.constant(int.class, false);
+                fail();
+            } catch (ClassCastException expected) {
+            }
+
+            try {
+                MethodHandles.constant(int.class, 0.1f);
+                fail();
+            } catch (ClassCastException expected) {
+            }
+
+            try {
+                MethodHandles.constant(int.class, 0.2);
+                fail();
+            } catch (ClassCastException expected) {
+            }
+
+            try {
+                MethodHandles.constant(int.class, 73l);
+                fail();
+            } catch (ClassCastException expected) {
+            }
+        }
+
+        // long constants.
+        {
+            MethodHandle constant = MethodHandles.constant(long.class, 56l);
+            assertEquals(56l, (long) constant.invoke());
+
+            constant = MethodHandles.constant(long.class, (int) 56);
+            assertEquals(56l, (long) constant.invoke());
+        }
+
+        // byte constants.
+        {
+            MethodHandle constant = MethodHandles.constant(byte.class, (byte) 0x12);
+            assertEquals((byte) 0x12, (byte) constant.invoke());
+        }
+
+        // boolean constants.
+        {
+            MethodHandle constant = MethodHandles.constant(boolean.class, true);
+            assertTrue((boolean) constant.invoke());
+        }
+
+        // char constants.
+        {
+            MethodHandle constant = MethodHandles.constant(char.class, 'f');
+            assertEquals('f', (char) constant.invoke());
+        }
+
+        // short constants.
+        {
+            MethodHandle constant = MethodHandles.constant(short.class, (short) 123);
+            assertEquals((short) 123, (short) constant.invoke());
+        }
+
+        // float constants.
+        {
+            MethodHandle constant = MethodHandles.constant(float.class, 56.0f);
+            assertEquals(56.0f, (float) constant.invoke());
+        }
+
+        // double constants.
+        {
+            MethodHandle constant = MethodHandles.constant(double.class, 256.0);
+            assertEquals(256.0, (double) constant.invoke());
+        }
+
+        // reference constants.
+        {
+            MethodHandle constant = MethodHandles.constant(String.class, "256.0");
+            assertEquals("256.0", (String) constant.invoke());
+        }
+    }
+
+    public static void testBindTo() throws Throwable {
+        MethodHandle stringCharAt = MethodHandles.lookup().findVirtual(
+                String.class, "charAt", MethodType.methodType(char.class, int.class));
+
+        char value = (char) stringCharAt.invoke("foo", 0);
+        if (value != 'f') {
+            fail("Unexpected value: " + value);
+        }
+
+        MethodHandle bound = stringCharAt.bindTo("foo");
+        value = (char) bound.invoke(0);
+        if (value != 'f') {
+            fail("Unexpected value: " + value);
+        }
+
+        try {
+            stringCharAt.bindTo(new Object());
+            fail();
+        } catch (ClassCastException expected) {
+        }
+
+        bound = stringCharAt.bindTo(null);
+        try {
+            bound.invoke(0);
+            fail();
+        } catch (NullPointerException expected) {
+        }
+
+        MethodHandle integerParseInt = MethodHandles.lookup().findStatic(
+                Integer.class, "parseInt", MethodType.methodType(int.class, String.class));
+
+        bound = integerParseInt.bindTo("78452");
+        int intValue = (int) bound.invoke();
+        if (intValue != 78452) {
+            fail("Unexpected value: " + intValue);
+        }
+    }
+
+    public static String filterReturnValue_target(int a) {
+        return "ReturnValue" + a;
+    }
+
+    public static boolean filterReturnValue_filter(String value) {
+        return value.indexOf("42") != -1;
+    }
+
+    public static int filterReturnValue_intTarget(String a) {
+        return Integer.parseInt(a);
+    }
+
+    public static int filterReturnValue_intFilter(int b) {
+        return b + 1;
+    }
+
+    public static void filterReturnValue_voidTarget() {
+    }
+
+    public static int filterReturnValue_voidFilter() {
+        return 42;
+    }
+
+    public static void testFilterReturnValue() throws Throwable {
+        // A target that returns a reference.
+        {
+            final MethodHandle target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                    "filterReturnValue_target", MethodType.methodType(String.class, int.class));
+            final MethodHandle filter = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                    "filterReturnValue_filter", MethodType.methodType(boolean.class, String.class));
+
+            MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
+
+            boolean value = (boolean) adapter.invoke((int) 42);
+            if (!value) {
+                fail("Unexpected value: " + value);
+            }
+            value = (boolean) adapter.invoke((int) 43);
+            if (value) {
+                fail("Unexpected value: " + value);
+            }
+        }
+
+        // A target that returns a primitive.
+        {
+            final MethodHandle target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                    "filterReturnValue_intTarget", MethodType.methodType(int.class, String.class));
+            final MethodHandle filter = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                    "filterReturnValue_intFilter", MethodType.methodType(int.class, int.class));
+
+            MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
+
+            int value = (int) adapter.invoke("56");
+            if (value != 57) {
+                fail("Unexpected value: " + value);
+            }
+        }
+
+        // A target that returns void.
+        {
+            final MethodHandle target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                    "filterReturnValue_voidTarget", MethodType.methodType(void.class));
+            final MethodHandle filter = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                    "filterReturnValue_voidFilter", MethodType.methodType(int.class));
+
+            MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
+
+            int value = (int) adapter.invoke();
+            if (value != 42) {
+                fail("Unexpected value: " + value);
+            }
+        }
+    }
+
+    public static void permuteArguments_callee(boolean a, byte b, char c,
+                                               short d, int e, long f, float g, double h) {
+        assertTrue(a);
+        assertEquals((byte) 'b', b);
+        assertEquals('c', c);
+        assertEquals((short) 56, d);
+        assertEquals(78, e);
+        assertEquals(97l, f);
+        assertEquals(98.0f, g);
+        assertEquals(97.0, h);
+    }
+
+    public static void permuteArguments_boxingCallee(boolean a, Integer b) {
+        assertTrue(a);
+        assertEquals(Integer.valueOf(42), b);
+    }
+
+    public static void testPermuteArguments() throws Throwable {
+        {
+            final MethodHandle target = MethodHandles.lookup().findStatic(
+                    MethodHandleCombinersTest.class, "permuteArguments_callee",
+                    MethodType.methodType(void.class, new Class<?>[]{
+                            boolean.class, byte.class, char.class, short.class, int.class,
+                            long.class, float.class, double.class}));
+
+            final MethodType newType = MethodType.methodType(void.class, new Class<?>[]{
+                    double.class, float.class, long.class, int.class, short.class, char.class,
+                    byte.class, boolean.class});
+
+            final MethodHandle permutation = MethodHandles.permuteArguments(
+                    target, newType, new int[]{7, 6, 5, 4, 3, 2, 1, 0});
+
+            permutation.invoke((double) 97.0, (float) 98.0f, (long) 97, 78,
+                    (short) 56, 'c', (byte) 'b', (boolean) true);
+
+            // The permutation array was not of the right length.
+            try {
+                MethodHandles.permuteArguments(target, newType,
+                        new int[]{7});
+                fail();
+            } catch (IllegalArgumentException expected) {
+            }
+
+            // The permutation array has an element that's out of bounds
+            // (there's no argument with idx == 8).
+            try {
+                MethodHandles.permuteArguments(target, newType,
+                        new int[]{8, 6, 5, 4, 3, 2, 1, 0});
+                fail();
+            } catch (IllegalArgumentException expected) {
+            }
+
+            // The permutation array maps to an incorrect type.
+            try {
+                MethodHandles.permuteArguments(target, newType,
+                        new int[]{7, 7, 5, 4, 3, 2, 1, 0});
+                fail();
+            } catch (IllegalArgumentException expected) {
+            }
+        }
+
+        // Tests for reference arguments as well as permutations that
+        // repeat arguments.
+        {
+            final MethodHandle target = MethodHandles.lookup().findVirtual(
+                    String.class, "concat", MethodType.methodType(String.class, String.class));
+
+            final MethodType newType = MethodType.methodType(String.class, String.class,
+                    String.class);
+
+            assertEquals("foobar", (String) target.invoke("foo", "bar"));
+
+            MethodHandle permutation = MethodHandles.permuteArguments(target,
+                    newType, new int[]{1, 0});
+            assertEquals("barfoo", (String) permutation.invoke("foo", "bar"));
+
+            permutation = MethodHandles.permuteArguments(target, newType, new int[]{0, 0});
+            assertEquals("foofoo", (String) permutation.invoke("foo", "bar"));
+
+            permutation = MethodHandles.permuteArguments(target, newType, new int[]{1, 1});
+            assertEquals("barbar", (String) permutation.invoke("foo", "bar"));
+        }
+
+        // Tests for boxing and unboxing.
+        {
+            final MethodHandle target = MethodHandles.lookup().findStatic(
+                    MethodHandleCombinersTest.class, "permuteArguments_boxingCallee",
+                    MethodType.methodType(void.class, new Class<?>[]{boolean.class, Integer.class}));
+
+            final MethodType newType = MethodType.methodType(void.class,
+                    new Class<?>[]{Integer.class, boolean.class});
+
+            MethodHandle permutation = MethodHandles.permuteArguments(target,
+                    newType, new int[]{1, 0});
+
+            permutation.invoke(42, true);
+            permutation.invoke(42, Boolean.TRUE);
+            permutation.invoke(Integer.valueOf(42), true);
+            permutation.invoke(Integer.valueOf(42), Boolean.TRUE);
+        }
+    }
+
+    private static Object returnBar() {
+        return "bar";
+    }
+
+    public static void testInvokers() throws Throwable {
+        final MethodType targetType = MethodType.methodType(String.class, String.class);
+        final MethodHandle target = MethodHandles.lookup().findVirtual(
+                String.class, "concat", targetType);
+
+        MethodHandle invoker = MethodHandles.invoker(target.type());
+        assertEquals("barbar", (String) invoker.invoke(target, "bar", "bar"));
+        assertEquals("barbar", (String) invoker.invoke(target, (Object) returnBar(), "bar"));
+        try {
+            String foo = (String) invoker.invoke(target, "bar", "bar", 24);
+            fail();
+        } catch (WrongMethodTypeException expected) {
+        }
+
+        MethodHandle exactInvoker = MethodHandles.exactInvoker(target.type());
+        assertEquals("barbar", (String) exactInvoker.invoke(target, "bar", "bar"));
+        try {
+            String foo = (String) exactInvoker.invoke(target, (Object) returnBar(), "bar");
+            fail();
+        } catch (WrongMethodTypeException expected) {
+        }
+        try {
+            String foo = (String) exactInvoker.invoke(target, "bar", "bar", 24);
+            fail();
+        } catch (WrongMethodTypeException expected) {
+        }
+    }
+
+    public static int spreadReferences(String a, String b, String c) {
+        assertEquals("a", a);
+        assertEquals("b", b);
+        assertEquals("c", c);
+        return 42;
+    }
+
+    public static int spreadReferences_Unbox(String a, int b) {
+        assertEquals("a", a);
+        assertEquals(43, b);
+        return 43;
+    }
+
+    public static void testSpreaders_reference() throws Throwable {
+        MethodType methodType = MethodType.methodType(int.class,
+                new Class<?>[]{String.class, String.class, String.class});
+        MethodHandle delegate = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "spreadReferences", methodType);
+
+        // Basic checks on array lengths.
+        //
+        // Array size = 0
+        MethodHandle mhAsSpreader = delegate.asSpreader(String[].class, 0);
+        int ret = (int) mhAsSpreader.invoke("a", "b", "c", new String[]{});
+        assertEquals(42, ret);
+        // Array size = 1
+        mhAsSpreader = delegate.asSpreader(String[].class, 1);
+        ret = (int) mhAsSpreader.invoke("a", "b", new String[]{"c"});
+        assertEquals(42, ret);
+        // Array size = 2
+        mhAsSpreader = delegate.asSpreader(String[].class, 2);
+        ret = (int) mhAsSpreader.invoke("a", new String[]{"b", "c"});
+        assertEquals(42, ret);
+        // Array size = 3
+        mhAsSpreader = delegate.asSpreader(String[].class, 3);
+        ret = (int) mhAsSpreader.invoke(new String[]{"a", "b", "c"});
+        assertEquals(42, ret);
+
+        // Exception case, array size = 4 is illegal.
+        try {
+            delegate.asSpreader(String[].class, 4);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        // Exception case, calling with an arg of the wrong size.
+        // Array size = 3
+        mhAsSpreader = delegate.asSpreader(String[].class, 3);
+        try {
+            ret = (int) mhAsSpreader.invoke(new String[]{"a", "b"});
+        } catch (IllegalArgumentException expected) {
+        }
+
+        // Various other hijinks, pass as Object[] arrays, Object etc.
+        mhAsSpreader = delegate.asSpreader(Object[].class, 2);
+        ret = (int) mhAsSpreader.invoke("a", new String[]{"b", "c"});
+        assertEquals(42, ret);
+
+        mhAsSpreader = delegate.asSpreader(Object[].class, 2);
+        ret = (int) mhAsSpreader.invoke("a", new Object[]{"b", "c"});
+        assertEquals(42, ret);
+
+        mhAsSpreader = delegate.asSpreader(Object[].class, 2);
+        ret = (int) mhAsSpreader.invoke("a", (Object) new Object[]{"b", "c"});
+        assertEquals(42, ret);
+
+        // Test implicit unboxing.
+        MethodType methodType2 = MethodType.methodType(int.class,
+                new Class<?>[]{String.class, int.class});
+        MethodHandle delegate2 = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "spreadReferences_Unbox", methodType2);
+
+        // .. with an Integer[] array.
+        mhAsSpreader = delegate2.asSpreader(Integer[].class, 1);
+        ret = (int) mhAsSpreader.invoke("a", new Integer[]{43});
+        assertEquals(43, ret);
+
+        // .. with an Integer[] array declared as an Object[] argument type.
+        mhAsSpreader = delegate2.asSpreader(Object[].class, 1);
+        ret = (int) mhAsSpreader.invoke("a", new Integer[]{43});
+        assertEquals(43, ret);
+
+        // .. with an Object[] array.
+        mhAsSpreader = delegate2.asSpreader(Object[].class, 1);
+        ret = (int) mhAsSpreader.invoke("a", new Object[]{Integer.valueOf(43)});
+        assertEquals(43, ret);
+
+        // -- Part 2--
+        // Run a subset of these tests on MethodHandles.spreadInvoker, which only accepts
+        // a trailing argument type of Object[].
+        MethodHandle spreadInvoker = MethodHandles.spreadInvoker(methodType2, 1);
+        ret = (int) spreadInvoker.invoke(delegate2, "a", new Object[]{Integer.valueOf(43)});
+        assertEquals(43, ret);
+
+        ret = (int) spreadInvoker.invoke(delegate2, "a", new Integer[]{43});
+        assertEquals(43, ret);
+
+        // NOTE: Annoyingly, the second argument here is leadingArgCount and not
+        // arrayLength.
+        spreadInvoker = MethodHandles.spreadInvoker(methodType, 3);
+        ret = (int) spreadInvoker.invoke(delegate, "a", "b", "c", new String[]{});
+        assertEquals(42, ret);
+
+        spreadInvoker = MethodHandles.spreadInvoker(methodType, 0);
+        ret = (int) spreadInvoker.invoke(delegate, new String[]{"a", "b", "c"});
+        assertEquals(42, ret);
+
+        // Exact invokes: Double check that the expected parameter type is
+        // Object[] and not T[].
+        try {
+            spreadInvoker.invokeExact(delegate, new String[]{"a", "b", "c"});
+            fail();
+        } catch (WrongMethodTypeException expected) {
+        }
+
+        ret = (int) spreadInvoker.invoke(delegate, new Object[]{"a", "b", "c"});
+        assertEquals(42, ret);
+    }
+
+    public static int spreadBoolean(String a, Boolean b, boolean c) {
+        assertEquals("a", a);
+        assertSame(Boolean.TRUE, b);
+        assertFalse(c);
+
+        return 44;
+    }
+
+    public static int spreadByte(String a, Byte b, byte c,
+                                 short d, int e, long f, float g, double h) {
+        assertEquals("a", a);
+        assertEquals(Byte.valueOf((byte) 1), b);
+        assertEquals((byte) 2, c);
+        assertEquals((short) 3, d);
+        assertEquals(4, e);
+        assertEquals(5l, f);
+        assertEquals(6.0f, g);
+        assertEquals(7.0, h);
+
+        return 45;
+    }
+
+    public static int spreadChar(String a, Character b, char c,
+                                 int d, long e, float f, double g) {
+        assertEquals("a", a);
+        assertEquals(Character.valueOf('1'), b);
+        assertEquals('2', c);
+        assertEquals((short) '3', d);
+        assertEquals('4', e);
+        assertEquals((float) '5', f);
+        assertEquals((double) '6', g);
+
+        return 46;
+    }
+
+    public static int spreadShort(String a, Short b, short c,
+                                  int d, long e, float f, double g) {
+        assertEquals("a", a);
+        assertEquals(Short.valueOf((short) 1), b);
+        assertEquals(2, c);
+        assertEquals(3, d);
+        assertEquals(4l, e);
+        assertEquals(5.0f, f);
+        assertEquals(6.0, g);
+
+        return 47;
+    }
+
+    public static int spreadInt(String a, Integer b, int c,
+                                long d, float e, double f) {
+        assertEquals("a", a);
+        assertEquals(Integer.valueOf(1), b);
+        assertEquals(2, c);
+        assertEquals(3l, d);
+        assertEquals(4.0f, e);
+        assertEquals(5.0, f);
+
+        return 48;
+    }
+
+    public static int spreadLong(String a, Long b, long c, float d, double e) {
+        assertEquals("a", a);
+        assertEquals(Long.valueOf(1), b);
+        assertEquals(2l, c);
+        assertEquals(3.0f, d);
+        assertEquals(4.0, e);
+
+        return 49;
+    }
+
+    public static int spreadFloat(String a, Float b, float c, double d) {
+        assertEquals("a", a);
+        assertEquals(Float.valueOf(1.0f), b);
+        assertEquals(2.0f, c);
+        assertEquals(3.0, d);
+
+        return 50;
+    }
+
+    public static int spreadDouble(String a, Double b, double c) {
+        assertEquals("a", a);
+        assertEquals(Double.valueOf(1.0), b);
+        assertEquals(2.0, c);
+
+        return 51;
+    }
+
+    public static void testSpreaders_primitive() throws Throwable {
+        // boolean[]
+        // ---------------------
+        MethodType type = MethodType.methodType(int.class,
+                new Class<?>[]{String.class, Boolean.class, boolean.class});
+        MethodHandle delegate = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "spreadBoolean", type);
+
+        MethodHandle spreader = delegate.asSpreader(boolean[].class, 2);
+        int ret = (int) spreader.invokeExact("a", new boolean[]{true, false});
+        assertEquals(44, ret);
+        ret = (int) spreader.invoke("a", new boolean[]{true, false});
+        assertEquals(44, ret);
+
+        // boolean can't be cast to String (the first argument to the method).
+        try {
+            delegate.asSpreader(boolean[].class, 3);
+            fail();
+        } catch (WrongMethodTypeException expected) {
+        }
+
+        // int can't be cast to boolean to supply the last argument to the method.
+        try {
+            delegate.asSpreader(int[].class, 1);
+            fail();
+        } catch (WrongMethodTypeException expected) {
+        }
+
+        // byte[]
+        // ---------------------
+        type = MethodType.methodType(int.class,
+                new Class<?>[]{
+                        String.class, Byte.class, byte.class,
+                        short.class, int.class, long.class,
+                        float.class, double.class});
+        delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadByte", type);
+
+        spreader = delegate.asSpreader(byte[].class, 7);
+        ret = (int) spreader.invokeExact("a",
+                new byte[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7});
+        assertEquals(45, ret);
+        ret = (int) spreader.invoke("a",
+                new byte[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7});
+        assertEquals(45, ret);
+
+        // char[]
+        // ---------------------
+        type = MethodType.methodType(int.class,
+                new Class<?>[]{
+                        String.class, Character.class, char.class,
+                        int.class, long.class, float.class, double.class});
+        delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadChar", type);
+
+        spreader = delegate.asSpreader(char[].class, 6);
+        ret = (int) spreader.invokeExact("a",
+                new char[]{'1', '2', '3', '4', '5', '6'});
+        assertEquals(46, ret);
+        ret = (int) spreader.invokeExact("a",
+                new char[]{'1', '2', '3', '4', '5', '6'});
+        assertEquals(46, ret);
+
+        // short[]
+        // ---------------------
+        type = MethodType.methodType(int.class,
+                new Class<?>[]{
+                        String.class, Short.class, short.class,
+                        int.class, long.class, float.class, double.class});
+        delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadShort", type);
+
+        spreader = delegate.asSpreader(short[].class, 6);
+        ret = (int) spreader.invokeExact("a",
+                new short[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6});
+        assertEquals(47, ret);
+        ret = (int) spreader.invoke("a",
+                new short[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6});
+        assertEquals(47, ret);
+
+        // int[]
+        // ---------------------
+        type = MethodType.methodType(int.class,
+                new Class<?>[]{
+                        String.class, Integer.class, int.class,
+                        long.class, float.class, double.class});
+        delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadInt", type);
+
+        spreader = delegate.asSpreader(int[].class, 5);
+        ret = (int) spreader.invokeExact("a", new int[]{1, 2, 3, 4, 5});
+        assertEquals(48, ret);
+        ret = (int) spreader.invokeExact("a", new int[]{1, 2, 3, 4, 5});
+        assertEquals(48, ret);
+
+        // long[]
+        // ---------------------
+        type = MethodType.methodType(int.class,
+                new Class<?>[]{
+                        String.class, Long.class, long.class, float.class, double.class});
+        delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadLong", type);
+
+        spreader = delegate.asSpreader(long[].class, 4);
+        ret = (int) spreader.invokeExact("a",
+                new long[]{0x1, 0x2, 0x3, 0x4});
+        assertEquals(49, ret);
+        ret = (int) spreader.invoke("a",
+                new long[]{0x1, 0x2, 0x3, 0x4});
+        assertEquals(49, ret);
+
+        // float[]
+        // ---------------------
+        type = MethodType.methodType(int.class,
+                new Class<?>[]{
+                        String.class, Float.class, float.class, double.class});
+        delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadFloat", type);
+
+        spreader = delegate.asSpreader(float[].class, 3);
+        ret = (int) spreader.invokeExact("a",
+                new float[]{1.0f, 2.0f, 3.0f});
+        assertEquals(50, ret);
+        ret = (int) spreader.invokeExact("a",
+                new float[]{1.0f, 2.0f, 3.0f});
+        assertEquals(50, ret);
+
+        // double[]
+        // ---------------------
+        type = MethodType.methodType(int.class,
+                new Class<?>[]{String.class, Double.class, double.class});
+        delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadDouble", type);
+
+        spreader = delegate.asSpreader(double[].class, 2);
+        ret = (int) spreader.invokeExact("a", new double[]{1.0, 2.0});
+        assertEquals(51, ret);
+        ret = (int) spreader.invokeExact("a", new double[]{1.0, 2.0});
+        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(
+                MethodHandleCombinersTest.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) {
+        } catch (WrongMethodTypeException expected) {
+        }
+
+        // Test implicit unboxing.
+        MethodType methodType2 = MethodType.methodType(int.class,
+                new Class<?>[]{String.class, int.class});
+        MethodHandle handle2 = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "spreadReferences_Unbox", methodType2);
+
+        ret = (int) handle2.invokeWithArguments(new Object[]{"a", 43});
+        assertEquals(43, (int) ret);
+    }
+
+    public static int collectBoolean(String a, boolean[] b) {
+        assertEquals("a", a);
+        assertTrue(b[0]);
+        assertFalse(b[1]);
+
+        return 44;
+    }
+
+    public static int collectByte(String a, byte[] b) {
+        assertEquals("a", a);
+        assertEquals((byte) 1, b[0]);
+        assertEquals((byte) 2, b[1]);
+        return 45;
+    }
+
+    public static int collectChar(String a, char[] b) {
+        assertEquals("a", a);
+        assertEquals('a', b[0]);
+        assertEquals('b', b[1]);
+        return 46;
+    }
+
+    public static int collectShort(String a, short[] b) {
+        assertEquals("a", a);
+        assertEquals((short) 3, b[0]);
+        assertEquals((short) 4, b[1]);
+
+        return 47;
+    }
+
+    public static int collectInt(String a, int[] b) {
+        assertEquals("a", a);
+        assertEquals(42, b[0]);
+        assertEquals(43, b[1]);
+
+        return 48;
+    }
+
+    public static int collectLong(String a, long[] b) {
+        assertEquals("a", a);
+        assertEquals(100l, b[0]);
+        assertEquals(99l, b[1]);
+
+        return 49;
+    }
+
+    public static int collectFloat(String a, float[] b) {
+        assertEquals("a", a);
+        assertEquals(8.9f, b[0]);
+        assertEquals(9.1f, b[1]);
+
+        return 50;
+    }
+
+    public static int collectDouble(String a, double[] b) {
+        assertEquals("a", a);
+        assertEquals(6.7, b[0]);
+        assertEquals(7.8, b[1]);
+
+        return 51;
+    }
+
+    public static int collectCharSequence(String a, CharSequence[] b) {
+        assertEquals("a", a);
+        assertEquals("b", b[0]);
+        assertEquals("c", b[1]);
+        return 99;
+    }
+
+    public static void testAsCollector() throws Throwable {
+        // Reference arrays.
+        // -------------------
+        MethodHandle trailingRef = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "collectCharSequence",
+                MethodType.methodType(int.class, String.class, CharSequence[].class));
+
+        // int[] is not convertible to CharSequence[].class.
+        try {
+            trailingRef.asCollector(int[].class, 1);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        // Object[] is not convertible to CharSequence[].class.
+        try {
+            trailingRef.asCollector(Object[].class, 1);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        // String[].class is convertible to CharSequence.class
+        MethodHandle collector = trailingRef.asCollector(String[].class, 2);
+        assertEquals(99, (int) collector.invoke("a", "b", "c"));
+
+        // Too few arguments should fail with a WMTE.
+        try {
+            collector.invoke("a", "b");
+            fail();
+        } catch (WrongMethodTypeException expected) {
+        }
+
+        // Too many arguments should fail with a WMTE.
+        try {
+            collector.invoke("a", "b", "c", "d");
+            fail();
+        } catch (WrongMethodTypeException expected) {
+        }
+
+        // Sanity checks on other array types.
+
+        MethodHandle target = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "collectBoolean",
+                MethodType.methodType(int.class, String.class, boolean[].class));
+        assertEquals(44, (int) target.asCollector(boolean[].class, 2).invoke("a", true, false));
+
+        target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectByte",
+                MethodType.methodType(int.class, String.class, byte[].class));
+        assertEquals(45, (int) target.asCollector(byte[].class, 2).invoke("a", (byte) 1, (byte) 2));
+
+        target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectChar",
+                MethodType.methodType(int.class, String.class, char[].class));
+        assertEquals(46, (int) target.asCollector(char[].class, 2).invoke("a", 'a', 'b'));
+
+        target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectShort",
+                MethodType.methodType(int.class, String.class, short[].class));
+        assertEquals(47, (int) target.asCollector(short[].class, 2).invoke("a", (short) 3, (short) 4));
+
+        target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectInt",
+                MethodType.methodType(int.class, String.class, int[].class));
+        assertEquals(48, (int) target.asCollector(int[].class, 2).invoke("a", 42, 43));
+
+        target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectLong",
+                MethodType.methodType(int.class, String.class, long[].class));
+        assertEquals(49, (int) target.asCollector(long[].class, 2).invoke("a", 100, 99));
+
+        target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectFloat",
+                MethodType.methodType(int.class, String.class, float[].class));
+        assertEquals(50, (int) target.asCollector(float[].class, 2).invoke("a", 8.9f, 9.1f));
+
+        target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectDouble",
+                MethodType.methodType(int.class, String.class, double[].class));
+        assertEquals(51, (int) target.asCollector(double[].class, 2).invoke("a", 6.7, 7.8));
+    }
+
+    public static String filter1(char a) {
+        return String.valueOf(a);
+    }
+
+    public static char filter2(String b) {
+        return b.charAt(0);
+    }
+
+    public static String badFilter1(char a, char b) {
+        return "bad";
+    }
+
+    public static int filterTarget(String a, char b, String c, char d) {
+        assertEquals("a", a);
+        assertEquals('b', b);
+        assertEquals("c", c);
+        assertEquals('d', d);
+        return 56;
+    }
+
+    public static void testFilterArguments() throws Throwable {
+        MethodHandle filter1 = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "filter1", MethodType.methodType(String.class, char.class));
+        MethodHandle filter2 = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "filter2", MethodType.methodType(char.class, String.class));
+
+        MethodHandle target = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "filterTarget", MethodType.methodType(int.class,
+                        String.class, char.class, String.class, char.class));
+
+        // In all the cases below, the values printed will be 'a', 'b', 'c', 'd'.
+
+        // Filter arguments [0, 1] - all other arguments are passed through
+        // as is.
+        MethodHandle adapter = MethodHandles.filterArguments(
+                target, 0, filter1, filter2);
+        assertEquals(56, (int) adapter.invokeExact('a', "bXXXX", "c", 'd'));
+
+        // Filter arguments [1, 2].
+        adapter = MethodHandles.filterArguments(target, 1, filter2, filter1);
+        assertEquals(56, (int) adapter.invokeExact("a", "bXXXX", 'c', 'd'));
+
+        // Filter arguments [2, 3].
+        adapter = MethodHandles.filterArguments(target, 2, filter1, filter2);
+        assertEquals(56, (int) adapter.invokeExact("a", 'b', 'c', "dXXXXX"));
+
+        // Try out a few error cases :
+
+        // The return types of the filter doesn't align with the expected argument
+        // type of the target.
+        try {
+            adapter = MethodHandles.filterArguments(target, 2, filter2, filter1);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        // There are more filters than arguments.
+        try {
+            adapter = MethodHandles.filterArguments(target, 3, filter2, filter1);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        // We pass in an obviously bogus position.
+        try {
+            adapter = MethodHandles.filterArguments(target, -1, filter2, filter1);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException expected) {
+        }
+
+        // We pass in a function that has more than one argument.
+        MethodHandle badFilter1 = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "badFilter1",
+                MethodType.methodType(String.class, char.class, char.class));
+
+        try {
+            adapter = MethodHandles.filterArguments(target, 0, badFilter1, filter2);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    static void voidFilter(char a, char b) {
+    }
+
+    static String filter(char a, char b) {
+        return String.valueOf(a) + "+" + b;
+    }
+
+    static char badFilter(char a, char b) {
+        return 0;
+    }
+
+    static String target(String a, String b, String c) {
+        return ("a: " + a + ", b: " + b + ", c: " + c);
+    }
+
+    public static void testCollectArguments() throws Throwable {
+        // Test non-void filters.
+        MethodHandle filter = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "filter",
+                MethodType.methodType(String.class, char.class, char.class));
+
+        MethodHandle target = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "target",
+                MethodType.methodType(String.class, String.class, String.class, String.class));
+
+        // Filter at position 0.
+        MethodHandle adapter = MethodHandles.collectArguments(target, 0, filter);
+        assertEquals("a: a+b, b: c, c: d",
+                (String) adapter.invokeExact('a', 'b', "c", "d"));
+
+        // Filter at position 1.
+        adapter = MethodHandles.collectArguments(target, 1, filter);
+        assertEquals("a: a, b: b+c, c: d",
+                (String) adapter.invokeExact("a", 'b', 'c', "d"));
+
+        // Filter at position 2.
+        adapter = MethodHandles.collectArguments(target, 2, filter);
+        assertEquals("a: a, b: b, c: c+d",
+                (String) adapter.invokeExact("a", "b", 'c', 'd'));
+
+        // Test void filters. Note that we're passing in one more argument
+        // than usual because the filter returns nothing - we have to invoke with
+        // the full set of filter args and the full set of target args.
+        filter = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "voidFilter",
+                MethodType.methodType(void.class, char.class, char.class));
+        adapter = MethodHandles.collectArguments(target, 0, filter);
+        assertEquals("a: a, b: b, c: c",
+                (String) adapter.invokeExact('a', 'b', "a", "b", "c"));
+
+        adapter = MethodHandles.collectArguments(target, 1, filter);
+        assertEquals("a: a, b: b, c: c",
+                (String) adapter.invokeExact("a", 'a', 'b', "b", "c"));
+
+        // Test out a few failure cases.
+        filter = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "filter",
+                MethodType.methodType(String.class, char.class, char.class));
+
+        // Bogus filter position.
+        try {
+            adapter = MethodHandles.collectArguments(target, 3, filter);
+            fail();
+        } catch (IndexOutOfBoundsException expected) {
+        }
+
+        // Mismatch in filter return type.
+        filter = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "badFilter",
+                MethodType.methodType(char.class, char.class, char.class));
+        try {
+            adapter = MethodHandles.collectArguments(target, 0, filter);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    static int insertReceiver(String a, int b, Integer c, String d) {
+        assertEquals("foo", a);
+        assertEquals(56, b);
+        assertEquals(Integer.valueOf(57), c);
+        assertEquals("bar", d);
+
+        return 73;
+    }
+
+    public static void testInsertArguments() throws Throwable {
+        MethodHandle target = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "insertReceiver",
+                MethodType.methodType(int.class,
+                        String.class, int.class, Integer.class, String.class));
+
+        // Basic single element array inserted at position 0.
+        MethodHandle adapter = MethodHandles.insertArguments(
+                target, 0, new Object[]{"foo"});
+        assertEquals(73, (int) adapter.invokeExact(56, Integer.valueOf(57), "bar"));
+
+        // Exercise unboxing.
+        adapter = MethodHandles.insertArguments(
+                target, 1, new Object[]{Integer.valueOf(56), 57});
+        assertEquals(73, (int) adapter.invokeExact("foo", "bar"));
+
+        // Exercise a widening conversion.
+        adapter = MethodHandles.insertArguments(
+                target, 1, new Object[]{(short) 56, Integer.valueOf(57)});
+        assertEquals(73, (int) adapter.invokeExact("foo", "bar"));
+
+        // Insert an argument at the last position.
+        adapter = MethodHandles.insertArguments(
+                target, 3, new Object[]{"bar"});
+        assertEquals(73, (int) adapter.invokeExact("foo", 56, Integer.valueOf(57)));
+
+        // Exercise a few error cases.
+
+        // A reference type that can't be cast to another reference type.
+        try {
+            MethodHandles.insertArguments(target, 3, new Object[]{new Object()});
+            fail();
+        } catch (ClassCastException expected) {
+        }
+
+        // A boxed type that can't be unboxed correctly.
+        try {
+            MethodHandles.insertArguments(target, 1, new Object[]{Long.valueOf(56)});
+            fail();
+        } catch (ClassCastException expected) {
+        }
+    }
+
+    public static String foldFilter(char a, char b) {
+        return String.valueOf(a) + "+" + b;
+    }
+
+    public static void voidFoldFilter(String e, char a, char b) {
+        assertEquals("a", e);
+        assertEquals('c', a);
+        assertEquals('d', b);
+    }
+
+    public static String foldTarget(String a, char b, char c, String d) {
+        return ("a: " + a + " ,b:" + b + " ,c:" + c + " ,d:" + d);
+    }
+
+    public static void mismatchedVoidFilter(Integer a) {
+    }
+
+    public static Integer mismatchedNonVoidFilter(char a, char b) {
+        return null;
+    }
+
+    public static void testFoldArguments() throws Throwable {
+        // Test non-void filters.
+        MethodHandle filter = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "foldFilter",
+                MethodType.methodType(String.class, char.class, char.class));
+
+        MethodHandle target = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "foldTarget",
+                MethodType.methodType(String.class, String.class,
+                        char.class, char.class, String.class));
+
+        // Folder with a non-void type.
+        MethodHandle adapter = MethodHandles.foldArguments(target, filter);
+        assertEquals("a: c+d ,b:c ,c:d ,d:e",
+                (String) adapter.invokeExact('c', 'd', "e"));
+
+        // Folder with a void type.
+        filter = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "voidFoldFilter",
+                MethodType.methodType(void.class, String.class, char.class, char.class));
+        adapter = MethodHandles.foldArguments(target, filter);
+        assertEquals("a: a ,b:c ,c:d ,d:e",
+                (String) adapter.invokeExact("a", 'c', 'd', "e"));
+
+        // Test a few erroneous cases.
+
+        filter = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "mismatchedVoidFilter",
+                MethodType.methodType(void.class, Integer.class));
+        try {
+            adapter = MethodHandles.foldArguments(target, filter);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        filter = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "mismatchedNonVoidFilter",
+                MethodType.methodType(Integer.class, char.class, char.class));
+        try {
+            adapter = MethodHandles.foldArguments(target, filter);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+}
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java
index 3705744..f833840 100644
--- a/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java
@@ -152,6 +152,23 @@
         }
     }
 
+    public void test_methodType_basicTestsReturnTypeAndMethodTypeParameters() {
+        MethodType mt = MethodType.methodType(int.class, long.class, String.class);
+        assertEquals(int.class, mt.returnType());
+
+        MethodType mt2 = MethodType.methodType(long.class, mt);
+
+        assertEquals(long.class, mt2.returnType());
+        assertEquals(long.class, mt2.parameterType(0));
+        assertEquals(String.class, mt2.parameterType(1));
+
+        try {
+            MethodType.methodType(int.class, (MethodType) null);
+            fail();
+        } catch (NullPointerException expected) {
+        }
+    }
+
     public void testGenericMethodType() {
         MethodType mt = MethodType.genericMethodType(0);
         assertEquals(0, mt.parameterCount());
diff --git a/luni/src/test/java/libcore/java/net/URLConnectionTest.java b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
index 9231cd0..c80d2ec 100644
--- a/luni/src/test/java/libcore/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
@@ -1068,7 +1068,35 @@
     }
 
     // http://b/33763156
-    public void testDisconnectDuringConnect() throws IOException {
+    public void testDisconnectDuringConnect_getInputStream() throws IOException {
+        checkDisconnectDuringConnect(HttpURLConnection::getInputStream);
+    }
+
+    // http://b/33763156
+    public void testDisconnectDuringConnect_getOutputStream() throws IOException {
+        checkDisconnectDuringConnect(HttpURLConnection::getOutputStream);
+    }
+
+    // http://b/33763156
+    public void testDisconnectDuringConnect_getResponseCode() throws IOException {
+        checkDisconnectDuringConnect(HttpURLConnection::getResponseCode);
+    }
+
+    // http://b/33763156
+    public void testDisconnectDuringConnect_getResponseMessage() throws IOException {
+        checkDisconnectDuringConnect(HttpURLConnection::getResponseMessage);
+    }
+
+    interface ConnectStrategy {
+        /**
+         * Causes the given {@code connection}, which was previously disconnected,
+         * to initiate the connection.
+         */
+        void connect(HttpURLConnection connection) throws IOException;
+    }
+
+    // http://b/33763156
+    private void checkDisconnectDuringConnect(ConnectStrategy connectStrategy) throws IOException {
         server.enqueue(new MockResponse().setBody("This should never be sent"));
         server.play();
 
@@ -1088,7 +1116,7 @@
             HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
             connectionHolder.set(connection);
             try {
-                connection.getInputStream();
+                connectStrategy.connect(connection);
                 fail();
             } catch (IOException expected) {
                 assertEquals("Canceled", expected.getMessage());
diff --git a/luni/src/test/java/libcore/java/nio/file/DirectoryIteratorExceptionTest.java b/luni/src/test/java/libcore/java/nio/file/DirectoryIteratorExceptionTest.java
new file mode 100644
index 0000000..8fb2571
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/DirectoryIteratorExceptionTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.nio.file.DirectoryIteratorException;
+
+public class DirectoryIteratorExceptionTest extends TestCase {
+
+    public void test_constructor() {
+        IOException ioException = new IOException();
+        DirectoryIteratorException exception = new DirectoryIteratorException(ioException);
+
+        assertSame(ioException, exception.getCause());
+
+        try {
+            new DirectoryIteratorException(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/FileSystemAlreadyExistsExceptionTest.java b/luni/src/test/java/libcore/java/nio/file/FileSystemAlreadyExistsExceptionTest.java
new file mode 100644
index 0000000..4130ddc
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/FileSystemAlreadyExistsExceptionTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 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
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.nio.file.FileSystemAlreadyExistsException;
+
+public class FileSystemAlreadyExistsExceptionTest extends TestCase {
+
+    public void test_constructor$String() {
+        String message = "message";
+        FileSystemAlreadyExistsException exception = new FileSystemAlreadyExistsException(message);
+        assertEquals(message, exception.getMessage());
+
+        message = null;
+        exception = new FileSystemAlreadyExistsException(message);
+        assertEquals(message, exception.getMessage());
+    }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/FileSystemNotFoundExceptionTest.java b/luni/src/test/java/libcore/java/nio/file/FileSystemNotFoundExceptionTest.java
new file mode 100644
index 0000000..2a0fe1e
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/FileSystemNotFoundExceptionTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 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
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.nio.file.FileSystemNotFoundException;
+
+public class FileSystemNotFoundExceptionTest extends TestCase {
+
+    public void test_constructor_empty() {
+        FileSystemNotFoundException exception = new FileSystemNotFoundException();
+        assertEquals(null, exception.getMessage());
+    }
+
+    public void test_constructor$String() {
+        String message = "message";
+        FileSystemNotFoundException exception = new FileSystemNotFoundException(message);
+        assertEquals(message, exception.getMessage());
+    }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/InvalidPathExceptionTest.java b/luni/src/test/java/libcore/java/nio/file/InvalidPathExceptionTest.java
new file mode 100644
index 0000000..267581c
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/InvalidPathExceptionTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 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
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.nio.file.InvalidPathException;
+
+public class InvalidPathExceptionTest extends TestCase {
+
+    public void test_Constructor$String$String$Int() {
+        String reason = "reason";
+        String input = "input";
+        int index = 0;
+
+        InvalidPathException exception = new InvalidPathException(input, reason, index);
+        assertEquals(index, exception.getIndex());
+        assertEquals(reason, exception.getReason());
+        assertEquals(input, exception.getInput());
+
+        // Test the case where index = -1.
+        index = -1;
+        exception = new InvalidPathException(input, reason, index);
+        assertEquals(index, exception.getIndex());
+        assertEquals(reason, exception.getReason());
+        assertEquals(input, exception.getInput());
+
+        // Test the case where index < -1;
+        index = -2;
+        try {
+            new InvalidPathException(input, reason, index);
+            fail();
+        } catch (IllegalArgumentException expected) {}
+
+        // Test the case where input is null, reason is not null and index >= -1.
+        try {
+            index = 0;
+            new InvalidPathException(null, reason, index);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        // Test the case where input is null, reason is not null and index < -1.
+        try {
+            index = -1;
+            new InvalidPathException(null, reason, index);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        // Test the case where reason is null, input is not null and index >= -1.
+        try {
+            index = 0;
+            new InvalidPathException(input, null, index);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        // Test the case where input is not null, reason is null and index < -1.
+        try {
+            index = -1;
+            new InvalidPathException(input, null, index);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    public void test_Constructor$String$String() {
+        String reason = "reason";
+        String input = "input";
+
+        InvalidPathException exception = new InvalidPathException(input, reason);
+        assertEquals(-1, exception.getIndex());
+        assertEquals(reason, exception.getReason());
+        assertEquals(input, exception.getInput());
+
+        // Test the case where input is null and reason is not null.
+        try {
+            new InvalidPathException(null, reason);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        // Test the case where reason is null and input is not null.
+        try {
+            new InvalidPathException(input, null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/LinkPermissionTest.java b/luni/src/test/java/libcore/java/nio/file/LinkPermissionTest.java
new file mode 100644
index 0000000..b01350d
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/LinkPermissionTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 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
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.nio.file.LinkPermission;
+
+public class LinkPermissionTest extends TestCase {
+
+    public void test_constructor$String() {
+        // Only "hard" and "symbolic" are the supported permission target names.
+        LinkPermission linkPermission = new LinkPermission("hard");
+        assertNull(linkPermission.getName());
+
+        linkPermission = new LinkPermission("symbolic");
+        assertNull(linkPermission.getName());
+
+        // Non supported permission target names.
+        try {
+            new LinkPermission("test");
+            fail();
+        } catch (IllegalArgumentException expected) {}
+    }
+
+    public void test_constructor$String$String() {
+        // Only empty string or null is accepted as action.
+        String actions = "";
+        LinkPermission linkPermission = new LinkPermission("hard", actions);
+        assertEquals("", linkPermission.getActions());
+
+        actions = null;
+        linkPermission = new LinkPermission("hard", actions);
+        assertEquals("", linkPermission.getActions());
+
+        // When actions is non empty string.
+        try {
+            actions = "abc";
+            new LinkPermission("hard", actions);
+            fail();
+        } catch (IllegalArgumentException expected) {}
+    }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/ProviderNotFoundExceptionTest.java b/luni/src/test/java/libcore/java/nio/file/ProviderNotFoundExceptionTest.java
new file mode 100644
index 0000000..277db4f
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/ProviderNotFoundExceptionTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 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
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.nio.file.ProviderNotFoundException;
+
+public class ProviderNotFoundExceptionTest extends TestCase {
+
+    public void test_constructor$String() {
+        String message = "message";
+        ProviderNotFoundException exception = new ProviderNotFoundException(message);
+        assertEquals(message, exception.getMessage());
+
+        message = null;
+        exception = new ProviderNotFoundException(message);
+        assertEquals(message, exception.getMessage());
+    }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/SimpleFileVisitorTest.java b/luni/src/test/java/libcore/java/nio/file/SimpleFileVisitorTest.java
new file mode 100644
index 0000000..f712cbf
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/SimpleFileVisitorTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 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
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+
+import static org.mockito.Mockito.mock;
+
+public class SimpleFileVisitorTest extends TestCase {
+
+    public void test_preVisitDirectory() throws IOException {
+        Path stubPath = mock(Path.class);
+        BasicFileAttributes stubAttributes = mock(BasicFileAttributes.class);
+        SimpleFileVisitor<Path> fileVisitor = new TestSimpleFileVisitor();
+
+        assertEquals(FileVisitResult.CONTINUE, fileVisitor.preVisitDirectory(stubPath,
+                stubAttributes));
+
+        try {
+            fileVisitor.preVisitDirectory(null, stubAttributes);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            fileVisitor.preVisitDirectory(stubPath, null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    public void test_postVisitDirectory() throws IOException {
+        Path stubPath = mock(Path.class);
+        IOException ioException = new IOException();
+        SimpleFileVisitor<Path> fileVisitor = new TestSimpleFileVisitor();
+
+        assertEquals(FileVisitResult.CONTINUE, fileVisitor.postVisitDirectory(stubPath, null));
+
+        try {
+            fileVisitor.postVisitDirectory(null, ioException);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            fileVisitor.postVisitDirectory(stubPath, ioException);
+            fail();
+        } catch (IOException actual) {
+            assertSame(ioException, actual);
+        }
+    }
+
+    public void test_visitFile() throws IOException {
+        Path stubPath = mock(Path.class);
+        BasicFileAttributes stubAttributes = mock(BasicFileAttributes.class);
+        SimpleFileVisitor<Path> fileVisitor = new TestSimpleFileVisitor();
+
+        assertEquals(FileVisitResult.CONTINUE, fileVisitor.visitFile(stubPath, stubAttributes));
+
+        try {
+            fileVisitor.visitFile(null, stubAttributes);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            fileVisitor.visitFile(stubPath, null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    public void test_visitFileFailed() throws IOException {
+        Path stubPath = mock(Path.class);
+        IOException ioException = new IOException();
+        SimpleFileVisitor<Path> fileVisitor = new TestSimpleFileVisitor();
+
+        try {
+            assertEquals(FileVisitResult.CONTINUE, fileVisitor.visitFileFailed(stubPath, null));
+            fail();
+        } catch (NullPointerException expected) {
+        }
+
+        try {
+            assertEquals(FileVisitResult.CONTINUE, fileVisitor.visitFileFailed(null,
+                    ioException));
+            fail();
+        } catch (NullPointerException expected) {
+        }
+
+        try {
+            assertEquals(FileVisitResult.CONTINUE, fileVisitor.visitFileFailed(stubPath,
+                    ioException));
+            fail();
+        } catch (IOException actual) {
+            assertSame(ioException, actual);
+        }
+    }
+
+    /**
+     * SimpleFileVisitor only has a protected constructor so we use a basic subclass for tests.
+     */
+    private static class TestSimpleFileVisitor extends SimpleFileVisitor<Path> {
+    }
+}
diff --git a/luni/src/test/java/libcore/util/NativeAllocationRegistryTest.java b/luni/src/test/java/libcore/util/NativeAllocationRegistryTest.java
index af45bfa..99be1fd 100644
--- a/luni/src/test/java/libcore/util/NativeAllocationRegistryTest.java
+++ b/luni/src/test/java/libcore/util/NativeAllocationRegistryTest.java
@@ -87,9 +87,8 @@
 
         // Verify most of the allocations have been freed.
         long nativeBytes = getNumNativeBytesAllocated();
-        assertTrue("Native bytes allocated (" + nativeBytes + ")"
-                + " exceeds max memory (" + max + ")",
-                getNumNativeBytesAllocated() < max);
+        assertTrue("Excessive native bytes still allocated (" + nativeBytes + ")"
+                + " given max memory of (" + max + ")", nativeBytes < 2 * max);
     }
 
     public void testNativeAllocationAllocatorAndSharedRegistry() {
diff --git a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
index 383a358..c67a0a4 100644
--- a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
+++ b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -113,29 +113,56 @@
     }
 
     /**
-     * This method has the same contract as ensureCapacity, but is
-     * never synchronized.
+     * For positive values of {@code minimumCapacity}, this method
+     * behaves like {@code ensureCapacity}, however it is never
+     * synchronized.
+     * If {@code minimumCapacity} is non positive due to numeric
+     * overflow, this method throws {@code OutOfMemoryError}.
      */
     private void ensureCapacityInternal(int minimumCapacity) {
         // overflow-conscious code
-        if (minimumCapacity - value.length > 0)
-            expandCapacity(minimumCapacity);
+        if (minimumCapacity - value.length > 0) {
+            value = Arrays.copyOf(value,
+                    newCapacity(minimumCapacity));
+        }
     }
 
     /**
-     * This implements the expansion semantics of ensureCapacity with no
-     * size check or synchronization.
+     * The maximum size of array to allocate (unless necessary).
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
      */
-    void expandCapacity(int minimumCapacity) {
-        int newCapacity = value.length * 2 + 2;
-        if (newCapacity - minimumCapacity < 0)
-            newCapacity = minimumCapacity;
-        if (newCapacity < 0) {
-            if (minimumCapacity < 0) // overflow
-                throw new OutOfMemoryError();
-            newCapacity = Integer.MAX_VALUE;
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Returns a capacity at least as large as the given minimum capacity.
+     * Returns the current capacity increased by the same amount + 2 if
+     * that suffices.
+     * Will not return a capacity greater than {@code MAX_ARRAY_SIZE}
+     * unless the given minimum capacity is greater than that.
+     *
+     * @param  minCapacity the desired minimum capacity
+     * @throws OutOfMemoryError if minCapacity is less than zero or
+     *         greater than Integer.MAX_VALUE
+     */
+    private int newCapacity(int minCapacity) {
+        // overflow-conscious code
+        int newCapacity = (value.length << 1) + 2;
+        if (newCapacity - minCapacity < 0) {
+            newCapacity = minCapacity;
         }
-        value = Arrays.copyOf(value, newCapacity);
+        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
+           ? hugeCapacity(minCapacity)
+            : newCapacity;
+    }
+
+    private int hugeCapacity(int minCapacity) {
+        if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
+            throw new OutOfMemoryError();
+        }
+        return (minCapacity > MAX_ARRAY_SIZE)
+            ? minCapacity : MAX_ARRAY_SIZE;
     }
 
     /**
diff --git a/ojluni/src/main/java/java/lang/StringBuffer.java b/ojluni/src/main/java/java/lang/StringBuffer.java
index 95a583d..6781f11 100644
--- a/ojluni/src/main/java/java/lang/StringBuffer.java
+++ b/ojluni/src/main/java/java/lang/StringBuffer.java
@@ -171,9 +171,7 @@
 
     @Override
     public synchronized void ensureCapacity(int minimumCapacity) {
-        if (minimumCapacity > value.length) {
-            expandCapacity(minimumCapacity);
-        }
+        super.ensureCapacity(minimumCapacity);
     }
 
     /**
diff --git a/ojluni/src/main/java/java/time/Instant.java b/ojluni/src/main/java/java/time/Instant.java
index 91a177c..9b9efa5 100644
--- a/ojluni/src/main/java/java/time/Instant.java
+++ b/ojluni/src/main/java/java/time/Instant.java
@@ -1229,8 +1229,14 @@
      * @throws ArithmeticException if numeric overflow occurs
      */
     public long toEpochMilli() {
-        long millis = Math.multiplyExact(seconds, 1000);
-        return millis + nanos / 1000_000;
+        if (seconds < 0 && nanos > 0) {
+            long millis = Math.multiplyExact(seconds+1, 1000);
+            long adjustment = nanos / 1000_000 - 1000;
+            return Math.addExact(millis, adjustment);
+        } else {
+            long millis = Math.multiplyExact(seconds, 1000);
+            return Math.addExact(millis, nanos / 1000_000);
+        }
     }
 
     //-----------------------------------------------------------------------
diff --git a/ojluni/src/main/java/java/time/chrono/HijrahChronology.java b/ojluni/src/main/java/java/time/chrono/HijrahChronology.java
index 67cca69..9fc86c4 100644
--- a/ojluni/src/main/java/java/time/chrono/HijrahChronology.java
+++ b/ojluni/src/main/java/java/time/chrono/HijrahChronology.java
@@ -544,10 +544,9 @@
     //-----------------------------------------------------------------------
     @Override
     public boolean isLeapYear(long prolepticYear) {
-        checkCalendarInit();
-        int epochMonth = yearToEpochMonth((int) prolepticYear);
-        if (epochMonth < 0 || epochMonth > maxEpochDay) {
-            throw new DateTimeException("Hijrah date out of range");
+      checkCalendarInit();
+        if (prolepticYear < getMinimumYear() || prolepticYear > getMaximumYear()) {
+            return false;
         }
         int len = getYearLength((int) prolepticYear);
         return (len > 354);
diff --git a/ojluni/src/main/java/java/util/zip/Deflater.java b/ojluni/src/main/java/java/util/zip/Deflater.java
index 54a649f..ca9fc14 100644
--- a/ojluni/src/main/java/java/util/zip/Deflater.java
+++ b/ojluni/src/main/java/java/util/zip/Deflater.java
@@ -320,7 +320,9 @@
      * should be called in order to provide more input
      */
     public boolean needsInput() {
-        return len <= 0;
+        synchronized (zsRef) {
+            return len <= 0;
+        }
     }
 
     /**
diff --git a/ojluni/src/main/java/sun/invoke/empty/Empty.java b/ojluni/src/main/java/sun/invoke/empty/Empty.java
deleted file mode 100644
index f75d2b3..0000000
--- a/ojluni/src/main/java/sun/invoke/empty/Empty.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.invoke.empty;
-
-/**
- * An empty class in an empty package.
- * Used as a proxy for unprivileged code, since making access checks
- * against it will only succeed against public methods in public types.
- * <p>
- * This class also stands (internally to sun.invoke) for the type of a
- * value that cannot be produced, because the expression of this type
- * always returns abnormally.  (Cf. Nothing in the closures proposal.)
- * @author jrose
- */
-public class Empty {
-    private Empty() { throw new InternalError(); }
-}
diff --git a/ojluni/src/main/java/sun/invoke/util/package-info.java b/ojluni/src/main/java/sun/invoke/util/package-info.java
deleted file mode 100644
index 785ca80..0000000
--- a/ojluni/src/main/java/sun/invoke/util/package-info.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * Extra support for using JSR 292 RI, package java.lang.invoke.
- * @author jrose
- */
-
-package sun.invoke.util;
diff --git a/ojluni/src/main/java/sun/misc/JavaSecurityProtectionDomainAccess.java b/ojluni/src/main/java/sun/misc/JavaSecurityProtectionDomainAccess.java
deleted file mode 100644
index 95560ff..0000000
--- a/ojluni/src/main/java/sun/misc/JavaSecurityProtectionDomainAccess.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.misc;
-
-import java.security.PermissionCollection;
-import java.security.ProtectionDomain;
-
-public interface JavaSecurityProtectionDomainAccess {
-    interface ProtectionDomainCache {
-        void put(ProtectionDomain pd, PermissionCollection pc);
-        PermissionCollection get(ProtectionDomain pd);
-    }
-    /**
-     * Returns the ProtectionDomainCache.
-     */
-    ProtectionDomainCache getProtectionDomainCache();
-}
diff --git a/ojluni/src/main/java/sun/misc/Service.java b/ojluni/src/main/java/sun/misc/Service.java
deleted file mode 100644
index 96eb20c..0000000
--- a/ojluni/src/main/java/sun/misc/Service.java
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.TreeSet;
-
-
-/**
- * A simple service-provider lookup mechanism.  A <i>service</i> is a
- * well-known set of interfaces and (usually abstract) classes.  A <i>service
- * provider</i> is a specific implementation of a service.  The classes in a
- * provider typically implement the interfaces and subclass the classes defined
- * in the service itself.  Service providers may be installed in an
- * implementation of the Java platform in the form of extensions, that is, jar
- * files placed into any of the usual extension directories.  Providers may
- * also be made available by adding them to the applet or application class
- * path or by some other platform-specific means.
- *
- * <p> In this lookup mechanism a service is represented by an interface or an
- * abstract class.  (A concrete class may be used, but this is not
- * recommended.)  A provider of a given service contains one or more concrete
- * classes that extend this <i>service class</i> with data and code specific to
- * the provider.  This <i>provider class</i> will typically not be the entire
- * provider itself but rather a proxy that contains enough information to
- * decide whether the provider is able to satisfy a particular request together
- * with code that can create the actual provider on demand.  The details of
- * provider classes tend to be highly service-specific; no single class or
- * interface could possibly unify them, so no such class has been defined.  The
- * only requirement enforced here is that provider classes must have a
- * zero-argument constructor so that they may be instantiated during lookup.
- *
- * <p> A service provider identifies itself by placing a provider-configuration
- * file in the resource directory <tt>META-INF/services</tt>.  The file's name
- * should consist of the fully-qualified name of the abstract service class.
- * The file should contain a list of fully-qualified concrete provider-class
- * names, one per line.  Space and tab characters surrounding each name, as
- * well as blank lines, are ignored.  The comment character is <tt>'#'</tt>
- * (<tt>0x23</tt>); on each line all characters following the first comment
- * character are ignored.  The file must be encoded in UTF-8.
- *
- * <p> If a particular concrete provider class is named in more than one
- * configuration file, or is named in the same configuration file more than
- * once, then the duplicates will be ignored.  The configuration file naming a
- * particular provider need not be in the same jar file or other distribution
- * unit as the provider itself.  The provider must be accessible from the same
- * class loader that was initially queried to locate the configuration file;
- * note that this is not necessarily the class loader that found the file.
- *
- * <p> <b>Example:</b> Suppose we have a service class named
- * <tt>java.io.spi.CharCodec</tt>.  It has two abstract methods:
- *
- * <pre>
- *   public abstract CharEncoder getEncoder(String encodingName);
- *   public abstract CharDecoder getDecoder(String encodingName);
- * </pre>
- *
- * Each method returns an appropriate object or <tt>null</tt> if it cannot
- * translate the given encoding.  Typical <tt>CharCodec</tt> providers will
- * support more than one encoding.
- *
- * <p> If <tt>sun.io.StandardCodec</tt> is a provider of the <tt>CharCodec</tt>
- * service then its jar file would contain the file
- * <tt>META-INF/services/java.io.spi.CharCodec</tt>.  This file would contain
- * the single line:
- *
- * <pre>
- *   sun.io.StandardCodec    # Standard codecs for the platform
- * </pre>
- *
- * To locate an encoder for a given encoding name, the internal I/O code would
- * do something like this:
- *
- * <pre>
- *   CharEncoder getEncoder(String encodingName) {
- *       Iterator ps = Service.providers(CharCodec.class);
- *       while (ps.hasNext()) {
- *           CharCodec cc = (CharCodec)ps.next();
- *           CharEncoder ce = cc.getEncoder(encodingName);
- *           if (ce != null)
- *               return ce;
- *       }
- *       return null;
- *   }
- * </pre>
- *
- * The provider-lookup mechanism always executes in the security context of the
- * caller.  Trusted system code should typically invoke the methods in this
- * class from within a privileged security context.
- *
- * @author Mark Reinhold
- * @since 1.3
- */
-
-public final class Service {
-
-    private static final String prefix = "META-INF/services/";
-
-    private Service() { }
-
-    private static void fail(Class service, String msg, Throwable cause)
-        throws ServiceConfigurationError
-    {
-        ServiceConfigurationError sce
-            = new ServiceConfigurationError(service.getName() + ": " + msg);
-        sce.initCause(cause);
-        throw sce;
-    }
-
-    private static void fail(Class service, String msg)
-        throws ServiceConfigurationError
-    {
-        throw new ServiceConfigurationError(service.getName() + ": " + msg);
-    }
-
-    private static void fail(Class service, URL u, int line, String msg)
-        throws ServiceConfigurationError
-    {
-        fail(service, u + ":" + line + ": " + msg);
-    }
-
-    /**
-     * Parse a single line from the given configuration file, adding the name
-     * on the line to both the names list and the returned set iff the name is
-     * not already a member of the returned set.
-     */
-    private static int parseLine(Class service, URL u, BufferedReader r, int lc,
-                                 List names, Set returned)
-        throws IOException, ServiceConfigurationError
-    {
-        String ln = r.readLine();
-        if (ln == null) {
-            return -1;
-        }
-        int ci = ln.indexOf('#');
-        if (ci >= 0) ln = ln.substring(0, ci);
-        ln = ln.trim();
-        int n = ln.length();
-        if (n != 0) {
-            if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
-                fail(service, u, lc, "Illegal configuration-file syntax");
-            int cp = ln.codePointAt(0);
-            if (!Character.isJavaIdentifierStart(cp))
-                fail(service, u, lc, "Illegal provider-class name: " + ln);
-            for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
-                cp = ln.codePointAt(i);
-                if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
-                    fail(service, u, lc, "Illegal provider-class name: " + ln);
-            }
-            if (!returned.contains(ln)) {
-                names.add(ln);
-                returned.add(ln);
-            }
-        }
-        return lc + 1;
-    }
-
-    /**
-     * Parse the content of the given URL as a provider-configuration file.
-     *
-     * @param  service
-     *         The service class for which providers are being sought;
-     *         used to construct error detail strings
-     *
-     * @param  url
-     *         The URL naming the configuration file to be parsed
-     *
-     * @param  returned
-     *         A Set containing the names of provider classes that have already
-     *         been returned.  This set will be updated to contain the names
-     *         that will be yielded from the returned <tt>Iterator</tt>.
-     *
-     * @return A (possibly empty) <tt>Iterator</tt> that will yield the
-     *         provider-class names in the given configuration file that are
-     *         not yet members of the returned set
-     *
-     * @throws ServiceConfigurationError
-     *         If an I/O error occurs while reading from the given URL, or
-     *         if a configuration-file format error is detected
-     */
-    private static Iterator parse(Class service, URL u, Set returned)
-        throws ServiceConfigurationError
-    {
-        InputStream in = null;
-        BufferedReader r = null;
-        ArrayList names = new ArrayList();
-        try {
-            in = u.openStream();
-            r = new BufferedReader(new InputStreamReader(in, "utf-8"));
-            int lc = 1;
-            while ((lc = parseLine(service, u, r, lc, names, returned)) >= 0);
-        } catch (IOException x) {
-            fail(service, ": " + x);
-        } finally {
-            try {
-                if (r != null) r.close();
-                if (in != null) in.close();
-            } catch (IOException y) {
-                fail(service, ": " + y);
-            }
-        }
-        return names.iterator();
-    }
-
-
-    /**
-     * Private inner class implementing fully-lazy provider lookup
-     */
-    private static class LazyIterator implements Iterator {
-
-        Class service;
-        ClassLoader loader;
-        Enumeration configs = null;
-        Iterator pending = null;
-        Set returned = new TreeSet();
-        String nextName = null;
-
-        private LazyIterator(Class service, ClassLoader loader) {
-            this.service = service;
-            this.loader = loader;
-        }
-
-        public boolean hasNext() throws ServiceConfigurationError {
-            if (nextName != null) {
-                return true;
-            }
-            if (configs == null) {
-                try {
-                    String fullName = prefix + service.getName();
-                    if (loader == null)
-                        configs = ClassLoader.getSystemResources(fullName);
-                    else
-                        configs = loader.getResources(fullName);
-                } catch (IOException x) {
-                    fail(service, ": " + x);
-                }
-            }
-            while ((pending == null) || !pending.hasNext()) {
-                if (!configs.hasMoreElements()) {
-                    return false;
-                }
-                pending = parse(service, (URL)configs.nextElement(), returned);
-            }
-            nextName = (String)pending.next();
-            return true;
-        }
-
-        public Object next() throws ServiceConfigurationError {
-            if (!hasNext()) {
-                throw new NoSuchElementException();
-            }
-            String cn = nextName;
-            nextName = null;
-            Class<?> c = null;
-            try {
-                c = Class.forName(cn, false, loader);
-            } catch (ClassNotFoundException x) {
-                fail(service,
-                     "Provider " + cn + " not found");
-            }
-            if (!service.isAssignableFrom(c)) {
-                fail(service,
-                     "Provider " + cn  + " not a subtype");
-            }
-            try {
-                return service.cast(c.newInstance());
-            } catch (Throwable x) {
-                fail(service,
-                     "Provider " + cn + " could not be instantiated: " + x,
-                     x);
-            }
-            return null;        /* This cannot happen */
-        }
-
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-
-    }
-
-
-    /**
-     * Locates and incrementally instantiates the available providers of a
-     * given service using the given class loader.
-     *
-     * <p> This method transforms the name of the given service class into a
-     * provider-configuration filename as described above and then uses the
-     * <tt>getResources</tt> method of the given class loader to find all
-     * available files with that name.  These files are then read and parsed to
-     * produce a list of provider-class names.  The iterator that is returned
-     * uses the given class loader to lookup and then instantiate each element
-     * of the list.
-     *
-     * <p> Because it is possible for extensions to be installed into a running
-     * Java virtual machine, this method may return different results each time
-     * it is invoked. <p>
-     *
-     * @param  service
-     *         The service's abstract service class
-     *
-     * @param  loader
-     *         The class loader to be used to load provider-configuration files
-     *         and instantiate provider classes, or <tt>null</tt> if the system
-     *         class loader (or, failing that the bootstrap class loader) is to
-     *         be used
-     *
-     * @return An <tt>Iterator</tt> that yields provider objects for the given
-     *         service, in some arbitrary order.  The iterator will throw a
-     *         <tt>ServiceConfigurationError</tt> if a provider-configuration
-     *         file violates the specified format or if a provider class cannot
-     *         be found and instantiated.
-     *
-     * @throws ServiceConfigurationError
-     *         If a provider-configuration file violates the specified format
-     *         or names a provider class that cannot be found and instantiated
-     *
-     * @see #providers(java.lang.Class)
-     * @see #installedProviders(java.lang.Class)
-     */
-    public static Iterator providers(Class service, ClassLoader loader)
-        throws ServiceConfigurationError
-    {
-        return new LazyIterator(service, loader);
-    }
-
-
-    /**
-     * Locates and incrementally instantiates the available providers of a
-     * given service using the context class loader.  This convenience method
-     * is equivalent to
-     *
-     * <pre>
-     *   ClassLoader cl = Thread.currentThread().getContextClassLoader();
-     *   return Service.providers(service, cl);
-     * </pre>
-     *
-     * @param  service
-     *         The service's abstract service class
-     *
-     * @return An <tt>Iterator</tt> that yields provider objects for the given
-     *         service, in some arbitrary order.  The iterator will throw a
-     *         <tt>ServiceConfigurationError</tt> if a provider-configuration
-     *         file violates the specified format or if a provider class cannot
-     *         be found and instantiated.
-     *
-     * @throws ServiceConfigurationError
-     *         If a provider-configuration file violates the specified format
-     *         or names a provider class that cannot be found and instantiated
-     *
-     * @see #providers(java.lang.Class, java.lang.ClassLoader)
-     */
-    public static Iterator providers(Class service)
-        throws ServiceConfigurationError
-    {
-        ClassLoader cl = Thread.currentThread().getContextClassLoader();
-        return Service.providers(service, cl);
-    }
-
-
-    /**
-     * Locates and incrementally instantiates the available providers of a
-     * given service using the extension class loader.  This convenience method
-     * simply locates the extension class loader, call it
-     * <tt>extClassLoader</tt>, and then does
-     *
-     * <pre>
-     *   return Service.providers(service, extClassLoader);
-     * </pre>
-     *
-     * If the extension class loader cannot be found then the system class
-     * loader is used; if there is no system class loader then the bootstrap
-     * class loader is used.
-     *
-     * @param  service
-     *         The service's abstract service class
-     *
-     * @return An <tt>Iterator</tt> that yields provider objects for the given
-     *         service, in some arbitrary order.  The iterator will throw a
-     *         <tt>ServiceConfigurationError</tt> if a provider-configuration
-     *         file violates the specified format or if a provider class cannot
-     *         be found and instantiated.
-     *
-     * @throws ServiceConfigurationError
-     *         If a provider-configuration file violates the specified format
-     *         or names a provider class that cannot be found and instantiated
-     *
-     * @see #providers(java.lang.Class, java.lang.ClassLoader)
-     */
-    public static Iterator installedProviders(Class service)
-        throws ServiceConfigurationError
-    {
-        ClassLoader cl = ClassLoader.getSystemClassLoader();
-        ClassLoader prev = null;
-        while (cl != null) {
-            prev = cl;
-            cl = cl.getParent();
-        }
-        return Service.providers(service, prev);
-    }
-
-}
diff --git a/ojluni/src/main/java/sun/misc/ServiceConfigurationError.java b/ojluni/src/main/java/sun/misc/ServiceConfigurationError.java
deleted file mode 100644
index 5659b23..0000000
--- a/ojluni/src/main/java/sun/misc/ServiceConfigurationError.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 1999, 2000, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-
-/**
- * Error thrown when something goes wrong while looking up service providers.
- * In particular, this error will be thrown in the following situations:
- *
- *   <ul>
- *   <li> A concrete provider class cannot be found,
- *   <li> A concrete provider class cannot be instantiated,
- *   <li> The format of a provider-configuration file is illegal, or
- *   <li> An IOException occurs while reading a provider-configuration file.
- *   </ul>
- *
- * @author Mark Reinhold
- * @since 1.3
- */
-
-public class ServiceConfigurationError extends Error {
-
-    /**
-     * Constructs a new instance with the specified detail string.
-     */
-    public ServiceConfigurationError(String msg) {
-        super(msg);
-    }
-
-    /**
-     * Constructs a new instance that wraps the specified throwable.
-     */
-    public ServiceConfigurationError(Throwable x) {
-        super(x);
-    }
-
-}
diff --git a/ojluni/src/main/java/sun/misc/SoftCache.java b/ojluni/src/main/java/sun/misc/SoftCache.java
deleted file mode 100644
index b1d98ff..0000000
--- a/ojluni/src/main/java/sun/misc/SoftCache.java
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-import java.lang.ref.SoftReference;
-import java.lang.ref.ReferenceQueue;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.AbstractMap;
-import java.util.HashMap;
-import java.util.Set;
-import java.util.AbstractSet;
-import java.util.NoSuchElementException;
-
-
-/**
- * A memory-sensitive implementation of the <code>Map</code> interface.
- *
- * <p> A <code>SoftCache</code> object uses {@link java.lang.ref.SoftReference
- * soft references} to implement a memory-sensitive hash map.  If the garbage
- * collector determines at a certain point in time that a value object in a
- * <code>SoftCache</code> entry is no longer strongly reachable, then it may
- * remove that entry in order to release the memory occupied by the value
- * object.  All <code>SoftCache</code> objects are guaranteed to be completely
- * cleared before the virtual machine will throw an
- * <code>OutOfMemoryError</code>.  Because of this automatic clearing feature,
- * the behavior of this class is somewhat different from that of other
- * <code>Map</code> implementations.
- *
- * <p> Both null values and the null key are supported.  This class has the
- * same performance characteristics as the <code>HashMap</code> class, and has
- * the same efficiency parameters of <em>initial capacity</em> and <em>load
- * factor</em>.
- *
- * <p> Like most collection classes, this class is not synchronized.  A
- * synchronized <code>SoftCache</code> may be constructed using the
- * <code>Collections.synchronizedMap</code> method.
- *
- * <p> In typical usage this class will be subclassed and the <code>fill</code>
- * method will be overridden.  When the <code>get</code> method is invoked on a
- * key for which there is no mapping in the cache, it will in turn invoke the
- * <code>fill</code> method on that key in an attempt to construct a
- * corresponding value.  If the <code>fill</code> method returns such a value
- * then the cache will be updated and the new value will be returned.  Thus,
- * for example, a simple URL-content cache can be constructed as follows:
- *
- * <pre>
- *     public class URLCache extends SoftCache {
- *         protected Object fill(Object key) {
- *             return ((URL)key).getContent();
- *         }
- *     }
- * </pre>
- *
- * <p> The behavior of the <code>SoftCache</code> class depends in part upon
- * the actions of the garbage collector, so several familiar (though not
- * required) <code>Map</code> invariants do not hold for this class.  <p>
- * Because entries are removed from a <code>SoftCache</code> in response to
- * dynamic advice from the garbage collector, a <code>SoftCache</code> may
- * behave as though an unknown thread is silently removing entries.  In
- * particular, even if you synchronize on a <code>SoftCache</code> instance and
- * invoke none of its mutator methods, it is possible for the <code>size</code>
- * method to return smaller values over time, for the <code>isEmpty</code>
- * method to return <code>false</code> and then <code>true</code>, for the
- * <code>containsKey</code> method to return <code>true</code> and later
- * <code>false</code> for a given key, for the <code>get</code> method to
- * return a value for a given key but later return <code>null</code>, for the
- * <code>put</code> method to return <code>null</code> and the
- * <code>remove</code> method to return <code>false</code> for a key that
- * previously appeared to be in the map, and for successive examinations of the
- * key set, the value set, and the entry set to yield successively smaller
- * numbers of elements.
- *
- * @author      Mark Reinhold
- * @since       1.2
- * @see         java.util.HashMap
- * @see         java.lang.ref.SoftReference
- */
-
-
-public class SoftCache extends AbstractMap implements Map {
-
-    /* The basic idea of this implementation is to maintain an internal HashMap
-       that maps keys to soft references whose referents are the keys' values;
-       the various accessor methods dereference these soft references before
-       returning values.  Because we don't have access to the innards of the
-       HashMap, each soft reference must contain the key that maps to it so
-       that the processQueue method can remove keys whose values have been
-       discarded.  Thus the HashMap actually maps keys to instances of the
-       ValueCell class, which is a simple extension of the SoftReference class.
-     */
-
-
-    static private class ValueCell extends SoftReference {
-        static private Object INVALID_KEY = new Object();
-        static private int dropped = 0;
-        private Object key;
-
-        private ValueCell(Object key, Object value, ReferenceQueue queue) {
-            super(value, queue);
-            this.key = key;
-        }
-
-        private static ValueCell create(Object key, Object value,
-                                        ReferenceQueue queue)
-        {
-            if (value == null) return null;
-            return new ValueCell(key, value, queue);
-        }
-
-        private static Object strip(Object val, boolean drop) {
-            if (val == null) return null;
-            ValueCell vc = (ValueCell)val;
-            Object o = vc.get();
-            if (drop) vc.drop();
-            return o;
-        }
-
-        private boolean isValid() {
-            return (key != INVALID_KEY);
-        }
-
-        private void drop() {
-            super.clear();
-            key = INVALID_KEY;
-            dropped++;
-        }
-
-    }
-
-
-    /* Hash table mapping keys to ValueCells */
-    private Map hash;
-
-    /* Reference queue for cleared ValueCells */
-    private ReferenceQueue queue = new ReferenceQueue();
-
-
-    /* Process any ValueCells that have been cleared and enqueued by the
-       garbage collector.  This method should be invoked once by each public
-       mutator in this class.  We don't invoke this method in public accessors
-       because that can lead to surprising ConcurrentModificationExceptions.
-     */
-    private void processQueue() {
-        ValueCell vc;
-        while ((vc = (ValueCell)queue.poll()) != null) {
-            if (vc.isValid()) hash.remove(vc.key);
-            else ValueCell.dropped--;
-        }
-    }
-
-
-    /* -- Constructors -- */
-
-    /**
-     * Construct a new, empty <code>SoftCache</code> with the given
-     * initial capacity and the given load factor.
-     *
-     * @param  initialCapacity  The initial capacity of the cache
-     *
-     * @param  loadFactor       A number between 0.0 and 1.0
-     *
-     * @throws IllegalArgumentException  If the initial capacity is less than
-     *                                   or equal to zero, or if the load
-     *                                   factor is less than zero
-     */
-    public SoftCache(int initialCapacity, float loadFactor) {
-        hash = new HashMap(initialCapacity, loadFactor);
-    }
-
-    /**
-     * Construct a new, empty <code>SoftCache</code> with the given
-     * initial capacity and the default load factor.
-     *
-     * @param  initialCapacity  The initial capacity of the cache
-     *
-     * @throws IllegalArgumentException  If the initial capacity is less than
-     *                                   or equal to zero
-     */
-    public SoftCache(int initialCapacity) {
-        hash = new HashMap(initialCapacity);
-    }
-
-    /**
-     * Construct a new, empty <code>SoftCache</code> with the default
-     * capacity and the default load factor.
-     */
-    public SoftCache() {
-        hash = new HashMap();
-    }
-
-
-    /* -- Simple queries -- */
-
-    /**
-     * Return the number of key-value mappings in this cache.  The time
-     * required by this operation is linear in the size of the map.
-     */
-    public int size() {
-        return entrySet().size();
-    }
-
-    /**
-     * Return <code>true</code> if this cache contains no key-value mappings.
-     */
-    public boolean isEmpty() {
-        return entrySet().isEmpty();
-    }
-
-    /**
-     * Return <code>true</code> if this cache contains a mapping for the
-     * specified key.  If there is no mapping for the key, this method will not
-     * attempt to construct one by invoking the <code>fill</code> method.
-     *
-     * @param   key   The key whose presence in the cache is to be tested
-     */
-    public boolean containsKey(Object key) {
-        return ValueCell.strip(hash.get(key), false) != null;
-    }
-
-
-    /* -- Lookup and modification operations -- */
-
-    /**
-     * Create a value object for the given <code>key</code>.  This method is
-     * invoked by the <code>get</code> method when there is no entry for
-     * <code>key</code>.  If this method returns a non-<code>null</code> value,
-     * then the cache will be updated to map <code>key</code> to that value,
-     * and that value will be returned by the <code>get</code> method.
-     *
-     * <p> The default implementation of this method simply returns
-     * <code>null</code> for every <code>key</code> value.  A subclass may
-     * override this method to provide more useful behavior.
-     *
-     * @param  key  The key for which a value is to be computed
-     *
-     * @return      A value for <code>key</code>, or <code>null</code> if one
-     *              could not be computed
-     * @see #get
-     */
-    protected Object fill(Object key) {
-        return null;
-    }
-
-    /**
-     * Return the value to which this cache maps the specified
-     * <code>key</code>.  If the cache does not presently contain a value for
-     * this key, then invoke the <code>fill</code> method in an attempt to
-     * compute such a value.  If that method returns a non-<code>null</code>
-     * value, then update the cache and return the new value.  Otherwise,
-     * return <code>null</code>.
-     *
-     * <p> Note that because this method may update the cache, it is considered
-     * a mutator and may cause <code>ConcurrentModificationException</code>s to
-     * be thrown if invoked while an iterator is in use.
-     *
-     * @param  key  The key whose associated value, if any, is to be returned
-     *
-     * @see #fill
-     */
-    public Object get(Object key) {
-        processQueue();
-        Object v = hash.get(key);
-        if (v == null) {
-            v = fill(key);
-            if (v != null) {
-                hash.put(key, ValueCell.create(key, v, queue));
-                return v;
-            }
-        }
-        return ValueCell.strip(v, false);
-    }
-
-    /**
-     * Update this cache so that the given <code>key</code> maps to the given
-     * <code>value</code>.  If the cache previously contained a mapping for
-     * <code>key</code> then that mapping is replaced and the old value is
-     * returned.
-     *
-     * @param  key    The key that is to be mapped to the given
-     *                <code>value</code>
-     * @param  value  The value to which the given <code>key</code> is to be
-     *                mapped
-     *
-     * @return  The previous value to which this key was mapped, or
-     *          <code>null</code> if if there was no mapping for the key
-     */
-    public Object put(Object key, Object value) {
-        processQueue();
-        ValueCell vc = ValueCell.create(key, value, queue);
-        return ValueCell.strip(hash.put(key, vc), true);
-    }
-
-    /**
-     * Remove the mapping for the given <code>key</code> from this cache, if
-     * present.
-     *
-     * @param  key  The key whose mapping is to be removed
-     *
-     * @return  The value to which this key was mapped, or <code>null</code> if
-     *          there was no mapping for the key
-     */
-    public Object remove(Object key) {
-        processQueue();
-        return ValueCell.strip(hash.remove(key), true);
-    }
-
-    /**
-     * Remove all mappings from this cache.
-     */
-    public void clear() {
-        processQueue();
-        hash.clear();
-    }
-
-
-    /* -- Views -- */
-
-    private static boolean valEquals(Object o1, Object o2) {
-        return (o1 == null) ? (o2 == null) : o1.equals(o2);
-    }
-
-
-    /* Internal class for entries.
-       Because it uses SoftCache.this.queue, this class cannot be static.
-     */
-    private class Entry implements Map.Entry {
-        private Map.Entry ent;
-        private Object value;   /* Strong reference to value, to prevent the GC
-                                   from flushing the value while this Entry
-                                   exists */
-
-        Entry(Map.Entry ent, Object value) {
-            this.ent = ent;
-            this.value = value;
-        }
-
-        public Object getKey() {
-            return ent.getKey();
-        }
-
-        public Object getValue() {
-            return value;
-        }
-
-        public Object setValue(Object value) {
-            return ent.setValue(ValueCell.create(ent.getKey(), value, queue));
-        }
-
-        public boolean equals(Object o) {
-            if (! (o instanceof Map.Entry)) return false;
-            Map.Entry e = (Map.Entry)o;
-            return (valEquals(ent.getKey(), e.getKey())
-                    && valEquals(value, e.getValue()));
-        }
-
-        public int hashCode() {
-            Object k;
-            return ((((k = getKey()) == null) ? 0 : k.hashCode())
-                    ^ ((value == null) ? 0 : value.hashCode()));
-        }
-
-    }
-
-
-    /* Internal class for entry sets */
-    private class EntrySet extends AbstractSet {
-        Set hashEntries = hash.entrySet();
-
-        public Iterator iterator() {
-
-            return new Iterator() {
-                Iterator hashIterator = hashEntries.iterator();
-                Entry next = null;
-
-                public boolean hasNext() {
-                    while (hashIterator.hasNext()) {
-                        Map.Entry ent = (Map.Entry)hashIterator.next();
-                        ValueCell vc = (ValueCell)ent.getValue();
-                        Object v = null;
-                        if ((vc != null) && ((v = vc.get()) == null)) {
-                            /* Value has been flushed by GC */
-                            continue;
-                        }
-                        next = new Entry(ent, v);
-                        return true;
-                    }
-                    return false;
-                }
-
-                public Object next() {
-                    if ((next == null) && !hasNext())
-                        throw new NoSuchElementException();
-                    Entry e = next;
-                    next = null;
-                    return e;
-                }
-
-                public void remove() {
-                    hashIterator.remove();
-                }
-
-            };
-        }
-
-        public boolean isEmpty() {
-            return !(iterator().hasNext());
-        }
-
-        public int size() {
-            int j = 0;
-            for (Iterator i = iterator(); i.hasNext(); i.next()) j++;
-            return j;
-        }
-
-        public boolean remove(Object o) {
-            processQueue();
-            if (o instanceof Entry) return hashEntries.remove(((Entry)o).ent);
-            else return false;
-        }
-
-    }
-
-
-    private Set entrySet = null;
-
-    /**
-     * Return a <code>Set</code> view of the mappings in this cache.
-     */
-    public Set entrySet() {
-        if (entrySet == null) entrySet = new EntrySet();
-        return entrySet;
-    }
-
-}
diff --git a/ojluni/src/main/java/sun/net/spi/nameservice/NameServiceDescriptor.java b/ojluni/src/main/java/sun/net/spi/nameservice/NameServiceDescriptor.java
deleted file mode 100644
index 6e246c5..0000000
--- a/ojluni/src/main/java/sun/net/spi/nameservice/NameServiceDescriptor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.spi.nameservice;
-
-public interface NameServiceDescriptor {
-    /**
-     * Create a new instance of the corresponding name service.
-     */
-    public NameService createNameService () throws Exception ;
-
-    /**
-     * Returns this service provider's name
-     *
-     */
-    public String getProviderName();
-
-    /**
-     * Returns this name service type
-     * "dns" "nis" etc
-     */
-    public String getType();
-}
diff --git a/ojluni/src/main/java/sun/reflect/ConstructorAccessor.java b/ojluni/src/main/java/sun/reflect/ConstructorAccessor.java
deleted file mode 100644
index 7aac26f..0000000
--- a/ojluni/src/main/java/sun/reflect/ConstructorAccessor.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.reflect;
-
-import java.lang.reflect.InvocationTargetException;
-
-/** This interface provides the declaration for
-    java.lang.reflect.Constructor.invoke(). Each Constructor object is
-    configured with a (possibly dynamically-generated) class which
-    implements this interface. */
-
-public interface ConstructorAccessor {
-    /** Matches specification in {@link java.lang.reflect.Constructor} */
-    public Object newInstance(Object[] args)
-        throws InstantiationException,
-               IllegalArgumentException,
-               InvocationTargetException;
-}
diff --git a/ojluni/src/main/java/sun/reflect/package.html b/ojluni/src/main/java/sun/reflect/package.html
deleted file mode 100644
index 7f2bb85..0000000
--- a/ojluni/src/main/java/sun/reflect/package.html
+++ /dev/null
@@ -1,190 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<HTML>
-<HEAD>
-<!--
-
- Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
- DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-
- This code is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License version 2 only, as
- published by the Free Software Foundation.  Oracle designates this
- particular file as subject to the "Classpath" exception as provided
- by Oracle in the LICENSE file that accompanied this code.
-
- This code is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- version 2 for more details (a copy is included in the LICENSE file that
- accompanied this code).
-
- You should have received a copy of the GNU General Public License version
- 2 along with this work; if not, write to the Free Software Foundation,
- Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
- Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- or visit www.oracle.com if you need additional information or have any
- questions.
- 
--->
-</HEAD>
-<BODY BGCOLOR="white">
-<P>
-
-<B> Licensee impact of JDK 1.4 reflection changes </B>
-
-</P>
-<P>
-
-Sun's JDK 1.4 contains a new implementation of java.lang.reflect which
-offers substantially higher performance than previous JDKs' native
-code. Licensees can at their discretion port these changes. There are
-no public API or documentation changes associated with the new
-reflection implementation aside from a few minor clarifications in the
-specifications of Method.invoke(), Constructor.newInstance(), and a
-few methods in java.lang.reflect.Field.
-
-</P>
-<P>
-
-The bulk of the new implementation is Java programming language code
-which generates bytecodes, and is therefore portable. If licensees
-desire to port it, the following JVM changes are required:
-
-<OL>
-<LI> The following four new JVM entry points must be added:
-
- <UL>
- <LI> JVM_GetClassDeclaredConstructors
- <LI> JVM_GetClassDeclaredFields
- <LI> JVM_GetClassDeclaredMethods
- <LI> JVM_GetClassAccessFlags
- </UL>
-
-The first three return the declared constructors, fields, and methods
-for a given class, with an option to return only the public ones. They
-are similar in functionality to the earlier GetClassConstructors,
-GetClassFields, and GetClassMethods.  JVM_GetClassDeclaredFields and
-JVM_GetClassDeclaredMethods must intern the Strings for the names of
-the Field and Method objects returned. The fouth returns the access
-flags for a given class as marked in the class file, as opposed to in
-the InnerClasses attribute if the class is an inner class, and
-therefore differs from JVM_GetClassModifiers for inner classes (most
-importantly, protected inner classes; see 4471811.)
-
-<LI> The JVM's link resolver must be modified to allow all field and
-method references from subclasses of sun.reflect.MagicAccessorImpl to
-any other class (even to private members of other classes) to
-succeed. This allows setAccessible() and its associated checks to be
-implemented in Java.
-
-<LI> The code which calls the verifier must skip verification for all
-subclasses of sun.reflect.MagicAccessorImpl. (It was originally
-intended that only a subset of the stub classes used for serialization
-would not pass the verifier, specifically, those subclassing
-SerializationConstructorAccessorImpl; see 4486457 for a case where
-this does not work.)
-
-<LI> The stack walker for security checks must be modified to skip not
-only all Method.invoke() frames, but also any frames for which the
-class is a subclass of sun.reflect.MethodAccessorImpl.
-
-<LI> The JVM entry points JVM_InvokeMethod and
-JVM_NewInstanceFromConstructor are currently still used because the
-first invocation of the bytecode-based reflection is currently slower
-than the original native code. The security checks they perform can,
-however, be disabled, as they are now performed by Java programming
-language code.
-
-</OL>
-
-</P>
-<P>
-
-The following changes were discovered to be necessary for backward
-compatibility with certain applications (see bug 4474172):
-
-<OL>
-
-<LI> The existing JVM entry point JVM_LatestUserDefinedLoader
-(typically used in applications which rely on the 1.1 security
-framework) must skip reflection-related frames in its stack walk:
-specifically all frames associated with subclasses of
-sun.reflect.MethodAccessorImpl and
-sun.reflect.ConstructorAccessorImpl.
-
-<LI> The new reflection implementation can cause class loading to
-occur in previously-unexpected places (namely during reflective
-calls).  This can cause class loaders which contain subtle bugs to
-break.  In general it is not possible to guarantee complete backward
-bug compatibility, but one kind of bug has been observed more than
-once: the inability of a user-defined loader to handle delegation to
-it for a class it has already loaded. The new reflection
-implementation is predicated on delegation working properly, as it
-loads stub classes into newly-fabricated class loaders of type
-sun.reflect.DelegatingClassLoader, one stub class per loader, to allow
-unloading of the stub classes to occur more quickly. To handle this
-kind of bug, the JVM's internal class lookup mechanism must be
-slightly modified to check for instances of
-sun.reflect.DelegatingClassLoader as the incoming class loader and
-silently traverse the "parent" field once for such loaders before
-entering the bulk of the resolution code. This avoids an upcall to
-Java programming language code which certain loaders can not handle.
-
-</OL>
-
-</P>
-<P>
-
-The following JVM entry points may be deleted:
-
-<UL>
-<LI> JVM_GetClassFields
-<LI> JVM_GetClassMethods
-<LI> JVM_GetClassConstructors
-<LI> JVM_GetClassField
-<LI> JVM_GetClassMethod
-<LI> JVM_GetClassConstructor
-<LI> JVM_NewInstance
-<LI> JVM_GetField
-<LI> JVM_GetPrimitiveField
-<LI> JVM_SetField
-<LI> JVM_SetPrimitiveField
-</UL>
-
-</P>
-<P>
-
-To keep using the previous reflection implementation, licensees should
-not take changes from Sun's JDK 1.4 relating specifically to the
-implementation of reflection in the following classes/methods and
-any associated native code:
-
-<UL>
-<LI> java.lang.Class.newInstance0
-<LI> java.lang.Class.getClassLoader0
-<LI> java.lang.Class.getFields
-<LI> java.lang.Class.getMethods
-<LI> java.lang.Class.getDeclaredFields
-<LI> java.lang.Class.getDeclaredMethods
-<LI> java.lang.Class.getFields0
-<LI> java.lang.Class.getMethods0
-<LI> java.lang.Class.getConstructors0
-<LI> java.lang.Class.getField0
-<LI> java.lang.Class.getMethod0
-<LI> java.lang.Class.getConstructor0
-<LI> java.lang.ClassLoader.getCallerClassLoader
-<LI> java.lang.System.getCallerClass
-<LI> java.lang.reflect.AccessibleObject
-<LI> java.lang.reflect.Constructor
-<LI> java.lang.reflect.Field
-<LI> java.lang.reflect.Method
-<LI> java.lang.reflect.Modifier
-<LI> sun.misc.ClassReflector
-</UL>
-
-</P>
-<!-- Begin ANDROID changed -->
-</BODY>
-<!-- End ANDROID changed -->
-</HTML>
diff --git a/ojluni/src/main/java/sun/security/action/LoadLibraryAction.java b/ojluni/src/main/java/sun/security/action/LoadLibraryAction.java
deleted file mode 100644
index c351015..0000000
--- a/ojluni/src/main/java/sun/security/action/LoadLibraryAction.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.action;
-
-/**
- * A convenience class for loading a system library as a privileged action.
- *
- * <p>An instance of this class can be used as the argument of
- * <code>AccessController.doPrivileged</code>.
- *
- * <p>The following code attempts to load the system library named
- * <code>"lib"</code> as a privileged action: <p>
- *
- * <pre>
- * java.security.AccessController.doPrivileged(new LoadLibraryAction("lib"));
- * </pre>
- *
- * @author Roland Schemers
- * @see java.security.PrivilegedAction
- * @see java.security.AccessController
- * @since 1.2
- */
-
-public class LoadLibraryAction implements java.security.PrivilegedAction<Void> {
-    private String theLib;
-
-    /**
-     * Constructor that takes the name of the system library that needs to be
-     * loaded.
-     *
-     * <p>The manner in which a library name is mapped to the
-     * actual system library is system dependent.
-     *
-     * @param theLib the name of the library.
-     */
-    public LoadLibraryAction(String theLib) {
-        this.theLib = theLib;
-    }
-
-    /**
-     * Loads the system library whose name was specified in the constructor.
-     */
-    public Void run() {
-        System.loadLibrary(theLib);
-        return null;
-    }
-}
diff --git a/ojluni/src/main/java/sun/util/calendar/TzIDOldMapping.java b/ojluni/src/main/java/sun/util/calendar/TzIDOldMapping.java
deleted file mode 100644
index 4f23007..0000000
--- a/ojluni/src/main/java/sun/util/calendar/TzIDOldMapping.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.util.calendar;
-
-import java.util.Map;
-import java.util.HashMap;
-
-class TzIDOldMapping {
-    static final Map<String, String> MAP = new HashMap<String, String>();
-    static {
-        String[][] oldmap = {
-            { "ACT", "Australia/Darwin" },
-            { "AET", "Australia/Sydney" },
-            { "AGT", "America/Argentina/Buenos_Aires" },
-            { "ART", "Africa/Cairo" },
-            { "AST", "America/Anchorage" },
-            { "BET", "America/Sao_Paulo" },
-            { "BST", "Asia/Dhaka" },
-            { "CAT", "Africa/Harare" },
-            { "CNT", "America/St_Johns" },
-            { "CST", "America/Chicago" },
-            { "CTT", "Asia/Shanghai" },
-            { "EAT", "Africa/Addis_Ababa" },
-            { "ECT", "Europe/Paris" },
-            { "EST", "America/New_York" },
-            { "HST", "Pacific/Honolulu" },
-            { "IET", "America/Indianapolis" },
-            { "IST", "Asia/Calcutta" },
-            { "JST", "Asia/Tokyo" },
-            { "MIT", "Pacific/Apia" },
-            { "MST", "America/Denver" },
-            { "NET", "Asia/Yerevan" },
-            { "NST", "Pacific/Auckland" },
-            { "PLT", "Asia/Karachi" },
-            { "PNT", "America/Phoenix" },
-            { "PRT", "America/Puerto_Rico" },
-            { "PST", "America/Los_Angeles" },
-            { "SST", "Pacific/Guadalcanal" },
-            { "VST", "Asia/Saigon" },
-        };
-        for (String[] pair : oldmap) {
-            MAP.put(pair[0], pair[1]);
-        }
-    }
-}
diff --git a/ojluni/src/test/java/time/tck/java/time/TCKInstant.java b/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
index 3d89db5..1b8fea7 100644
--- a/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
+++ b/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
@@ -1931,6 +1931,16 @@
         Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1).toEpochMilli();
     }
 
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_toEpochMillis_overflow() {
+        Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 809_000_000).toEpochMilli();
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_toEpochMillis_overflow2() {
+        Instant.ofEpochSecond(-9223372036854776L, 1).toEpochMilli();
+    }
+
     //-----------------------------------------------------------------------
     // compareTo()
     //-----------------------------------------------------------------------
diff --git a/ojluni/src/test/java/time/test/java/time/TestInstant.java b/ojluni/src/test/java/time/test/java/time/TestInstant.java
index cf135a1..203bb57 100644
--- a/ojluni/src/test/java/time/test/java/time/TestInstant.java
+++ b/ojluni/src/test/java/time/test/java/time/TestInstant.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -62,6 +62,8 @@
 import java.time.Instant;
 
 import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.assertEquals;
 
 /**
  * Test Instant.
@@ -74,4 +76,24 @@
         assertImmutable(Instant.class);
     }
 
+    @DataProvider(name="sampleEpochMillis")
+    private Object[][] provider_sampleEpochMillis() {
+        return new Object[][] {
+            {"Long.MAX_VALUE", Long.MAX_VALUE},
+            {"Long.MAX_VALUE-1", Long.MAX_VALUE - 1},
+            {"1", 1L},
+            {"0", 0L},
+            {"-1", -1L},
+            {"Long.MIN_VALUE+1", Long.MIN_VALUE + 1},
+            {"Long.MIN_VALUE", Long.MIN_VALUE}
+        };
+    }
+
+    @Test(dataProvider="sampleEpochMillis")
+    public void test_epochMillis(String name, long millis) {
+        Instant t1 = Instant.ofEpochMilli(millis);
+        long m = t1.toEpochMilli();
+        assertEquals(millis, m, name);
+    }
+
 }
diff --git a/ojluni/src/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java b/ojluni/src/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java
index 9fbe6d1..ab61c71 100644
--- a/ojluni/src/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java
+++ b/ojluni/src/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java
@@ -30,6 +30,7 @@
 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
 import static java.time.temporal.ChronoField.YEAR;
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
@@ -530,6 +531,23 @@
         assertEquals(date.isLeapYear(), leapyear);
     }
 
+    // Data provider to verify that a given hijrah year is outside the range of supported years
+    // The values are dependent on the currently configured UmmAlQura calendar data
+    @DataProvider(name="OutOfRangeLeapYears")
+    Object[][] data_invalid_leapyears() {
+        return new Object[][] {
+                {1299},
+                {1601},
+                {Integer.MAX_VALUE},
+                {Integer.MIN_VALUE},
+        };
+    }
+
+    @Test(dataProvider="OutOfRangeLeapYears")
+    public void test_notLeapYears(int y) {
+        assertFalse(HijrahChronology.INSTANCE.isLeapYear(y), "Out of range leap year");
+    }
+
     // Date samples to convert HijrahDate to LocalDate and vice versa
     @DataProvider(name="samples")
     Object[][] data_samples() {
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index a64b131..50c4b84 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -800,7 +800,6 @@
     ojluni/src/main/java/java/time/Duration.java \
     ojluni/src/main/java/java/time/LocalDateTime.java \
     ojluni/src/main/java/java/time/OffsetDateTime.java \
-    ojluni/src/main/java/java/time/overview.html \
     ojluni/src/main/java/java/time/Instant.java \
     ojluni/src/main/java/java/time/temporal/ValueRange.java \
     ojluni/src/main/java/java/time/temporal/TemporalAmount.java \
@@ -1357,7 +1356,6 @@
     ojluni/src/main/java/jdk/net/NetworkPermission.java \
     ojluni/src/main/java/jdk/net/SocketFlow.java \
     ojluni/src/main/java/jdk/net/Sockets.java \
-    ojluni/src/main/java/sun/invoke/empty/Empty.java \
     ojluni/src/main/java/sun/invoke/util/BytecodeDescriptor.java \
     ojluni/src/main/java/sun/invoke/util/Wrapper.java \
     ojluni/src/main/java/sun/invoke/util/VerifyAccess.java \
@@ -1381,7 +1379,6 @@
     ojluni/src/main/java/sun/misc/IOUtils.java \
     ojluni/src/main/java/sun/misc/JarIndex.java \
     ojluni/src/main/java/sun/misc/JavaIOFileDescriptorAccess.java \
-    ojluni/src/main/java/sun/misc/JavaSecurityProtectionDomainAccess.java \
     ojluni/src/main/java/sun/misc/LRUCache.java \
     ojluni/src/main/java/sun/misc/MessageUtils.java \
     ojluni/src/main/java/sun/misc/MetaIndex.java \
@@ -1389,10 +1386,7 @@
     ojluni/src/main/java/sun/misc/RegexpPool.java \
     ojluni/src/main/java/sun/misc/RegexpTarget.java \
     ojluni/src/main/java/sun/misc/Resource.java \
-    ojluni/src/main/java/sun/misc/ServiceConfigurationError.java \
     ojluni/src/main/java/sun/misc/SharedSecrets.java \
-    ojluni/src/main/java/sun/misc/Service.java \
-    ojluni/src/main/java/sun/misc/SoftCache.java \
     ojluni/src/main/java/sun/misc/URLClassPath.java \
     ojluni/src/main/java/sun/misc/Unsafe.java \
     ojluni/src/main/java/sun/misc/Version.java \
@@ -1420,7 +1414,6 @@
     ojluni/src/main/java/sun/net/ResourceManager.java \
     ojluni/src/main/java/sun/net/SocksProxy.java \
     ojluni/src/main/java/sun/net/spi/DefaultProxySelector.java \
-    ojluni/src/main/java/sun/net/spi/nameservice/NameServiceDescriptor.java \
     ojluni/src/main/java/sun/net/spi/nameservice/NameService.java \
     ojluni/src/main/java/sun/net/TelnetInputStream.java \
     ojluni/src/main/java/sun/net/TelnetOutputStream.java \
@@ -1556,13 +1549,11 @@
     ojluni/src/main/java/sun/nio/fs/UnixUriUtils.java \
     ojluni/src/main/java/sun/nio/fs/UnixUserPrincipals.java \
     ojluni/src/main/java/sun/nio/fs/Util.java \
-    ojluni/src/main/java/sun/reflect/ConstructorAccessor.java \
     ojluni/src/main/java/sun/reflect/misc/ReflectUtil.java \
     ojluni/src/main/java/sun/reflect/Reflection.java \
     ojluni/src/main/java/sun/security/action/GetBooleanAction.java \
     ojluni/src/main/java/sun/security/action/GetIntegerAction.java \
     ojluni/src/main/java/sun/security/action/GetPropertyAction.java \
-    ojluni/src/main/java/sun/security/action/LoadLibraryAction.java \
     ojluni/src/main/java/sun/security/jca/GetInstance.java \
     ojluni/src/main/java/sun/security/jca/JCAUtil.java \
     ojluni/src/main/java/sun/security/jca/ProviderConfig.java \
@@ -1721,7 +1712,6 @@
     ojluni/src/main/java/sun/util/calendar/ImmutableGregorianDate.java \
     ojluni/src/main/java/sun/util/calendar/JulianCalendar.java \
     ojluni/src/main/java/sun/util/calendar/LocalGregorianCalendar.java \
-    ojluni/src/main/java/sun/util/calendar/TzIDOldMapping.java \
     ojluni/src/main/java/sun/util/locale/BaseLocale.java \
     ojluni/src/main/java/sun/util/locale/Extension.java \
     ojluni/src/main/java/sun/util/locale/InternalLocaleBuilder.java \
diff --git a/tzdata/update2/src/main/libcore/tzdata/update2/BundleVersion.java b/tzdata/update2/src/main/libcore/tzdata/update2/BundleVersion.java
index 1889f18..775846f 100644
--- a/tzdata/update2/src/main/libcore/tzdata/update2/BundleVersion.java
+++ b/tzdata/update2/src/main/libcore/tzdata/update2/BundleVersion.java
@@ -28,7 +28,8 @@
 
     /**
      * The major bundle format version supported by this device.
-     * Increment this for non-backwards compatible changes to the bundle format.
+     * Increment this for non-backwards compatible changes to the bundle format. Reset the minor
+     * version to 1 when doing so.
      */
     public static final int CURRENT_FORMAT_MAJOR_VERSION = 1;
 
@@ -189,8 +190,9 @@
     }
 
     private static int validate3DigitVersion(int value) throws BundleException {
-        if (value < 1 || value > 999) {
-            throw new BundleException("Expected 1 <= value <= 999, was " + value);
+        // 0 is allowed but is reserved for testing.
+        if (value < 0 || value > 999) {
+            throw new BundleException("Expected 0 <= value <= 999, was " + value);
         }
         return value;
     }
diff --git a/tzdata/update2/src/test/libcore/tzdata/update2/BundleVersionTest.java b/tzdata/update2/src/test/libcore/tzdata/update2/BundleVersionTest.java
index 3c2bff8..fe9023e 100644
--- a/tzdata/update2/src/test/libcore/tzdata/update2/BundleVersionTest.java
+++ b/tzdata/update2/src/test/libcore/tzdata/update2/BundleVersionTest.java
@@ -20,7 +20,7 @@
 
 public class BundleVersionTest extends TestCase {
 
-    private static final int INVALID_VERSION_LOW = 0;
+    private static final int INVALID_VERSION_LOW = -1;
     private static final int VALID_VERSION = 23;
     private static final int INVALID_VERSION_HIGH = 1000;
     private static final String VALID_RULES_VERSION = "2016a";
@@ -79,19 +79,20 @@
                 BundleVersion.CURRENT_FORMAT_MINOR_VERSION + 1);
         assertTrue(BundleVersion.isCompatibleWithThisDevice(newerMinor));
 
-        if (BundleVersion.CURRENT_FORMAT_MAJOR_VERSION > 1) {
-            BundleVersion olderMajor = createBundleVersion(
-                    BundleVersion.CURRENT_FORMAT_MAJOR_VERSION - 1,
-                    BundleVersion.CURRENT_FORMAT_MINOR_VERSION);
-            assertFalse(BundleVersion.isCompatibleWithThisDevice(olderMajor));
-        }
+        // The constant versions should never be below 1. We allow 0 but want to start version
+        // numbers at 1 to allow testing of older version logic.
+        assertTrue(BundleVersion.CURRENT_FORMAT_MAJOR_VERSION >= 1);
+        assertTrue(BundleVersion.CURRENT_FORMAT_MINOR_VERSION >= 1);
 
-        if (BundleVersion.CURRENT_FORMAT_MINOR_VERSION > 1) {
-            BundleVersion olderMinor = createBundleVersion(
-                    BundleVersion.CURRENT_FORMAT_MAJOR_VERSION,
-                    BundleVersion.CURRENT_FORMAT_MINOR_VERSION - 1);
-            assertFalse(BundleVersion.isCompatibleWithThisDevice(olderMinor));
-        }
+        BundleVersion olderMajor = createBundleVersion(
+                BundleVersion.CURRENT_FORMAT_MAJOR_VERSION - 1,
+                BundleVersion.CURRENT_FORMAT_MINOR_VERSION);
+        assertFalse(BundleVersion.isCompatibleWithThisDevice(olderMajor));
+
+        BundleVersion olderMinor = createBundleVersion(
+                BundleVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                BundleVersion.CURRENT_FORMAT_MINOR_VERSION - 1);
+        assertFalse(BundleVersion.isCompatibleWithThisDevice(olderMinor));
     }
 
     private BundleVersion createBundleVersion(int majorFormatVersion, int minorFormatVersion)