Merge "Update misc java.util classes to OpenJDK 9+181 and immediately expose API" am: 7566262b49 am: 216f859e2c am: bc064c373f

Change-Id: I60309d4fb0370a3965f5c29dc233c6abfa136df8
diff --git a/luni/src/module/java/module-info.java b/luni/src/module/java/module-info.java
index 8a290d9..6c2bc12 100644
--- a/luni/src/module/java/module-info.java
+++ b/luni/src/module/java/module-info.java
@@ -69,6 +69,8 @@
     exports javax.security.auth.x500;
     exports javax.security.cert;
     exports javax.sql;
+    exports jdk.internal.util;
+    exports jdk.internal.vm.annotation;
     exports jdk.net;
     exports sun.invoke.util;
     exports sun.misc;
diff --git a/luni/src/test/java/libcore/java/util/AbstractListTest.java b/luni/src/test/java/libcore/java/util/AbstractListTest.java
new file mode 100644
index 0000000..e0c4db2
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/AbstractListTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2020 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.util;
+
+import junit.framework.AssertionFailedError;
+
+import org.junit.Test;
+
+import java.util.AbstractList;
+import java.util.AbstractSequentialList;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.RandomAccess;
+import java.util.Spliterator;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class AbstractListTest {
+    @Test public void sublist_outOfBounds() {
+        assertSubListOutOfBounds(new RandomAccessList(/* size */ 0), 0, 1);
+        assertSubListOutOfBounds(new RandomAccessList(/* size */ 10), 0, 11);
+        assertSubListOutOfBounds(new RandomAccessList(/* size */ 10), -1, 10);
+        assertSubListOutOfBounds(new RandomAccessList(/* size */ 10), -1, 11);
+
+        assertSubListOutOfBounds(new SequentialList(/* elements */), 0, 1);
+        assertSubListOutOfBounds(new SequentialList(/* elements */ 10, 20, 30), 0, 4);
+        assertSubListOutOfBounds(new SequentialList(/* elements */ 10, 20, 30), -1, 3);
+
+        // These ones work
+        new RandomAccessList(/* size */ 0).subList(0, 0);
+        new RandomAccessList(/* size */ 10).subList(0, 10);
+        new RandomAccessList(/* size */ 10).subList(2, 5);
+        new SequentialList(/* elements */).subList(0, 0);
+        new SequentialList(/* elements */ 10, 20, 30).subList(0, 3);
+    }
+
+    private static<T> void assertSubListOutOfBounds(List<T> list, int startIndex, int endIndex) {
+        try {
+            list.subList(startIndex, endIndex);
+            fail();
+        } catch (IndexOutOfBoundsException expected) {
+        }
+    }
+
+    /** Checks that list.spliterator() is late-binding. */
+    @Test public void spliterator_lateBinding() {
+        List<Integer> list = new RandomAccessList(50);
+        Spliterator<Integer> spliterator = list.spliterator();
+        Integer newFirstValue = list.get(0) + 3000;
+        list.add(0, newFirstValue); // prepend
+        AtomicReference<Integer> receivedValue = new AtomicReference<>(null);
+        // No ConcurrentModificationException because of late-binding Spliterator
+        boolean didAdvance = spliterator.tryAdvance(value -> receivedValue.set(value));
+        // Expect the values at index 0 from after the add(), not from after the spliterator().
+        assertEquals(newFirstValue, receivedValue.get());
+        assertTrue(didAdvance);
+    }
+
+    @Test public void spliterator_modification_failFast() {
+        List<Integer> list = new RandomAccessList(50);
+        Integer expectedValue = list.get(2);
+        Spliterator<Integer> spliterator = list.spliterator();
+        // We need to perform at least one action on the spliterator because only then does
+        // it initialize its internal expectedModCount.
+        assertTrue(spliterator.tryAdvance(value -> {}));
+        assertTrue(spliterator.tryAdvance(value -> {}));
+        list.add(42); // concurrent modification
+        AtomicReference<Integer> receivedValue = new AtomicReference<>(null);
+        try {
+            spliterator.tryAdvance(value -> receivedValue.set(value));
+            fail();
+        } catch (ConcurrentModificationException expected) {
+        }
+        // I believe it would also be within spec for this to remain unset (null),
+        // but the current implementation checks for concurrent modification only after
+        // delivering the value. We're asserting that so that we notice if the behavior
+        // ever changes in future.
+        assertEquals(expectedValue, receivedValue.get());
+    }
+
+    @Test public void spliteratorOfRandomAccessList_usesOnlyRandomAccess() {
+        checkSpliteratorOfOnlyRandomAccessList_usesOnlyRandomAccess(0);
+        checkSpliteratorOfOnlyRandomAccessList_usesOnlyRandomAccess(1);
+        checkSpliteratorOfOnlyRandomAccessList_usesOnlyRandomAccess(2);
+        checkSpliteratorOfOnlyRandomAccessList_usesOnlyRandomAccess(100);
+    }
+
+    private static void checkSpliteratorOfOnlyRandomAccessList_usesOnlyRandomAccess(int listSize) {
+        checkSpliteratorOfRandomAccessList(listSize,
+                () -> new OnlyRandomAccessList(listSize));
+        int subListSize = listSize / 2;
+        checkSpliteratorOfRandomAccessList(
+                subListSize,
+                () -> new OnlyRandomAccessList(listSize).subList(0, subListSize));
+    }
+
+    /**
+     * Checks basic operations on supplied RandomAccess Lists. If the supplied Lists are
+     * {@link OnlyRandomAccessList} or its sublists, then that has the side-effect of
+     * checking that only random-access operations are attempted.
+     */
+    // We're using a Supplier<List> to keep constructing new Lists because some of the testers
+    // have the side effect of sorting the List.
+    private static void checkSpliteratorOfRandomAccessList(int size,
+            Supplier<List<Integer>> listSupplier) {
+        assertTrue(listSupplier.get() instanceof RandomAccess);
+        assertEquals(size, listSupplier.get().size());
+
+        Supplier<Spliterator<Integer>> spliteratorSupplier = () -> listSupplier.get().spliterator();
+        List<Integer> expectedList = new ArrayList<>();
+        for (int index = 0; index < size; index++) {
+            expectedList.add(RandomAccessList.initialValue(index));
+        }
+
+        SpliteratorTester.runBasicIterationTests(spliteratorSupplier.get(), expectedList);
+        SpliteratorTester.runBasicSplitTests(spliteratorSupplier.get(), expectedList,
+                Comparator.naturalOrder());
+        SpliteratorTester.testSpliteratorNPE(spliteratorSupplier.get());
+
+        assertTrue(spliteratorSupplier.get().hasCharacteristics(
+                Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED));
+
+        SpliteratorTester.runSizedTests(spliteratorSupplier.get(), size /* expected size */);
+        if (spliteratorSupplier.get().trySplit() != null) {
+            SpliteratorTester.runSubSizedTests(spliteratorSupplier.get(), size);
+        } else {
+            assertTrue(size <= 1); // trySplit() should work for lists sized > 1.
+        }
+    }
+
+    static class SequentialList extends AbstractSequentialList<Integer> {
+        private final List<Integer> delegate;
+
+        public SequentialList(Integer... elements) {
+            this.delegate = Collections.unmodifiableList(Arrays.asList(elements));
+        }
+
+        @Override public ListIterator<Integer> listIterator(int index) {
+            return delegate.listIterator(index);
+        }
+
+        @Override public int size() { return delegate.size(); }
+    }
+
+    /**
+     * A simple list that allows random-access {@code get()} and modifications. This
+     * implementation increases {@link AbstractList#modCount} during {@code add()}
+     * and {@code remove()} to provide fail-fast Spliterators.
+     */
+    static class RandomAccessList extends AbstractList<Integer> implements RandomAccess {
+        protected final List<Integer> delegate;
+
+        public RandomAccessList(int size) {
+            this.delegate = new ArrayList<>(size);
+            for (int i = 0; i < size; i++) {
+                delegate.add(initialValue(i));
+            }
+        }
+
+        static Integer initialValue(int index) { return 31337 ^ index; }
+
+        @Override public Integer get(int index) { return delegate.get(index); }
+        @Override public int size() { return delegate.size(); }
+        @Override public Integer set(int index, Integer v) { return delegate.set(index, v); }
+        @Override public void add(int index, Integer element) {
+            modCount++;
+            delegate.add(index, element);
+        }
+        @Override public Integer remove(int index) {
+            modCount++;
+            return delegate.remove(index);
+        }
+    }
+
+    /**
+     * A {@link RandomAccessList} that throws if a caller attempts {@link #iterator()
+     * iterative access}.
+     */
+    static class OnlyRandomAccessList extends RandomAccessList {
+        public OnlyRandomAccessList(int size) {
+            super(size);
+        }
+        @Override public Iterator<Integer> iterator() {
+            throw new AssertionFailedError();
+        }
+
+        @Override public ListIterator<Integer> listIterator(int index) {
+            throw new AssertionFailedError();
+        }
+
+    }
+
+}
diff --git a/luni/src/test/java/libcore/java/util/ListOfTest.java b/luni/src/test/java/libcore/java/util/ListOfTest.java
new file mode 100644
index 0000000..04b787f
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/ListOfTest.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2020 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.util;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.RandomAccess;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import libcore.libcore.util.SerializationTester;
+import libcore.util.NonNull;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class ListOfTest {
+
+    @Test
+    public void serializationCompatibility_empty() {
+        String golden = "ACED00057372001F6A6176612E7574696C2E436F6C6C656374696F6E7324456D7074794C69"
+                + "73747AB817B43CA79EDE0200007870";
+        new SerializationTester<>(List.<String>of(), golden).test();
+    }
+
+    @Test public void serializationCompatibility_oneElement() {
+        String golden = "ACED0005737200266A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C654C697374FC0F2531B5EC8E100200014C00046C6973747400104C6A6176612F7574696C"
+                + "2F4C6973743B7872002C6A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F64696669"
+                + "61626C65436F6C6C656374696F6E19420080CB5EF71E0200014C0001637400164C6A6176612F7574"
+                + "696C2F436F6C6C656374696F6E3B7870737200136A6176612E7574696C2E41727261794C69737478"
+                + "81D21D99C7619D03000149000473697A657870000000017704000000017400036F6E657871007E00"
+                + "06";
+        new SerializationTester<>(List.of("one"), golden).test();
+    }
+
+    @Test public void serializationCompatibility_manyElements() {
+        String golden = "ACED0005737200266A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C654C697374FC0F2531B5EC8E100200014C00046C6973747400104C6A6176612F7574696C"
+                + "2F4C6973743B7872002C6A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F64696669"
+                + "61626C65436F6C6C656374696F6E19420080CB5EF71E0200014C0001637400164C6A6176612F7574"
+                + "696C2F436F6C6C656374696F6E3B7870737200136A6176612E7574696C2E41727261794C69737478"
+                + "81D21D99C7619D03000149000473697A6578700000000D77040000000D737200116A6176612E6C61"
+                + "6E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C61"
+                + "6E672E4E756D62657286AC951D0B94E08B02000078700000000C7371007E00070000000B7371007E"
+                + "00070000000A7371007E0007000000097371007E0007000000087371007E0007000000077371007E"
+                + "0007000000067371007E0007000000057371007E0007000000047371007E0007000000037371007E"
+                + "0007000000027371007E0007000000017371007E0007000000007871007E0006";
+        new SerializationTester<>(List.of(12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), golden).test();
+    }
+
+    @Test public void mixedTypes() {
+        List<?> list = List.of("element", 42);
+        assertEquals(asList("element", 42), list);
+
+        assertTrue(list.contains("element"));
+        assertTrue(list.contains(42));
+        assertFalse(list.contains(new Object()));
+        assertFalse(list.contains(31));
+    }
+
+    @Test public void duplicates_allowed() {
+        // duplicates values are allowed for List.of(), but not for Set.of()
+        check_nonEmpty(asList("duplicate", "duplicate"), List.of("duplicate", "duplicate"));
+    }
+
+    @Test public void empty() {
+        assertBehaviorCommonToAllOfInstances(
+                Collections.<String>emptyList(), List.<String>of(), "non-null example String");
+    }
+
+    @Test public void nonEmpty() {
+        check_nonEmpty(asList("one"), List.of("one"));
+        check_nonEmpty(asList("one", "two"), List.of("one", "two"));
+        check_nonEmpty(asList("one", "two", "three"), List.of("one", "two", "three"));
+        check_nonEmpty(asList("one", "two", "three", "four"),
+                List.of("one", "two", "three", "four"));
+        check_nonEmpty(asList("one", "two", "three", "four", "five"),
+                List.of("one", "two", "three", "four", "five"));
+        check_nonEmpty(asList("one", "two", "three", "four", "five", "six"),
+                List.of("one", "two", "three", "four", "five", "six"));
+        check_nonEmpty(asList("one", "two", "three", "four", "five", "six", "seven"),
+                List.of("one", "two", "three", "four", "five", "six", "seven"));
+        check_nonEmpty(asList(1, 2, 3, 4, 5, 6, 7, 8), List.of(1, 2, 3, 4, 5, 6, 7, 8));
+        check_nonEmpty(asList(1, 2, 3, 4, 5, 6, 7, 8, 9), List.of(1, 2, 3, 4, 5, 6, 7, 8, 9));
+        check_nonEmpty(asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
+                List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
+        check_nonEmpty(asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
+                List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
+        check_nonEmpty(asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
+                List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12));
+        check_nonEmpty(asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+                List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13));
+    }
+
+    @Test public void null_examples() {
+        assertThrowsNpe(() -> List.<String>of((String) null)); // one-arg version
+        assertThrowsNpe(() -> List.<String[]>of((String[]) null)); // null var-args array
+        assertThrowsNpe(() -> List.<String>of(new String[] { "one", null, "three"})); // var-args
+
+        assertThrowsNpe(() -> List.of(null, "two"));
+        assertThrowsNpe(() -> List.of("one", null));
+        assertThrowsNpe(
+                () -> List.of(null, "two", "three", "four", "five", "six", "seven"));
+        assertThrowsNpe(
+                () -> List.of("one", "two", "three", "four", "five", "six", null));
+    }
+
+    @Test public void null_comprehensive() {
+        List<Integer> template = asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
+        for (int i = 0; i < template.size(); i++) {
+            Integer[] l = template.toArray(new Integer[0]);
+            l[i] = null;
+            npe(i <= 0, () -> List.of(l[0]));
+            npe(i <= 1, () -> List.of(l[0], l[1]));
+            npe(i <= 2, () -> List.of(l[0], l[1], l[2]));
+            npe(i <= 3, () -> List.of(l[0], l[1], l[2], l[3]));
+            npe(i <= 4, () -> List.of(l[0], l[1], l[2], l[3], l[4]));
+            npe(i <= 5, () -> List.of(l[0], l[1], l[2], l[3], l[4], l[5]));
+            npe(i <= 6, () -> List.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6]));
+            npe(i <= 7, () -> List.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7]));
+            npe(i <= 8, () -> List.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8]));
+            npe(i <= 9, () -> List.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9]));
+            npe(i <= 10, () -> List.of(
+                    l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10]));
+            npe(i <= 11, () -> List.of(
+                    l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10], l[11]));
+            npe(i <= 12, () -> List.of(
+                    l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10], l[11], l[12])
+            );
+        }
+    }
+
+    /**
+     * Asserts that {@code runnable.run()} throws {@link NullPointerException} if
+     * any only if {@code expectedToThrowNpe}.
+     */
+    private static void npe(boolean expectedToThrowNpe, Runnable runnable) {
+        if (expectedToThrowNpe) {
+            assertThrowsNpe(runnable);
+        } else {
+            runnable.run(); // should not throw
+        }
+    }
+
+    private static<T extends Comparable<T>> void check_nonEmpty(List<T> expected, List<T> actual) {
+        T example = actual.iterator().next();
+        assertBehaviorCommonToAllOfInstances(expected, actual, example);
+    }
+
+    /** Checks assertions that hold for all List.of() instances. */
+    private static<T extends Comparable<T>> void assertBehaviorCommonToAllOfInstances(
+            List<T> expected, List<T> actual, @NonNull T example) {
+        assertNotNull(example);
+        assertEquals(expected, actual);
+        assertEquals(expected.size(), actual.size());
+        assertEquals(expected.hashCode(), actual.hashCode());
+        assertEquals(actual.isEmpty(), actual.isEmpty());
+        assertEquals(actual.size() == 0, actual.isEmpty());
+        SpliteratorTester.runBasicIterationTests(actual.spliterator(), expected);
+        if (expected.isEmpty()) {
+            assertEquals(expected, actual.subList(0, 0));
+        } else {
+            assertEquals(expected.subList(1, expected.size()), actual.subList(1, actual.size()));
+        }
+        assertEquals(expected.contains(example), actual.contains(example));
+        assertFalse(actual.contains("absent-element"));
+        assertFalse(actual.contains(new Object()));
+        assertThrowsNpe(() -> actual.contains(null));
+        assertEquals(expected.toString(), actual.toString());
+
+        assertUnmodifiable(actual, example);
+        assertEquals(actual, reserialize((Serializable) actual));
+        assertTrue(actual instanceof RandomAccess);
+    }
+
+    private static<T extends Comparable<T>> void assertUnmodifiable(List<T> list, T example) {
+        List<T> examples = Collections.singletonList(example);
+        assertThrowsUoe(() -> { list.add(example); } );
+        assertThrowsUoe(() -> { list.addAll(examples); } );
+        assertThrowsUoe(() -> { list.addAll(0, examples); } );
+        // List.of() documentation guarantees that the following operations throw
+        // UnsupportedOperationException, even though some other implementations don't
+        // do that in the case of isEmpty().
+        assertThrowsUoe(() -> { list.clear(); });
+        assertThrowsUoe(() -> { list.remove(example); } );
+        assertThrowsUoe(() -> { list.removeAll(examples); } );
+        assertThrowsUoe(() -> { list.removeIf(Predicate.isEqual(example)); } );
+        assertThrowsUoe(() -> { list.replaceAll(UnaryOperator.identity()); } );
+        assertThrowsUoe(() -> { list.retainAll(examples); } );
+        assertThrowsUoe(() -> { list.sort(Comparator.<T>naturalOrder()); } );
+    }
+
+    private static void assertThrowsUoe(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    private static void assertThrowsNpe(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (NullPointerException expected) {
+        }
+    }
+
+    private static <S extends Serializable> S reserialize(S value) {
+        try {
+            return (S) SerializationTester.reserialize(value);
+        } catch (IOException | ClassNotFoundException e) {
+            fail("Unexpected exception: " + e.getMessage());
+            throw new AssertionError(e); // unreachable
+        }
+    }
+}
diff --git a/luni/src/test/java/libcore/java/util/MapOfTest.java b/luni/src/test/java/libcore/java/util/MapOfTest.java
new file mode 100644
index 0000000..68e20a7
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/MapOfTest.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2020 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.util;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import libcore.libcore.util.SerializationTester;
+
+import static java.util.Map.entry;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests {@code Map.of()} overloads and {@code Map.ofEntries(...)}.
+ */
+@RunWith(Parameterized.class)
+public class MapOfTest {
+
+    @Test public void serializationCompatibility_empty() {
+        String golden = "ACED0005737200256A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C654D6170F1A5A8FE74F507420200014C00016D74000F4C6A6176612F7574696C2F4D6170"
+                + "3B7870737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F"
+                + "6164466163746F724900097468726573686F6C6478703F4000000000000177080000000100000000"
+                + "78";
+        new SerializationTester<>(create(), golden).test();
+    }
+
+    @Test public void serializationCompatibility_oneElement() {
+        String golden = "ACED0005737200256A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C654D6170F1A5A8FE74F507420200014C00016D74000F4C6A6176612F7574696C2F4D6170"
+                + "3B7870737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F"
+                + "6164466163746F724900097468726573686F6C6478703F4000000000000177080000000200000001"
+                + "7400036F6E65737200116A6176612E6C616E672E496E746567657212E2A0A4F78187380200014900"
+                + "0576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000"
+                + "00000178";
+        new SerializationTester<>(create(entry("one", 1)), golden).test();
+    }
+
+    @Test public void serializationCompatibility_manyElements() {
+        String golden = "ACED0005737200256A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C654D6170F1A5A8FE74F507420200014C00016D74000F4C6A6176612F7574696C2F4D6170"
+                + "3B7870737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F"
+                + "6164466163746F724900097468726573686F6C6478703F4000000000000C7708000000100000000A"
+                + "7400046E696E65737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149"
+                + "000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870"
+                + "000000097400037369787371007E000600000006740004666F75727371007E000600000004740003"
+                + "6F6E657371007E000600000001740005736576656E7371007E00060000000774000374656E737100"
+                + "7E00060000000A74000374776F7371007E00060000000274000574687265657371007E0006000000"
+                + "03740004666976657371007E00060000000574000565696768747371007E00060000000878";
+        new SerializationTester<>(
+                create(entry("one", 1), entry("two", 2), entry("three", 3),
+                entry("four", 4), entry("five", 5), entry("six", 6), entry("seven", 7),
+                entry("eight", 8), entry("nine", 9), entry("ten", 10)), golden).test();
+    }
+
+    @Test public void duplicates_sameKey() {
+        Map.Entry[] entries = { entry("duplicateKey", 23), entry("duplicateKey", 42) };
+        assertThrowsIae(() -> creator.create(entries));
+    }
+
+    @Test public void duplicates_sameEntry() {
+        Map.Entry[] entries = { entry("duplicateKey", 42), entry("duplicateKey", 42) };
+        assertThrowsIae(() -> creator.create(entries));
+    }
+
+    @Test public void duplicates_manyElements() {
+        Map.Entry[] entries = {
+                entry("key1", 1),
+                entry("duplicateKey", 23),
+                entry("key2", 2),
+                entry("duplicateKey", 42) };
+        assertThrowsIae(() -> creator.create(entries));
+    }
+
+    @Test public void empty() {
+        assertBehaviorCommonToAllOfInstances("exampleKey", 42);
+    }
+
+    @Test public void nullEntries() {
+        assertThrowsNpe(() -> Map.ofEntries((Map.Entry[]) null));
+        assertThrowsNpe(() -> Map.ofEntries((Map.Entry) null));
+        List<Map.Entry<String, Integer>> sampleEntries = new ArrayList<>();
+        for (int i = 0; i < 10; i++) {
+            sampleEntries.add(entry("key" + i, i));
+        }
+        for (int size = 0; size <= sampleEntries.size(); size++) {
+            for (int nullIndex = 0; nullIndex < size; nullIndex++) {
+                Map.Entry[] entries = sampleEntries.subList(0, size).toArray(
+                        (Map.Entry<String, Integer>[]) new Map.Entry[0]);
+                entries[nullIndex] = null;
+                assertThrowsNpe(() -> Map.ofEntries(entries));
+            }
+        }
+    }
+
+    @Test public void oneEntry() {
+        assertBehaviorCommonToAllOfInstances(
+                "exampleKey", 42, entry("key", "value"));
+    }
+
+    @Test public void twoEntries() {
+        assertBehaviorCommonToAllOfInstances(
+                "exampleKey", 42, entry("key1", "value1"), entry("key2", "value2"));
+    }
+
+    @Test public void manyEntries() {
+        List<Map.Entry<String, Integer>> sampleEntries = new ArrayList<>();
+        for (int i = 0; i < 10; i++) {
+            sampleEntries.add(entry("key" + i, i));
+        }
+        for (int size = 0; size <= sampleEntries.size(); size++) {
+            Map.Entry[] entries = sampleEntries.subList(0, size).toArray(
+                    (Map.Entry<String, Integer>[]) new Map.Entry[0]);
+            assertBehaviorCommonToAllOfInstances("key0", 42, entries);
+        }
+    }
+
+    @Test public void entry_nullKeyOrValue() {
+        assertThrowsNpe(() -> entry(null, "value"));
+        assertThrowsNpe(() -> entry("key", null));
+        assertThrowsNpe(() -> entry(null, null));
+
+        // This one works
+        entry("key", "value");
+    }
+
+    @Test public void of_nullKeyOrValue() {
+        assertThrowsNpe(() -> Map.of(null, "value"));
+        assertThrowsNpe(() -> Map.of("key", null));
+        assertThrowsNpe(() -> Map.of("k1", "v1", "k2", "v2", null, "v3", "k4", "v4"));
+        assertThrowsNpe(() -> Map.of("k1", "v1", "k2", "v2", "k3", null, "k4", "v4"));
+    }
+
+    @Test public void mixedEntryTypes() {
+        assertBehaviorCommonToAllOfInstances(
+                "onekey", "new value", entry("oneKey", 1), entry(2, "twoValue"));
+    }
+
+    private static<K, V> void assertUnmodifiable(Map<K, V> map, K exampleKey, V exampleValue) {
+        Map<K, V> exampleEntries = Collections.singletonMap(exampleKey, exampleValue);
+        assertThrowsUoe(() -> map.put(exampleKey, exampleValue));
+        assertThrowsUoe(() -> map.putAll(exampleEntries));
+        assertThrowsUoe(() -> map.remove(exampleKey));
+        assertThrowsUoe(() -> map.remove(exampleKey, exampleValue));
+        assertThrowsUoe(() -> map.clear());
+        assertThrowsUoe(() -> map.replace(exampleKey, exampleValue, null));
+        assertThrowsUoe(() -> map.putIfAbsent(exampleKey, exampleValue));
+        assertThrowsUoe(() -> map.entrySet().clear());
+        assertThrowsUoe(() -> map.keySet().clear());
+        assertThrowsUoe(() -> map.values().clear());
+
+        if (!map.isEmpty()) {
+            Map.Entry<K, V> firstEntry = map.entrySet().iterator().next();
+            assertThrowsUoe(() -> firstEntry.setValue(exampleValue));
+        }
+    }
+
+    /** Checks assertions that hold for all Map.of() / Map.ofEntries() instances. */
+    private <K, V> void assertBehaviorCommonToAllOfInstances(K exampleKey, V exampleValue,
+            Map.Entry<K, V>...entries) {
+        Map<K, V> expected = hashMapOf(entries);
+        Map<K, V> actual = creator.create(entries);
+        assertBehaviorCommonToAllOfInstances(expected, actual, exampleKey, exampleValue);
+    }
+
+    private static<K, V> void assertBehaviorCommonToAllOfInstances(Map<K, V> expected,
+            Map<K, V> actual, K exampleKey, V exampleValue) {
+        assertDoesNotSupportNull(actual);
+        assertMapEquals(expected, actual);
+        assertUnmodifiable(actual, exampleKey, exampleValue);
+    }
+
+    private static<K, V> void assertDoesNotSupportNull(Map<K, V> map) {
+        assertThrowsNpe(() -> map.containsKey(null));
+        assertThrowsNpe(() -> map.keySet().contains(null));
+        assertThrowsNpe(() -> map.values().contains(null));
+    }
+
+    private static<K, V> void assertMapEquals(Map<K, V> expected, Map<K, V> actual) {
+        assertEquals(expected, actual);
+        assertEquals(actual, expected);
+        assertEquals(expected.size(), actual.size());
+        assertEquals(expected.entrySet(), actual.entrySet());
+
+        assertSetEquals(expected.entrySet(), actual.entrySet());
+        assertSetEquals(expected.keySet(), actual.keySet());
+        assertCollectionEquals(new HashSet<>(expected.values()), new HashSet<>(actual.values()));
+    }
+
+    private static<T> void assertSetEquals(Set<T> expected, Set<T> actual) {
+        assertCollectionEquals(expected, actual);
+    }
+
+    private static<T> void assertCollectionEquals(Collection<T> expected, Collection<T> actual) {
+        assertEquals(expected, actual);
+        assertEquals(actual, expected);
+        assertEquals(expected.hashCode(), actual.hashCode());
+
+        assertEquals(expected.size(), actual.size());
+        assertTrue(expected.containsAll(actual));
+        assertTrue(actual.containsAll(expected));
+    }
+
+    private final Creator creator;
+
+    public MapOfTest(Creator creator) {
+        this.creator = Objects.requireNonNull(creator);
+    }
+
+    private<K, V> Map<K, V> create(Map.Entry<K, V>... entries) {
+        return creator.create(entries);
+    }
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<Creator> getCreators() {
+        return Arrays.asList(Creator.OF, Creator.OF_ENTRIES);
+    }
+
+    private static<K, V> Map<K, V> hashMapOf(Map.Entry<K, V>... entries) {
+        HashMap<K, V> result = new HashMap<>();
+        for (Map.Entry<K, V> entry : entries) {
+            result.put(entry.getKey(), entry.getValue());
+        }
+        return result;
+    }
+
+    enum Creator {
+        OF {
+            private<K,V> K k(int index, Map.Entry<K, V>... entries) {
+                return entries[index].getKey();
+            }
+            private<K,V> V v(int index, Map.Entry<K, V>... entries) {
+                return entries[index].getValue();
+            }
+
+            @Override
+            <K, V> Map<K, V> create(Map.Entry<K, V>... e) {
+                switch (e.length) {
+                    case 0: return Map.of();
+                    case 1: return Map.of(k(0, e), v(0, e));
+                    case 2: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e));
+                    case 3: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e));
+                    case 4: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e));
+                    case 5: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e), k(4, e), v(4, e));
+                    case 6: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e), k(4, e), v(4, e), k(5, e), v(5, e));
+                    case 7: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e), k(4, e), v(4, e), k(5, e), v(5, e), k(6, e), v(6, e));
+                    case 8: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e), k(4, e), v(4, e), k(5, e), v(5, e), k(6, e), v(6, e), k(7, e), v(7, e));
+                    case 9: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e), k(4, e), v(4, e), k(5, e), v(5, e), k(6, e), v(6, e), k(7, e), v(7, e), k(8, e), v(8, e));
+                   case 10: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e), k(4, e), v(4, e), k(5, e), v(5, e), k(6, e), v(6, e), k(7, e), v(7, e), k(8, e), v(8, e), k(9, e), v(9, e));
+                    default:
+                        fail(this + " requires 0 to 10 entries");
+                        throw new AssertionError("unreachable");
+                }
+
+            }
+        },
+        OF_ENTRIES {
+            @Override
+            <K, V> Map<K, V> create(Map.Entry<K, V>... entries) {
+                return Map.ofEntries(entries);
+            }
+        }
+        ;
+        abstract <K,V> Map<K, V> create(Map.Entry<K,V>... entries);
+    }
+
+    private static void assertThrowsIae(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    private static void assertThrowsUoe(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    private static void assertThrowsNpe(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (NullPointerException expected) {
+        }
+    }
+}
diff --git a/luni/src/test/java/libcore/java/util/ObjectsTest.java b/luni/src/test/java/libcore/java/util/ObjectsTest.java
index dcaa20c..6e118e9 100644
--- a/luni/src/test/java/libcore/java/util/ObjectsTest.java
+++ b/luni/src/test/java/libcore/java/util/ObjectsTest.java
@@ -25,6 +25,111 @@
     public String toString() { return "hello"; }
   }
 
+  public void test_checkFromIndexSize_valid() {
+    Objects.checkFromIndexSize(/* fromIndex */ 0, /* size */ 0, /* length */ 10);
+    Objects.checkFromIndexSize(/* fromIndex */ 10, /* size */ 0, /* length */ 10);
+    Objects.checkFromIndexSize(/* fromIndex */ 5, /* size */ 1, /* length */ 10);
+    Objects.checkFromIndexSize(/* fromIndex */ 0, /* size */ 10, /* length */ 10);
+    Objects.checkFromIndexSize(/* fromIndex */ 1, /* size */ 9, /* length */ 10);
+    Objects.checkFromIndexSize(/* fromIndex */ 0, /* size */ 9, /* length */ 10);
+  }
+
+  public void test_checkFromIndexSize_negativeSize() {
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ -1, /* size */ 10, /* length */ 100);
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ 5, /* size */ -1, /* length */ 100);
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ 0, /* size */ -1, /* length */ 100);
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ 0, /* size */ -1, /* length */ -1);
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ 0, /* size */ 0, /* length */ -1);
+  }
+
+  public void test_checkFromIndexSize_beyondEnd() {
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ 0, /* size */ 10, /* length */ 9);
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ 1, /* size */ 10, /* length */ 10);
+
+    // Invalid, but fromIndex + size overflows and is < length.
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ Integer.MAX_VALUE - 10, /* size */ 11,
+            /* length */ Integer.MAX_VALUE);
+  }
+
+  private static void assertFromIndexSizeOutOfBounds(int fromIndex, int size, int length) {
+    try {
+      Objects.checkFromIndexSize(fromIndex, size, length);
+      fail();
+    } catch (IndexOutOfBoundsException expected) {
+    }
+  }
+
+  public void test_checkFromToIndex_valid() {
+    Objects.checkFromToIndex(/* fromIndex */ 0, /* toIndex */ 0, /* length */ 10);
+    Objects.checkFromToIndex(/* fromIndex */ 10, /* toIndex */ 10, /* length */ 10);
+    Objects.checkFromToIndex(/* fromIndex */ 5, /* toIndex */ 6, /* length */ 10);
+    Objects.checkFromToIndex(/* fromIndex */ 0, /* toIndex */ 10, /* length */ 10);
+    Objects.checkFromToIndex(/* fromIndex */ 1, /* toIndex */ 10, /* length */ 10);
+    Objects.checkFromToIndex(/* fromIndex */ 0, /* toIndex */ 0, /* length */ 10);
+  }
+
+  public void test_checkFromToIndex_negativeSize() {
+    assertFromToIndexOutOfBounds(/* fromIndex */ -1, /* toIndex */ 9, /* length */ 100);
+    assertFromToIndexOutOfBounds(/* fromIndex */ 5, /* toIndex */ 4, /* length */ 100);
+    assertFromToIndexOutOfBounds(/* fromIndex */ 0, /* toIndex */ -1, /* length */ 100);
+    assertFromToIndexOutOfBounds(/* fromIndex */ 0, /* toIndex */ -1, /* length */ -1);
+    assertFromToIndexOutOfBounds(/* fromIndex */ 0, /* toIndex */ 0, /* length */ -1);
+  }
+
+  public void test_checkFromToIndex_beyondEnd() {
+    assertFromToIndexOutOfBounds(/* fromIndex */ 0, /* toIndex */ 10, /* length */ 9);
+    assertFromToIndexOutOfBounds(/* fromIndex */ 1, /* toIndex */ 11, /* length */ 10);
+    assertFromToIndexOutOfBounds(/* fromIndex */ Integer.MAX_VALUE - 10,
+            /* toIndex */ Integer.MIN_VALUE, /* length */ Integer.MAX_VALUE);
+  }
+
+  private static void assertFromToIndexOutOfBounds(int fromIndex, int toIndex, int length) {
+    try {
+      Objects.checkFromToIndex(fromIndex, toIndex, length);
+      fail();
+    } catch (IndexOutOfBoundsException expected) {
+    }
+  }
+
+  public void test_checkIndex_empty() {
+    assertIndexOutOfBounds(0, 0);
+    assertIndexOutOfBounds(1, 0);
+    assertIndexOutOfBounds(-1, 0);
+    assertIndexOutOfBounds(100, 0);
+    assertIndexOutOfBounds(-100, 0);
+    assertIndexOutOfBounds(Integer.MAX_VALUE, 0);
+    assertIndexOutOfBounds(Integer.MAX_VALUE, 0);
+  }
+
+  public void test_checkIndex_size1() {
+    Objects.checkIndex(0, 1);
+    assertIndexOutOfBounds(1, 1);
+    assertIndexOutOfBounds(-1, 1);
+    assertIndexOutOfBounds(100, 1);
+    assertIndexOutOfBounds(-100, 1);
+    assertIndexOutOfBounds(Integer.MAX_VALUE, 1);
+    assertIndexOutOfBounds(Integer.MAX_VALUE, 1);
+  }
+
+  public void test_checkIndex_largeSize() {
+    Objects.checkIndex(0, 100);
+    Objects.checkIndex(99, 100);
+    Objects.checkIndex(100, Integer.MAX_VALUE);
+    Objects.checkIndex(Integer.MAX_VALUE - 1, Integer.MAX_VALUE);
+    assertIndexOutOfBounds(-1, 100);
+    assertIndexOutOfBounds(100, 100);
+    assertIndexOutOfBounds(Integer.MAX_VALUE, Integer.MAX_VALUE);
+    assertIndexOutOfBounds(-1, Integer.MAX_VALUE);
+  }
+
+  private static void assertIndexOutOfBounds(int index, int length) {
+    try {
+      Objects.checkIndex(index, length);
+      fail();
+    } catch (IndexOutOfBoundsException expected) {
+    }
+  }
+
   public void test_compare() throws Exception {
     assertEquals(0, Objects.compare(null, null, String.CASE_INSENSITIVE_ORDER));
     assertEquals(0, Objects.compare("a", "A", String.CASE_INSENSITIVE_ORDER));
@@ -134,6 +239,35 @@
     }
   }
 
+  public void test_requireNonNullElse() {
+    assertEquals("obj", Objects.requireNonNullElse("obj", "default"));
+    assertEquals("default", Objects.requireNonNullElse(null, "default"));
+    assertEquals("obj", Objects.requireNonNullElse("obj", null));
+    assertThrowsNpe(() -> Objects.requireNonNullElse(null, null));
+  }
+
+  public void test_requireNonNullElseGet_obj() {
+    assertEquals("obj", Objects.requireNonNullElseGet("obj", () -> "default"));
+    // null supplier / supplier that returns null is tolerated when obj != null.
+    assertEquals("obj", Objects.requireNonNullElseGet("obj", () -> null));
+    assertEquals("obj", Objects.requireNonNullElseGet("obj", null));
+  }
+
+  public void test_requireNonNullElseGet_nullObj() {
+    assertEquals("default", Objects.requireNonNullElseGet(null, () -> "default"));
+    // null supplier and supplier of null both throw.
+    assertThrowsNpe(() -> Objects.requireNonNullElseGet(null, (Supplier<?>) () -> null));
+    assertThrowsNpe(() -> Objects.requireNonNullElse(null, null));
+  }
+
+  private static void assertThrowsNpe(Runnable runnable) {
+    try {
+      runnable.run();
+      fail();
+    } catch (NullPointerException expected) {
+    }
+  }
+
   public void test_toString_Object() throws Exception {
     assertEquals("hello", Objects.toString(new Hello()));
     assertEquals("null", Objects.toString(null));
diff --git a/luni/src/test/java/libcore/java/util/SetOfTest.java b/luni/src/test/java/libcore/java/util/SetOfTest.java
new file mode 100644
index 0000000..86dfc74
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/SetOfTest.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2020 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.util;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+import libcore.libcore.util.SerializationTester;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class SetOfTest {
+
+    @Test public void of_serializationCompatibility_empty() {
+        String golden = "ACED00057372001E6A6176612E7574696C2E436F6C6C656374696F6E7324456D7074795365"
+                + "7415F5721DB403CB280200007870";
+        new SerializationTester<>(Set.<String>of(), golden).test();
+    }
+
+    @Test public void of_serializationCompatibility_oneElement() {
+        String golden = "ACED0005737200256A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C65536574801D92D18F9B80550200007872002C6A6176612E7574696C2E436F6C6C656374"
+                + "696F6E7324556E6D6F6469666961626C65436F6C6C656374696F6E19420080CB5EF71E0200014C00"
+                + "01637400164C6A6176612F7574696C2F436F6C6C656374696F6E3B7870737200116A6176612E7574"
+                + "696C2E48617368536574BA44859596B8B7340300007870770C000000023F40000000000001740003"
+                + "6F6E6578";
+        new SerializationTester<>(Set.of("one"), golden).test();
+    }
+
+    @Test public void of_serializationCompatibility_manyElements() {
+        String golden = "ACED0005737200256A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C65536574801D92D18F9B80550200007872002C6A6176612E7574696C2E436F6C6C656374"
+                + "696F6E7324556E6D6F6469666961626C65436F6C6C656374696F6E19420080CB5EF71E0200014C00"
+                + "01637400164C6A6176612F7574696C2F436F6C6C656374696F6E3B7870737200116A6176612E7574"
+                + "696C2E48617368536574BA44859596B8B7340300007870770C000000203F4000000000000D737200"
+                + "116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200"
+                + "106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000007371007E0006"
+                + "000000017371007E0006000000027371007E0006000000037371007E0006000000047371007E0006"
+                + "000000057371007E0006000000067371007E0006000000077371007E0006000000087371007E0006"
+                + "000000097371007E00060000000A7371007E00060000000B7371007E00060000000C78";
+        new SerializationTester<>(Set.of(12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), golden).test();
+    }
+
+    @Test public void mixedTypes() {
+        Set<?> list = Set.of("element", 42);
+        assertEquals(asSet("element", 42), list);
+
+        assertTrue(list.contains("element"));
+        assertTrue(list.contains(42));
+        assertFalse(list.contains(new Object()));
+        assertFalse(list.contains(31));
+    }
+
+    @Test public void duplicate() {
+        assertThrowsIae(() -> { Set.of("duplicate", "duplicate"); });
+        assertThrowsIae(() -> { Set.of("duplicate", "duplicate", "duplicate"); });
+        assertThrowsIae(() -> { Set.of("a", "duplicate", "duplicate"); });
+        assertThrowsIae(() -> {
+            Set.of("a", "duplicate", "b", "c", "d", "e", "f", "g", "duplicate");
+        });
+        assertThrowsIae(() -> { Set.of("a", "duplicate", "b", "c", "d", "e", "f", "g",
+                "duplicate", "h", "i", "j", "k", "l"); });
+    }
+
+    /**
+     * Checks that when there is both a duplicate and null, the exception that is thrown
+     * depends on which occurs first.
+     */
+    @Test public void duplicateAndNull() {
+        assertThrowsNpe(() -> { Set.of("duplicate", null, "duplicate"); }); // null first
+        assertThrowsIae(() -> { Set.of("duplicate", "duplicate", null); }); // duplicate first
+    }
+
+    @Test public void empty() {
+        check_commonBehavior(Collections.<String>emptySet(), Set.<String>of(), "non-null example");
+    }
+
+    @Test public void nonEmpty() {
+        check_nonEmpty(asSet("one"), Set.of("one"));
+        check_nonEmpty(asSet("one", "two"), Set.of("one", "two"));
+        check_nonEmpty(asSet("one", "two", "three"), Set.of("one", "two", "three"));
+        check_nonEmpty(asSet("one", "two", "three", "four"),
+                Set.of("one", "two", "three", "four"));
+        check_nonEmpty(asSet("one", "two", "three", "four", "five"),
+                Set.of("one", "two", "three", "four", "five"));
+        check_nonEmpty(asSet("one", "two", "three", "four", "five", "six"),
+                Set.of("one", "two", "three", "four", "five", "six"));
+        check_nonEmpty(asSet("one", "two", "three", "four", "five", "six", "seven"),
+                Set.of("one", "two", "three", "four", "five", "six", "seven"));
+        check_nonEmpty(asSet(1, 2, 3, 4, 5, 6, 7, 8), Set.of(1, 2, 3, 4, 5, 6, 7, 8));
+        check_nonEmpty(asSet(1, 2, 3, 4, 5, 6, 7, 8, 9), Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9));
+        check_nonEmpty(asSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
+                Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
+        check_nonEmpty(asSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
+                Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
+        check_nonEmpty(asSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
+                Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12));
+        check_nonEmpty(asSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+                Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13));
+    }
+
+    @Test public void null_examples() {
+        assertThrowsNpe(() -> List.<String>of((String) null)); // one-arg version
+        assertThrowsNpe(() -> List.<String[]>of((String[]) null)); // null var-args array
+        assertThrowsNpe(() -> List.<String>of(new String[] { "one", null, "three"})); // var-args
+
+        assertThrowsNpe(() -> Set.of(null, "two"));
+        assertThrowsNpe(() -> Set.of("one", null));
+        assertThrowsNpe(
+                () -> Set.of(null, "two", "three", "four", "five", "six", "seven"));
+        assertThrowsNpe(
+                () -> Set.of("one", "two", "three", "four", "five", "six", null));
+    }
+
+    @Test public void null_comprehensive() {
+        Set<Integer> template = asSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
+        for (int i = 0; i < template.size(); i++) {
+            Integer[] l = template.toArray(new Integer[0]);
+            l[i] = null;
+            npe(i <= 0, () -> Set.of(l[0]));
+            npe(i <= 1, () -> Set.of(l[0], l[1]));
+            npe(i <= 2, () -> Set.of(l[0], l[1], l[2]));
+            npe(i <= 3, () -> Set.of(l[0], l[1], l[2], l[3]));
+            npe(i <= 4, () -> Set.of(l[0], l[1], l[2], l[3], l[4]));
+            npe(i <= 5, () -> Set.of(l[0], l[1], l[2], l[3], l[4], l[5]));
+            npe(i <= 6, () -> Set.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6]));
+            npe(i <= 7, () -> Set.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7]));
+            npe(i <= 8, () -> Set.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8]));
+            npe(i <= 9, () -> Set.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9]));
+            npe(i <= 10, () -> Set.of(
+                    l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10]));
+            npe(i <= 11, () -> Set.of(
+                    l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10], l[11]));
+            npe(i <= 12, () -> Set.of(
+                    l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10], l[11], l[12])
+            );
+        }
+    }
+
+    /**
+     * Asserts that {@code runnable.run()} throws {@link NullPointerException} if
+     * any only if {@code expectedToThrowNpe}.
+     */
+    private static void npe(boolean expectedToThrowNpe, Runnable runnable) {
+        if (expectedToThrowNpe) {
+            assertThrowsNpe(runnable);
+        } else {
+            runnable.run(); // should not throw
+        }
+    }
+
+    private static<T extends Comparable<T>> void check_nonEmpty(Set<T> expected, Set<T> actual) {
+        T example = actual.iterator().next();
+        check_commonBehavior(expected, actual, example);
+    }
+
+    /** Checks assertions that hold for all Set.of() instances. */
+    private static<T extends Comparable<T>> void check_commonBehavior(
+            Set<T> expected, Set<T> actual, T nonNullExample) {
+        assertNotNull(nonNullExample);
+        assertEquals(expected, actual);
+        assertEquals(expected.size(), actual.size());
+        assertEquals(expected.hashCode(), actual.hashCode());
+        assertEquals(actual.isEmpty(), actual.isEmpty());
+        assertEquals(actual.size() == 0, actual.isEmpty());
+        assertEquals(expected.contains(nonNullExample), actual.contains(nonNullExample));
+        assertFalse(actual.contains("absent-element"));
+        assertFalse(actual.contains(new Object()));
+        assertThrowsNpe(() -> actual.contains(null));
+
+        assertUnmodifiable(actual, nonNullExample);
+        assertEquals(actual, reserialize((Serializable) actual));
+    }
+
+    private static<T extends Comparable<T>> void assertUnmodifiable(Set<T> set, T example) {
+        Set<T> examples = Collections.singleton(example);
+        assertTrue(throwsUoe(() -> { set.add(example); } ));
+        assertTrue(throwsUoe(() -> { set.addAll(examples); } ));
+        // List.of() documentation guarantees that the following operations throw
+        // UnsupportedOperationException, even though some other implementations don't
+        // do that in the case of isEmpty().
+        assertTrue(throwsUoe(() -> { set.clear(); }));
+        assertTrue(throwsUoe(() -> { set.remove(example); } ));
+        assertTrue(throwsUoe(() -> { set.removeAll(examples); } ));
+        assertTrue(throwsUoe(() -> { set.removeIf(Predicate.isEqual(example)); } ));
+        assertTrue(throwsUoe(() -> { set.retainAll(examples); } ));
+    }
+
+    private static boolean throwsUoe(Runnable runnable) {
+        try {
+            runnable.run();
+            return false;
+        } catch (UnsupportedOperationException tolerated) {
+            return  true;
+        }
+    }
+
+    private static void assertThrowsIae(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    private static void assertThrowsNpe(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (NullPointerException expected) {
+        }
+    }
+
+    private static <S extends Serializable> S reserialize(S value) {
+        try {
+            return (S) SerializationTester.reserialize(value);
+        } catch (IOException | ClassNotFoundException e) {
+            fail("Unexpected exception: " + e.getMessage());
+            throw new AssertionError(e); // unreachable
+        }
+    }
+
+    private static<T> Set<T> asSet(T... values) {
+        return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(values)));
+    }
+
+}
diff --git a/ojluni/annotations/sdk/nullability/java/util/List.annotated.java b/ojluni/annotations/sdk/nullability/java/util/List.annotated.java
index 958b335..2ef4a6f 100644
--- a/ojluni/annotations/sdk/nullability/java/util/List.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/util/List.annotated.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -86,4 +86,29 @@
 @libcore.util.NonNull public java.util.List<@libcore.util.NullFromTypeParam E> subList(int fromIndex, int toIndex);
 
 @libcore.util.NonNull public default java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of() { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9, @libcore.util.NonNull E e10) { throw new RuntimeException("Stub!"); }
+
+@java.lang.SafeVarargs
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(E @libcore.util.NonNull ... elements) { throw new RuntimeException("Stub!"); }
 }
diff --git a/ojluni/annotations/sdk/nullability/java/util/Map.annotated.java b/ojluni/annotations/sdk/nullability/java/util/Map.annotated.java
index 4008996..c19add2 100644
--- a/ojluni/annotations/sdk/nullability/java/util/Map.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/util/Map.annotated.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -80,6 +80,33 @@
 @libcore.util.Nullable public default V compute(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.Nullable V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
 
 @libcore.util.Nullable public default V merge(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull V value, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull V,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of() { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7, @libcore.util.NonNull K k8, @libcore.util.NonNull V v8) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7, @libcore.util.NonNull K k8, @libcore.util.NonNull V v8, @libcore.util.NonNull K k9, @libcore.util.NonNull V v9) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7, @libcore.util.NonNull K k8, @libcore.util.NonNull V v8, @libcore.util.NonNull K k9, @libcore.util.NonNull V v9, @libcore.util.NonNull K k10, @libcore.util.NonNull V v10) { throw new RuntimeException("Stub!"); }
+
+@java.lang.SafeVarargs
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> ofEntries(@libcore.util.NonNull java.util.Map.Entry<? extends @libcore.util.NonNull K,? extends @libcore.util.NonNull V>... entries) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map.Entry<@libcore.util.NonNull K, @libcore.util.NonNull V> entry(@libcore.util.NonNull K k, @libcore.util.NonNull V v) { throw new RuntimeException("Stub!"); }
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public static interface Entry<K, V> {
 
diff --git a/ojluni/annotations/sdk/nullability/java/util/Objects.annotated.java b/ojluni/annotations/sdk/nullability/java/util/Objects.annotated.java
index 591a022..ee1b692 100644
--- a/ojluni/annotations/sdk/nullability/java/util/Objects.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/util/Objects.annotated.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -55,5 +55,9 @@
 
 public static boolean nonNull(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
 
+@libcore.util.NonNull public static <T> T requireNonNullElse(@libcore.util.Nullable T obj, @libcore.util.NonNull T defaultObj) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <T> T requireNonNullElseGet(@libcore.util.Nullable T obj, @libcore.util.NonNull java.util.function.Supplier<? extends @libcore.util.NonNull T> supplier) { throw new RuntimeException("Stub!"); }
+
 @libcore.util.NonNull public static <T> T requireNonNull(@libcore.util.Nullable T obj, @libcore.util.NonNull java.util.function.Supplier<@libcore.util.NonNull java.lang.String> messageSupplier) { throw new RuntimeException("Stub!"); }
 }
diff --git a/ojluni/annotations/sdk/nullability/java/util/Set.annotated.java b/ojluni/annotations/sdk/nullability/java/util/Set.annotated.java
index 1257b5c..bae8bdd 100644
--- a/ojluni/annotations/sdk/nullability/java/util/Set.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/util/Set.annotated.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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,4 +62,29 @@
 public int hashCode();
 
 @libcore.util.NonNull public default java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of() { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9, @libcore.util.NonNull E e10) { throw new RuntimeException("Stub!"); }
+
+@java.lang.SafeVarargs
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(E @libcore.util.NonNull ... elements) { throw new RuntimeException("Stub!"); }
 }
diff --git a/ojluni/src/main/java/java/util/AbstractList.java b/ojluni/src/main/java/java/util/AbstractList.java
index a183624..c8c160d 100644
--- a/ojluni/src/main/java/java/util/AbstractList.java
+++ b/ojluni/src/main/java/java/util/AbstractList.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -25,6 +25,8 @@
 
 package java.util;
 
+import java.util.function.Consumer;
+
 /**
  * This class provides a skeletal implementation of the {@link List}
  * interface to minimize the effort required to implement this interface
@@ -87,7 +89,8 @@
      * classes should clearly specify in their documentation any restrictions
      * on what elements may be added.
      *
-     * <p>This implementation calls {@code add(size(), e)}.
+     * @implSpec
+     * This implementation calls {@code add(size(), e)}.
      *
      * <p>Note that this implementation throws an
      * {@code UnsupportedOperationException} unless
@@ -114,12 +117,13 @@
      *
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
-    abstract public E get(int index);
+    public abstract E get(int index);
 
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation always throws an
+     * @implSpec
+     * This implementation always throws an
      * {@code UnsupportedOperationException}.
      *
      * @throws UnsupportedOperationException {@inheritDoc}
@@ -135,7 +139,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation always throws an
+     * @implSpec
+     * This implementation always throws an
      * {@code UnsupportedOperationException}.
      *
      * @throws UnsupportedOperationException {@inheritDoc}
@@ -151,7 +156,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation always throws an
+     * @implSpec
+     * This implementation always throws an
      * {@code UnsupportedOperationException}.
      *
      * @throws UnsupportedOperationException {@inheritDoc}
@@ -167,7 +173,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation first gets a list iterator (with
+     * @implSpec
+     * This implementation first gets a list iterator (with
      * {@code listIterator()}).  Then, it iterates over the list until the
      * specified element is found or the end of the list is reached.
      *
@@ -191,7 +198,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation first gets a list iterator that points to the end
+     * @implSpec
+     * This implementation first gets a list iterator that points to the end
      * of the list (with {@code listIterator(size())}).  Then, it iterates
      * backwards over the list until the specified element is found, or the
      * beginning of the list is reached.
@@ -220,7 +228,8 @@
      * Removes all of the elements from this list (optional operation).
      * The list will be empty after this call returns.
      *
-     * <p>This implementation calls {@code removeRange(0, size())}.
+     * @implSpec
+     * This implementation calls {@code removeRange(0, size())}.
      *
      * <p>Note that this implementation throws an
      * {@code UnsupportedOperationException} unless {@code remove(int
@@ -237,7 +246,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation gets an iterator over the specified collection
+     * @implSpec
+     * This implementation gets an iterator over the specified collection
      * and iterates over it, inserting the elements obtained from the
      * iterator into this list at the appropriate position, one at a time,
      * using {@code add(int, E)}.
@@ -269,7 +279,8 @@
     /**
      * Returns an iterator over the elements in this list in proper sequence.
      *
-     * <p>This implementation returns a straightforward implementation of the
+     * @implSpec
+     * This implementation returns a straightforward implementation of the
      * iterator interface, relying on the backing list's {@code size()},
      * {@code get(int)}, and {@code remove(int)} methods.
      *
@@ -291,7 +302,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation returns {@code listIterator(0)}.
+     * @implSpec
+     * This implementation returns {@code listIterator(0)}.
      *
      * @see #listIterator(int)
      */
@@ -302,7 +314,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation returns a straightforward implementation of the
+     * @implSpec
+     * This implementation returns a straightforward implementation of the
      * {@code ListIterator} interface that extends the implementation of the
      * {@code Iterator} interface returned by the {@code iterator()} method.
      * The {@code ListIterator} implementation relies on the backing list's
@@ -448,12 +461,12 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation returns a list that subclasses
+     * @implSpec
+     * This implementation returns a list that subclasses
      * {@code AbstractList}.  The subclass stores, in private fields, the
-     * offset of the subList within the backing list, the size of the subList
-     * (which can change over its lifetime), and the expected
-     * {@code modCount} value of the backing list.  There are two variants
-     * of the subclass, one of which implements {@code RandomAccess}.
+     * size of the subList (which can change over its lifetime), and the
+     * expected {@code modCount} value of the backing list.  There are two
+     * variants of the subclass, one of which implements {@code RandomAccess}.
      * If this list implements {@code RandomAccess} the returned list will
      * be an instance of the subclass that implements {@code RandomAccess}.
      *
@@ -481,11 +494,22 @@
      *         {@code (fromIndex > toIndex)}
      */
     public List<E> subList(int fromIndex, int toIndex) {
+        subListRangeCheck(fromIndex, toIndex, size());
         return (this instanceof RandomAccess ?
                 new RandomAccessSubList<>(this, fromIndex, toIndex) :
                 new SubList<>(this, fromIndex, toIndex));
     }
 
+    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+        if (toIndex > size)
+            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+        if (fromIndex > toIndex)
+            throw new IllegalArgumentException("fromIndex(" + fromIndex +
+                                               ") > toIndex(" + toIndex + ")");
+    }
+
     // Comparison and hashing
 
     /**
@@ -495,8 +519,9 @@
      * the two lists are <i>equal</i>.  (Two elements {@code e1} and
      * {@code e2} are <i>equal</i> if {@code (e1==null ? e2==null :
      * e1.equals(e2))}.)  In other words, two lists are defined to be
-     * equal if they contain the same elements in the same order.<p>
+     * equal if they contain the same elements in the same order.
      *
+     * @implSpec
      * This implementation first checks if the specified object is this
      * list. If so, it returns {@code true}; if not, it checks if the
      * specified object is a list. If not, it returns {@code false}; if so,
@@ -529,7 +554,8 @@
     /**
      * Returns the hash code value for this list.
      *
-     * <p>This implementation uses exactly the code that is used to define the
+     * @implSpec
+     * This implementation uses exactly the code that is used to define the
      * list hash function in the documentation for the {@link List#hashCode}
      * method.
      *
@@ -555,7 +581,8 @@
      * improve the performance of the {@code clear} operation on this list
      * and its subLists.
      *
-     * <p>This implementation gets a list iterator positioned before
+     * @implSpec
+     * This implementation gets a list iterator positioned before
      * {@code fromIndex}, and repeatedly calls {@code ListIterator.next}
      * followed by {@code ListIterator.remove} until the entire range has
      * been removed.  <b>Note: if {@code ListIterator.remove} requires linear
@@ -608,174 +635,308 @@
     private String outOfBoundsMsg(int index) {
         return "Index: "+index+", Size: "+size();
     }
-}
 
-class SubList<E> extends AbstractList<E> {
-    private final AbstractList<E> l;
-    private final int offset;
-    private int size;
+    /**
+     * An index-based split-by-two, lazily initialized Spliterator covering
+     * a List that access elements via {@link List#get}.
+     *
+     * If access results in an IndexOutOfBoundsException then a
+     * ConcurrentModificationException is thrown instead (since the list has
+     * been structurally modified while traversing).
+     *
+     * If the List is an instance of AbstractList then concurrent modification
+     * checking is performed using the AbstractList's modCount field.
+     */
+    static final class RandomAccessSpliterator<E> implements Spliterator<E> {
 
-    SubList(AbstractList<E> list, int fromIndex, int toIndex) {
-        if (fromIndex < 0)
-            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
-        if (toIndex > list.size())
-            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
-        if (fromIndex > toIndex)
-            throw new IllegalArgumentException("fromIndex(" + fromIndex +
-                                               ") > toIndex(" + toIndex + ")");
-        l = list;
-        offset = fromIndex;
-        size = toIndex - fromIndex;
-        this.modCount = l.modCount;
-    }
+        private final List<E> list;
+        private int index; // current index, modified on advance/split
+        private int fence; // -1 until used; then one past last index
 
-    public E set(int index, E element) {
-        rangeCheck(index);
-        checkForComodification();
-        return l.set(index+offset, element);
-    }
+        // The following fields are valid if covering an AbstractList
+        private final AbstractList<E> alist;
+        private int expectedModCount; // initialized when fence set
 
-    public E get(int index) {
-        rangeCheck(index);
-        checkForComodification();
-        return l.get(index+offset);
-    }
+        RandomAccessSpliterator(List<E> list) {
+            assert list instanceof RandomAccess;
 
-    public int size() {
-        checkForComodification();
-        return size;
-    }
+            this.list = list;
+            this.index = 0;
+            this.fence = -1;
 
-    public void add(int index, E element) {
-        rangeCheckForAdd(index);
-        checkForComodification();
-        l.add(index+offset, element);
-        this.modCount = l.modCount;
-        size++;
-    }
+            this.alist = list instanceof AbstractList ? (AbstractList<E>) list : null;
+            this.expectedModCount = alist != null ? alist.modCount : 0;
+        }
 
-    public E remove(int index) {
-        rangeCheck(index);
-        checkForComodification();
-        E result = l.remove(index+offset);
-        this.modCount = l.modCount;
-        size--;
-        return result;
-    }
+        /** Create new spliterator covering the given  range */
+        private RandomAccessSpliterator(RandomAccessSpliterator<E> parent,
+                                int origin, int fence) {
+            this.list = parent.list;
+            this.index = origin;
+            this.fence = fence;
 
-    protected void removeRange(int fromIndex, int toIndex) {
-        checkForComodification();
-        l.removeRange(fromIndex+offset, toIndex+offset);
-        this.modCount = l.modCount;
-        size -= (toIndex-fromIndex);
-    }
+            this.alist = parent.alist;
+            this.expectedModCount = parent.expectedModCount;
+        }
 
-    public boolean addAll(Collection<? extends E> c) {
-        return addAll(size, c);
-    }
+        private int getFence() { // initialize fence to size on first use
+            int hi;
+            List<E> lst = list;
+            if ((hi = fence) < 0) {
+                if (alist != null) {
+                    expectedModCount = alist.modCount;
+                }
+                hi = fence = lst.size();
+            }
+            return hi;
+        }
 
-    public boolean addAll(int index, Collection<? extends E> c) {
-        rangeCheckForAdd(index);
-        int cSize = c.size();
-        if (cSize==0)
+        public Spliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null : // divide range in half unless too small
+                    new RandomAccessSpliterator<>(this, lo, index = mid);
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int hi = getFence(), i = index;
+            if (i < hi) {
+                index = i + 1;
+                action.accept(get(list, i));
+                checkAbstractListModCount(alist, expectedModCount);
+                return true;
+            }
             return false;
+        }
 
-        checkForComodification();
-        l.addAll(offset+index, c);
-        this.modCount = l.modCount;
-        size += cSize;
-        return true;
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            List<E> lst = list;
+            int hi = getFence();
+            int i = index;
+            index = hi;
+            for (; i < hi; i++) {
+                action.accept(get(lst, i));
+            }
+            checkAbstractListModCount(alist, expectedModCount);
+        }
+
+        public long estimateSize() {
+            return (long) (getFence() - index);
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        private static <E> E get(List<E> list, int i) {
+            try {
+                return list.get(i);
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        static void checkAbstractListModCount(AbstractList<?> alist, int expectedModCount) {
+            if (alist != null && alist.modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
     }
 
-    public Iterator<E> iterator() {
-        return listIterator();
+    private static class SubList<E> extends AbstractList<E> {
+        private final AbstractList<E> root;
+        private final SubList<E> parent;
+        private final int offset;
+        protected int size;
+
+        /**
+         * Constructs a sublist of an arbitrary AbstractList, which is
+         * not a SubList itself.
+         */
+        public SubList(AbstractList<E> root, int fromIndex, int toIndex) {
+            this.root = root;
+            this.parent = null;
+            this.offset = fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = root.modCount;
+        }
+
+        /**
+         * Constructs a sublist of another SubList.
+         */
+        protected SubList(SubList<E> parent, int fromIndex, int toIndex) {
+            this.root = parent.root;
+            this.parent = parent;
+            this.offset = parent.offset + fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = root.modCount;
+        }
+
+        public E set(int index, E element) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            return root.set(offset + index, element);
+        }
+
+        public E get(int index) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            return root.get(offset + index);
+        }
+
+        public int size() {
+            checkForComodification();
+            return size;
+        }
+
+        public void add(int index, E element) {
+            rangeCheckForAdd(index);
+            checkForComodification();
+            root.add(offset + index, element);
+            updateSizeAndModCount(1);
+        }
+
+        public E remove(int index) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            E result = root.remove(offset + index);
+            updateSizeAndModCount(-1);
+            return result;
+        }
+
+        protected void removeRange(int fromIndex, int toIndex) {
+            checkForComodification();
+            root.removeRange(offset + fromIndex, offset + toIndex);
+            updateSizeAndModCount(fromIndex - toIndex);
+        }
+
+        public boolean addAll(Collection<? extends E> c) {
+            return addAll(size, c);
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            rangeCheckForAdd(index);
+            int cSize = c.size();
+            if (cSize==0)
+                return false;
+            checkForComodification();
+            root.addAll(offset + index, c);
+            updateSizeAndModCount(cSize);
+            return true;
+        }
+
+        public Iterator<E> iterator() {
+            return listIterator();
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            checkForComodification();
+            rangeCheckForAdd(index);
+
+            return new ListIterator<E>() {
+                private final ListIterator<E> i =
+                        root.listIterator(offset + index);
+
+                public boolean hasNext() {
+                    return nextIndex() < size;
+                }
+
+                public E next() {
+                    if (hasNext())
+                        return i.next();
+                    else
+                        throw new NoSuchElementException();
+                }
+
+                public boolean hasPrevious() {
+                    return previousIndex() >= 0;
+                }
+
+                public E previous() {
+                    if (hasPrevious())
+                        return i.previous();
+                    else
+                        throw new NoSuchElementException();
+                }
+
+                public int nextIndex() {
+                    return i.nextIndex() - offset;
+                }
+
+                public int previousIndex() {
+                    return i.previousIndex() - offset;
+                }
+
+                public void remove() {
+                    i.remove();
+                    updateSizeAndModCount(-1);
+                }
+
+                public void set(E e) {
+                    i.set(e);
+                }
+
+                public void add(E e) {
+                    i.add(e);
+                    updateSizeAndModCount(1);
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return new SubList<>(this, fromIndex, toIndex);
+        }
+
+        private void rangeCheckForAdd(int index) {
+            if (index < 0 || index > size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+        }
+
+        private String outOfBoundsMsg(int index) {
+            return "Index: "+index+", Size: "+size;
+        }
+
+        private void checkForComodification() {
+            if (root.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+        }
+
+        private void updateSizeAndModCount(int sizeChange) {
+            SubList<E> slist = this;
+            do {
+                slist.size += sizeChange;
+                slist.modCount = root.modCount;
+                slist = slist.parent;
+            } while (slist != null);
+        }
     }
 
-    public ListIterator<E> listIterator(final int index) {
-        checkForComodification();
-        rangeCheckForAdd(index);
+    private static class RandomAccessSubList<E>
+            extends SubList<E> implements RandomAccess {
 
-        return new ListIterator<E>() {
-            private final ListIterator<E> i = l.listIterator(index+offset);
+        /**
+         * Constructs a sublist of an arbitrary AbstractList, which is
+         * not a RandomAccessSubList itself.
+         */
+        RandomAccessSubList(AbstractList<E> root,
+                int fromIndex, int toIndex) {
+            super(root, fromIndex, toIndex);
+        }
 
-            public boolean hasNext() {
-                return nextIndex() < size;
-            }
+        /**
+         * Constructs a sublist of another RandomAccessSubList.
+         */
+        RandomAccessSubList(RandomAccessSubList<E> parent,
+                int fromIndex, int toIndex) {
+            super(parent, fromIndex, toIndex);
+        }
 
-            public E next() {
-                if (hasNext())
-                    return i.next();
-                else
-                    throw new NoSuchElementException();
-            }
-
-            public boolean hasPrevious() {
-                return previousIndex() >= 0;
-            }
-
-            public E previous() {
-                if (hasPrevious())
-                    return i.previous();
-                else
-                    throw new NoSuchElementException();
-            }
-
-            public int nextIndex() {
-                return i.nextIndex() - offset;
-            }
-
-            public int previousIndex() {
-                return i.previousIndex() - offset;
-            }
-
-            public void remove() {
-                i.remove();
-                SubList.this.modCount = l.modCount;
-                size--;
-            }
-
-            public void set(E e) {
-                i.set(e);
-            }
-
-            public void add(E e) {
-                i.add(e);
-                SubList.this.modCount = l.modCount;
-                size++;
-            }
-        };
-    }
-
-    public List<E> subList(int fromIndex, int toIndex) {
-        return new SubList<>(this, fromIndex, toIndex);
-    }
-
-    private void rangeCheck(int index) {
-        if (index < 0 || index >= size)
-            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
-    }
-
-    private void rangeCheckForAdd(int index) {
-        if (index < 0 || index > size)
-            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
-    }
-
-    private String outOfBoundsMsg(int index) {
-        return "Index: "+index+", Size: "+size;
-    }
-
-    private void checkForComodification() {
-        if (this.modCount != l.modCount)
-            throw new ConcurrentModificationException();
-    }
-}
-
-class RandomAccessSubList<E> extends SubList<E> implements RandomAccess {
-    RandomAccessSubList(AbstractList<E> list, int fromIndex, int toIndex) {
-        super(list, fromIndex, toIndex);
-    }
-
-    public List<E> subList(int fromIndex, int toIndex) {
-        return new RandomAccessSubList<>(this, fromIndex, toIndex);
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return new RandomAccessSubList<>(this, fromIndex, toIndex);
+        }
     }
 }
diff --git a/ojluni/src/main/java/java/util/ImmutableCollections.java b/ojluni/src/main/java/java/util/ImmutableCollections.java
new file mode 100644
index 0000000..2bc0cc1
--- /dev/null
+++ b/ojluni/src/main/java/java/util/ImmutableCollections.java
@@ -0,0 +1,964 @@
+/*
+ * Copyright (c) 2016, 2017, 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 java.util;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import jdk.internal.vm.annotation.Stable;
+
+/**
+ * Container class for immutable collections. Not part of the public API.
+ * Mainly for namespace management and shared infrastructure.
+ *
+ * Serial warnings are suppressed throughout because all implementation
+ * classes use a serial proxy and thus have no need to declare serialVersionUID.
+ */
+@SuppressWarnings("serial")
+class ImmutableCollections {
+    /**
+     * A "salt" value used for randomizing iteration order. This is initialized once
+     * and stays constant for the lifetime of the JVM. It need not be truly random, but
+     * it needs to vary sufficiently from one run to the next so that iteration order
+     * will vary between JVM runs.
+     */
+    static final int SALT;
+    static {
+        long nt = System.nanoTime();
+        SALT = (int)((nt >>> 32) ^ nt);
+    }
+
+    /** No instances. */
+    private ImmutableCollections() { }
+
+    /**
+     * The reciprocal of load factor. Given a number of elements
+     * to store, multiply by this factor to get the table size.
+     */
+    static final int EXPAND_FACTOR = 2;
+
+    static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
+
+    // ---------- List Implementations ----------
+
+    abstract static class AbstractImmutableList<E> extends AbstractList<E>
+                                                implements RandomAccess, Serializable {
+        @Override public boolean add(E e) { throw uoe(); }
+        @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
+        @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
+        @Override public void    clear() { throw uoe(); }
+        @Override public boolean remove(Object o) { throw uoe(); }
+        @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
+        @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
+        @Override public void    replaceAll(UnaryOperator<E> operator) { throw uoe(); }
+        @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
+        @Override public void    sort(Comparator<? super E> c) { throw uoe(); }
+    }
+
+    static final class List0<E> extends AbstractImmutableList<E> {
+        private static final List0<?> INSTANCE = new List0<>();
+
+        @SuppressWarnings("unchecked")
+        static <T> List0<T> instance() {
+            return (List0<T>) INSTANCE;
+        }
+
+        private List0() { }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, 0); // always throws IndexOutOfBoundsException
+            return null;                  // but the compiler doesn't know this
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return Collections.emptyIterator();
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST);
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> o) {
+            return o.isEmpty(); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            return 1;
+        }
+    }
+
+    static final class List1<E> extends AbstractImmutableList<E> {
+        @Stable
+        private final E e0;
+
+        List1(E e0) {
+            this.e0 = Objects.requireNonNull(e0);
+        }
+
+        @Override
+        public int size() {
+            return 1;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, 1);
+            return e0;
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST, e0);
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 + e0.hashCode();
+        }
+    }
+
+    static final class List2<E> extends AbstractImmutableList<E> {
+        @Stable
+        private final E e0;
+        @Stable
+        private final E e1;
+
+        List2(E e0, E e1) {
+            this.e0 = Objects.requireNonNull(e0);
+            this.e1 = Objects.requireNonNull(e1);
+        }
+
+        @Override
+        public int size() {
+            return 2;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, 2);
+            if (index == 0) {
+                return e0;
+            } else { // index == 1
+                return e1;
+            }
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 31 + e0.hashCode();
+            return 31 * hash + e1.hashCode();
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST, e0, e1);
+        }
+    }
+
+    static final class ListN<E> extends AbstractImmutableList<E> {
+        @Stable
+        private final E[] elements;
+
+        @SafeVarargs
+        ListN(E... input) {
+            // copy and check manually to avoid TOCTOU
+            @SuppressWarnings("unchecked")
+            E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
+            for (int i = 0; i < input.length; i++) {
+                tmp[i] = Objects.requireNonNull(input[i]);
+            }
+            this.elements = tmp;
+        }
+
+        @Override
+        public int size() {
+            return elements.length;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, elements.length);
+            return elements[index];
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            for (E e : elements) {
+                if (o.equals(e)) { // implicit nullcheck of o
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 1;
+            for (E e : elements) {
+                hash = 31 * hash + e.hashCode();
+            }
+            return hash;
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST, elements);
+        }
+    }
+
+    // ---------- Set Implementations ----------
+
+    abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
+        @Override public boolean add(E e) { throw uoe(); }
+        @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
+        @Override public void    clear() { throw uoe(); }
+        @Override public boolean remove(Object o) { throw uoe(); }
+        @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
+        @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
+        @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
+    }
+
+    static final class Set0<E> extends AbstractImmutableSet<E> {
+        private static final Set0<?> INSTANCE = new Set0<>();
+
+        @SuppressWarnings("unchecked")
+        static <T> Set0<T> instance() {
+            return (Set0<T>) INSTANCE;
+        }
+
+        private Set0() { }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> o) {
+            return o.isEmpty(); // implicit nullcheck of o
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return Collections.emptyIterator();
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_SET);
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+    }
+
+    static final class Set1<E> extends AbstractImmutableSet<E> {
+        @Stable
+        private final E e0;
+
+        Set1(E e0) {
+            this.e0 = Objects.requireNonNull(e0);
+        }
+
+        @Override
+        public int size() {
+            return 1;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0); // implicit nullcheck of o
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return Collections.singletonIterator(e0);
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_SET, e0);
+        }
+
+        @Override
+        public int hashCode() {
+            return e0.hashCode();
+        }
+    }
+
+    static final class Set2<E> extends AbstractImmutableSet<E> {
+        @Stable
+        final E e0;
+        @Stable
+        final E e1;
+
+        Set2(E e0, E e1) {
+            if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
+                throw new IllegalArgumentException("duplicate element: " + e0);
+            }
+
+            if (SALT >= 0) {
+                this.e0 = e0;
+                this.e1 = e1;
+            } else {
+                this.e0 = e1;
+                this.e1 = e0;
+            }
+        }
+
+        @Override
+        public int size() {
+            return 2;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            return e0.hashCode() + e1.hashCode();
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new Iterator<E>() {
+                private int idx = 0;
+
+                @Override
+                public boolean hasNext() {
+                    return idx < 2;
+                }
+
+                @Override
+                public E next() {
+                    if (idx == 0) {
+                        idx = 1;
+                        return e0;
+                    } else if (idx == 1) {
+                        idx = 2;
+                        return e1;
+                    } else {
+                        throw new NoSuchElementException();
+                    }
+                }
+            };
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_SET, e0, e1);
+        }
+    }
+
+    /**
+     * An array-based Set implementation. The element array must be strictly
+     * larger than the size (the number of contained elements) so that at
+     * least one null is always present.
+     * @param <E> the element type
+     */
+    static final class SetN<E> extends AbstractImmutableSet<E> {
+        @Stable
+        final E[] elements;
+        @Stable
+        final int size;
+
+        @SafeVarargs
+        @SuppressWarnings("unchecked")
+        SetN(E... input) {
+            size = input.length; // implicit nullcheck of input
+
+            elements = (E[])new Object[EXPAND_FACTOR * input.length];
+            for (int i = 0; i < input.length; i++) {
+                E e = input[i];
+                int idx = probe(e); // implicit nullcheck of e
+                if (idx >= 0) {
+                    throw new IllegalArgumentException("duplicate element: " + e);
+                } else {
+                    elements[-(idx + 1)] = e;
+                }
+            }
+        }
+
+        @Override
+        public int size() {
+            return size;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return probe(o) >= 0; // implicit nullcheck of o
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new Iterator<E>() {
+                private int idx = 0;
+
+                @Override
+                public boolean hasNext() {
+                    while (idx < elements.length) {
+                        if (elements[idx] != null)
+                            return true;
+                        idx++;
+                    }
+                    return false;
+                }
+
+                @Override
+                public E next() {
+                    if (! hasNext()) {
+                        throw new NoSuchElementException();
+                    }
+                    return elements[idx++];
+                }
+            };
+        }
+
+        @Override
+        public int hashCode() {
+            int h = 0;
+            for (E e : elements) {
+                if (e != null) {
+                    h += e.hashCode();
+                }
+            }
+            return h;
+        }
+
+        // returns index at which element is present; or if absent,
+        // (-i - 1) where i is location where element should be inserted.
+        // Callers are relying on this method to perform an implicit nullcheck
+        // of pe
+        private int probe(Object pe) {
+            int idx = Math.floorMod(pe.hashCode() ^ SALT, elements.length);
+            while (true) {
+                E ee = elements[idx];
+                if (ee == null) {
+                    return -idx - 1;
+                } else if (pe.equals(ee)) {
+                    return idx;
+                } else if (++idx == elements.length) {
+                    idx = 0;
+                }
+            }
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            Object[] array = new Object[size];
+            int dest = 0;
+            for (Object o : elements) {
+                if (o != null) {
+                    array[dest++] = o;
+                }
+            }
+            return new CollSer(CollSer.IMM_SET, array);
+        }
+    }
+
+    // ---------- Map Implementations ----------
+
+    abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
+        @Override public void clear() { throw uoe(); }
+        @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
+        @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V put(K key, V value) { throw uoe(); }
+        @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
+        @Override public V putIfAbsent(K key, V value) { throw uoe(); }
+        @Override public V remove(Object key) { throw uoe(); }
+        @Override public boolean remove(Object key, Object value) { throw uoe(); }
+        @Override public V replace(K key, V value) { throw uoe(); }
+        @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
+        @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
+    }
+
+    static final class Map0<K,V> extends AbstractImmutableMap<K,V> {
+        private static final Map0<?,?> INSTANCE = new Map0<>();
+
+        @SuppressWarnings("unchecked")
+        static <K,V> Map0<K,V> instance() {
+            return (Map0<K,V>) INSTANCE;
+        }
+
+        private Map0() { }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return Set.of();
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_MAP);
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+    }
+
+    static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
+        @Stable
+        private final K k0;
+        @Stable
+        private final V v0;
+
+        Map1(K k0, V v0) {
+            this.k0 = Objects.requireNonNull(k0);
+            this.v0 = Objects.requireNonNull(v0);
+        }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return Set.of(new KeyValueHolder<>(k0, v0));
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            return o.equals(k0); // implicit nullcheck of o
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            return o.equals(v0); // implicit nullcheck of o
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_MAP, k0, v0);
+        }
+
+        @Override
+        public int hashCode() {
+            return k0.hashCode() ^ v0.hashCode();
+        }
+    }
+
+    /**
+     * An array-based Map implementation. There is a single array "table" that
+     * contains keys and values interleaved: table[0] is kA, table[1] is vA,
+     * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
+     * also be strictly larger than the size (the number of key-value pairs contained
+     * in the map) so that at least one null key is always present.
+     * @param <K> the key type
+     * @param <V> the value type
+     */
+    static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
+        @Stable
+        final Object[] table; // pairs of key, value
+        @Stable
+        final int size; // number of pairs
+
+        MapN(Object... input) {
+            if ((input.length & 1) != 0) { // implicit nullcheck of input
+                throw new InternalError("length is odd");
+            }
+            size = input.length >> 1;
+
+            int len = EXPAND_FACTOR * input.length;
+            len = (len + 1) & ~1; // ensure table is even length
+            table = new Object[len];
+
+            for (int i = 0; i < input.length; i += 2) {
+                @SuppressWarnings("unchecked")
+                    K k = Objects.requireNonNull((K)input[i]);
+                @SuppressWarnings("unchecked")
+                    V v = Objects.requireNonNull((V)input[i+1]);
+                int idx = probe(k);
+                if (idx >= 0) {
+                    throw new IllegalArgumentException("duplicate key: " + k);
+                } else {
+                    int dest = -(idx + 1);
+                    table[dest] = k;
+                    table[dest+1] = v;
+                }
+            }
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            return probe(o) >= 0; // implicit nullcheck of o
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            for (int i = 1; i < table.length; i += 2) {
+                Object v = table[i];
+                if (v != null && o.equals(v)) { // implicit nullcheck of o
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 0;
+            for (int i = 0; i < table.length; i += 2) {
+                Object k = table[i];
+                if (k != null) {
+                    hash += k.hashCode() ^ table[i + 1].hashCode();
+                }
+            }
+            return hash;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public V get(Object o) {
+            int i = probe(o);
+            if (i >= 0) {
+                return (V)table[i+1];
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public int size() {
+            return size;
+        }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return new AbstractSet<Map.Entry<K,V>>() {
+                @Override
+                public int size() {
+                    return MapN.this.size;
+                }
+
+                @Override
+                public Iterator<Map.Entry<K,V>> iterator() {
+                    return new Iterator<Map.Entry<K,V>>() {
+                        int idx = 0;
+
+                        @Override
+                        public boolean hasNext() {
+                            while (idx < table.length) {
+                                if (table[idx] != null)
+                                    return true;
+                                idx += 2;
+                            }
+                            return false;
+                        }
+
+                        @Override
+                        public Map.Entry<K,V> next() {
+                            if (hasNext()) {
+                                @SuppressWarnings("unchecked")
+                                Map.Entry<K,V> e =
+                                    new KeyValueHolder<>((K)table[idx], (V)table[idx+1]);
+                                idx += 2;
+                                return e;
+                            } else {
+                                throw new NoSuchElementException();
+                            }
+                        }
+                    };
+                }
+            };
+        }
+
+        // returns index at which the probe key is present; or if absent,
+        // (-i - 1) where i is location where element should be inserted.
+        // Callers are relying on this method to perform an implicit nullcheck
+        // of pk.
+        private int probe(Object pk) {
+            int idx = Math.floorMod(pk.hashCode() ^ SALT, table.length >> 1) << 1;
+            while (true) {
+                @SuppressWarnings("unchecked")
+                K ek = (K)table[idx];
+                if (ek == null) {
+                    return -idx - 1;
+                } else if (pk.equals(ek)) {
+                    return idx;
+                } else if ((idx += 2) == table.length) {
+                    idx = 0;
+                }
+            }
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            Object[] array = new Object[2 * size];
+            int len = table.length;
+            int dest = 0;
+            for (int i = 0; i < len; i += 2) {
+                if (table[i] != null) {
+                    array[dest++] = table[i];
+                    array[dest++] = table[i+1];
+                }
+            }
+            return new CollSer(CollSer.IMM_MAP, array);
+        }
+    }
+}
+
+// ---------- Serialization Proxy ----------
+
+/**
+ * A unified serialization proxy class for the immutable collections.
+ *
+ * @serial
+ * @since 9
+ */
+final class CollSer implements Serializable {
+    private static final long serialVersionUID = 6309168927139932177L;
+
+    static final int IMM_LIST = 1;
+    static final int IMM_SET = 2;
+    static final int IMM_MAP = 3;
+
+    /**
+     * Indicates the type of collection that is serialized.
+     * The low order 8 bits have the value 1 for an immutable
+     * {@code List}, 2 for an immutable {@code Set}, and 3 for
+     * an immutable {@code Map}. Any other value causes an
+     * {@link InvalidObjectException} to be thrown. The high
+     * order 24 bits are zero when an instance is serialized,
+     * and they are ignored when an instance is deserialized.
+     * They can thus be used by future implementations without
+     * causing compatibility issues.
+     *
+     * <p>The tag value also determines the interpretation of the
+     * transient {@code Object[] array} field.
+     * For {@code List} and {@code Set}, the array's length is the size
+     * of the collection, and the array contains the elements of the collection.
+     * Null elements are not allowed. For {@code Set}, duplicate elements
+     * are not allowed.
+     *
+     * <p>For {@code Map}, the array's length is twice the number of mappings
+     * present in the map. The array length is necessarily even.
+     * The array contains a succession of key and value pairs:
+     * {@code k1, v1, k2, v2, ..., kN, vN.} Nulls are not allowed,
+     * and duplicate keys are not allowed.
+     *
+     * @serial
+     * @since 9
+     */
+    private final int tag;
+
+    /**
+     * @serial
+     * @since 9
+     */
+    private transient Object[] array;
+
+    CollSer(int t, Object... a) {
+        tag = t;
+        array = a;
+    }
+
+    /**
+     * Reads objects from the stream and stores them
+     * in the transient {@code Object[] array} field.
+     *
+     * @serialData
+     * A nonnegative int, indicating the count of objects,
+     * followed by that many objects.
+     *
+     * @param ois the ObjectInputStream from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     * @throws InvalidObjectException if the count is negative
+     * @since 9
+     */
+    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+        ois.defaultReadObject();
+        int len = ois.readInt();
+
+        if (len < 0) {
+            throw new InvalidObjectException("negative length " + len);
+        }
+
+        Object[] a = new Object[len];
+        for (int i = 0; i < len; i++) {
+            a[i] = ois.readObject();
+        }
+
+        array = a;
+    }
+
+    /**
+     * Writes objects to the stream from
+     * the transient {@code Object[] array} field.
+     *
+     * @serialData
+     * A nonnegative int, indicating the count of objects,
+     * followed by that many objects.
+     *
+     * @param oos the ObjectOutputStream to which data is written
+     * @throws IOException if an I/O error occurs
+     * @since 9
+     */
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+        oos.defaultWriteObject();
+        oos.writeInt(array.length);
+        for (int i = 0; i < array.length; i++) {
+            oos.writeObject(array[i]);
+        }
+    }
+
+    /**
+     * Creates and returns an immutable collection from this proxy class.
+     * The instance returned is created as if by calling one of the
+     * static factory methods for
+     * <a href="List.html#immutable">List</a>,
+     * <a href="Map.html#immutable">Map</a>, or
+     * <a href="Set.html#immutable">Set</a>.
+     * This proxy class is the serial form for all immutable collection instances,
+     * regardless of implementation type. This is necessary to ensure that the
+     * existence of any particular implementation type is kept out of the
+     * serialized form.
+     *
+     * @return a collection created from this proxy object
+     * @throws InvalidObjectException if the tag value is illegal or if an exception
+     *         is thrown during creation of the collection
+     * @throws ObjectStreamException if another serialization error has occurred
+     * @since 9
+     */
+    private Object readResolve() throws ObjectStreamException {
+        try {
+            if (array == null) {
+                throw new InvalidObjectException("null array");
+            }
+
+            // use low order 8 bits to indicate "kind"
+            // ignore high order 24 bits
+            switch (tag & 0xff) {
+                case IMM_LIST:
+                    return List.of(array);
+                case IMM_SET:
+                    return Set.of(array);
+                case IMM_MAP:
+                    if (array.length == 0) {
+                        return ImmutableCollections.Map0.instance();
+                    } else if (array.length == 2) {
+                        return new ImmutableCollections.Map1<>(array[0], array[1]);
+                    } else {
+                        return new ImmutableCollections.MapN<>(array);
+                    }
+                default:
+                    throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
+            }
+        } catch (NullPointerException|IllegalArgumentException ex) {
+            InvalidObjectException ioe = new InvalidObjectException("invalid object");
+            ioe.initCause(ex);
+            throw ioe;
+        }
+    }
+}
diff --git a/ojluni/src/main/java/java/util/KeyValueHolder.java b/ojluni/src/main/java/java/util/KeyValueHolder.java
new file mode 100644
index 0000000..3b7250e
--- /dev/null
+++ b/ojluni/src/main/java/java/util/KeyValueHolder.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015, 2017, 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 java.util;
+
+import jdk.internal.vm.annotation.Stable;
+
+/**
+ * An immutable container for a key and a value, suitable for use
+ * in creating and populating {@code Map} instances.
+ *
+ * <p>This is a <a href="../lang/doc-files/ValueBased.html">value-based</a>
+ * class; use of identity-sensitive operations (including reference equality
+ * ({@code ==}), identity hash code, or synchronization) on instances of
+ * {@code KeyValueHolder} may have unpredictable results and should be avoided.
+ *
+ * @apiNote
+ * This class is not public. Instances can be created using the
+ * {@link Map#entry Map.entry(k, v)} factory method, which is public.
+ *
+ * <p>This class differs from AbstractMap.SimpleImmutableEntry in the following ways:
+ * it is not serializable, it is final, and its key and value must be non-null.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ *
+ * @see Map#ofEntries Map.ofEntries()
+ * @since 9
+ */
+final class KeyValueHolder<K,V> implements Map.Entry<K,V> {
+    @Stable
+    final K key;
+    @Stable
+    final V value;
+
+    KeyValueHolder(K k, V v) {
+        key = Objects.requireNonNull(k);
+        value = Objects.requireNonNull(v);
+    }
+
+    /**
+     * Gets the key from this holder.
+     *
+     * @return the key
+     */
+    @Override
+    public K getKey() {
+        return key;
+    }
+
+    /**
+     * Gets the value from this holder.
+     *
+     * @return the value
+     */
+    @Override
+    public V getValue() {
+        return value;
+    }
+
+    /**
+     * Throws {@link UnsupportedOperationException}.
+     *
+     * @param value ignored
+     * @return never returns normally
+     */
+    @Override
+    public V setValue(V value) {
+        throw new UnsupportedOperationException("not supported");
+    }
+
+    /**
+     * Compares the specified object with this entry for equality.
+     * Returns {@code true} if the given object is also a map entry and
+     * the two entries' keys and values are equal. Note that key and
+     * value are non-null, so equals() can be called safely on them.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof Map.Entry))
+            return false;
+        Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+        return key.equals(e.getKey()) && value.equals(e.getValue());
+    }
+
+    /**
+     * Returns the hash code value for this map entry. The hash code
+     * is {@code key.hashCode() ^ value.hashCode()}. Note that key and
+     * value are non-null, so hashCode() can be called safely on them.
+     */
+    @Override
+    public int hashCode() {
+        return key.hashCode() ^ value.hashCode();
+    }
+
+    /**
+     * Returns a String representation of this map entry.  This
+     * implementation returns the string representation of this
+     * entry's key followed by the equals character ("{@code =}")
+     * followed by the string representation of this entry's value.
+     *
+     * @return a String representation of this map entry
+     */
+    @Override
+    public String toString() {
+        return key + "=" + value;
+    }
+}
diff --git a/ojluni/src/main/java/java/util/List.java b/ojluni/src/main/java/java/util/List.java
index 41568e7..1b9deb3 100644
--- a/ojluni/src/main/java/java/util/List.java
+++ b/ojluni/src/main/java/java/util/List.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -27,6 +27,7 @@
 
 import java.util.function.UnaryOperator;
 
+// Android-removed: removed link to collections framework docs
 /**
  * An ordered collection (also known as a <i>sequence</i>).  The user of this
  * interface has precise control over where in the list each element is
@@ -34,50 +35,50 @@
  * the list), and search for elements in the list.<p>
  *
  * Unlike sets, lists typically allow duplicate elements.  More formally,
- * lists typically allow pairs of elements <tt>e1</tt> and <tt>e2</tt>
- * such that <tt>e1.equals(e2)</tt>, and they typically allow multiple
+ * lists typically allow pairs of elements {@code e1} and {@code e2}
+ * such that {@code e1.equals(e2)}, and they typically allow multiple
  * null elements if they allow null elements at all.  It is not inconceivable
  * that someone might wish to implement a list that prohibits duplicates, by
  * throwing runtime exceptions when the user attempts to insert them, but we
  * expect this usage to be rare.<p>
  *
- * The <tt>List</tt> interface places additional stipulations, beyond those
- * specified in the <tt>Collection</tt> interface, on the contracts of the
- * <tt>iterator</tt>, <tt>add</tt>, <tt>remove</tt>, <tt>equals</tt>, and
- * <tt>hashCode</tt> methods.  Declarations for other inherited methods are
+ * The {@code List} interface places additional stipulations, beyond those
+ * specified in the {@code Collection} interface, on the contracts of the
+ * {@code iterator}, {@code add}, {@code remove}, {@code equals}, and
+ * {@code hashCode} methods.  Declarations for other inherited methods are
  * also included here for convenience.<p>
  *
- * The <tt>List</tt> interface provides four methods for positional (indexed)
+ * The {@code List} interface provides four methods for positional (indexed)
  * access to list elements.  Lists (like Java arrays) are zero based.  Note
  * that these operations may execute in time proportional to the index value
- * for some implementations (the <tt>LinkedList</tt> class, for
+ * for some implementations (the {@code LinkedList} class, for
  * example). Thus, iterating over the elements in a list is typically
  * preferable to indexing through it if the caller does not know the
  * implementation.<p>
  *
- * The <tt>List</tt> interface provides a special iterator, called a
- * <tt>ListIterator</tt>, that allows element insertion and replacement, and
+ * The {@code List} interface provides a special iterator, called a
+ * {@code ListIterator}, that allows element insertion and replacement, and
  * bidirectional access in addition to the normal operations that the
- * <tt>Iterator</tt> interface provides.  A method is provided to obtain a
+ * {@code Iterator} interface provides.  A method is provided to obtain a
  * list iterator that starts at a specified position in the list.<p>
  *
- * The <tt>List</tt> interface provides two methods to search for a specified
+ * The {@code List} interface provides two methods to search for a specified
  * object.  From a performance standpoint, these methods should be used with
  * caution.  In many implementations they will perform costly linear
  * searches.<p>
  *
- * The <tt>List</tt> interface provides two methods to efficiently insert and
+ * The {@code List} interface provides two methods to efficiently insert and
  * remove multiple elements at an arbitrary point in the list.<p>
  *
  * Note: While it is permissible for lists to contain themselves as elements,
- * extreme caution is advised: the <tt>equals</tt> and <tt>hashCode</tt>
+ * extreme caution is advised: the {@code equals} and {@code hashCode}
  * methods are no longer well defined on such a list.
  *
  * <p>Some list implementations have restrictions on the elements that
  * they may contain.  For example, some implementations prohibit null elements,
  * and some have restrictions on the types of their elements.  Attempting to
  * add an ineligible element throws an unchecked exception, typically
- * <tt>NullPointerException</tt> or <tt>ClassCastException</tt>.  Attempting
+ * {@code NullPointerException} or {@code ClassCastException}.  Attempting
  * to query the presence of an ineligible element may throw an exception,
  * or it may simply return false; some implementations will exhibit the former
  * behavior and some will exhibit the latter.  More generally, attempting an
@@ -87,9 +88,31 @@
  * Such exceptions are marked as "optional" in the specification for this
  * interface.
  *
- * <p>This interface is a member of the
- * <a href="{@docRoot}/../technotes/guides/collections/index.html">
- * Java Collections Framework</a>.
+ * <h2><a id="immutable">Immutable List Static Factory Methods</a></h2>
+ * <p>The {@link List#of(Object...) List.of()} static factory methods
+ * provide a convenient way to create immutable lists. The {@code List}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <em>structurally immutable</em>. Elements cannot be added, removed,
+ * or replaced. Calling any mutator method will always cause
+ * {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained elements are themselves mutable,
+ * this may cause the List's contents to appear to change.
+ * <li>They disallow {@code null} elements. Attempts to create them with
+ * {@code null} elements result in {@code NullPointerException}.
+ * <li>They are serializable if all elements are serializable.
+ * <li>The order of elements in the list is the same as the order of the
+ * provided arguments, or of the elements in the provided array.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Callers should make no assumptions about the identity of the returned instances.
+ * Factories are free to create new instances or reuse existing ones. Therefore,
+ * identity-sensitive operations on these instances (reference equality ({@code ==}),
+ * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
  *
  * @param <E> the type of elements in this list
  *
@@ -113,28 +136,28 @@
 
     /**
      * Returns the number of elements in this list.  If this list contains
-     * more than <tt>Integer.MAX_VALUE</tt> elements, returns
-     * <tt>Integer.MAX_VALUE</tt>.
+     * more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
      *
      * @return the number of elements in this list
      */
     int size();
 
     /**
-     * Returns <tt>true</tt> if this list contains no elements.
+     * Returns {@code true} if this list contains no elements.
      *
-     * @return <tt>true</tt> if this list contains no elements
+     * @return {@code true} if this list contains no elements
      */
     boolean isEmpty();
 
     /**
-     * Returns <tt>true</tt> if this list contains the specified element.
-     * More formally, returns <tt>true</tt> if and only if this list contains
-     * at least one element <tt>e</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     * Returns {@code true} if this list contains the specified element.
+     * More formally, returns {@code true} if and only if this list contains
+     * at least one element {@code e} such that
+     * {@code Objects.equals(o, e)}.
      *
      * @param o element whose presence in this list is to be tested
-     * @return <tt>true</tt> if this list contains the specified element
+     * @return {@code true} if this list contains the specified element
      * @throws ClassCastException if the type of the specified element
      *         is incompatible with this list
      * (<a href="Collection.html#optional-restrictions">optional</a>)
@@ -179,7 +202,7 @@
      *
      * <p>If the list fits in the specified array with room to spare (i.e.,
      * the array has more elements than the list), the element in the array
-     * immediately following the end of the list is set to <tt>null</tt>.
+     * immediately following the end of the list is set to {@code null}.
      * (This is useful in determining the length of the list <i>only</i> if
      * the caller knows that the list does not contain any null elements.)
      *
@@ -188,16 +211,16 @@
      * precise control over the runtime type of the output array, and may,
      * under certain circumstances, be used to save allocation costs.
      *
-     * <p>Suppose <tt>x</tt> is a list known to contain only strings.
+     * <p>Suppose {@code x} is a list known to contain only strings.
      * The following code can be used to dump the list into a newly
-     * allocated array of <tt>String</tt>:
+     * allocated array of {@code String}:
      *
      * <pre>{@code
      *     String[] y = x.toArray(new String[0]);
      * }</pre>
      *
-     * Note that <tt>toArray(new Object[0])</tt> is identical in function to
-     * <tt>toArray()</tt>.
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
      *
      * @param a the array into which the elements of this list are to
      *          be stored, if it is big enough; otherwise, a new array of the
@@ -225,8 +248,8 @@
      * on what elements may be added.
      *
      * @param e element to be appended to this list
-     * @return <tt>true</tt> (as specified by {@link Collection#add})
-     * @throws UnsupportedOperationException if the <tt>add</tt> operation
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws UnsupportedOperationException if the {@code add} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of the specified element
      *         prevents it from being added to this list
@@ -241,21 +264,21 @@
      * Removes the first occurrence of the specified element from this list,
      * if it is present (optional operation).  If this list does not contain
      * the element, it is unchanged.  More formally, removes the element with
-     * the lowest index <tt>i</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
-     * (if such an element exists).  Returns <tt>true</tt> if this list
+     * the lowest index {@code i} such that
+     * {@code Objects.equals(o, get(i))}
+     * (if such an element exists).  Returns {@code true} if this list
      * contained the specified element (or equivalently, if this list changed
      * as a result of the call).
      *
      * @param o element to be removed from this list, if present
-     * @return <tt>true</tt> if this list contained the specified element
+     * @return {@code true} if this list contained the specified element
      * @throws ClassCastException if the type of the specified element
      *         is incompatible with this list
      * (<a href="Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null and this
      *         list does not permit null elements
      * (<a href="Collection.html#optional-restrictions">optional</a>)
-     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
+     * @throws UnsupportedOperationException if the {@code remove} operation
      *         is not supported by this list
      */
     boolean remove(Object o);
@@ -264,11 +287,11 @@
     // Bulk Modification Operations
 
     /**
-     * Returns <tt>true</tt> if this list contains all of the elements of the
+     * Returns {@code true} if this list contains all of the elements of the
      * specified collection.
      *
      * @param  c collection to be checked for containment in this list
-     * @return <tt>true</tt> if this list contains all of the elements of the
+     * @return {@code true} if this list contains all of the elements of the
      *         specified collection
      * @throws ClassCastException if the types of one or more elements
      *         in the specified collection are incompatible with this
@@ -292,8 +315,8 @@
      * specified collection is this list, and it's nonempty.)
      *
      * @param c collection containing elements to be added to this list
-     * @return <tt>true</tt> if this list changed as a result of the call
-     * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code addAll} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of an element of the specified
      *         collection prevents it from being added to this list
@@ -320,8 +343,8 @@
      * @param index index at which to insert the first element from the
      *              specified collection
      * @param c collection containing elements to be added to this list
-     * @return <tt>true</tt> if this list changed as a result of the call
-     * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code addAll} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of an element of the specified
      *         collection prevents it from being added to this list
@@ -331,7 +354,7 @@
      * @throws IllegalArgumentException if some property of an element of the
      *         specified collection prevents it from being added to this list
      * @throws IndexOutOfBoundsException if the index is out of range
-     *         (<tt>index &lt; 0 || index &gt; size()</tt>)
+     *         ({@code index < 0 || index > size()})
      */
     boolean addAll(int index, Collection<? extends E> c);
 
@@ -340,8 +363,8 @@
      * specified collection (optional operation).
      *
      * @param c collection containing elements to be removed from this list
-     * @return <tt>true</tt> if this list changed as a result of the call
-     * @throws UnsupportedOperationException if the <tt>removeAll</tt> operation
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code removeAll} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of an element of this list
      *         is incompatible with the specified collection
@@ -362,8 +385,8 @@
      * specified collection.
      *
      * @param c collection containing elements to be retained in this list
-     * @return <tt>true</tt> if this list changed as a result of the call
-     * @throws UnsupportedOperationException if the <tt>retainAll</tt> operation
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code retainAll} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of an element of this list
      *         is incompatible with the specified collection
@@ -510,7 +533,7 @@
      * Removes all of the elements from this list (optional operation).
      * The list will be empty after this call returns.
      *
-     * @throws UnsupportedOperationException if the <tt>clear</tt> operation
+     * @throws UnsupportedOperationException if the {@code clear} operation
      *         is not supported by this list
      */
     void clear();
@@ -520,17 +543,17 @@
 
     /**
      * Compares the specified object with this list for equality.  Returns
-     * <tt>true</tt> if and only if the specified object is also a list, both
+     * {@code true} if and only if the specified object is also a list, both
      * lists have the same size, and all corresponding pairs of elements in
-     * the two lists are <i>equal</i>.  (Two elements <tt>e1</tt> and
-     * <tt>e2</tt> are <i>equal</i> if <tt>(e1==null ? e2==null :
-     * e1.equals(e2))</tt>.)  In other words, two lists are defined to be
+     * the two lists are <i>equal</i>.  (Two elements {@code e1} and
+     * {@code e2} are <i>equal</i> if {@code Objects.equals(e1, e2)}.)
+     * In other words, two lists are defined to be
      * equal if they contain the same elements in the same order.  This
      * definition ensures that the equals method works properly across
-     * different implementations of the <tt>List</tt> interface.
+     * different implementations of the {@code List} interface.
      *
      * @param o the object to be compared for equality with this list
-     * @return <tt>true</tt> if the specified object is equal to this list
+     * @return {@code true} if the specified object is equal to this list
      */
     boolean equals(Object o);
 
@@ -542,9 +565,9 @@
      *     for (E e : list)
      *         hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
      * }</pre>
-     * This ensures that <tt>list1.equals(list2)</tt> implies that
-     * <tt>list1.hashCode()==list2.hashCode()</tt> for any two lists,
-     * <tt>list1</tt> and <tt>list2</tt>, as required by the general
+     * This ensures that {@code list1.equals(list2)} implies that
+     * {@code list1.hashCode()==list2.hashCode()} for any two lists,
+     * {@code list1} and {@code list2}, as required by the general
      * contract of {@link Object#hashCode}.
      *
      * @return the hash code value for this list
@@ -562,7 +585,7 @@
      * @param index index of the element to return
      * @return the element at the specified position in this list
      * @throws IndexOutOfBoundsException if the index is out of range
-     *         (<tt>index &lt; 0 || index &gt;= size()</tt>)
+     *         ({@code index < 0 || index >= size()})
      */
     E get(int index);
 
@@ -573,7 +596,7 @@
      * @param index index of the element to replace
      * @param element element to be stored at the specified position
      * @return the element previously at the specified position
-     * @throws UnsupportedOperationException if the <tt>set</tt> operation
+     * @throws UnsupportedOperationException if the {@code set} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of the specified element
      *         prevents it from being added to this list
@@ -582,7 +605,7 @@
      * @throws IllegalArgumentException if some property of the specified
      *         element prevents it from being added to this list
      * @throws IndexOutOfBoundsException if the index is out of range
-     *         (<tt>index &lt; 0 || index &gt;= size()</tt>)
+     *         ({@code index < 0 || index >= size()})
      */
     E set(int index, E element);
 
@@ -594,7 +617,7 @@
      *
      * @param index index at which the specified element is to be inserted
      * @param element element to be inserted
-     * @throws UnsupportedOperationException if the <tt>add</tt> operation
+     * @throws UnsupportedOperationException if the {@code add} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of the specified element
      *         prevents it from being added to this list
@@ -603,7 +626,7 @@
      * @throws IllegalArgumentException if some property of the specified
      *         element prevents it from being added to this list
      * @throws IndexOutOfBoundsException if the index is out of range
-     *         (<tt>index &lt; 0 || index &gt; size()</tt>)
+     *         ({@code index < 0 || index > size()})
      */
     void add(int index, E element);
 
@@ -615,10 +638,10 @@
      *
      * @param index the index of the element to be removed
      * @return the element previously at the specified position
-     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
+     * @throws UnsupportedOperationException if the {@code remove} operation
      *         is not supported by this list
      * @throws IndexOutOfBoundsException if the index is out of range
-     *         (<tt>index &lt; 0 || index &gt;= size()</tt>)
+     *         ({@code index < 0 || index >= size()})
      */
     E remove(int index);
 
@@ -628,8 +651,8 @@
     /**
      * Returns the index of the first occurrence of the specified element
      * in this list, or -1 if this list does not contain the element.
-     * More formally, returns the lowest index <tt>i</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
+     * More formally, returns the lowest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
      * or -1 if there is no such index.
      *
      * @param o element to search for
@@ -647,8 +670,8 @@
     /**
      * Returns the index of the last occurrence of the specified element
      * in this list, or -1 if this list does not contain the element.
-     * More formally, returns the highest index <tt>i</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
+     * More formally, returns the highest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
      * or -1 if there is no such index.
      *
      * @param o element to search for
@@ -696,8 +719,8 @@
 
     /**
      * Returns a view of the portion of this list between the specified
-     * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.  (If
-     * <tt>fromIndex</tt> and <tt>toIndex</tt> are equal, the returned list is
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
+     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
      * empty.)  The returned list is backed by this list, so non-structural
      * changes in the returned list are reflected in this list, and vice-versa.
      * The returned list supports all of the optional list operations supported
@@ -711,9 +734,9 @@
      * <pre>{@code
      *      list.subList(from, to).clear();
      * }</pre>
-     * Similar idioms may be constructed for <tt>indexOf</tt> and
-     * <tt>lastIndexOf</tt>, and all of the algorithms in the
-     * <tt>Collections</tt> class can be applied to a subList.<p>
+     * Similar idioms may be constructed for {@code indexOf} and
+     * {@code lastIndexOf}, and all of the algorithms in the
+     * {@code Collections} class can be applied to a subList.<p>
      *
      * The semantics of the list returned by this method become undefined if
      * the backing list (i.e., this list) is <i>structurally modified</i> in
@@ -725,8 +748,8 @@
      * @param toIndex high endpoint (exclusive) of the subList
      * @return a view of the specified range within this list
      * @throws IndexOutOfBoundsException for an illegal endpoint index value
-     *         (<tt>fromIndex &lt; 0 || toIndex &gt; size ||
-     *         fromIndex &gt; toIndex</tt>)
+     *         ({@code fromIndex < 0 || toIndex > size ||
+     *         fromIndex > toIndex})
      */
     List<E> subList(int fromIndex, int toIndex);
 
@@ -739,9 +762,22 @@
      *
      * @implSpec
      * The default implementation creates a
-     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
-     * from the list's {@code Iterator}.  The spliterator inherits the
-     * <em>fail-fast</em> properties of the list's iterator.
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * spliterator as follows:
+     * <ul>
+     * <li>If the list is an instance of {@link RandomAccess} then the default
+     *     implementation creates a spliterator that traverses elements by
+     *     invoking the method {@link List#get}.  If such invocation results or
+     *     would result in an {@code IndexOutOfBoundsException} then the
+     *     spliterator will <em>fail-fast</em> and throw a
+     *     {@code ConcurrentModificationException}.
+     *     If the list is also an instance of {@link AbstractList} then the
+     *     spliterator will use the list's {@link AbstractList#modCount modCount}
+     *     field to provide additional <em>fail-fast</em> behavior.
+     * <li>Otherwise, the default implementation creates a spliterator from the
+     *     list's {@code Iterator}.  The spliterator inherits the
+     *     <em>fail-fast</em> of the list's iterator.
+     * </ul>
      *
      * @implNote
      * The created {@code Spliterator} additionally reports
@@ -752,6 +788,274 @@
      */
     @Override
     default Spliterator<E> spliterator() {
-        return Spliterators.spliterator(this, Spliterator.ORDERED);
+        if (this instanceof RandomAccess) {
+            return new AbstractList.RandomAccessSpliterator<>(this);
+        } else {
+            return Spliterators.spliterator(this, Spliterator.ORDERED);
+        }
+    }
+
+    /**
+     * Returns an immutable list containing zero elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @return an empty {@code List}
+     *
+     * @since 9
+     */
+    static <E> List<E> of() {
+        return ImmutableCollections.List0.instance();
+    }
+
+    /**
+     * Returns an immutable list containing one element.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the single element
+     * @return a {@code List} containing the specified element
+     * @throws NullPointerException if the element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1) {
+        return new ImmutableCollections.List1<>(e1);
+    }
+
+    /**
+     * Returns an immutable list containing two elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2) {
+        return new ImmutableCollections.List2<>(e1, e2);
+    }
+
+    /**
+     * Returns an immutable list containing three elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3);
+    }
+
+    /**
+     * Returns an immutable list containing four elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4);
+    }
+
+    /**
+     * Returns an immutable list containing five elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5);
+    }
+
+    /**
+     * Returns an immutable list containing six elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6);
+    }
+
+    /**
+     * Returns an immutable list containing seven elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7);
+    }
+
+    /**
+     * Returns an immutable list containing eight elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7, e8);
+    }
+
+    /**
+     * Returns an immutable list containing nine elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7, e8, e9);
+    }
+
+    /**
+     * Returns an immutable list containing ten elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @param e10 the tenth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7, e8, e9, e10);
+    }
+
+    /**
+     * Returns an immutable list containing an arbitrary number of elements.
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @apiNote
+     * This method also accepts a single array as an argument. The element type of
+     * the resulting list will be the component type of the array, and the size of
+     * the list will be equal to the length of the array. To create a list with
+     * a single element that is an array, do the following:
+     *
+     * <pre>{@code
+     *     String[] array = ... ;
+     *     List<String[]> list = List.<String[]>of(array);
+     * }</pre>
+     *
+     * This will cause the {@link List#of(Object) List.of(E)} method
+     * to be invoked instead.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param elements the elements to be contained in the list
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null} or if the array is {@code null}
+     *
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <E> List<E> of(E... elements) {
+        switch (elements.length) { // implicit null check of elements
+            case 0:
+                return ImmutableCollections.List0.instance();
+            case 1:
+                return new ImmutableCollections.List1<>(elements[0]);
+            case 2:
+                return new ImmutableCollections.List2<>(elements[0], elements[1]);
+            default:
+                return new ImmutableCollections.ListN<>(elements);
+        }
     }
 }
diff --git a/ojluni/src/main/java/java/util/Map.java b/ojluni/src/main/java/java/util/Map.java
index 2715b15..ed365ec 100644
--- a/ojluni/src/main/java/java/util/Map.java
+++ b/ojluni/src/main/java/java/util/Map.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -30,7 +30,6 @@
 import java.util.function.Function;
 import java.io.Serializable;
 
-// Android-changed: removed docs for removed OpenJDK 9 Immutable Map static methods
 // Android-changed: removed link to collections framework docs
 /**
  * An object that maps keys to values.  A map cannot contain duplicate keys;
@@ -112,6 +111,35 @@
  * Implementations may optionally handle the self-referential scenario, however
  * most current implementations do not do so.
  *
+ * <h2><a id="immutable">Immutable Map Static Factory Methods</a></h2>
+ * <p>The {@link Map#of() Map.of()} and
+ * {@link Map#ofEntries(Map.Entry...) Map.ofEntries()}
+ * static factory methods provide a convenient way to create immutable maps.
+ * The {@code Map}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <em>structurally immutable</em>. Keys and values cannot be added,
+ * removed, or updated. Calling any mutator method will always cause
+ * {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained keys or values are themselves mutable, this may cause the
+ * Map to behave inconsistently or its contents to appear to change.
+ * <li>They disallow {@code null} keys and values. Attempts to create them with
+ * {@code null} keys or values result in {@code NullPointerException}.
+ * <li>They are serializable if all keys and values are serializable.
+ * <li>They reject duplicate keys at creation time. Duplicate keys
+ * passed to a static factory method result in {@code IllegalArgumentException}.
+ * <li>The iteration order of mappings is unspecified and is subject to change.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Callers should make no assumptions about the identity of the returned instances.
+ * Factories are free to create new instances or reuse existing ones. Therefore,
+ * identity-sensitive operations on these instances (reference equality ({@code ==}),
+ * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
+ *
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
  *
@@ -1245,5 +1273,384 @@
         return newValue;
     }
 
-    // Android-removed: OpenJDK 9 Immutable Map static methods
+    /**
+     * Returns an immutable map containing zero mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @return an empty {@code Map}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of() {
+        return ImmutableCollections.Map0.instance();
+    }
+
+    /**
+     * Returns an immutable map containing a single mapping.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the mapping's key
+     * @param v1 the mapping's value
+     * @return a {@code Map} containing the specified mapping
+     * @throws NullPointerException if the key or the value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1) {
+        return new ImmutableCollections.Map1<>(k1, v1);
+    }
+
+    /**
+     * Returns an immutable map containing two mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if the keys are duplicates
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
+    }
+
+    /**
+     * Returns an immutable map containing three mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3);
+    }
+
+    /**
+     * Returns an immutable map containing four mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4);
+    }
+
+    /**
+     * Returns an immutable map containing five mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
+    }
+
+    /**
+     * Returns an immutable map containing six mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6);
+    }
+
+    /**
+     * Returns an immutable map containing seven mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7);
+    }
+
+    /**
+     * Returns an immutable map containing eight mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8);
+    }
+
+    /**
+     * Returns an immutable map containing nine mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @param k9 the ninth mapping's key
+     * @param v9 the ninth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8, k9, v9);
+    }
+
+    /**
+     * Returns an immutable map containing ten mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @param k9 the ninth mapping's key
+     * @param v9 the ninth mapping's value
+     * @param k10 the tenth mapping's key
+     * @param v10 the tenth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8, k9, v9, k10, v10);
+    }
+
+    /**
+     * Returns an immutable map containing keys and values extracted from the given entries.
+     * The entries themselves are not stored in the map.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @apiNote
+     * It is convenient to create the map entries using the {@link Map#entry Map.entry()} method.
+     * For example,
+     *
+     * <pre>{@code
+     *     import static java.util.Map.entry;
+     *
+     *     Map<Integer,String> map = Map.ofEntries(
+     *         entry(1, "a"),
+     *         entry(2, "b"),
+     *         entry(3, "c"),
+     *         ...
+     *         entry(26, "z"));
+     * }</pre>
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param entries {@code Map.Entry}s containing the keys and values from which the map is populated
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any entry, key, or value is {@code null}, or if
+     *         the {@code entries} array is {@code null}
+     *
+     * @see Map#entry Map.entry()
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
+        if (entries.length == 0) { // implicit null check of entries
+            return ImmutableCollections.Map0.instance();
+        } else if (entries.length == 1) {
+            return new ImmutableCollections.Map1<>(entries[0].getKey(),
+                                                   entries[0].getValue());
+        } else {
+            Object[] kva = new Object[entries.length << 1];
+            int a = 0;
+            for (Entry<? extends K, ? extends V> entry : entries) {
+                kva[a++] = entry.getKey();
+                kva[a++] = entry.getValue();
+            }
+            return new ImmutableCollections.MapN<>(kva);
+        }
+    }
+
+    /**
+     * Returns an immutable {@link Entry} containing the given key and value.
+     * These entries are suitable for populating {@code Map} instances using the
+     * {@link Map#ofEntries Map.ofEntries()} method.
+     * The {@code Entry} instances created by this method have the following characteristics:
+     *
+     * <ul>
+     * <li>They disallow {@code null} keys and values. Attempts to create them using a {@code null}
+     * key or value result in {@code NullPointerException}.
+     * <li>They are immutable. Calls to {@link Entry#setValue Entry.setValue()}
+     * on a returned {@code Entry} result in {@code UnsupportedOperationException}.
+     * <li>They are not serializable.
+     * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+     * Callers should make no assumptions about the identity of the returned instances.
+     * This method is free to create new instances or reuse existing ones. Therefore,
+     * identity-sensitive operations on these instances (reference equality ({@code ==}),
+     * identity hash code, and synchronization) are unreliable and should be avoided.
+     * </ul>
+     *
+     * @apiNote
+     * For a serializable {@code Entry}, see {@link AbstractMap.SimpleEntry} or
+     * {@link AbstractMap.SimpleImmutableEntry}.
+     *
+     * @param <K> the key's type
+     * @param <V> the value's type
+     * @param k the key
+     * @param v the value
+     * @return an {@code Entry} containing the specified key and value
+     * @throws NullPointerException if the key or value is {@code null}
+     *
+     * @see Map#ofEntries Map.ofEntries()
+     * @since 9
+     */
+    static <K, V> Entry<K, V> entry(K k, V v) {
+        // KeyValueHolder checks for nulls
+        return new KeyValueHolder<>(k, v);
+    }
 }
diff --git a/ojluni/src/main/java/java/util/Objects.java b/ojluni/src/main/java/java/util/Objects.java
index e526079..1f76487 100644
--- a/ojluni/src/main/java/java/util/Objects.java
+++ b/ojluni/src/main/java/java/util/Objects.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -25,13 +25,30 @@
 
 package java.util;
 
+import jdk.internal.util.Preconditions;
+
 import java.util.function.Supplier;
 
 /**
  * This class consists of {@code static} utility methods for operating
- * on objects.  These utilities include {@code null}-safe or {@code
- * null}-tolerant methods for computing the hash code of an object,
- * returning a string for an object, and comparing two objects.
+ * on objects, or checking certain conditions before operation.  These utilities
+ * include {@code null}-safe or {@code null}-tolerant methods for computing the
+ * hash code of an object, returning a string for an object, comparing two
+ * objects, and checking if indexes or sub-range values are out-of-bounds.
+ *
+ * @apiNote
+ * Static methods such as {@link Objects#checkIndex},
+ * {@link Objects#checkFromToIndex}, and {@link Objects#checkFromIndexSize} are
+ * provided for the convenience of checking if values corresponding to indexes
+ * and sub-ranges are out-of-bounds.
+ * Variations of these static methods support customization of the runtime
+ * exception, and corresponding exception detail message, that is thrown when
+ * values are out-of-bounds.  Such methods accept a functional interface
+ * argument, instances of {@code BiFunction}, that maps out-of-bound values to a
+ * runtime exception.  Care should be taken when using such methods in
+ * combination with an argument that is a lambda expression, method reference or
+ * class that capture values.  In such cases the cost of capture, related to
+ * functional interface allocation, may exceed the cost of checking bounds.
  *
  * @since 1.7
  */
@@ -266,6 +283,44 @@
     }
 
     /**
+     * Returns the first argument if it is non-{@code null} and
+     * otherwise returns the non-{@code null} second argument.
+     *
+     * @param obj an object
+     * @param defaultObj a non-{@code null} object to return if the first argument
+     *                   is {@code null}
+     * @param <T> the type of the reference
+     * @return the first argument if it is non-{@code null} and
+     *        otherwise the second argument if it is non-{@code null}
+     * @throws NullPointerException if both {@code obj} is null and
+     *        {@code defaultObj} is {@code null}
+     * @since 9
+     */
+    public static <T> T requireNonNullElse(T obj, T defaultObj) {
+        return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj");
+    }
+
+    /**
+     * Returns the first argument if it is non-{@code null} and otherwise
+     * returns the non-{@code null} value of {@code supplier.get()}.
+     *
+     * @param obj an object
+     * @param supplier of a non-{@code null} object to return if the first argument
+     *                 is {@code null}
+     * @param <T> the type of the first argument and return type
+     * @return the first argument if it is non-{@code null} and otherwise
+     *         the value from {@code supplier.get()} if it is non-{@code null}
+     * @throws NullPointerException if both {@code obj} is null and
+     *        either the {@code supplier} is {@code null} or
+     *        the {@code supplier.get()} value is {@code null}
+     * @since 9
+     */
+    public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier) {
+        return (obj != null) ? obj
+                : requireNonNull(requireNonNull(supplier, "supplier").get(), "supplier.get()");
+    }
+
+    /**
      * Checks that the specified object reference is not {@code null} and
      * throws a customized {@link NullPointerException} if it is.
      *
@@ -287,7 +342,86 @@
      */
     public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
         if (obj == null)
-            throw new NullPointerException(messageSupplier.get());
+            throw new NullPointerException(messageSupplier == null ?
+                                           null : messageSupplier.get());
         return obj;
     }
+
+    /**
+     * Checks if the {@code index} is within the bounds of the range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The {@code index} is defined to be out-of-bounds if any of the
+     * following inequalities is true:
+     * <ul>
+     *  <li>{@code index < 0}</li>
+     *  <li>{@code index >= length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param index the index
+     * @param length the upper-bound (exclusive) of the range
+     * @return {@code index} if it is within bounds of the range
+     * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds
+     * @since 9
+     */
+    // Android-removed: @ForceInline is an unsupported attribute.
+    //@ForceInline
+    public static
+    int checkIndex(int index, int length) {
+        return Preconditions.checkIndex(index, length, null);
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code toIndex} (exclusive) is within the bounds of range from {@code 0}
+     * (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out-of-bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code fromIndex > toIndex}</li>
+     *  <li>{@code toIndex > length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param fromIndex the lower-bound (inclusive) of the sub-range
+     * @param toIndex the upper-bound (exclusive) of the sub-range
+     * @param length the upper-bound (exclusive) the range
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds
+     * @since 9
+     */
+    public static
+    int checkFromToIndex(int fromIndex, int toIndex, int length) {
+        return Preconditions.checkFromToIndex(fromIndex, toIndex, length, null);
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code fromIndex + size} (exclusive) is within the bounds of range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out-of-bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code size < 0}</li>
+     *  <li>{@code fromIndex + size > length}, taking into account integer overflow</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param fromIndex the lower-bound (inclusive) of the sub-interval
+     * @param size the size of the sub-range
+     * @param length the upper-bound (exclusive) of the range
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds
+     * @since 9
+     */
+    public static
+    int checkFromIndexSize(int fromIndex, int size, int length) {
+        return Preconditions.checkFromIndexSize(fromIndex, size, length, null);
+    }
+
 }
diff --git a/ojluni/src/main/java/java/util/Set.java b/ojluni/src/main/java/java/util/Set.java
index 2703049..0499ea3 100644
--- a/ojluni/src/main/java/java/util/Set.java
+++ b/ojluni/src/main/java/java/util/Set.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -27,16 +27,16 @@
 
 /**
  * A collection that contains no duplicate elements.  More formally, sets
- * contain no pair of elements <code>e1</code> and <code>e2</code> such that
- * <code>e1.equals(e2)</code>, and at most one null element.  As implied by
+ * contain no pair of elements {@code e1} and {@code e2} such that
+ * {@code e1.equals(e2)}, and at most one null element.  As implied by
  * its name, this interface models the mathematical <i>set</i> abstraction.
  *
- * <p>The <tt>Set</tt> interface places additional stipulations, beyond those
- * inherited from the <tt>Collection</tt> interface, on the contracts of all
- * constructors and on the contracts of the <tt>add</tt>, <tt>equals</tt> and
- * <tt>hashCode</tt> methods.  Declarations for other inherited methods are
+ * <p>The {@code Set} interface places additional stipulations, beyond those
+ * inherited from the {@code Collection} interface, on the contracts of all
+ * constructors and on the contracts of the {@code add}, {@code equals} and
+ * {@code hashCode} methods.  Declarations for other inherited methods are
  * also included here for convenience.  (The specifications accompanying these
- * declarations have been tailored to the <tt>Set</tt> interface, but they do
+ * declarations have been tailored to the {@code Set} interface, but they do
  * not contain any additional stipulations.)
  *
  * <p>The additional stipulation on constructors is, not surprisingly,
@@ -45,7 +45,7 @@
  *
  * <p>Note: Great care must be exercised if mutable objects are used as set
  * elements.  The behavior of a set is not specified if the value of an object
- * is changed in a manner that affects <tt>equals</tt> comparisons while the
+ * is changed in a manner that affects {@code equals} comparisons while the
  * object is an element in the set.  A special case of this prohibition is
  * that it is not permissible for a set to contain itself as an element.
  *
@@ -53,7 +53,7 @@
  * they may contain.  For example, some implementations prohibit null elements,
  * and some have restrictions on the types of their elements.  Attempting to
  * add an ineligible element throws an unchecked exception, typically
- * <tt>NullPointerException</tt> or <tt>ClassCastException</tt>.  Attempting
+ * {@code NullPointerException} or {@code ClassCastException}.  Attempting
  * to query the presence of an ineligible element may throw an exception,
  * or it may simply return false; some implementations will exhibit the former
  * behavior and some will exhibit the latter.  More generally, attempting an
@@ -63,6 +63,33 @@
  * Such exceptions are marked as "optional" in the specification for this
  * interface.
  *
+ * <h2><a id="immutable">Immutable Set Static Factory Methods</a></h2>
+ * <p>The {@link Set#of(Object...) Set.of()} static factory methods
+ * provide a convenient way to create immutable sets. The {@code Set}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <em>structurally immutable</em>. Elements cannot be added or
+ * removed. Calling any mutator method will always cause
+ * {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained elements are themselves mutable, this may cause the
+ * Set to behave inconsistently or its contents to appear to change.
+ * <li>They disallow {@code null} elements. Attempts to create them with
+ * {@code null} elements result in {@code NullPointerException}.
+ * <li>They are serializable if all elements are serializable.
+ * <li>They reject duplicate elements at creation time. Duplicate elements
+ * passed to a static factory method result in {@code IllegalArgumentException}.
+ * <li>The iteration order of set elements is unspecified and is subject to change.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Callers should make no assumptions about the identity of the returned instances.
+ * Factories are free to create new instances or reuse existing ones. Therefore,
+ * identity-sensitive operations on these instances (reference equality ({@code ==}),
+ * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
+ *
  * <p>This interface is a member of the
  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
@@ -87,28 +114,28 @@
 
     /**
      * Returns the number of elements in this set (its cardinality).  If this
-     * set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
-     * <tt>Integer.MAX_VALUE</tt>.
+     * set contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
      *
      * @return the number of elements in this set (its cardinality)
      */
     int size();
 
     /**
-     * Returns <tt>true</tt> if this set contains no elements.
+     * Returns {@code true} if this set contains no elements.
      *
-     * @return <tt>true</tt> if this set contains no elements
+     * @return {@code true} if this set contains no elements
      */
     boolean isEmpty();
 
     /**
-     * Returns <tt>true</tt> if this set contains the specified element.
-     * More formally, returns <tt>true</tt> if and only if this set
-     * contains an element <tt>e</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that
+     * {@code Objects.equals(o, e)}.
      *
      * @param o element whose presence in this set is to be tested
-     * @return <tt>true</tt> if this set contains the specified element
+     * @return {@code true} if this set contains the specified element
      * @throws ClassCastException if the type of the specified element
      *         is incompatible with this set
      * (<a href="Collection.html#optional-restrictions">optional</a>)
@@ -155,7 +182,7 @@
      * <p>If this set fits in the specified array with room to spare
      * (i.e., the array has more elements than this set), the element in
      * the array immediately following the end of the set is set to
-     * <tt>null</tt>.  (This is useful in determining the length of this
+     * {@code null}.  (This is useful in determining the length of this
      * set <i>only</i> if the caller knows that this set does not contain
      * any null elements.)
      *
@@ -168,15 +195,15 @@
      * precise control over the runtime type of the output array, and may,
      * under certain circumstances, be used to save allocation costs.
      *
-     * <p>Suppose <tt>x</tt> is a set known to contain only strings.
+     * <p>Suppose {@code x} is a set known to contain only strings.
      * The following code can be used to dump the set into a newly allocated
-     * array of <tt>String</tt>:
+     * array of {@code String}:
      *
      * <pre>
      *     String[] y = x.toArray(new String[0]);</pre>
      *
-     * Note that <tt>toArray(new Object[0])</tt> is identical in function to
-     * <tt>toArray()</tt>.
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
      *
      * @param a the array into which the elements of this set are to be
      *        stored, if it is big enough; otherwise, a new array of the same
@@ -195,25 +222,25 @@
     /**
      * Adds the specified element to this set if it is not already present
      * (optional operation).  More formally, adds the specified element
-     * <tt>e</tt> to this set if the set contains no element <tt>e2</tt>
+     * {@code e} to this set if the set contains no element {@code e2}
      * such that
-     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
+     * {@code Objects.equals(e, e2)}.
      * If this set already contains the element, the call leaves the set
-     * unchanged and returns <tt>false</tt>.  In combination with the
+     * unchanged and returns {@code false}.  In combination with the
      * restriction on constructors, this ensures that sets never contain
      * duplicate elements.
      *
      * <p>The stipulation above does not imply that sets must accept all
      * elements; sets may refuse to add any particular element, including
-     * <tt>null</tt>, and throw an exception, as described in the
+     * {@code null}, and throw an exception, as described in the
      * specification for {@link Collection#add Collection.add}.
      * Individual set implementations should clearly document any
      * restrictions on the elements that they may contain.
      *
      * @param e element to be added to this set
-     * @return <tt>true</tt> if this set did not already contain the specified
+     * @return {@code true} if this set did not already contain the specified
      *         element
-     * @throws UnsupportedOperationException if the <tt>add</tt> operation
+     * @throws UnsupportedOperationException if the {@code add} operation
      *         is not supported by this set
      * @throws ClassCastException if the class of the specified element
      *         prevents it from being added to this set
@@ -227,23 +254,23 @@
 
     /**
      * Removes the specified element from this set if it is present
-     * (optional operation).  More formally, removes an element <tt>e</tt>
+     * (optional operation).  More formally, removes an element {@code e}
      * such that
-     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>, if
-     * this set contains such an element.  Returns <tt>true</tt> if this set
+     * {@code Objects.equals(o, e)}, if
+     * this set contains such an element.  Returns {@code true} if this set
      * contained the element (or equivalently, if this set changed as a
      * result of the call).  (This set will not contain the element once the
      * call returns.)
      *
      * @param o object to be removed from this set, if present
-     * @return <tt>true</tt> if this set contained the specified element
+     * @return {@code true} if this set contained the specified element
      * @throws ClassCastException if the type of the specified element
      *         is incompatible with this set
      * (<a href="Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null and this
      *         set does not permit null elements
      * (<a href="Collection.html#optional-restrictions">optional</a>)
-     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
+     * @throws UnsupportedOperationException if the {@code remove} operation
      *         is not supported by this set
      */
     boolean remove(Object o);
@@ -252,12 +279,12 @@
     // Bulk Operations
 
     /**
-     * Returns <tt>true</tt> if this set contains all of the elements of the
+     * Returns {@code true} if this set contains all of the elements of the
      * specified collection.  If the specified collection is also a set, this
-     * method returns <tt>true</tt> if it is a <i>subset</i> of this set.
+     * method returns {@code true} if it is a <i>subset</i> of this set.
      *
      * @param  c collection to be checked for containment in this set
-     * @return <tt>true</tt> if this set contains all of the elements of the
+     * @return {@code true} if this set contains all of the elements of the
      *         specified collection
      * @throws ClassCastException if the types of one or more elements
      *         in the specified collection are incompatible with this
@@ -275,15 +302,15 @@
     /**
      * Adds all of the elements in the specified collection to this set if
      * they're not already present (optional operation).  If the specified
-     * collection is also a set, the <tt>addAll</tt> operation effectively
+     * collection is also a set, the {@code addAll} operation effectively
      * modifies this set so that its value is the <i>union</i> of the two
      * sets.  The behavior of this operation is undefined if the specified
      * collection is modified while the operation is in progress.
      *
      * @param  c collection containing elements to be added to this set
-     * @return <tt>true</tt> if this set changed as a result of the call
+     * @return {@code true} if this set changed as a result of the call
      *
-     * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
+     * @throws UnsupportedOperationException if the {@code addAll} operation
      *         is not supported by this set
      * @throws ClassCastException if the class of an element of the
      *         specified collection prevents it from being added to this set
@@ -305,8 +332,8 @@
      * <i>intersection</i> of the two sets.
      *
      * @param  c collection containing elements to be retained in this set
-     * @return <tt>true</tt> if this set changed as a result of the call
-     * @throws UnsupportedOperationException if the <tt>retainAll</tt> operation
+     * @return {@code true} if this set changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code retainAll} operation
      *         is not supported by this set
      * @throws ClassCastException if the class of an element of this set
      *         is incompatible with the specified collection
@@ -327,8 +354,8 @@
      * the two sets.
      *
      * @param  c collection containing elements to be removed from this set
-     * @return <tt>true</tt> if this set changed as a result of the call
-     * @throws UnsupportedOperationException if the <tt>removeAll</tt> operation
+     * @return {@code true} if this set changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code removeAll} operation
      *         is not supported by this set
      * @throws ClassCastException if the class of an element of this set
      *         is incompatible with the specified collection
@@ -346,7 +373,7 @@
      * Removes all of the elements from this set (optional operation).
      * The set will be empty after this call returns.
      *
-     * @throws UnsupportedOperationException if the <tt>clear</tt> method
+     * @throws UnsupportedOperationException if the {@code clear} method
      *         is not supported by this set
      */
     void clear();
@@ -356,7 +383,7 @@
 
     /**
      * Compares the specified object with this set for equality.  Returns
-     * <tt>true</tt> if the specified object is also a set, the two sets
+     * {@code true} if the specified object is also a set, the two sets
      * have the same size, and every member of the specified set is
      * contained in this set (or equivalently, every member of this set is
      * contained in the specified set).  This definition ensures that the
@@ -364,17 +391,17 @@
      * set interface.
      *
      * @param o object to be compared for equality with this set
-     * @return <tt>true</tt> if the specified object is equal to this set
+     * @return {@code true} if the specified object is equal to this set
      */
     boolean equals(Object o);
 
     /**
      * Returns the hash code value for this set.  The hash code of a set is
      * defined to be the sum of the hash codes of the elements in the set,
-     * where the hash code of a <tt>null</tt> element is defined to be zero.
-     * This ensures that <tt>s1.equals(s2)</tt> implies that
-     * <tt>s1.hashCode()==s2.hashCode()</tt> for any two sets <tt>s1</tt>
-     * and <tt>s2</tt>, as required by the general contract of
+     * where the hash code of a {@code null} element is defined to be zero.
+     * This ensures that {@code s1.equals(s2)} implies that
+     * {@code s1.hashCode()==s2.hashCode()} for any two sets {@code s1}
+     * and {@code s2}, as required by the general contract of
      * {@link Object#hashCode}.
      *
      * @return the hash code value for this set
@@ -410,4 +437,267 @@
     default Spliterator<E> spliterator() {
         return Spliterators.spliterator(this, Spliterator.DISTINCT);
     }
+
+    /**
+     * Returns an immutable set containing zero elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @return an empty {@code Set}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of() {
+        return ImmutableCollections.Set0.instance();
+    }
+
+    /**
+     * Returns an immutable set containing one element.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the single element
+     * @return a {@code Set} containing the specified element
+     * @throws NullPointerException if the element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1) {
+        return new ImmutableCollections.Set1<>(e1);
+    }
+
+    /**
+     * Returns an immutable set containing two elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if the elements are duplicates
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2) {
+        return new ImmutableCollections.Set2<>(e1, e2);
+    }
+
+    /**
+     * Returns an immutable set containing three elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3);
+    }
+
+    /**
+     * Returns an immutable set containing four elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4);
+    }
+
+    /**
+     * Returns an immutable set containing five elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5);
+    }
+
+    /**
+     * Returns an immutable set containing six elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6);
+    }
+
+    /**
+     * Returns an immutable set containing seven elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7);
+    }
+
+    /**
+     * Returns an immutable set containing eight elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8);
+    }
+
+    /**
+     * Returns an immutable set containing nine elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8, e9);
+    }
+
+    /**
+     * Returns an immutable set containing ten elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @param e10 the tenth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8, e9, e10);
+    }
+
+    /**
+     * Returns an immutable set containing an arbitrary number of elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @apiNote
+     * This method also accepts a single array as an argument. The element type of
+     * the resulting set will be the component type of the array, and the size of
+     * the set will be equal to the length of the array. To create a set with
+     * a single element that is an array, do the following:
+     *
+     * <pre>{@code
+     *     String[] array = ... ;
+     *     Set<String[]> list = Set.<String[]>of(array);
+     * }</pre>
+     *
+     * This will cause the {@link Set#of(Object) Set.of(E)} method
+     * to be invoked instead.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param elements the elements to be contained in the set
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null} or if the array is {@code null}
+     *
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <E> Set<E> of(E... elements) {
+        switch (elements.length) { // implicit null check of elements
+            case 0:
+                return ImmutableCollections.Set0.instance();
+            case 1:
+                return new ImmutableCollections.Set1<>(elements[0]);
+            case 2:
+                return new ImmutableCollections.Set2<>(elements[0], elements[1]);
+            default:
+                return new ImmutableCollections.SetN<>(elements);
+        }
+    }
 }
diff --git a/ojluni/src/main/java/jdk/internal/util/Preconditions.java b/ojluni/src/main/java/jdk/internal/util/Preconditions.java
new file mode 100644
index 0000000..0e91afd
--- /dev/null
+++ b/ojluni/src/main/java/jdk/internal/util/Preconditions.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.util;
+
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/**
+ * Utility methods to check if state or arguments are correct.
+ *
+ */
+public class Preconditions {
+
+    /**
+     * Maps out-of-bounds values to a runtime exception.
+     *
+     * @param checkKind the kind of bounds check, whose name may correspond
+     *        to the name of one of the range check methods, checkIndex,
+     *        checkFromToIndex, checkFromIndexSize
+     * @param args the out-of-bounds arguments that failed the range check.
+     *        If the checkKind corresponds a the name of a range check method
+     *        then the bounds arguments are those that can be passed in order
+     *        to the method.
+     * @param oobef the exception formatter that when applied with a checkKind
+     *        and a list out-of-bounds arguments returns a runtime exception.
+     *        If {@code null} then, it is as if an exception formatter was
+     *        supplied that returns {@link IndexOutOfBoundsException} for any
+     *        given arguments.
+     * @return the runtime exception
+     */
+    private static RuntimeException outOfBounds(
+            BiFunction<String, List<Integer>, ? extends RuntimeException> oobef,
+            String checkKind,
+            Integer... args) {
+        List<Integer> largs = List.of(args);
+        RuntimeException e = oobef == null
+                             ? null : oobef.apply(checkKind, largs);
+        return e == null
+               ? new IndexOutOfBoundsException(outOfBoundsMessage(checkKind, largs)) : e;
+    }
+
+    private static RuntimeException outOfBoundsCheckIndex(
+            BiFunction<String, List<Integer>, ? extends RuntimeException> oobe,
+            int index, int length) {
+        return outOfBounds(oobe, "checkIndex", index, length);
+    }
+
+    private static RuntimeException outOfBoundsCheckFromToIndex(
+            BiFunction<String, List<Integer>, ? extends RuntimeException> oobe,
+            int fromIndex, int toIndex, int length) {
+        return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length);
+    }
+
+    private static RuntimeException outOfBoundsCheckFromIndexSize(
+            BiFunction<String, List<Integer>, ? extends RuntimeException> oobe,
+            int fromIndex, int size, int length) {
+        return outOfBounds(oobe, "checkFromIndexSize", fromIndex, size, length);
+    }
+
+    /**
+     * Returns an out-of-bounds exception formatter from an given exception
+     * factory.  The exception formatter is a function that formats an
+     * out-of-bounds message from its arguments and applies that message to the
+     * given exception factory to produce and relay an exception.
+     *
+     * <p>The exception formatter accepts two arguments: a {@code String}
+     * describing the out-of-bounds range check that failed, referred to as the
+     * <em>check kind</em>; and a {@code List<Integer>} containing the
+     * out-of-bound integer values that failed the check.  The list of
+     * out-of-bound values is not modified.
+     *
+     * <p>Three check kinds are supported {@code checkIndex},
+     * {@code checkFromToIndex} and {@code checkFromIndexSize} corresponding
+     * respectively to the specified application of an exception formatter as an
+     * argument to the out-of-bounds range check methods
+     * {@link #checkIndex(int, int, BiFunction) checkIndex},
+     * {@link #checkFromToIndex(int, int, int, BiFunction) checkFromToIndex}, and
+     * {@link #checkFromIndexSize(int, int, int, BiFunction) checkFromIndexSize}.
+     * Thus a supported check kind corresponds to a method name and the
+     * out-of-bound integer values correspond to method argument values, in
+     * order, preceding the exception formatter argument (similar in many
+     * respects to the form of arguments required for a reflective invocation of
+     * such a range check method).
+     *
+     * <p>Formatter arguments conforming to such supported check kinds will
+     * produce specific exception messages describing failed out-of-bounds
+     * checks.  Otherwise, more generic exception messages will be produced in
+     * any of the following cases: the check kind is supported but fewer
+     * or more out-of-bounds values are supplied, the check kind is not
+     * supported, the check kind is {@code null}, or the list of out-of-bound
+     * values is {@code null}.
+     *
+     * @apiNote
+     * This method produces an out-of-bounds exception formatter that can be
+     * passed as an argument to any of the supported out-of-bounds range check
+     * methods declared by {@code Objects}.  For example, a formatter producing
+     * an {@code ArrayIndexOutOfBoundsException} may be produced and stored on a
+     * {@code static final} field as follows:
+     * <pre>{@code
+     * static final
+     * BiFunction<String, List<Integer>, ArrayIndexOutOfBoundsException> AIOOBEF =
+     *     outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new);
+     * }</pre>
+     * The formatter instance {@code AIOOBEF} may be passed as an argument to an
+     * out-of-bounds range check method, such as checking if an {@code index}
+     * is within the bounds of a {@code limit}:
+     * <pre>{@code
+     * checkIndex(index, limit, AIOOBEF);
+     * }</pre>
+     * If the bounds check fails then the range check method will throw an
+     * {@code ArrayIndexOutOfBoundsException} with an appropriate exception
+     * message that is a produced from {@code AIOOBEF} as follows:
+     * <pre>{@code
+     * AIOOBEF.apply("checkIndex", List.of(index, limit));
+     * }</pre>
+     *
+     * @param f the exception factory, that produces an exception from a message
+     *        where the message is produced and formatted by the returned
+     *        exception formatter.  If this factory is stateless and side-effect
+     *        free then so is the returned formatter.
+     *        Exceptions thrown by the factory are relayed to the caller
+     *        of the returned formatter.
+     * @param <X> the type of runtime exception to be returned by the given
+     *        exception factory and relayed by the exception formatter
+     * @return the out-of-bounds exception formatter
+     */
+    public static <X extends RuntimeException>
+    BiFunction<String, List<Integer>, X> outOfBoundsExceptionFormatter(Function<String, X> f) {
+        // Use anonymous class to avoid bootstrap issues if this method is
+        // used early in startup
+        return new BiFunction<String, List<Integer>, X>() {
+            @Override
+            public X apply(String checkKind, List<Integer> args) {
+                return f.apply(outOfBoundsMessage(checkKind, args));
+            }
+        };
+    }
+
+    private static String outOfBoundsMessage(String checkKind, List<Integer> args) {
+        if (checkKind == null && args == null) {
+            return String.format("Range check failed");
+        } else if (checkKind == null) {
+            return String.format("Range check failed: %s", args);
+        } else if (args == null) {
+            return String.format("Range check failed: %s", checkKind);
+        }
+
+        int argSize = 0;
+        switch (checkKind) {
+            case "checkIndex":
+                argSize = 2;
+                break;
+            case "checkFromToIndex":
+            case "checkFromIndexSize":
+                argSize = 3;
+                break;
+            default:
+        }
+
+        // Switch to default if fewer or more arguments than required are supplied
+        switch ((args.size() != argSize) ? "" : checkKind) {
+            case "checkIndex":
+                return String.format("Index %d out-of-bounds for length %d",
+                                     args.get(0), args.get(1));
+            case "checkFromToIndex":
+                return String.format("Range [%d, %d) out-of-bounds for length %d",
+                                     args.get(0), args.get(1), args.get(2));
+            case "checkFromIndexSize":
+                return String.format("Range [%d, %<d + %d) out-of-bounds for length %d",
+                                     args.get(0), args.get(1), args.get(2));
+            default:
+                return String.format("Range check failed: %s %s", checkKind, args);
+        }
+    }
+
+    /**
+     * Checks if the {@code index} is within the bounds of the range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The {@code index} is defined to be out-of-bounds if any of the
+     * following inequalities is true:
+     * <ul>
+     *  <li>{@code index < 0}</li>
+     *  <li>{@code index >= length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * <p>If the {@code index} is out-of-bounds, then a runtime exception is
+     * thrown that is the result of applying the following arguments to the
+     * exception formatter: the name of this method, {@code checkIndex};
+     * and an unmodifiable list integers whose values are, in order, the
+     * out-of-bounds arguments {@code index} and {@code length}.
+     *
+     * @param <X> the type of runtime exception to throw if the arguments are
+     *        out-of-bounds
+     * @param index the index
+     * @param length the upper-bound (exclusive) of the range
+     * @param oobef the exception formatter that when applied with this
+     *        method name and out-of-bounds arguments returns a runtime
+     *        exception.  If {@code null} or returns {@code null} then, it is as
+     *        if an exception formatter produced from an invocation of
+     *        {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used
+     *        instead (though it may be more efficient).
+     *        Exceptions thrown by the formatter are relayed to the caller.
+     * @return {@code index} if it is within bounds of the range
+     * @throws X if the {@code index} is out-of-bounds and the exception
+     *         formatter is non-{@code null}
+     * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds
+     *         and the exception formatter is {@code null}
+     * @since 9
+     *
+     * @implNote
+     * This method is made intrinsic in optimizing compilers to guide them to
+     * perform unsigned comparisons of the index and length when it is known the
+     * length is a non-negative value (such as that of an array length or from
+     * the upper bound of a loop)
+    */
+    // Android-removed: @HotSpotIntrinsicCandidate not present on Android yet (could reconsider).
+    // @HotSpotIntrinsicCandidate
+    public static <X extends RuntimeException>
+    int checkIndex(int index, int length,
+                   BiFunction<String, List<Integer>, X> oobef) {
+        if (index < 0 || index >= length)
+            throw outOfBoundsCheckIndex(oobef, index, length);
+        return index;
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code toIndex} (exclusive) is within the bounds of range from {@code 0}
+     * (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out-of-bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code fromIndex > toIndex}</li>
+     *  <li>{@code toIndex > length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * <p>If the sub-range  is out-of-bounds, then a runtime exception is
+     * thrown that is the result of applying the following arguments to the
+     * exception formatter: the name of this method, {@code checkFromToIndex};
+     * and an unmodifiable list integers whose values are, in order, the
+     * out-of-bounds arguments {@code fromIndex}, {@code toIndex}, and {@code length}.
+     *
+     * @param <X> the type of runtime exception to throw if the arguments are
+     *        out-of-bounds
+     * @param fromIndex the lower-bound (inclusive) of the sub-range
+     * @param toIndex the upper-bound (exclusive) of the sub-range
+     * @param length the upper-bound (exclusive) the range
+     * @param oobef the exception formatter that when applied with this
+     *        method name and out-of-bounds arguments returns a runtime
+     *        exception.  If {@code null} or returns {@code null} then, it is as
+     *        if an exception formatter produced from an invocation of
+     *        {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used
+     *        instead (though it may be more efficient).
+     *        Exceptions thrown by the formatter are relayed to the caller.
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws X if the sub-range is out-of-bounds and the exception factory
+     *         function is non-{@code null}
+     * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and
+     *         the exception factory function is {@code null}
+     * @since 9
+     */
+    public static <X extends RuntimeException>
+    int checkFromToIndex(int fromIndex, int toIndex, int length,
+                         BiFunction<String, List<Integer>, X> oobef) {
+        if (fromIndex < 0 || fromIndex > toIndex || toIndex > length)
+            throw outOfBoundsCheckFromToIndex(oobef, fromIndex, toIndex, length);
+        return fromIndex;
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code fromIndex + size} (exclusive) is within the bounds of range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out-of-bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code size < 0}</li>
+     *  <li>{@code fromIndex + size > length}, taking into account integer overflow</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * <p>If the sub-range  is out-of-bounds, then a runtime exception is
+     * thrown that is the result of applying the following arguments to the
+     * exception formatter: the name of this method, {@code checkFromIndexSize};
+     * and an unmodifiable list integers whose values are, in order, the
+     * out-of-bounds arguments {@code fromIndex}, {@code size}, and
+     * {@code length}.
+     *
+     * @param <X> the type of runtime exception to throw if the arguments are
+     *        out-of-bounds
+     * @param fromIndex the lower-bound (inclusive) of the sub-interval
+     * @param size the size of the sub-range
+     * @param length the upper-bound (exclusive) of the range
+     * @param oobef the exception formatter that when applied with this
+     *        method name and out-of-bounds arguments returns a runtime
+     *        exception.  If {@code null} or returns {@code null} then, it is as
+     *        if an exception formatter produced from an invocation of
+     *        {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used
+     *        instead (though it may be more efficient).
+     *        Exceptions thrown by the formatter are relayed to the caller.
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws X if the sub-range is out-of-bounds and the exception factory
+     *         function is non-{@code null}
+     * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and
+     *         the exception factory function is {@code null}
+     * @since 9
+     */
+    public static <X extends RuntimeException>
+    int checkFromIndexSize(int fromIndex, int size, int length,
+                           BiFunction<String, List<Integer>, X> oobef) {
+        if ((length | fromIndex | size) < 0 || size > length - fromIndex)
+            throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length);
+        return fromIndex;
+    }
+}
diff --git a/ojluni/src/main/java/jdk/internal/vm/annotation/Stable.java b/ojluni/src/main/java/jdk/internal/vm/annotation/Stable.java
new file mode 100644
index 0000000..34b6540
--- /dev/null
+++ b/ojluni/src/main/java/jdk/internal/vm/annotation/Stable.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012, 2013, 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 jdk.internal.vm.annotation;
+
+import java.lang.annotation.*;
+
+// Android-removed: HotSpot-specific implementation notes not relevant for Android.
+/**
+ * A field may be annotated as stable if all of its component variables
+ * changes value at most once.
+ * A field's value counts as its component value.
+ * If the field is typed as an array, then all the non-null components
+ * of the array, of depth up to the rank of the field's array type,
+ * also count as component values.
+ * By extension, any variable (either array or field) which has annotated
+ * as stable is called a stable variable, and its non-null or non-zero
+ * value is called a stable value.
+ * <p>
+ * Since all fields begin with a default value of null for references
+ * (resp., zero for primitives), it follows that this annotation indicates
+ * that the first non-null (resp., non-zero) value stored in the field
+ * will never be changed.
+ * <p>
+ * If the field is not of an array type, there are no array elements,
+ * then the value indicated as stable is simply the value of the field.
+ * If the dynamic type of the field value is an array but the static type
+ * is not, the components of the array are <em>not</em> regarded as stable.
+ * <p>
+ * If the field is an array type, then both the field value and
+ * all the components of the field value (if the field value is non-null)
+ * are indicated to be stable.
+ * If the field type is an array type with rank {@code N > 1},
+ * then each component of the field value (if the field value is non-null),
+ * is regarded as a stable array of rank {@code N-1}.
+ * <p>
+ * Fields which are declared {@code final} may also be annotated as stable.
+ * Since final fields already behave as stable values, such an annotation
+ * conveys no additional information regarding change of the field's value, but
+ * still conveys information regarding change of additional components values if
+ * the type of the field is an array type (as described above).
+ * <p>
+ * It is (currently) undefined what happens if a field annotated as stable
+ * is given a third value (by explicitly updating a stable field, a component of
+ * a stable array, or a final stable field via reflection or other means).
+ *
+ * @implNote
+ * This annotation only takes effect for fields of classes loaded by the boot
+ * loader.  Annoations on fields of classes loaded outside of the boot loader
+ * are ignored.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Stable {
+}
diff --git a/openjdk_java_files.bp b/openjdk_java_files.bp
index 0db67c7..31f5447 100644
--- a/openjdk_java_files.bp
+++ b/openjdk_java_files.bp
@@ -1434,6 +1434,8 @@
         "ojluni/src/main/java/java/beans/ChangeListenerMap.java",
         "ojluni/src/main/java/java/time/zone/IcuZoneRulesProvider.java",
         "ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java",
+        "ojluni/src/main/java/java/util/ImmutableCollections.java",
+        "ojluni/src/main/java/java/util/KeyValueHolder.java",
         "ojluni/src/main/java/java/util/JapaneseImperialCalendar.java",
         "ojluni/src/main/java/java/util/concurrent/Flow.java",
         "ojluni/src/main/java/sun/misc/FDBigInteger.java",
@@ -1442,6 +1444,8 @@
         "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/jdk/internal/vm/annotation/Stable.java",
+        "ojluni/src/main/java/jdk/internal/util/Preconditions.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",